├── src ├── Backend │ ├── Shared │ │ └── Euro2024Challenge.Shared │ │ │ ├── Events │ │ │ ├── IEvent.cs │ │ │ ├── IEventHandler.cs │ │ │ ├── IEventDispatcher.cs │ │ │ ├── IEventBus.cs │ │ │ ├── InMemoryMessageQueue.cs │ │ │ ├── EventBus.cs │ │ │ ├── IntegrationEventProcessorJob.cs │ │ │ └── EventDispatcher.cs │ │ │ ├── Domain │ │ │ ├── IAggregateRoot.cs │ │ │ ├── BaseEntity.cs │ │ │ └── ValueObject.cs │ │ │ ├── Database │ │ │ ├── IUnitOfWork.cs │ │ │ ├── DatabaseOptions.cs │ │ │ ├── UnitOfWork.cs │ │ │ ├── DatabaseOptionsSetup.cs │ │ │ └── Extensions.cs │ │ │ ├── DependencyInjection.cs │ │ │ └── Euro2024Challenge.Shared.csproj │ ├── Modules │ │ ├── Tournaments │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournaments.Core │ │ │ │ ├── DTO │ │ │ │ │ ├── AddTeamRequest.cs │ │ │ │ │ ├── GetFootballerRequest.cs │ │ │ │ │ ├── UpdateFootballerGoalsRequest.cs │ │ │ │ │ ├── AddFootballerRequest.cs │ │ │ │ │ ├── UpdateMatchResultRequest.cs │ │ │ │ │ └── AddMatchRequest.cs │ │ │ │ ├── Cache │ │ │ │ │ ├── ITeamsCache.cs │ │ │ │ │ └── TeamsCache.cs │ │ │ │ ├── Services │ │ │ │ │ ├── IFootballerService.cs │ │ │ │ │ ├── ITeamService.cs │ │ │ │ │ ├── IMatchService.cs │ │ │ │ │ ├── FootballerService.cs │ │ │ │ │ ├── TeamService.cs │ │ │ │ │ └── MatchService.cs │ │ │ │ ├── Repositories │ │ │ │ │ ├── IFootballerRepository.cs │ │ │ │ │ ├── ITeamRepository.cs │ │ │ │ │ ├── IMatchRepository.cs │ │ │ │ │ ├── FootballerRepository.cs │ │ │ │ │ ├── TeamRepository.cs │ │ │ │ │ └── MatchRepository.cs │ │ │ │ ├── Entities │ │ │ │ │ ├── Team.cs │ │ │ │ │ ├── Footballer.cs │ │ │ │ │ └── Match.cs │ │ │ │ ├── BackgroundServices │ │ │ │ │ └── FetchTournamentDataJob.cs │ │ │ │ ├── Database │ │ │ │ │ ├── Configurations │ │ │ │ │ │ ├── MatchConfiguration.cs │ │ │ │ │ │ ├── FootballerConfiguration.cs │ │ │ │ │ │ └── TeamConfiguration.cs │ │ │ │ │ ├── TournamentDbContext.cs │ │ │ │ │ └── Migrations │ │ │ │ │ │ ├── 20240522181806_ChangeColumnName.cs │ │ │ │ │ │ ├── TournamentDbContextModelSnapshot.cs │ │ │ │ │ │ ├── 20240414180511_Initial.Designer.cs │ │ │ │ │ │ └── 20240522181806_ChangeColumnName.Designer.cs │ │ │ │ ├── Extensions │ │ │ │ │ ├── FootballerExtensions.cs │ │ │ │ │ ├── TeamExtensions.cs │ │ │ │ │ └── MatchExtension.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournaments.Core.csproj │ │ │ │ ├── Clients │ │ │ │ │ └── TournamentModuleApi.cs │ │ │ │ └── DependencyInjection.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournament.Shared │ │ │ │ ├── DTO │ │ │ │ │ ├── TeamResponse.cs │ │ │ │ │ ├── FootballerResponse.cs │ │ │ │ │ └── MatchResponse.cs │ │ │ │ ├── IntegrationEvents │ │ │ │ │ ├── TournamentEnd.cs │ │ │ │ │ └── MatchUpdated.cs │ │ │ │ ├── ITournamentModuleApi.cs │ │ │ │ └── Euro2024Challenge.Backend.Modules.Tournament.Shared.csproj │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournaments.Presentation │ │ │ │ ├── DependencyInjection.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournaments.Presentation.csproj │ │ │ │ └── TournamentsEndpoints.cs │ │ │ └── Euro2024Challenge.Backend.Modules.Tournaments.Api │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Tournaments.Api.csproj │ │ │ │ └── RegisterModule.cs │ │ ├── Players │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Api │ │ │ │ ├── appsettings.Development.json │ │ │ │ ├── appsettings.json │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Api.http │ │ │ │ ├── Program.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Api │ │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Api.csproj │ │ │ │ │ └── RegisterModule.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Api_org.csproj │ │ │ │ └── Properties │ │ │ │ │ └── launchSettings.json │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Domain │ │ │ │ ├── Enums │ │ │ │ │ └── MatchWinner.cs │ │ │ │ ├── Entities │ │ │ │ │ ├── TournamentWinnerBet.cs │ │ │ │ │ ├── TopScorerBet.cs │ │ │ │ │ ├── MatchBet.cs │ │ │ │ │ └── Player.cs │ │ │ │ ├── DependencyInjection.cs │ │ │ │ ├── Services │ │ │ │ │ ├── IPointsCalculator.cs │ │ │ │ │ └── PointsCalculator.cs │ │ │ │ ├── Repositories │ │ │ │ │ ├── IPlayersRepository.cs │ │ │ │ │ └── IPlayersBetsRepository.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Domain.csproj │ │ │ │ └── ValueObjects │ │ │ │ │ └── MatchResult.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Application │ │ │ │ ├── Bets │ │ │ │ │ ├── Get │ │ │ │ │ │ ├── GetPlayerBetsRequest.cs │ │ │ │ │ │ ├── GetPlayerMatchBetsRequest.cs │ │ │ │ │ │ ├── GetPlayerMatchBetsQuery.cs │ │ │ │ │ │ ├── GetPlayerBetsQuery.cs │ │ │ │ │ │ ├── GetPlayerMatchBetsQueryHandler.cs │ │ │ │ │ │ └── GetPlayerBetsQueryHandler.cs │ │ │ │ │ ├── Create │ │ │ │ │ │ ├── CreateTournamentWinnerBetRequest.cs │ │ │ │ │ │ ├── CreateTopScorerBetRequest.cs │ │ │ │ │ │ ├── CreateTournamentWinnerBetCommand.cs │ │ │ │ │ │ ├── CreateTopScorerBetCommand.cs │ │ │ │ │ │ ├── CreateMatchBetRequest.cs │ │ │ │ │ │ ├── CreateMatchBetCommand.cs │ │ │ │ │ │ ├── CreateTournamentWinnerBetCommandHandler.cs │ │ │ │ │ │ ├── CreateTopScorerBetCommandHandler.cs │ │ │ │ │ │ └── CreateMatchBetCommandHandler.cs │ │ │ │ │ ├── Update │ │ │ │ │ │ ├── UpdateTournamentWinnerBetRequest.cs │ │ │ │ │ │ ├── UpdateTournamentWinnerBetCommand.cs │ │ │ │ │ │ ├── UpdateTopScorerBetRequest.cs │ │ │ │ │ │ ├── UpdateMatchBetRequest.cs │ │ │ │ │ │ ├── UpdateTopScorerBetCommand.cs │ │ │ │ │ │ ├── UpdateMatchBetCommand.cs │ │ │ │ │ │ ├── UpdateTopScorerBetCommandHandler.cs │ │ │ │ │ │ ├── UpdateTournamentWinnerBetCommandHandler.cs │ │ │ │ │ │ └── UpdateMatchBetCommandHandler.cs │ │ │ │ │ └── DTO │ │ │ │ │ │ ├── PlayerTournamentWinnerBetDto.cs │ │ │ │ │ │ ├── PlayerTopScorerBetDto.cs │ │ │ │ │ │ ├── PlayerBetsDto.cs │ │ │ │ │ │ └── PlayerMatchBetDto.cs │ │ │ │ ├── Players │ │ │ │ │ ├── Create │ │ │ │ │ │ ├── CreatePlayerRequest.cs │ │ │ │ │ │ ├── CreatePlayerCommand.cs │ │ │ │ │ │ └── CreatePlayerCommandHandler.cs │ │ │ │ │ ├── DTO │ │ │ │ │ │ └── PlayerDto.cs │ │ │ │ │ └── Get │ │ │ │ │ │ ├── GetPlayerQuery.cs │ │ │ │ │ │ ├── GetPlayersQuery.cs │ │ │ │ │ │ ├── GetPlayerQueryHandler.cs │ │ │ │ │ │ └── GetPlayersQueryHandler.cs │ │ │ │ ├── DependencyInjection.cs │ │ │ │ ├── Extensions │ │ │ │ │ ├── TournamentWinnerBetExtensions.cs │ │ │ │ │ ├── TopScorerBetExtensions.cs │ │ │ │ │ ├── MatchWinnerExtension.cs │ │ │ │ │ ├── MatchBetExtensions.cs │ │ │ │ │ └── PlayerExtensions.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Application.csproj │ │ │ │ ├── Clients │ │ │ │ │ └── PlayerModuleClient.cs │ │ │ │ └── IntegrationEvents │ │ │ │ │ └── Handlers │ │ │ │ │ └── MatchUpdatedHandler.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Shared │ │ │ │ ├── Events │ │ │ │ │ └── PlayersMatchBetsClaculated.cs │ │ │ │ ├── IPlayerModuleApi.cs │ │ │ │ └── Euro2024Challenge.Backend.Modules.Players.Shared.csproj │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Presentation │ │ │ │ ├── DependencyInjection.cs │ │ │ │ ├── Euro2024Challenge.Backend.Modules.Players.Presentation.csproj │ │ │ │ ├── PlayersEndpoints.cs │ │ │ │ └── PlayerBetsEndpoints.cs │ │ │ └── Euro2024Challenge.Backend.Modules.Players.Infrastructure │ │ │ │ ├── Database │ │ │ │ ├── Configuration │ │ │ │ │ ├── TopScorerBetsConfiguration.cs │ │ │ │ │ ├── TournamentWinnerBetsConfiguration.cs │ │ │ │ │ ├── PlayerConfiguration.cs │ │ │ │ │ └── MatchBetsConfiguration.cs │ │ │ │ ├── PlayersDbContext.cs │ │ │ │ ├── Migrations │ │ │ │ │ └── 20240504104836_UpdateMatchBet.cs │ │ │ │ └── Repositories │ │ │ │ │ ├── PlayersRepository.cs │ │ │ │ │ └── PlayersBetsRepository.cs │ │ │ │ ├── DependencyInjection.cs │ │ │ │ └── Euro2024Challenge.Backend.Modules.Players.Infrastructure.csproj │ │ └── Classification │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Domain │ │ │ ├── Entities │ │ │ │ ├── PlayersPoints.cs │ │ │ │ ├── BetPoints.cs │ │ │ │ └── PlayerBetPoints.cs │ │ │ ├── DependencyInjection.cs │ │ │ ├── Repositories │ │ │ │ └── IClassificationRepository.cs │ │ │ └── Euro2024Challenge.Backend.Modules.Classification.Domain.csproj │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Application │ │ │ ├── Dto │ │ │ │ └── BetPointsDto.cs │ │ │ ├── Services │ │ │ │ ├── IPlayerClassificationService.cs │ │ │ │ └── PlayerClassifiactionService.cs │ │ │ ├── Classifications │ │ │ │ ├── CreatePlayerClassification │ │ │ │ │ ├── CreatePlayerClassificationRequest.cs │ │ │ │ │ ├── CreatePlayerClassificationCommand.cs │ │ │ │ │ └── CreatePlayerClassificationCommandHandler.cs │ │ │ │ ├── GetClassifications │ │ │ │ │ ├── GetClassificationsQuery.cs │ │ │ │ │ ├── GetClassificationsResponse.cs │ │ │ │ │ └── GetClassificationsQueryHandler.cs │ │ │ │ └── GetPlayerClassifications │ │ │ │ │ ├── GetPlayerClassificationsQuery.cs │ │ │ │ │ ├── GetPlayerClassificationsResponse.cs │ │ │ │ │ └── GetPlayerClassificationsQueryHandler.cs │ │ │ ├── DependencyInjection.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Application.csproj │ │ │ ├── IntegrationEvents │ │ │ │ └── Handlers │ │ │ │ │ └── PlayersMatchBetsClaculatedHandler.cs │ │ │ └── Extensions │ │ │ │ └── PlayerBetPointsExtensions.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Presentation │ │ │ ├── DependencyInjection.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Presentation.csproj │ │ │ └── ClassificationEndpoints.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Infrastructure │ │ │ ├── Database │ │ │ │ ├── Settings │ │ │ │ │ ├── ClassificationDatabaseSettings.cs │ │ │ │ │ └── ClassificationDatabaseSettingsSetup.cs │ │ │ │ └── Repositories │ │ │ │ │ └── PlayersClassificationRepository.cs │ │ │ ├── Euro2024Challenge.Backend.Modules.Classification.Infrastructure.csproj │ │ │ └── DependencyInjection.cs │ │ │ └── Euro2024Challenge.Backend.Modules.Classification.Api │ │ │ ├── RegisterModule.cs │ │ │ └── Euro2024Challenge.Backend.Modules.Classification.Api.csproj │ └── Bootstrapper │ │ └── Euro2024Challenge.Backend.Bootstrapper │ │ ├── appsettings.Development.json │ │ ├── Euro2024Challenge.Backend.Bootstrapper.http │ │ ├── appsettings.json │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ └── Euro2024Challenge.Backend.Bootstrapper.csproj └── Frontend │ └── Euro2024Challange │ ├── wwwroot │ ├── favicon.png │ └── app.css │ ├── Components │ ├── Pages │ │ ├── Home.razor │ │ ├── Counter.razor │ │ ├── Classification.razor │ │ ├── Players.razor │ │ ├── Error.razor │ │ └── Weather.razor │ ├── Routes.razor │ ├── _Imports.razor │ ├── App.razor │ └── Layout │ │ ├── MainLayout.razor │ │ ├── NavMenu.razor │ │ ├── MainLayout.razor.css │ │ └── NavMenu.razor.css │ ├── appsettings.Development.json │ ├── Models │ ├── Player.cs │ └── PlayersClassification.cs │ ├── appsettings.json │ ├── Euro2024Challange.csproj │ ├── Program.cs │ └── Properties │ └── launchSettings.json ├── tests └── Modules │ ├── Players │ └── DomainTests │ │ ├── Modules.Players.Domain.Tests.csproj │ │ └── Services │ │ └── PointsCalculatorTests.cs │ └── Tournaments │ └── Tournamnets.Core.Tests │ ├── Modules.Tournamnets.Core.Tests.csproj │ └── Services │ └── FootballerServiceTests.cs └── README.md /src/Backend/Shared/Euro2024Challenge.Shared/Events/IEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared; 2 | 3 | public interface IEvent 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krzyspie/Euro2024Challenge/HEAD/src/Frontend/Euro2024Challange/wwwroot/favicon.png -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Domain/IAggregateRoot.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared.Domain; 2 | 3 | public interface IAggregateRoot 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Home.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Home 4 | 5 |

Hello, world!

6 | 7 | Welcome to your new app. 8 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Models/Player.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challange.Models; 2 | 3 | public class Player 4 | { 5 | public string Email {get; set; } 6 | public string Username {get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/AddTeamRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record AddTeamRequest(string Name); -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/DTO/TeamResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | public sealed record TeamResponse(int Id, string Name); -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/GetFootballerRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record GetFootballerRequest(int Id); -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Database/IUnitOfWork.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared.Database; 2 | 3 | public interface IUnitOfWork 4 | { 5 | Task SaveChangesAsync(CancellationToken cancellationToken = default); 6 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Enums/MatchWinner.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | 3 | public enum MatchWinner 4 | { 5 | Draw, 6 | HomeTeam, 7 | AwayTeam 8 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/UpdateFootballerGoalsRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record UpdateFootballerGoalsRequest(int Goals); -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Models/PlayersClassification.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challange.Models; 2 | 3 | public class PlayersClassification 4 | { 5 | public string PlayerUsername { get; set; } 6 | public int Points { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/AddFootballerRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record AddFootballerRequest(string Name, int TeamId, int Goals); -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerBetsRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 2 | { 3 | public sealed record GetPlayerBetsRequest(Guid PlayerId); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/DTO/FootballerResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | public sealed record FootballerResponse(int Id, string FullName, int Goals, string TeamName); -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/UpdateMatchResultRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record UpdateMatchResultRequest(int GuestTeamGoals, int AwayTeamGoals); -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerMatchBetsRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 2 | { 3 | public sealed record GetPlayerMatchBetsRequest(Guid PlayerId); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Create/CreatePlayerRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Create 2 | { 3 | public sealed record CreatePlayerRequest(string Email, string Username); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/IEventHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared; 2 | 3 | public interface IEventHandler where TEvent : class, IEvent 4 | { 5 | Task HandleAsync(TEvent integrationEvent, CancellationToken cancellationToken = default); 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTournamentWinnerBetRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 2 | { 3 | public sealed record CreateTournamentWinnerBetRequest(Guid PlayerId, int TeamId); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTournamentWinnerBetRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 2 | { 3 | public sealed record UpdateTournamentWinnerBetRequest(Guid PlayerId, int TeamId); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/Euro2024Challenge.Backend.Bootstrapper.http: -------------------------------------------------------------------------------- 1 | @Euro2024Challenge.Backend.Bootstrapper_HostAddress = http://localhost:5047 2 | 3 | GET {{Euro2024Challenge.Backend.Bootstrapper_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTopScorerBetRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 2 | { 3 | public sealed record CreateTopScorerBetRequest(Guid PlayerId, int FootballerId, int Goals); 4 | } 5 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerMatchBetsQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 4 | { 5 | public sealed record GetPlayerMatchBetsQuery(Guid PlayerId) : IRequest; 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/IntegrationEvents/TournamentEnd.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared.IntegrationEvents; 2 | 3 | public record class TournamentEnd(string TeamWinner, int TopScoresFootballer, int TopScoresFootballerGoals); -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/Entities/PlayersPoints.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 2 | 3 | public class PlayersPoints 4 | { 5 | public Guid PlayerId { get; set; } 6 | public int Points { get; set; } 7 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Shared/Events/PlayersMatchBetsClaculated.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Shared.Events; 4 | 5 | public record class PlayerBetClaculated(Guid PlayerId, Guid BetId, int Points) : IEvent; -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Shared/IPlayerModuleApi.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Shared 2 | { 3 | public interface IPlayerModuleApi 4 | { 5 | Task> GetPlayersUsernames(IEnumerable playersId); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DTO/AddMatchRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | 3 | public sealed record AddMatchRequest(int Number, int GuestTeamId, int AwayTeamId, int GuestTeamGoals, int AwayTeamGoals, DateTime StartHour); -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Domain/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared.Domain 2 | { 3 | public class BaseEntity 4 | { 5 | public Guid Id { get; set; } = Guid.NewGuid(); 6 | 7 | public DateTime CreatedAt { get; set; } = DateTime.UtcNow; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/IEventDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared; 2 | 3 | public interface IEventDispatcher 4 | { 5 | Task PublishAsync(TEvent integrationEvent, CancellationToken cancellationToken = default) 6 | where TEvent : class, IEvent; 7 | } 8 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Euro2024Challange.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Dto/BetPointsDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Dto; 2 | 3 | public class BetPointsDto 4 | { 5 | public Guid BetId { get; set; } 6 | public int Points { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/IntegrationEvents/MatchUpdated.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared; 4 | 5 | public record class MatchUpdated(int MatchId, int HomeTeamGoals, int AwayTeamGoals) : IEvent; 6 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Create/CreatePlayerCommand.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Create 4 | { 5 | public sealed record CreatePlayerCommand(string Email, string Username) : IRequest; 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/IEventBus.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared; 2 | 3 | public interface IEventBus 4 | { 5 | Task PublishAsync( 6 | T integrationEvent, 7 | CancellationToken cancellationToken = default) 8 | where T : class, IEvent; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Routes.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Euro2024Challenge.Backend.Modules.Players.Api.http: -------------------------------------------------------------------------------- 1 | @Euro2024Challenge.Backend.Modules.Players.Api_HostAddress = http://localhost:5119 2 | 3 | GET {{Euro2024Challenge.Backend.Modules.Players.Api_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTournamentWinnerBetCommand.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 4 | { 5 | public sealed record CreateTournamentWinnerBetCommand(Guid PLayerId, int TeamId) : IRequest; 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTournamentWinnerBetCommand.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 4 | { 5 | public sealed record UpdateTournamentWinnerBetCommand(Guid PLayerId, int TeamId) : IRequest; 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/DTO/PlayerDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 2 | 3 | public class PlayerDto 4 | { 5 | public Guid Id { get; set; } 6 | public string Email { get; set; } 7 | public string Username { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Cache/ITeamsCache.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Cache; 2 | 3 | public interface ITeamsCache 4 | { 5 | bool TryGetValue(out Dictionary? value); 6 | 7 | void Set(Dictionary value); 8 | } 9 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTopScorerBetCommand.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 4 | { 5 | public sealed record CreateTopScorerBetCommand(Guid PlayerId, int FootballerId, int Goals) : IRequest; 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Services/IPlayerClassificationService.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Services; 2 | 3 | public interface IPlayerClassificationService 4 | { 5 | Task UpdatePlayerPoints(Guid playerId, Guid betId, int points); 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Get/GetPlayerQuery.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Get; 5 | 6 | public sealed record GetPlayerQuery(Guid PlayerId) : IRequest; -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Database/DatabaseOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared.Database 2 | { 3 | internal sealed class DatabaseOptions 4 | { 5 | public string? ConnectionString { get; set; } 6 | 7 | public int MaxRetryCount { get; set; } 8 | 9 | public int CommandTimeout { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTopScorerBetRequest.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 4 | { 5 | public sealed record UpdateTopScorerBetRequest(Guid PlayerId, int FootballerId, int Goals); 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Get/GetPlayersQuery.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Get; 5 | 6 | public sealed record GetPlayersQuery() : IRequest>; 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/DTO/PlayerTournamentWinnerBetDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO 2 | { 3 | public class PlayerTournamentWinnerBetDto 4 | { 5 | public int TeamId { get; set; } 6 | 7 | public string TeamName { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerBetsQuery.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 5 | { 6 | public sealed record GetPlayerBetsQuery(Guid PlayerId) : IRequest; 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/Entities/BetPoints.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared.Domain; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 4 | 5 | public class BetPoints : BaseEntity 6 | { 7 | public Guid BetId { get; set; } 8 | 9 | public int Points { get; set; } 10 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/CreatePlayerClassification/CreatePlayerClassificationRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.CreatePlayerClassification; 2 | 3 | public sealed record CreatePlayerClassificationRequest(Guid PlayerId, Guid BetId, int Points); 4 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/IFootballerService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 4 | 5 | public interface IFootballerService 6 | { 7 | Task UpdateGoals(int id, int goals); 8 | Task Get(int id); 9 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetClassifications/GetClassificationsQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetClassifications; 4 | 5 | public sealed record GetClassificationsQuery() : IRequest>; 6 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/IFootballerRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 4 | 5 | public interface IFootballerRepository 6 | { 7 | Task UpdateAsync(Footballer footballer); 8 | Task Get(int id); 9 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateMatchBetRequest.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 4 | { 5 | public sealed record CreateMatchBetRequest(Guid PlayerId, int MatchId, MatchWinner Winner, int HomeTeamGoals, int AwayTeamGoals); 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateMatchBetRequest.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 4 | { 5 | public sealed record UpdateMatchBetRequest(Guid PlayerId, int MatchId, MatchWinner Winner, int HomeTeamGoals, int AwayTeamGoals); 6 | } 7 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTopScorerBetCommand.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 5 | { 6 | public sealed record UpdateTopScorerBetCommand(Guid PLayerId, int FootballerId, int Goals) : IRequest; 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Entities/TournamentWinnerBet.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared.Domain; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Entities 4 | { 5 | public class TournamentWinnerBet : BaseEntity 6 | { 7 | public Guid PlayerId { get; set; } 8 | 9 | public int TeamId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/ITeamService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 4 | 5 | public interface ITeamService 6 | { 7 | Task> GetTeamsAsync(List id); 8 | Task GetTeamAsync(int ids); 9 | } -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Database/UnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Euro2024Challenge.Shared.Database; 4 | 5 | public sealed class UnitOfWork(DbContext dbContext) : IUnitOfWork 6 | { 7 | public Task SaveChangesAsync(CancellationToken cancellationToken = default) 8 | { 9 | return dbContext.SaveChangesAsync(cancellationToken); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Entities/Team.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities 2 | { 3 | public class Team 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | 8 | public ICollection Footballers { get; set; } = new List(); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/CreatePlayerClassification/CreatePlayerClassificationCommand.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.CreatePlayerClassification; 4 | 5 | public sealed record CreatePlayerClassificationCommand(Guid PlayerId, Guid BetId, int Points) : IRequest; -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetPlayerClassifications/GetPlayerClassificationsQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetPlayerClassifications; 4 | 5 | public sealed record GetPlayerClassificationsQuery(Guid PlayerId) : IRequest; 6 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Domain; 4 | 5 | public static class DependencyInjection 6 | { 7 | public static IServiceCollection AddDomain(this IServiceCollection services) 8 | { 9 | return services; 10 | } 11 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/BackgroundServices/FetchTournamentDataJob.cs: -------------------------------------------------------------------------------- 1 | using Quartz; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.BackgroundServices; 4 | 5 | public class FetchTournamentDataJob : IJob 6 | { 7 | public Task Execute(IJobExecutionContext context) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateMatchBetCommand.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 5 | { 6 | public sealed record CreateMatchBetCommand(Guid PLayerId, int MatchId, MatchWinner Winner, int HomeTeamGoals, int AwayTeamGoals) : IRequest; 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateMatchBetCommand.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 5 | { 6 | public sealed record UpdateMatchBetCommand(Guid PLayerId, int MatchId, MatchWinner Winner, int HomeTeamGoals, int AwayTeamGoals) : IRequest; 7 | } 8 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Presentation/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Presentation; 4 | 5 | public static class DependencyInjection 6 | { 7 | public static IServiceCollection AddPresentation(this IServiceCollection services) 8 | { 9 | return services; 10 | } 11 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Entities/TopScorerBet.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared.Domain; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Entities 4 | { 5 | public class TopScorerBet : BaseEntity 6 | { 7 | public Guid PlayerId { get; set; } 8 | 9 | public int FootballerId { get; set; } 10 | 11 | public int Goals { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/DTO/MatchResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | public sealed record MatchResponse( 4 | int Id, 5 | int Number, 6 | int GuestTeamId, 7 | string GuestTeamName, 8 | int AwayTeamId, 9 | string AwayTeamName, 10 | int GuestTeamGoals, 11 | int AwayTeamGoals, 12 | DateTime StartHour); 13 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/InMemoryMessageQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Channels; 2 | 3 | namespace Euro2024Challenge.Shared; 4 | 5 | public class InMemoryMessageQueue 6 | { 7 | private readonly Channel _channel = 8 | Channel.CreateUnbounded(); 9 | 10 | public ChannelReader Reader => _channel.Reader; 11 | 12 | public ChannelWriter Writer => _channel.Writer; 13 | } 14 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Presentation/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Presentation 4 | { 5 | public static class DependencyInjection 6 | { 7 | public static IServiceCollection AddPresentation(this IServiceCollection services) 8 | { 9 | return services; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/ITournamentModuleApi.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournament.Shared; 4 | 5 | 6 | public interface ITournamentModuleApi 7 | { 8 | Task> GetMatches(int[] matchIds); 9 | Task GetTeam(int id); 10 | Task GetFootballer(int id); 11 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Entities/Footballer.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities 2 | { 3 | public class Footballer 4 | { 5 | public int Id { get; set; } 6 | public string FullName { get; set; } 7 | public int Goals { get; set; } 8 | 9 | public int TeamId { get; set; } 10 | public Team Team { get; set; } = null!; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetClassifications/GetClassificationsResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetClassifications; 2 | 3 | public class GetClassificationsResponse 4 | { 5 | public Guid PlayerId { get; set; } 6 | 7 | public string? PlayerUsername { get; set; } 8 | 9 | public int Points { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/ITeamRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 4 | 5 | public interface ITeamRepository 6 | { 7 | Task> GetTeamsAsync(IEnumerable ids); 8 | Task> GetAllTeamsAsync(); 9 | Task GetTeamAsync(int id); 10 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Infrastructure/Database/Settings/ClassificationDatabaseSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Settings; 2 | 3 | public class ClassificationDatabaseSettings 4 | { 5 | public string ConnectionString { get; set; } = null!; 6 | 7 | public string DatabaseName { get; set; } = null!; 8 | 9 | public string CollectionName { get; set; } = null!; 10 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using Euro2024Challange 10 | @using Euro2024Challange.Components 11 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | @rendermode InteractiveServer 3 | 4 | Counter 5 | 6 |

Counter

7 | 8 |

Current count: @currentCount

9 | 10 | 11 | 12 | @code { 13 | private int currentCount = 0; 14 | 15 | private void IncrementCount() 16 | { 17 | currentCount++; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Classification.razor: -------------------------------------------------------------------------------- 1 | @page "/classification" 2 | 3 | @using Models 4 | 5 | @inject HttpClient client 6 | 7 |

Classification

8 | 9 | @code { 10 | private List classifications = new(); 11 | protected override async Task OnInitializedAsync() 12 | { 13 | classifications = await client.GetFromJsonAsync>("/classifications-module/classifications"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Presentation/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.AspNetCore.Routing; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Presentation 5 | { 6 | public static class DependencyInjection 7 | { 8 | public static IServiceCollection AddPresentation(this IServiceCollection services) 9 | { 10 | return services; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/DTO/PlayerTopScorerBetDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO 2 | { 3 | public class PlayerTopScorerBetDto 4 | { 5 | public Guid PlayerId { get; set; } 6 | 7 | public int FootballerId { get; set; } 8 | 9 | public string FullName { get; set; } 10 | 11 | public string TeamName { get; set; } 12 | 13 | public int Goals { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/DTO/PlayerBetsDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO 2 | { 3 | public class PlayerBetsDto 4 | { 5 | public Guid PlayerId { get; set; } 6 | 7 | public IEnumerable MatchBets { get; set; } 8 | 9 | public PlayerTopScorerBetDto? TopScorerBet { get; set; } 10 | 11 | public PlayerTournamentWinnerBetDto? TournamentWinner { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Shared/Euro2024Challenge.Backend.Modules.Players.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | net8.0 9 | enable 10 | enable 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/Entities/PlayerBetPoints.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Classification.Domain.Entities 2 | { 3 | public class PlayerBetPoints 4 | { 5 | public string Id { get; set; } 6 | 7 | public string PlayerId { get; set; } 8 | 9 | public string BetId { get; set; } 10 | 11 | public int Points { get; set; } 12 | 13 | public DateTime CreatedAt { get; set; } = DateTime.UtcNow; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/IMatchRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 4 | 5 | public interface IMatchRepository 6 | { 7 | Task AddAsync(Match? match); 8 | Task UpdateAsync(Match? match); 9 | Task> GetAll(); 10 | Task GetByNumber(int number); 11 | Task> GetByNumbers(int[] numbers); 12 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournament.Shared/Euro2024Challenge.Backend.Modules.Tournament.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | net8.0 9 | enable 10 | enable 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Entities/Match.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities 2 | { 3 | public class Match 4 | { 5 | public int Id { get; set; } 6 | public int Number { get; set; } 7 | public int GuestTeamId { get; set; } 8 | public int AwayTeamId { get; set; } 9 | public int GuestTeamGoals { get; set; } 10 | public int AwayTeamGoals { get; set; } 11 | public DateTime StartHour { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetPlayerClassifications/GetPlayerClassificationsResponse.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Dto; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetPlayerClassifications; 4 | 5 | public class GetPlayerClassificationsResponse 6 | { 7 | public Guid PlayerId { get; set; } 8 | 9 | public IReadOnlyCollection BetsPoints { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application 4 | { 5 | public static class DependencyInjection 6 | { 7 | public static IServiceCollection AddApplication(this IServiceCollection services) 8 | { 9 | services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly)); 10 | return services; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/DTO/PlayerMatchBetDto.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO 2 | { 3 | public class PlayerMatchBetDto 4 | { 5 | public Guid PlayerId { get; set; } 6 | public int MatchId { get; set; } 7 | public string Result { get; set; } 8 | public int HomeTeamGoals { get; set; } 9 | public string HomeTeam { get; set; } 10 | public int AwayTeamGoals { get; set; } 11 | public string AwayTeam { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/EventBus.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared; 2 | 3 | public class EventBus : IEventBus 4 | { 5 | private readonly InMemoryMessageQueue _messageQueue; 6 | 7 | public EventBus(InMemoryMessageQueue messageQueue) 8 | { 9 | _messageQueue = messageQueue; 10 | } 11 | public async Task PublishAsync(T integrationEvent, CancellationToken cancellationToken) where T : class, IEvent 12 | { 13 | await _messageQueue.Writer.WriteAsync(integrationEvent, cancellationToken); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Services; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Domain 5 | { 6 | public static class DependencyInjection 7 | { 8 | public static IServiceCollection AddDomain(this IServiceCollection services) 9 | { 10 | services.AddSingleton(); 11 | return services; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Configurations/MatchConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Configurations 6 | { 7 | internal class MatchConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Services/IPointsCalculator.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Services; 4 | 5 | public interface IPointsCalculator 6 | { 7 | int CalculateMatchPoints(int homeTeamGoals, int awayTeamGoals, ValueObjects.MatchResult? bet); 8 | int CalculateTournamentWinnerPoints(int winnerTeamId, TournamentWinnerBet tournamentWinnerBet); 9 | int CalculateTopScorerFootballerPoints(int playerId, int playerGolas, TopScorerBet topScorerBet); 10 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Extensions/FootballerExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 5 | 6 | public static class FootballerExtensions 7 | { 8 | public static FootballerResponse ToFootballerResponse(this Footballer footballer) 9 | { 10 | return new FootballerResponse(footballer.Id, footballer.FullName, footballer.Goals, footballer.Team.Name); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Entities/MatchBet.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 3 | using Euro2024Challenge.Shared.Domain; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Entities 6 | { 7 | public class MatchBet : BaseEntity 8 | { 9 | public Guid PlayerId { get; set; } 10 | public int MatchId { get; set; } 11 | public MatchResult? Result { get; set; } 12 | public MatchWinner Winner { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Configuration/TopScorerBetsConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Configuration; 6 | 7 | internal class TopScorerBetsConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("TopScorerBet"); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/Repositories/IClassificationRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 4 | 5 | public interface IClassificationRepository 6 | { 7 | Task> GetAll(); 8 | Task Insert(PlayerBetPoints playerBetPoints); 9 | Task> Get(Guid playerId); 10 | Task GetBetPoints(Guid playerId, Guid betId); 11 | Task Update(PlayerBetPoints playerBetPoints); 12 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Extensions/TournamentWinnerBetExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 5 | 6 | public static class TournamentWinnerBetExtensions 7 | { 8 | private static PlayerTournamentWinnerBetDto ToTournamentWinnerBetDto(this TournamentWinnerBet bet) 9 | { 10 | return new PlayerTournamentWinnerBetDto 11 | { 12 | TeamId = bet.TeamId 13 | }; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Repositories/IPlayersRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Repositories 4 | { 5 | public interface IPlayersRepository 6 | { 7 | Task Create(Player player); 8 | 9 | Task Get(Guid playerId); 10 | Task> GetPlayers(List playersIds); 11 | Task> GetAllPlayers(); 12 | Task GetWithBets(Guid playerId); 13 | Task> GetAllPlayersMatchBets(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Configuration/TournamentWinnerBetsConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Configuration; 6 | 7 | public class TournamentWinnerBetsConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("TournamentWinnerBets"); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Extensions/TopScorerBetExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 5 | 6 | public static class TopScorerBetExtensions 7 | { 8 | public static PlayerTopScorerBetDto ToPlayerTopScorerBetDto(this TopScorerBet bet) 9 | { 10 | return new PlayerTopScorerBetDto 11 | { 12 | FootballerId = bet.FootballerId, 13 | Goals = bet.Goals 14 | }; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/IMatchService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 5 | 6 | public interface IMatchService 7 | { 8 | Task Add(AddMatchRequest match); 9 | Task UpdateResult(int number, int guestTeamGoals, int awayTeamGoals); 10 | Task> GetAll(); 11 | Task GetByNumber(int number); 12 | Task> GetByNumbers(int[] numbers); 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Euro2024Challenge.Backend.Modules.Players.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Configurations/FootballerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Configurations 6 | { 7 | internal class FootballerConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.FullName ).HasMaxLength(32); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
18 | 19 |
20 | An unhandled error has occurred. 21 | Reload 22 | 🗙 23 |
24 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Players.razor: -------------------------------------------------------------------------------- 1 | @page "/players" 2 | 3 | @using Models 4 | 5 | @inject HttpClient client 6 | 7 |

Players

8 |
9 | @foreach (var player in players) 10 | { 11 |
12 |
@player.Username, @player.Email
13 |
14 | } 15 |
16 | 17 | @code { 18 | private int number = 0; 19 | private List players = new(); 20 | protected override async Task OnInitializedAsync() 21 | { 22 | number++; 23 | players = await client.GetFromJsonAsync>("/players-module/players"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Configurations/TeamConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Configurations 6 | { 7 | internal class TeamConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.Name).HasMaxLength(16); 12 | builder.HasIndex(x => x.Name).IsUnique(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Extensions/MatchWinnerExtension.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Enums; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 4 | 5 | public static class MatchWinnerExtension 6 | { 7 | public static string ToStringOutput(this MatchWinner matchWinner, string awayTeamName, string homeTeamName) 8 | { 9 | return matchWinner switch 10 | { 11 | MatchWinner.Draw => "Draw", 12 | MatchWinner.HomeTeam => homeTeamName, 13 | MatchWinner.AwayTeam => awayTeamName, 14 | _ => string.Empty, 15 | }; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Repositories/IPlayersBetsRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 4 | 5 | public interface IPlayersBetsRepository 6 | { 7 | Task CreateMatchBetAsync(MatchBet matchBet); 8 | Task UpdateMatchBetAsync(MatchBet matchBet); 9 | Task CreateTopScorerBetAsync(TopScorerBet topScorerBet); 10 | Task UpdateTopScorerBetAsync(TopScorerBet topScorerBet); 11 | Task CreateTournamentWinnerBetAsync(TournamentWinnerBet tournamentWinnerBet); 12 | Task UpdateTournamentWinnerBetAsync(TournamentWinnerBet tournamentWinnerBet); 13 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Services; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Classification.Application; 5 | 6 | public static class DependencyInjection 7 | { 8 | public static IServiceCollection AddApplication(this IServiceCollection services) 9 | { 10 | services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly)); 11 | services.AddScoped(); 12 | return services; 13 | } 14 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Domain/Euro2024Challenge.Backend.Modules.Classification.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Extensions/TeamExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 5 | 6 | public static class TeamExtensions 7 | { 8 | public static IEnumerable ToTeamsResponse(this IDictionary teams) 9 | { 10 | return teams.Select(team => new TeamResponse(team.Key, team.Value)); 11 | } 12 | 13 | public static TeamResponse ToTeamResponse(this Team team) 14 | { 15 | return new TeamResponse(team.Id, team.Name); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerMatchBetsQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 2 | using MediatR; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 5 | { 6 | internal sealed class GetPlayerMatchBetsQueryHandler(IPlayersRepository playersRepository) : IRequestHandler 7 | { 8 | private readonly IPlayersRepository _playersRepository = playersRepository; 9 | 10 | public async Task Handle(GetPlayerMatchBetsQuery request, CancellationToken cancellationToken) 11 | { 12 | return Unit.Value; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DbConnection": "Host=localhost; Database=euro2024; Username=postgres; Password=admin" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Information", 8 | "Microsoft.AspNetCore": "Warning" 9 | } 10 | }, 11 | "AllowedHosts": "*", 12 | "DatabaseOptions": { 13 | "MaxRetryCount": 3, 14 | "CommandTimeout": 30 15 | }, 16 | "ClassificationDatabase": { 17 | "ConnectionString": "mongodb://localhost:27017", 18 | "DatabaseName": "PlayersPointsClassification", 19 | "CollectionName": "Classification" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Presentation/Euro2024Challenge.Backend.Modules.Players.Presentation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Presentation/Euro2024Challenge.Backend.Modules.Tournaments.Presentation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Infrastructure/Euro2024Challenge.Backend.Modules.Classification.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Api/Euro2024Challenge.Backend.Modules.Tournaments.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Infrastructure/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 2 | using Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Settings; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Classification.Infrastructure; 7 | 8 | public static class DependencyInjection 9 | { 10 | public static IServiceCollection AddInfrastructure(this IServiceCollection services) 11 | { 12 | services.ConfigureOptions(); 13 | services.AddSingleton(); 14 | return services; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Euro2024Challenge.Shared; 4 | 5 | public static class DependencyInjection 6 | { 7 | public static IServiceCollection RegisterShared(this IServiceCollection services) 8 | { 9 | services.AddSingleton(); 10 | services.AddSingleton(); 11 | services.AddSingleton(); 12 | services.AddHostedService(); 13 | services.Scan(s => s.FromAssemblies(AppDomain.CurrentDomain.GetAssemblies()) 14 | .AddClasses(c => c.AssignableTo(typeof(IEventHandler<>))) 15 | .AsImplementedInterfaces() 16 | .WithScopedLifetime()); 17 | 18 | return services; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/TournamentDbContext.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database 5 | { 6 | public class TournamentDbContext : DbContext 7 | { 8 | public TournamentDbContext(DbContextOptions options) : base(options) 9 | { 10 | } 11 | 12 | public DbSet Teams { get; set; } 13 | public DbSet Matches { get; set; } 14 | public DbSet Footballers { get; set; } 15 | 16 | protected override void OnModelCreating(ModelBuilder modelBuilder) 17 | { 18 | modelBuilder.HasDefaultSchema("tournaments"); 19 | modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); 20 | } 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Api/RegisterModule.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.AspNetCore.Routing; 4 | using Euro2024Challenge.Backend.Modules.Tournaments.Presentation; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Api 7 | { 8 | public static class RegisterModule 9 | { 10 | public static IServiceCollection RegisterTournamentsModule(this IServiceCollection services) 11 | { 12 | services 13 | .AddCore() 14 | .AddPresentation(); 15 | 16 | return services; 17 | } 18 | 19 | public static IEndpointRouteBuilder UseTournamentsModules(this IEndpointRouteBuilder app) 20 | { 21 | app.MapTournamentsEndpoints(); 22 | 23 | return app; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application; 2 | using Euro2024Challenge.Backend.Modules.Players.Infrastructure; 3 | using Euro2024Challenge.Backend.Modules.Players.Presentation; 4 | 5 | var builder = WebApplication.CreateBuilder(args); 6 | 7 | // Add services to the container. 8 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 9 | builder.Services.AddEndpointsApiExplorer(); 10 | builder.Services.AddSwaggerGen(); 11 | 12 | builder.Services 13 | .AddApplication() 14 | .AddInfrastructure() 15 | .AddPresentation(); 16 | 17 | var app = builder.Build(); 18 | 19 | // Configure the HTTP request pipeline. 20 | if (app.Environment.IsDevelopment()) 21 | { 22 | app.UseSwagger(); 23 | app.UseSwaggerUI(); 24 | } 25 | 26 | app.UseHttpsRedirection(); 27 | 28 | app.MapPlayersEndpoints(); 29 | 30 | app.Run(); 31 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Database/DatabaseOptionsSetup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.Options; 3 | 4 | namespace Euro2024Challenge.Shared.Database 5 | { 6 | internal class DatabaseOptionsSetup : IConfigureOptions 7 | { 8 | private const string ConfigurationSectionName = "DatabaseOptions"; 9 | private readonly IConfiguration _configuration; 10 | 11 | public DatabaseOptionsSetup(IConfiguration configuration) 12 | { 13 | _configuration = configuration; 14 | } 15 | 16 | public void Configure(DatabaseOptions options) 17 | { 18 | string connectionString = _configuration.GetConnectionString("DbConnection"); 19 | 20 | options.ConnectionString = connectionString; 21 | 22 | _configuration.GetSection(ConfigurationSectionName).Bind(options); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Configuration/PlayerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Configuration 6 | { 7 | internal class PlayerConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("Players"); 12 | 13 | builder.Property(x => x.Email) 14 | .IsRequired() 15 | .HasMaxLength(100); 16 | 17 | builder.Property(x => x.Username) 18 | .IsRequired() 19 | .HasMaxLength(25); 20 | 21 | builder.HasIndex(x => x.Email).IsUnique(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Get/GetPlayerQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 2 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 3 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 4 | using MediatR; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Get; 7 | 8 | public class GetPlayerQueryHandler : IRequestHandler 9 | { 10 | private readonly IPlayersRepository _playersRepository; 11 | 12 | public GetPlayerQueryHandler(IPlayersRepository playersRepository) 13 | { 14 | _playersRepository = playersRepository; 15 | } 16 | 17 | public async Task Handle(GetPlayerQuery request, CancellationToken cancellationToken) 18 | { 19 | return (await _playersRepository.Get(request.PlayerId)).ToPlayerDto(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/Program.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Api; 2 | using Euro2024Challenge.Backend.Modules.Players.Api; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Api; 4 | using Euro2024Challenge.Shared; 5 | 6 | var builder = WebApplication.CreateBuilder(args); 7 | 8 | builder.Services.AddEndpointsApiExplorer(); 9 | builder.Services.AddSwaggerGen(); 10 | 11 | builder.Services.RegisterPlayersModule(); 12 | builder.Services.RegisterTournamentsModule(); 13 | builder.Services.RegisterClassificationModule(); 14 | builder.Services.RegisterShared(); 15 | 16 | var app = builder.Build(); 17 | 18 | // Configure the HTTP request pipeline. 19 | if (app.Environment.IsDevelopment()) 20 | { 21 | app.UseSwagger(); 22 | app.UseSwaggerUI(); 23 | } 24 | 25 | app.UseHttpsRedirection(); 26 | 27 | app.UsePlayersModules(); 28 | app.UseTournamentsModules(); 29 | app.UseClassificationModules(); 30 | 31 | app.Run(); 32 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Cache/TeamsCache.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Memory; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Cache; 4 | 5 | public class TeamsCache : ITeamsCache 6 | { 7 | private const string TeamsKey = "teams-key"; 8 | private readonly IMemoryCache _cache; 9 | 10 | public TeamsCache(IMemoryCache cache) 11 | { 12 | _cache = cache; 13 | } 14 | 15 | public void Set(Dictionary? value) 16 | { 17 | if (value != null && value.Any()) 18 | { 19 | _cache.Set(TeamsKey, value); 20 | } 21 | } 22 | 23 | public bool TryGetValue(out Dictionary? allTeams) 24 | { 25 | Dictionary? teams = []; 26 | var hasValue = _cache.TryGetValue(TeamsKey, out teams); 27 | allTeams = teams; 28 | 29 | return hasValue; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Euro2024Challenge.Backend.Modules.Classification.Application.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Program.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challange.Components; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Add services to the container. 6 | builder.Services.AddRazorComponents() 7 | .AddInteractiveServerComponents(); 8 | 9 | builder.Services.AddScoped(sp => 10 | new HttpClient 11 | { 12 | BaseAddress = new Uri("http://localhost:5047") 13 | }); 14 | 15 | var app = builder.Build(); 16 | 17 | // Configure the HTTP request pipeline. 18 | if (!app.Environment.IsDevelopment()) 19 | { 20 | app.UseExceptionHandler("/Error", createScopeForErrors: true); 21 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 22 | app.UseHsts(); 23 | } 24 | 25 | app.UseHttpsRedirection(); 26 | 27 | app.UseStaticFiles(); 28 | app.UseAntiforgery(); 29 | 30 | app.MapRazorComponents() 31 | .AddInteractiveServerRenderMode(); 32 | 33 | app.Run(); 34 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Get/GetPlayersQueryHandler.cs: -------------------------------------------------------------------------------- 1 | 2 | using Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 3 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 4 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 5 | using MediatR; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Get; 8 | 9 | public class GetPlayersQueryHandler : IRequestHandler> 10 | { 11 | private readonly IPlayersRepository _playersRepository; 12 | 13 | public GetPlayersQueryHandler(IPlayersRepository playersRepository) 14 | { 15 | _playersRepository = playersRepository; 16 | } 17 | 18 | public async Task> Handle(GetPlayersQuery request, CancellationToken cancellationToken) 19 | { 20 | return (await _playersRepository.GetAllPlayers()).ToPlayersDto(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/PlayersDbContext.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database 5 | { 6 | public class PlayersDbContext : DbContext 7 | { 8 | public PlayersDbContext(DbContextOptions options) : base(options) 9 | { 10 | } 11 | 12 | public DbSet Players { get; set; } 13 | public DbSet MatchBets { get; set; } 14 | public DbSet TopScorerBets { get; set; } 15 | public DbSet TournamentWinnerBets { get; set; } 16 | 17 | protected override void OnModelCreating(ModelBuilder modelBuilder) 18 | { 19 | modelBuilder.HasDefaultSchema("players"); 20 | modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Api/RegisterModule.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application; 2 | using Euro2024Challenge.Backend.Modules.Classification.Infrastructure; 3 | using Euro2024Challenge.Backend.Modules.Classification.Presentation; 4 | using Microsoft.AspNetCore.Routing; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Classification.Api; 8 | 9 | public static class RegisterModule 10 | { 11 | public static IServiceCollection RegisterClassificationModule(this IServiceCollection services) 12 | { 13 | services 14 | .AddApplication() 15 | .AddPresentation() 16 | .AddInfrastructure(); 17 | 18 | return services; 19 | } 20 | 21 | public static IEndpointRouteBuilder UseClassificationModules(this IEndpointRouteBuilder app) 22 | { 23 | app.MapClassificationEndpoints(); 24 | 25 | return app; 26 | } 27 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Players/Create/CreatePlayerCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Players.Create 6 | { 7 | internal sealed class CreatePlayerCommandHandler(IPlayersRepository playersRepository) : IRequestHandler 8 | { 9 | private readonly IPlayersRepository _playersRepository = playersRepository; 10 | 11 | public async Task Handle(CreatePlayerCommand request, CancellationToken cancellationToken) 12 | { 13 | Player player = new() 14 | { 15 | Email = request.Email, 16 | Username = request.Username, 17 | }; 18 | 19 | await _playersRepository.Create(player); 20 | 21 | return Unit.Value; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Euro2024Challenge.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Infrastructure/Database/Settings/ClassificationDatabaseSettingsSetup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.Options; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Settings; 5 | 6 | public class ClassificationDatabaseSettingsSetup : IConfigureOptions 7 | { 8 | private const string ConfigurationSectionName = "ClassificationDatabase"; 9 | private readonly IConfiguration _configuration; 10 | 11 | public ClassificationDatabaseSettingsSetup(IConfiguration configuration) 12 | { 13 | _configuration = configuration; 14 | } 15 | 16 | public void Configure(ClassificationDatabaseSettings options) 17 | { 18 | string connectionString = _configuration.GetConnectionString("ConnectionString")!; 19 | 20 | options.ConnectionString = connectionString; 21 | 22 | _configuration.GetSection(ConfigurationSectionName).Bind(options); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Euro2024Challenge.Backend.Modules.Players.Api/Euro2024Challenge.Backend.Modules.Players.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Euro2024Challenge.Backend.Modules.Players.Application.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Configuration/MatchBetsConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Configuration 7 | { 8 | internal class MatchBetsConfiguration : IEntityTypeConfiguration 9 | { 10 | public void Configure(EntityTypeBuilder builder) 11 | { 12 | builder.ToTable("MatchBets"); 13 | 14 | builder.Property(x => x.PlayerId) 15 | .IsRequired(); 16 | builder.Property(x => x.Result) 17 | .HasConversion(v => $"{v.HomeTeamGoals} : {v.AwayTeamGoals}", 18 | v => MatchResult.CreateNew(v)); 19 | builder.Property(x => x.Winner) 20 | .HasConversion(); 21 | 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Database/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace Euro2024Challenge.Shared.Database 6 | { 7 | public static class Extensions 8 | { 9 | public static IServiceCollection AddPostgres(this IServiceCollection services) where T : DbContext 10 | { 11 | services.ConfigureOptions(); 12 | 13 | services.AddDbContext((serviceProvider, option) => 14 | { 15 | var databaseOptions = serviceProvider.GetService>()!.Value; 16 | option.UseNpgsql(databaseOptions.ConnectionString, sqlOption => 17 | { 18 | sqlOption.EnableRetryOnFailure(databaseOptions.MaxRetryCount); 19 | sqlOption.CommandTimeout(databaseOptions.CommandTimeout); 20 | }); 21 | }); 22 | 23 | return services; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Migrations/20240522181806_ChangeColumnName.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Migrations 6 | { 7 | /// 8 | public partial class ChangeColumnName : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.RenameColumn( 14 | name: "Golas", 15 | schema: "tournaments", 16 | table: "Footballers", 17 | newName: "Goals"); 18 | } 19 | 20 | /// 21 | protected override void Down(MigrationBuilder migrationBuilder) 22 | { 23 | migrationBuilder.RenameColumn( 24 | name: "Goals", 25 | schema: "tournaments", 26 | table: "Footballers", 27 | newName: "Golas"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Api/Euro2024Challenge.Backend.Modules.Classification.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/FootballerRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 6 | 7 | public class FootballerRepository : IFootballerRepository 8 | { 9 | private readonly TournamentDbContext _tournamentDbContext; 10 | private DbSet _footballers; 11 | 12 | public FootballerRepository(TournamentDbContext tournamentDbContext) 13 | { 14 | _tournamentDbContext = tournamentDbContext; 15 | _footballers = tournamentDbContext.Footballers; 16 | } 17 | 18 | public async Task UpdateAsync(Footballer footballer) 19 | { 20 | _footballers.Update(footballer); 21 | await _tournamentDbContext.SaveChangesAsync(); 22 | } 23 | 24 | public async Task Get(int id) 25 | { 26 | return await _footballers.SingleAsync(x => x.Id == id); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /tests/Modules/Players/DomainTests/Modules.Players.Domain.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/IntegrationEventProcessorJob.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | 3 | namespace Euro2024Challenge.Shared; 4 | 5 | internal sealed class IntegrationEventProcessorJob : BackgroundService 6 | { 7 | private readonly InMemoryMessageQueue _messageQueue; 8 | private readonly IEventDispatcher _eventDispatcher; 9 | 10 | public IntegrationEventProcessorJob(InMemoryMessageQueue messageQueue, IEventDispatcher eventDispatcher) 11 | { 12 | _messageQueue = messageQueue; 13 | _eventDispatcher = eventDispatcher; 14 | } 15 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 16 | { 17 | await foreach (var integrationEvent in _messageQueue.Reader.ReadAllAsync(stoppingToken)) 18 | { 19 | try 20 | { 21 | await _eventDispatcher.PublishAsync(integrationEvent, stoppingToken); 22 | } 23 | catch (Exception exception) 24 | { 25 | Console.WriteLine(exception.Message); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Euro2024Challenge.Backend.Modules.Tournaments.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/IntegrationEvents/Handlers/PlayersMatchBetsClaculatedHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Services; 2 | using Euro2024Challenge.Backend.Modules.Players.Shared.Events; 3 | using Euro2024Challenge.Shared; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.IntegrationEvents.Handlers; 6 | 7 | public class MatchUpdatedHandler : IEventHandler 8 | { 9 | private readonly IPlayerClassificationService _playerClassificationService; 10 | 11 | public MatchUpdatedHandler(IPlayerClassificationService playerClassificationService) 12 | { 13 | _playerClassificationService = playerClassificationService; 14 | } 15 | 16 | public async Task HandleAsync(PlayerBetClaculated integrationEvent, CancellationToken cancellationToken = default) 17 | { 18 | Console.WriteLine("PlayersMatchBetsClaculated integrationEvent"); 19 | 20 | await _playerClassificationService.UpdatePlayerPoints(integrationEvent.PlayerId, integrationEvent.BetId, integrationEvent.Points); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Clients; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database; 4 | using Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Repositories; 5 | using Euro2024Challenge.Backend.Modules.Players.Shared; 6 | using Euro2024Challenge.Shared.Database; 7 | using Microsoft.Extensions.DependencyInjection; 8 | 9 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure 10 | { 11 | public static class DependencyInjection 12 | { 13 | public static IServiceCollection AddInfrastructure(this IServiceCollection services) 14 | { 15 | services 16 | .AddPostgres() 17 | .AddScoped() 18 | .AddScoped() 19 | .AddScoped(); 20 | 21 | return services; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Euro2024Challenge.Backend.Modules.Players.Api/RegisterModule.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | using Euro2024Challenge.Backend.Modules.Players.Application; 4 | using Euro2024Challenge.Backend.Modules.Players.Infrastructure; 5 | using Euro2024Challenge.Backend.Modules.Players.Presentation; 6 | using Microsoft.AspNetCore.Routing; 7 | using Euro2024Challenge.Backend.Modules.Players.Domain; 8 | 9 | namespace Euro2024Challenge.Backend.Modules.Players.Api 10 | { 11 | public static class RegisterModule 12 | { 13 | public static IServiceCollection RegisterPlayersModule(this IServiceCollection services) 14 | { 15 | services 16 | .AddDomain() 17 | .AddApplication() 18 | .AddInfrastructure() 19 | .AddPresentation(); 20 | 21 | return services; 22 | } 23 | 24 | public static IEndpointRouteBuilder UsePlayersModules(this IEndpointRouteBuilder app) 25 | { 26 | app.MapPlayersEndpoints(); 27 | app.MapPlayerBetsEndpoints(); 28 | 29 | return app; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/Modules/Tournaments/Tournamnets.Core.Tests/Modules.Tournamnets.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Presentation/Euro2024Challenge.Backend.Modules.Classification.Presentation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ..\..\..\..\..\..\..\..\..\usr\local\share\dotnet\shared\Microsoft.AspNetCore.App\8.0.3\Microsoft.AspNetCore.Routing.dll 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/TeamRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 6 | 7 | public class TeamRepository : ITeamRepository 8 | { 9 | private readonly DbSet _teams; 10 | 11 | public TeamRepository(TournamentDbContext tournamentDbContext) 12 | { 13 | _teams = tournamentDbContext.Teams; 14 | } 15 | 16 | public async Task GetTeamAsync(int id) 17 | { 18 | return await _teams.SingleAsync(x => x.Id == id); 19 | } 20 | 21 | public async Task> GetTeamsAsync(IEnumerable ids) 22 | { 23 | return await _teams.Where(x => ids.Contains(x.Id)) 24 | .ToDictionaryAsync(key => key.Id, v => v.Name); 25 | } 26 | 27 | public async Task> GetAllTeamsAsync() 28 | { 29 | return await _teams.ToDictionaryAsync(key => key.Id, v => v.Name); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/FootballerService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 4 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 7 | 8 | public class FootballerService : IFootballerService 9 | { 10 | private readonly IFootballerRepository _footballerRepository; 11 | 12 | public FootballerService(IFootballerRepository footballerRepository) 13 | { 14 | _footballerRepository = footballerRepository; 15 | } 16 | 17 | public async Task UpdateGoals(int id, int goals) 18 | { 19 | Footballer footballer = await _footballerRepository.Get(id); 20 | footballer.Goals = goals; 21 | 22 | await _footballerRepository.UpdateAsync(footballer); 23 | } 24 | 25 | public async Task Get(int id) 26 | { 27 | var footballer = await _footballerRepository.Get(id); 28 | return footballer.ToFootballerResponse(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Extensions/MatchExtension.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 5 | 6 | public static class MatchExtension 7 | { 8 | public static MatchResponse ToMatchResponse(this Match match, IDictionary teams) 9 | { 10 | return new MatchResponse(match.Id, match.Number, match.GuestTeamId, teams[match.GuestTeamId], 11 | match.AwayTeamId, teams[match.AwayTeamId], match.GuestTeamGoals, 12 | match.AwayTeamGoals, match.StartHour); 13 | } 14 | 15 | public static IEnumerable ToMatchesResponse(this IEnumerable matches, IDictionary teams) 16 | { 17 | return matches 18 | .Select(x => new MatchResponse(x.Id, x.Number, x.GuestTeamId, teams[x.GuestTeamId], 19 | x.AwayTeamId, teams[x.AwayTeamId], x.GuestTeamGoals, 20 | x.AwayTeamGoals, x.StartHour)); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Euro2024Challenge.Backend.Modules.Players.Api_org.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTopScorerBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 6 | { 7 | public class UpdateTopScorerCommandHandler : IRequestHandler 8 | { 9 | private readonly IPlayersBetsRepository _playersBetsRepository; 10 | 11 | public UpdateTopScorerCommandHandler(IPlayersBetsRepository playersBetsRepository) 12 | { 13 | _playersBetsRepository = playersBetsRepository; 14 | } 15 | 16 | public async Task Handle(UpdateTopScorerBetCommand request, CancellationToken cancellationToken) 17 | { 18 | var bet = new TopScorerBet 19 | { 20 | PlayerId = request.PLayerId, 21 | Goals = request.Goals, 22 | FootballerId = request.FootballerId 23 | }; 24 | 25 | await _playersBetsRepository.UpdateTopScorerBetAsync(bet); 26 | 27 | return Unit.Value; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/ValueObjects/MatchResult.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Shared.Domain; 2 | 3 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 4 | 5 | public class MatchResult : ValueObject 6 | { 7 | public ushort HomeTeamGoals { get; } 8 | public ushort AwayTeamGoals { get; } 9 | 10 | private MatchResult(ushort homeTeamGoals, ushort awayTeamGoals) 11 | { 12 | HomeTeamGoals = homeTeamGoals; 13 | AwayTeamGoals = awayTeamGoals; 14 | } 15 | 16 | public static MatchResult CreateNew(ushort homeTeamGoals, ushort awayTeamGoals) 17 | { 18 | return new MatchResult(homeTeamGoals, awayTeamGoals); 19 | } 20 | 21 | public static MatchResult CreateNew(string result) 22 | { 23 | string[] goals = result.Split(':'); 24 | return new MatchResult( 25 | ushort.Parse(goals[0]), 26 | ushort.Parse(goals[1]) 27 | ); 28 | } 29 | 30 | protected override IEnumerable GetEqualityComponents() 31 | { 32 | yield return HomeTeamGoals; 33 | yield return AwayTeamGoals; 34 | } 35 | 36 | public override string ToString() => $"{HomeTeamGoals} : {AwayTeamGoals}"; 37 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTournamentWinnerBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 6 | { 7 | public class CreateTournamentWinnerBetCommandHandler : IRequestHandler 8 | { 9 | private readonly IPlayersBetsRepository _playersBetsRepository; 10 | 11 | public CreateTournamentWinnerBetCommandHandler(IPlayersBetsRepository playersBetsRepository) 12 | { 13 | _playersBetsRepository = playersBetsRepository; 14 | } 15 | 16 | public async Task Handle(CreateTournamentWinnerBetCommand request, CancellationToken cancellationToken) 17 | { 18 | var bet = new TournamentWinnerBet() 19 | { 20 | TeamId = request.TeamId, 21 | PlayerId = request.PLayerId 22 | }; 23 | 24 | await _playersBetsRepository.CreateTournamentWinnerBetAsync(bet); 25 | 26 | return Unit.Value; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateTournamentWinnerBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 6 | { 7 | public class UpdateTournamentWinnerBetCommandHandler : IRequestHandler 8 | { 9 | private readonly IPlayersBetsRepository _playersBetsRepository; 10 | 11 | public UpdateTournamentWinnerBetCommandHandler(IPlayersBetsRepository playersBetsRepository) 12 | { 13 | _playersBetsRepository = playersBetsRepository; 14 | } 15 | 16 | public async Task Handle(UpdateTournamentWinnerBetCommand request, CancellationToken cancellationToken) 17 | { 18 | var bet = new TournamentWinnerBet 19 | { 20 | TeamId = request.TeamId, 21 | PlayerId = request.PLayerId 22 | }; 23 | 24 | await _playersBetsRepository.UpdateTournamentWinnerBetAsync(bet); 25 | 26 | return Unit.Value; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateTopScorerBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 6 | { 7 | public class CreateTopScorerBetCommandHandler : IRequestHandler 8 | { 9 | private readonly IPlayersBetsRepository _playersBetsRepository; 10 | 11 | public CreateTopScorerBetCommandHandler(IPlayersBetsRepository playersBetsRepository) 12 | { 13 | _playersBetsRepository = playersBetsRepository; 14 | } 15 | 16 | public async Task Handle(CreateTopScorerBetCommand request, CancellationToken cancellationToken) 17 | { 18 | var bet = new TopScorerBet() 19 | { 20 | PlayerId = request.PlayerId, 21 | FootballerId = request.FootballerId, 22 | Goals = request.Goals 23 | }; 24 | 25 | await _playersBetsRepository.CreateTopScorerBetAsync(bet); 26 | 27 | return Unit.Value; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Clients/PlayerModuleClient.cs: -------------------------------------------------------------------------------- 1 | 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Players.Shared; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Clients 6 | { 7 | public class PlayerModuleClient : IPlayerModuleApi 8 | { 9 | private readonly IPlayersRepository _playersRepository; 10 | 11 | public PlayerModuleClient(IPlayersRepository playersRepository) 12 | { 13 | _playersRepository = playersRepository; 14 | } 15 | 16 | public async Task> GetPlayersUsernames(IEnumerable playersIds) 17 | { 18 | List players = await _playersRepository.GetPlayers(playersIds.ToList()); 19 | 20 | Dictionary result = []; 21 | 22 | foreach (var item in playersIds) 23 | { 24 | Domain.Entities.Player? player = players.FirstOrDefault(x => x.Id == item && !string.IsNullOrWhiteSpace(x.Username)); 25 | result.Add(item, player is null ? string.Empty : player.Username); 26 | } 27 | 28 | return result; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Events/EventDispatcher.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Euro2024Challenge.Shared; 5 | 6 | public class EventDispatcher : IEventDispatcher 7 | { 8 | private readonly IServiceProvider _serviceProvider; 9 | 10 | public EventDispatcher(IServiceProvider serviceProvider) 11 | { 12 | _serviceProvider = serviceProvider; 13 | } 14 | 15 | public async Task PublishAsync(TEvent integrationEvent, CancellationToken cancellationToken) where TEvent : class, IEvent 16 | { 17 | 18 | using var scope = _serviceProvider.CreateScope(); 19 | var handlers = scope.ServiceProvider.GetServices>(); 20 | 21 | var handlerType = typeof(IEventHandler<>).MakeGenericType(integrationEvent.GetType()); 22 | var handlers3 = scope.ServiceProvider.GetServices(handlerType); 23 | var method = handlerType.GetMethod(nameof(IEventHandler.HandleAsync)); 24 | var tasks = handlers3.Select(x => (Task)method.Invoke(x, new object[] { integrationEvent, cancellationToken })); 25 | var tasks2 = handlers.Select(x => x.HandleAsync(integrationEvent, cancellationToken)); 26 | 27 | await Task.WhenAll(tasks); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:54072", 8 | "sslPort": 44315 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5236", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7086;http://localhost:5236", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:62869", 8 | "sslPort": 44377 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5047", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:7049;http://localhost:5047", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:31985", 8 | "sslPort": 44332 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5119", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:7020;http://localhost:5119", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetPlayerClassifications/GetPlayerClassificationsQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Extensions; 2 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 3 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 4 | using MediatR; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetPlayerClassifications; 7 | 8 | public class GetPlayerClassificationsQueryHandler : IRequestHandler 9 | { 10 | private readonly IClassificationRepository _classificationRepository; 11 | 12 | public GetPlayerClassificationsQueryHandler(IClassificationRepository classificationRepository) 13 | { 14 | _classificationRepository = classificationRepository; 15 | } 16 | 17 | public async Task Handle(GetPlayerClassificationsQuery request, CancellationToken cancellationToken) 18 | { 19 | IReadOnlyCollection betsPoints = await _classificationRepository.Get(request.PlayerId); 20 | 21 | return betsPoints.ToGetPlayerClassificationsResponse(request.PlayerId); 22 | } 23 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Extensions/MatchBetExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 5 | 6 | public static class MatchBetExtensions 7 | { 8 | private static PlayerMatchBetDto ToPlayerMatchBetDto(this MatchBet matchBet, Tournament.Shared.DTO.MatchResponse match) 9 | { 10 | return new PlayerMatchBetDto 11 | { 12 | PlayerId = matchBet.PlayerId, 13 | MatchId = matchBet.MatchId, 14 | HomeTeam = match.GuestTeamName, 15 | HomeTeamGoals = matchBet.Result.HomeTeamGoals, 16 | AwayTeam = match.AwayTeamName, 17 | AwayTeamGoals = matchBet.Result.AwayTeamGoals, 18 | Result = matchBet.Winner.ToStringOutput(match.AwayTeamName, match.GuestTeamName) 19 | }; 20 | } 21 | 22 | public static IEnumerable ToPlayerMatchBetDto(this IEnumerable matchBets, IReadOnlyCollection matches) 23 | { 24 | return matchBets.Select(x => { 25 | var match = matches.First(m => m.Number == x.MatchId); 26 | return x.ToPlayerMatchBetDto(match); 27 | 28 | } ); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Error.razor: -------------------------------------------------------------------------------- 1 | @page "/Error" 2 | @using System.Diagnostics 3 | 4 | Error 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (ShowRequestId) 10 | { 11 |

12 | Request ID: @RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | 27 | @code{ 28 | [CascadingParameter] 29 | private HttpContext? HttpContext { get; set; } 30 | 31 | private string? RequestId { get; set; } 32 | private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 33 | 34 | protected override void OnInitialized() => 35 | RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; 36 | } 37 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/CreatePlayerClassification/CreatePlayerClassificationCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 3 | using MediatR; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.CreatePlayerClassification; 6 | 7 | public class CreatePlayerClassificationCommandHandler : IRequestHandler 8 | { 9 | readonly IClassificationRepository _classificationRepository; 10 | public CreatePlayerClassificationCommandHandler(IClassificationRepository classificationRepository) 11 | { 12 | _classificationRepository = classificationRepository; 13 | } 14 | 15 | public async Task Handle(CreatePlayerClassificationCommand request, CancellationToken cancellationToken) 16 | { 17 | PlayerBetPoints playerBetPoints = new() 18 | { 19 | Id = Guid.NewGuid().ToString(), 20 | PlayerId = request.PlayerId.ToString(), 21 | BetId = request.BetId.ToString(), 22 | Points = request.Points 23 | }; 24 | 25 | await _classificationRepository.Insert(playerBetPoints); 26 | 27 | return Unit.Value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Update/UpdateMatchBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 4 | using MediatR; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update 7 | { 8 | public class UpdateMatchBetCommandHandler : IRequestHandler 9 | { 10 | private readonly IPlayersBetsRepository _playersBetsRepository; 11 | 12 | public UpdateMatchBetCommandHandler(IPlayersBetsRepository playersBetsRepository) 13 | { 14 | _playersBetsRepository = playersBetsRepository; 15 | } 16 | 17 | public async Task Handle(UpdateMatchBetCommand request, CancellationToken cancellationToken) 18 | { 19 | var bet = new MatchBet 20 | { 21 | MatchId = request.MatchId, 22 | Result = MatchResult.CreateNew((ushort)request.HomeTeamGoals, (ushort)request.AwayTeamGoals), 23 | PlayerId = request.PLayerId, 24 | Winner = request.Winner 25 | }; 26 | 27 | await _playersBetsRepository.UpdateMatchBetAsync(bet); 28 | 29 | return Unit.Value; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Create/CreateMatchBetCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 4 | using MediatR; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create 7 | { 8 | public class CreateMatchBetCommandHandler : IRequestHandler 9 | { 10 | private readonly IPlayersBetsRepository _playersBetsRepository; 11 | 12 | public CreateMatchBetCommandHandler(IPlayersBetsRepository playersBetsRepository) 13 | { 14 | _playersBetsRepository = playersBetsRepository; 15 | } 16 | 17 | public async Task Handle(CreateMatchBetCommand request, CancellationToken cancellationToken) 18 | { 19 | var bet = new MatchBet 20 | { 21 | MatchId = request.MatchId, 22 | Result = MatchResult.CreateNew((ushort)request.HomeTeamGoals, (ushort)request.AwayTeamGoals), 23 | PlayerId = request.PLayerId, 24 | Winner = request.Winner 25 | }; 26 | 27 | await _playersBetsRepository.CreateMatchBetAsync(bet); 28 | 29 | return Unit.Value; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Euro2024Challenge.Backend.Modules.Players.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Backend/Shared/Euro2024Challenge.Shared/Domain/ValueObject.cs: -------------------------------------------------------------------------------- 1 | namespace Euro2024Challenge.Shared.Domain; 2 | 3 | public abstract class ValueObject 4 | { 5 | protected static bool EqualOperator(ValueObject left, ValueObject right) 6 | { 7 | if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) 8 | { 9 | return false; 10 | } 11 | return ReferenceEquals(left, right) || left.Equals(right); 12 | } 13 | 14 | protected static bool NotEqualOperator(ValueObject left, ValueObject right) 15 | { 16 | return !EqualOperator(left, right); 17 | } 18 | 19 | protected abstract IEnumerable GetEqualityComponents(); 20 | 21 | public override bool Equals(object? obj) 22 | { 23 | if (obj == null || obj.GetType() != GetType()) 24 | { 25 | return false; 26 | } 27 | 28 | var other = (ValueObject)obj; 29 | 30 | return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); 31 | } 32 | 33 | public override int GetHashCode() 34 | { 35 | return GetEqualityComponents() 36 | .Select(x => x != null ? x.GetHashCode() : 0) 37 | .Aggregate((x, y) => x ^ y); 38 | } 39 | 40 | public static bool operator ==(ValueObject one, ValueObject two) 41 | { 42 | return EqualOperator(one, two); 43 | } 44 | 45 | public static bool operator !=(ValueObject one, ValueObject two) 46 | { 47 | return NotEqualOperator(one, two); 48 | } 49 | } -------------------------------------------------------------------------------- /src/Backend/Bootstrapper/Euro2024Challenge.Backend.Bootstrapper/Euro2024Challenge.Backend.Bootstrapper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Repositories/MatchRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 6 | 7 | public class MatchRepository : IMatchRepository 8 | { 9 | private readonly TournamentDbContext _tournamentDbContext; 10 | private readonly DbSet _matches; 11 | 12 | public MatchRepository(TournamentDbContext tournamentDbContext) 13 | { 14 | _tournamentDbContext = tournamentDbContext; 15 | _matches = tournamentDbContext.Matches; 16 | } 17 | 18 | public async Task AddAsync(Match match) 19 | { 20 | await _matches.AddAsync(match); 21 | await _tournamentDbContext.SaveChangesAsync(); 22 | } 23 | 24 | public async Task UpdateAsync(Match match) 25 | { 26 | _matches.Update(match); 27 | await _tournamentDbContext.SaveChangesAsync(); 28 | } 29 | 30 | public async Task> GetAll() 31 | { 32 | return await _matches.ToListAsync(); 33 | } 34 | 35 | public async Task GetByNumber(int number) 36 | { 37 | return await _matches.SingleAsync(x => x.Number == number); 38 | } 39 | 40 | public async Task> GetByNumbers(int[] numbers) 41 | { 42 | return (await _matches.Where(x => numbers.Contains(x.Number)).ToListAsync()).AsReadOnly(); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Bets/Get/GetPlayerBetsQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 3 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 4 | using Euro2024Challenge.Backend.Modules.Tournament.Shared; 5 | using MediatR; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get 8 | { 9 | internal sealed class GetPlayerBetsQueryHandler(IPlayersRepository playersRepository, ITournamentModuleApi tournamentModuleApi) : IRequestHandler 10 | { 11 | private readonly IPlayersRepository _playersRepository = playersRepository; 12 | private readonly ITournamentModuleApi _tournamentModuleApi = tournamentModuleApi; 13 | 14 | public async Task Handle(GetPlayerBetsQuery request, CancellationToken cancellationToken) 15 | { 16 | var result = await _playersRepository.GetWithBets(request.PlayerId); 17 | 18 | var team = result.TournamentWinnerBet is null ? null : await _tournamentModuleApi.GetTeam(result.TournamentWinnerBet.TeamId); 19 | var match = await _tournamentModuleApi.GetMatches(result.MatchBets.Select(m => m.MatchId).ToArray()); 20 | var footballer = result.TopScorerBet is null ? null : await _tournamentModuleApi.GetFootballer(result.TopScorerBet.FootballerId); 21 | 22 | return result.ToPlayerBetsDto(team, footballer, match); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Clients/TournamentModuleApi.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared; 2 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core; 6 | 7 | public class TournamentModuleApi : ITournamentModuleApi 8 | { 9 | private readonly IMatchService _matchService; 10 | private readonly ITeamService _teamService; 11 | private readonly IFootballerService _footballerService; 12 | 13 | public TournamentModuleApi(IMatchService matchService, ITeamService teamService, IFootballerService footballerService) 14 | { 15 | _matchService = matchService; 16 | _teamService = teamService; 17 | _footballerService = footballerService; 18 | } 19 | 20 | public async Task GetTeam(int id) 21 | { 22 | var result = await _teamService.GetTeamAsync(id); 23 | return result; 24 | } 25 | 26 | public async Task GetFootballer(int id) 27 | { 28 | var result = await _footballerService.Get(id); 29 | return result; 30 | } 31 | 32 | public async Task> GetMatches(int[] matchIds) 33 | { 34 | if(!matchIds.Any()) 35 | { 36 | return (IReadOnlyCollection)Enumerable.Empty(); 37 | } 38 | 39 | var result = await _matchService.GetByNumbers(matchIds); 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Classifications/GetClassifications/GetClassificationsQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Extensions; 2 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 3 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 4 | using Euro2024Challenge.Backend.Modules.Players.Shared; 5 | using MediatR; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetClassifications; 8 | 9 | public class GetClassificationsQueryHandler : IRequestHandler> 10 | { 11 | private readonly IClassificationRepository _classificationRepository; 12 | private readonly IPlayerModuleApi _playerModuleApi; 13 | 14 | public GetClassificationsQueryHandler(IClassificationRepository classificationRepository, IPlayerModuleApi playerModuleApi) 15 | { 16 | _classificationRepository = classificationRepository; 17 | _playerModuleApi = playerModuleApi; 18 | } 19 | 20 | public async Task> Handle(GetClassificationsQuery request, CancellationToken cancellationToken) 21 | { 22 | IReadOnlyCollection betsPoints = await _classificationRepository.GetAll(); 23 | 24 | var playersUsernames = await _playerModuleApi.GetPlayersUsernames(betsPoints.Select(x => Guid.Parse(x.PlayerId)).Distinct()); 25 | 26 | return betsPoints.ToGetClassificationsResponse(playersUsernames).AsReadOnly(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Presentation/PlayersEndpoints.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Routing; 4 | using MediatR; 5 | 6 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.Create; 7 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.Get; 8 | using Microsoft.AspNetCore.Mvc; 9 | 10 | namespace Euro2024Challenge.Backend.Modules.Players.Presentation; 11 | 12 | public static class PlayersEndpoints 13 | { 14 | public static void MapPlayersEndpoints(this IEndpointRouteBuilder app) 15 | { 16 | var players = app.MapGroup("players-module/players"); 17 | 18 | players.MapPost("", CreatePlayer) 19 | .Produces(201); 20 | 21 | players.MapGet("/{playerId:guid}", GetPlayer) 22 | .Produces(200); 23 | 24 | players.MapGet("", GetAllPlayers) 25 | .Produces(200); 26 | } 27 | 28 | private static async Task CreatePlayer([FromServices] ISender sender, CreatePlayerRequest request) 29 | { 30 | await sender.Send(new CreatePlayerCommand(request.Email, request.Username)); 31 | 32 | return Results.Ok(); 33 | } 34 | 35 | private static async Task GetPlayer([FromServices] ISender sender, Guid playerId) 36 | { 37 | var player = await sender.Send(new GetPlayerQuery(playerId)); 38 | 39 | return Results.Ok(player); 40 | } 41 | 42 | private static async Task GetAllPlayers([FromServices] ISender sender) 43 | { 44 | var players = await sender.Send(new GetPlayersQuery()); 45 | 46 | return Results.Ok(players); 47 | } 48 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logoeuro](https://github.com/krzyspie/Euro2024Challenge/assets/47896601/156b1a23-9fe7-48f8-b313-8b190773748c) 2 | 3 | # Euro 2024 challange app 4 | 5 | ## About 6 | The Euro 2024 Challenge app is an application where football fans will have the opportunity to bet the Euro 2024 championship. 7 | 8 | ## Why this app? 9 | I decided to write this application because I'm personally a football fan, and I wanted to build an application from scratch. With this application, I aim to gain knowledge in software architecture, focusing mainly on modular monolith and DDD. 10 | 11 | ## Assumptions 12 | The application will be written as a modular monolith so that in the future, it could be rewritten as microservices, which will be my next learning step. Additionally, I want to incorporate Domain-Driven Design concepts. I haven't worked on applications using DDD in my career, so by writing this app, I aim to become familiar with this concept. 13 | I want to develop both the backend and frontend to create a fully functional app. The backend will be written in .NET 8 using C#, and for the frontend, I will use React. Since I don't have experience with React, this application is also an excellent opportunity for me to gain knowledge of the library. 14 | 15 | ## Features 16 | - Register a user. 17 | - Once registered, the user can create a player after logging in. 18 | - The player can select a team they believe will win the championship. 19 | - Before each match, the player can make predictions on the match result. 20 | - Players will earn points for each correctly predicted match. 21 | - A ranking of players will be presented. 22 | 23 | ## Tech stack 24 | - .NET 8 25 | - C# 26 | - Postgres 27 | - EF Core 28 | - React 29 | - Use channels for integral events 30 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Layout/NavMenu.razor: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 39 | 40 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Services/PlayerClassifiactionService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Services; 5 | 6 | public class PlayerClassifiactionService : IPlayerClassificationService 7 | { 8 | private readonly IClassificationRepository _classificationRepository; 9 | 10 | public PlayerClassifiactionService(IClassificationRepository classificationRepository) 11 | { 12 | _classificationRepository = classificationRepository; 13 | } 14 | 15 | public async Task UpdatePlayerPoints(Guid playerId, Guid betId, int points) 16 | { 17 | var playerBetPoints = await _classificationRepository.GetBetPoints(playerId, betId); 18 | 19 | if (playerBetPoints is null) 20 | { 21 | PlayerBetPoints betPoints = new() 22 | { 23 | Id = Guid.NewGuid().ToString(), 24 | PlayerId = playerId.ToString(), 25 | BetId = betId.ToString(), 26 | Points = points 27 | }; 28 | 29 | await _classificationRepository.Insert(betPoints); 30 | } 31 | else 32 | { 33 | PlayerBetPoints betPoints = new() 34 | { 35 | Id = playerBetPoints.Id, 36 | PlayerId = playerId.ToString(), 37 | BetId = betId.ToString(), 38 | Points = playerBetPoints.Points + points 39 | }; 40 | 41 | await _classificationRepository.Update(betPoints); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Migrations/20240504104836_UpdateMatchBet.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Migrations 6 | { 7 | /// 8 | public partial class UpdateMatchBet : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "Result", 15 | schema: "players", 16 | table: "MatchBets", 17 | type: "text", 18 | nullable: true, 19 | oldClrType: typeof(string), 20 | oldType: "text"); 21 | 22 | migrationBuilder.AddColumn( 23 | name: "Winner", 24 | schema: "players", 25 | table: "MatchBets", 26 | type: "integer", 27 | nullable: false, 28 | defaultValue: 0); 29 | } 30 | 31 | /// 32 | protected override void Down(MigrationBuilder migrationBuilder) 33 | { 34 | migrationBuilder.DropColumn( 35 | name: "Winner", 36 | schema: "players", 37 | table: "MatchBets"); 38 | 39 | migrationBuilder.AlterColumn( 40 | name: "Result", 41 | schema: "players", 42 | table: "MatchBets", 43 | type: "text", 44 | nullable: false, 45 | defaultValue: "", 46 | oldClrType: typeof(string), 47 | oldType: "text", 48 | oldNullable: true); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/IntegrationEvents/Handlers/MatchUpdatedHandler.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Services; 3 | using Euro2024Challenge.Backend.Modules.Players.Shared.Events; 4 | using Euro2024Challenge.Backend.Modules.Tournament.Shared; 5 | using Euro2024Challenge.Shared; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Players.Application.IntegrationEvents.Handlers; 8 | 9 | public class MatchUpdatedHandler : IEventHandler 10 | { 11 | private readonly IEventBus _eventBus; 12 | private readonly IPlayersRepository _playersRepository; 13 | private readonly IPointsCalculator _pointsCalculator; 14 | 15 | public MatchUpdatedHandler(IEventBus eventBus, IPlayersRepository playersRepository, IPointsCalculator pointsCalculator) 16 | { 17 | _eventBus = eventBus; 18 | _playersRepository = playersRepository; 19 | _pointsCalculator = pointsCalculator; 20 | } 21 | public async Task HandleAsync(MatchUpdated integrationEvent, CancellationToken cancellationToken = default) 22 | { 23 | Console.WriteLine("MatchUpdatedHandler integrationEvent"); 24 | 25 | var playersMatchBets = await _playersRepository.GetAllPlayersMatchBets(); 26 | 27 | foreach(var item in playersMatchBets) 28 | { 29 | var matchBet = item.MatchBets.FirstOrDefault(x => x.MatchId == integrationEvent.MatchId); 30 | if (matchBet is null) 31 | { 32 | continue; 33 | } 34 | 35 | var betPoints = _pointsCalculator.CalculateMatchPoints(integrationEvent.HomeTeamGoals, integrationEvent.AwayTeamGoals, matchBet.Result); 36 | 37 | await _eventBus.PublishAsync(new PlayerBetClaculated(matchBet.PlayerId, matchBet.Id, betPoints)); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Repositories/PlayersRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Repositories 6 | { 7 | internal class PlayersRepository : IPlayersRepository 8 | { 9 | private readonly PlayersDbContext _context; 10 | private readonly DbSet _players; 11 | 12 | public PlayersRepository(PlayersDbContext context) 13 | { 14 | _context = context; 15 | _players = _context.Players; 16 | } 17 | 18 | public async Task Create(Player player) 19 | { 20 | await _players.AddAsync(player); 21 | await _context.SaveChangesAsync(); 22 | } 23 | 24 | public Task Get(Guid playerId) 25 | { 26 | return _players.SingleAsync(p => p.Id == playerId); 27 | } 28 | 29 | public Task> GetPlayers(List playersIds) 30 | { 31 | return _players.Where(p => playersIds.Contains(p.Id)).ToListAsync(); 32 | } 33 | 34 | public async Task> GetAllPlayersMatchBets() 35 | { 36 | return await _players 37 | .Include(m => m.MatchBets).ToListAsync(); 38 | } 39 | 40 | public Task GetWithBets(Guid playerId) 41 | { 42 | return _players 43 | .Include(m => m.MatchBets) 44 | .Include(w => w.TournamentWinnerBet) 45 | .Include(s => s.TopScorerBet) 46 | .SingleAsync(p => p.Id == playerId); 47 | } 48 | 49 | public Task> GetAllPlayers() 50 | { 51 | return _players.ToListAsync(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Services/PointsCalculator.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Services; 5 | 6 | public class PointsCalculator : IPointsCalculator 7 | { 8 | public int CalculateMatchPoints(int homeTeamGoals, int awayTeamGoals, MatchResult? bet) 9 | { 10 | if (bet is null) 11 | { 12 | return 0; 13 | } 14 | 15 | if (bet.HomeTeamGoals == homeTeamGoals && bet.AwayTeamGoals == awayTeamGoals) 16 | { 17 | return 5; 18 | } 19 | 20 | var resultDifference = homeTeamGoals - awayTeamGoals; 21 | var betResultDifference = bet.HomeTeamGoals - bet.AwayTeamGoals; 22 | if (resultDifference == betResultDifference) 23 | { 24 | return 3; 25 | } 26 | 27 | if (homeTeamGoals > awayTeamGoals && bet.HomeTeamGoals > bet.AwayTeamGoals) 28 | { 29 | return 2; 30 | } 31 | if (homeTeamGoals < awayTeamGoals && bet.HomeTeamGoals < bet.AwayTeamGoals) 32 | { 33 | return 2; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | public int CalculateTournamentWinnerPoints(int winnerTeamId, TournamentWinnerBet tournamentWinnerBet) 40 | { 41 | return winnerTeamId == tournamentWinnerBet.TeamId ? 10 : 0; 42 | } 43 | 44 | public int CalculateTopScorerFootballerPoints(int playerId, int playerGolas, TopScorerBet topScorerBet) 45 | { 46 | if (playerId == topScorerBet.FootballerId && playerGolas == topScorerBet.Goals) 47 | { 48 | return 20; 49 | } 50 | 51 | if (playerId == topScorerBet.FootballerId) 52 | { 53 | return 10; 54 | } 55 | 56 | return 0; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Application/Extensions/PlayerBetPointsExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetClassifications; 2 | using Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetPlayerClassifications; 3 | using Euro2024Challenge.Backend.Modules.Classification.Application.Dto; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Classification.Application.Extensions; 6 | 7 | public static class PlayerBetPointsxtensions 8 | { 9 | public static GetPlayerClassificationsResponse ToGetPlayerClassificationsResponse(this IEnumerable betPoints, Guid playerId) 10 | { 11 | return new GetPlayerClassificationsResponse() 12 | { 13 | PlayerId = playerId, 14 | BetsPoints = betPoints 15 | .Select(x => new BetPointsDto() { BetId = Guid.Parse(x.BetId), Points = x.Points }) 16 | .ToList() 17 | .AsReadOnly() 18 | }; 19 | } 20 | 21 | public static List ToGetClassificationsResponse(this IEnumerable betPoints, IDictionary playersUsernames) 22 | { 23 | IEnumerable> playerBetPointsSum = betPoints.GroupBy(p => p.PlayerId, p => p.Points); 24 | 25 | List result = []; 26 | 27 | foreach (var item in playerBetPointsSum) 28 | { 29 | string userName = string.Empty; 30 | var id = Guid.Parse(item.Key); 31 | playersUsernames.TryGetValue(id, out userName); 32 | result.Add(new GetClassificationsResponse 33 | { 34 | PlayerId = id, 35 | PlayerUsername = userName, 36 | Points = item.Sum() 37 | }); 38 | } 39 | 40 | return result; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Pages/Weather.razor: -------------------------------------------------------------------------------- 1 | @page "/weather" 2 | @attribute [StreamRendering] 3 | 4 | Weather 5 | 6 |

Weather

7 | 8 |

This component demonstrates showing data.

9 | 10 | @if (forecasts == null) 11 | { 12 |

Loading...

13 | } 14 | else 15 | { 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | @foreach (var forecast in forecasts) 27 | { 28 | 29 | 30 | 31 | 32 | 33 | 34 | } 35 | 36 |
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
37 | } 38 | 39 | @code { 40 | private WeatherForecast[]? forecasts; 41 | 42 | protected override async Task OnInitializedAsync() 43 | { 44 | // Simulate asynchronous loading to demonstrate streaming rendering 45 | await Task.Delay(500); 46 | 47 | var startDate = DateOnly.FromDateTime(DateTime.Now); 48 | var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; 49 | forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast 50 | { 51 | Date = startDate.AddDays(index), 52 | TemperatureC = Random.Shared.Next(-20, 55), 53 | Summary = summaries[Random.Shared.Next(summaries.Length)] 54 | }).ToArray(); 55 | } 56 | 57 | private class WeatherForecast 58 | { 59 | public DateOnly Date { get; set; } 60 | public int TemperatureC { get; set; } 61 | public string? Summary { get; set; } 62 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Presentation/ClassificationEndpoints.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.CreatePlayerClassification; 2 | using Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetClassifications; 3 | using Euro2024Challenge.Backend.Modules.Classification.Application.Classifications.GetPlayerClassifications; 4 | using MediatR; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.AspNetCore.Routing; 9 | 10 | namespace Euro2024Challenge.Backend.Modules.Classification.Presentation; 11 | 12 | public static class ClassificationEndpoints 13 | { 14 | public static void MapClassificationEndpoints(this IEndpointRouteBuilder app) 15 | { 16 | var classifications = app.MapGroup("classifications-module/classifications"); 17 | 18 | classifications.MapGet("", GetClassifications) 19 | .Produces(200); 20 | 21 | classifications.MapGet("{playerId:guid}", GetPlayerClassifications) 22 | .Produces(200); 23 | 24 | classifications.MapPost("", CreatePlayerClassification) 25 | .Produces(200); 26 | } 27 | 28 | private static async Task> GetClassifications([FromServices] ISender sender) 29 | { 30 | var result = await sender.Send(new GetClassificationsQuery()); 31 | 32 | return result; 33 | } 34 | 35 | private static async Task GetPlayerClassifications([FromServices] ISender sender, Guid playerId) 36 | { 37 | var result = await sender.Send(new GetPlayerClassificationsQuery(playerId)); 38 | 39 | return result; 40 | } 41 | 42 | private static async Task CreatePlayerClassification([FromServices] ISender sender, CreatePlayerClassificationRequest request) 43 | { 44 | await sender.Send(new CreatePlayerClassificationCommand(request.PlayerId, request.BetId, request.Points)); 45 | 46 | return Results.Ok("Get for player"); 47 | } 48 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Domain/Entities/Player.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 2 | using Euro2024Challenge.Shared.Domain; 3 | 4 | namespace Euro2024Challenge.Backend.Modules.Players.Domain.Entities 5 | { 6 | public sealed class Player : BaseEntity, IAggregateRoot 7 | { 8 | public required string Email { get; set; } 9 | public required string Username { get; set; } 10 | 11 | public TopScorerBet TopScorerBet { get; private set; } = null!; 12 | public TournamentWinnerBet TournamentWinnerBet { get; private set; } = null!; 13 | public ICollection MatchBets { get; private set; } = new List(); 14 | 15 | public void ChangeTopScorerBet(int footballerId, int goals) 16 | { 17 | TopScorerBet = new TopScorerBet 18 | { 19 | PlayerId = Id, 20 | FootballerId = footballerId, 21 | Goals = goals 22 | }; 23 | } 24 | 25 | public void ChangeTournamentWinnerBet(int teamId) 26 | { 27 | TournamentWinnerBet = new TournamentWinnerBet 28 | { 29 | PlayerId = Id, 30 | TeamId = teamId 31 | }; 32 | } 33 | 34 | public void AddMatchBet(int matchId, ushort homeTeamGoals, ushort awayTeamGoals) 35 | { 36 | var matchBet = new MatchBet 37 | { 38 | PlayerId = Id, 39 | MatchId = matchId, 40 | Result = MatchResult.CreateNew(homeTeamGoals, awayTeamGoals) 41 | }; 42 | 43 | MatchBets.Add(matchBet); 44 | } 45 | 46 | public void UpdateMatchBet(int matchId, ushort homeTeamGoals, ushort awayTeamGoals) 47 | { 48 | var bet = MatchBets.SingleOrDefault(x => x.MatchId == matchId); 49 | 50 | if (bet is null) 51 | { 52 | return; 53 | } 54 | 55 | MatchBets.Remove(bet); 56 | 57 | AddMatchBet(matchId, homeTeamGoals, awayTeamGoals); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/Modules/Players/DomainTests/Services/PointsCalculatorTests.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Services; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.ValueObjects; 3 | 4 | namespace Modules.Players.Domain.Tests.Services; 5 | 6 | public class Tests 7 | { 8 | [Test] 9 | public void CalculateMatchPointsWhenMissingMatchResult() 10 | { 11 | //Arrange 12 | PointsCalculator pointsCalculator = new(); 13 | 14 | //Act 15 | var result = pointsCalculator.CalculateMatchPoints(0, 0, null); 16 | 17 | //Assert 18 | Assert.That(result, Is.Zero); 19 | } 20 | 21 | [Test] 22 | public void CalculateMatchPointsWhenBetsGoalsAndMatchGoalsEquals() 23 | { 24 | //Arrange 25 | PointsCalculator pointsCalculator = new(); 26 | var matchResult = MatchResult.CreateNew(2, 1); 27 | 28 | //Act 29 | var result = pointsCalculator.CalculateMatchPoints(2, 1, matchResult); 30 | 31 | //Assert 32 | Assert.That(result, Is.EqualTo(5)); 33 | } 34 | 35 | [Test] 36 | public void CalculateMatchPointsWhenBetsGoalsAndMatchGoalsDifferenceEquals() 37 | { 38 | //Arrange 39 | PointsCalculator pointsCalculator = new(); 40 | var matchResult = MatchResult.CreateNew(3, 2); 41 | 42 | //Act 43 | var result = pointsCalculator.CalculateMatchPoints(2, 1, matchResult); 44 | 45 | //Assert 46 | Assert.That(result, Is.EqualTo(3)); 47 | } 48 | 49 | 50 | [TestCase(2, 1, 3, 1)] 51 | [TestCase(1, 2, 1, 3)] 52 | public void CalculateMatchPointsWhenBetWinnerAndMatchWinnerEquals(int homeTeamGoals, int awayTeamGoals, int betHomeTeamGoals, int betAwayTemaGoals) 53 | { 54 | //Arrange 55 | PointsCalculator pointsCalculator = new(); 56 | var matchResult = MatchResult.CreateNew((ushort)betHomeTeamGoals, (ushort)betAwayTemaGoals); 57 | 58 | //Act 59 | var result = pointsCalculator.CalculateMatchPoints(homeTeamGoals, awayTeamGoals, matchResult); 60 | 61 | //Assert 62 | Assert.That(result, Is.EqualTo(2)); 63 | } 64 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.BackgroundServices; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 4 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 5 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 6 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Cache; 7 | using Euro2024Challenge.Shared.Database; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Quartz; 10 | 11 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core 12 | { 13 | public static class DependencyInjection 14 | { 15 | public static IServiceCollection AddCore(this IServiceCollection services) 16 | { 17 | services 18 | .AddPostgres() 19 | .AddMemoryCache() 20 | .AddScoped() 21 | .AddScoped() 22 | .AddScoped() 23 | .AddScoped() 24 | .AddScoped() 25 | .AddScoped() 26 | .AddTransient() 27 | .AddSingleton(); 28 | 29 | services.AddQuartz(configure => 30 | { 31 | var jobKey = new JobKey(nameof(FetchTournamentDataJob)); 32 | 33 | configure 34 | .AddJob(jobKey) 35 | .AddTrigger(t => t 36 | .ForJob(jobKey) 37 | .StartNow() 38 | .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 10))); 39 | }); 40 | services.AddQuartzHostedService(options => 41 | { 42 | options.WaitForJobsToComplete = true; 43 | }); 44 | 45 | return services; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Application/Extensions/PlayerExtensions.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.DTO; 2 | using Euro2024Challenge.Backend.Modules.Players.Application.Players.DTO; 3 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 4 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 5 | 6 | namespace Euro2024Challenge.Backend.Modules.Players.Application.Extensions; 7 | 8 | public static class PlayerExtensions 9 | { 10 | public static PlayerDto ToPlayerDto(this Player player) 11 | { 12 | return new PlayerDto 13 | { 14 | Id = player.Id, 15 | Username = player.Username, 16 | Email = player.Email 17 | }; 18 | } 19 | 20 | public static IEnumerable ToPlayersDto(this IEnumerable players) 21 | { 22 | return players.Select(x => new PlayerDto 23 | { 24 | Id = x.Id, 25 | Username = x.Username, 26 | Email = x.Email 27 | }); 28 | } 29 | 30 | public static PlayerBetsDto ToPlayerBetsDto(this Player player, TeamResponse? tournamentWinnerTeam, FootballerResponse? footballer, IReadOnlyCollection matches) 31 | { 32 | return new PlayerBetsDto 33 | { 34 | PlayerId = player.Id, 35 | TopScorerBet = player.TopScorerBet is null 36 | ? null 37 | : new PlayerTopScorerBetDto 38 | { 39 | //FootballerId = player.TopScorerBet.FootballerId, 40 | Goals = player.TopScorerBet.Goals, 41 | FullName = footballer.FullName, 42 | TeamName = footballer.TeamName 43 | }, 44 | TournamentWinner = player.TournamentWinnerBet is null 45 | ? null 46 | : new PlayerTournamentWinnerBetDto 47 | { 48 | TeamId = player.TournamentWinnerBet.TeamId, 49 | TeamName = tournamentWinnerTeam.Name 50 | }, 51 | MatchBets = player.MatchBets is null 52 | ? Enumerable.Empty() 53 | : player.MatchBets.ToPlayerMatchBetDto(matches) 54 | }; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Layout/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row ::deep .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | text-decoration: none; 28 | } 29 | 30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { 31 | text-decoration: underline; 32 | } 33 | 34 | .top-row ::deep a:first-child { 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | } 38 | 39 | @media (max-width: 640.98px) { 40 | .top-row { 41 | justify-content: space-between; 42 | } 43 | 44 | .top-row ::deep a, .top-row ::deep .btn-link { 45 | margin-left: 0; 46 | } 47 | } 48 | 49 | @media (min-width: 641px) { 50 | .page { 51 | flex-direction: row; 52 | } 53 | 54 | .sidebar { 55 | width: 250px; 56 | height: 100vh; 57 | position: sticky; 58 | top: 0; 59 | } 60 | 61 | .top-row { 62 | position: sticky; 63 | top: 0; 64 | z-index: 1; 65 | } 66 | 67 | .top-row.auth ::deep a:first-child { 68 | flex: 1; 69 | text-align: right; 70 | width: 0; 71 | } 72 | 73 | .top-row, article { 74 | padding-left: 2rem !important; 75 | padding-right: 1.5rem !important; 76 | } 77 | } 78 | 79 | #blazor-error-ui { 80 | background: lightyellow; 81 | bottom: 0; 82 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 83 | display: none; 84 | left: 0; 85 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 86 | position: fixed; 87 | width: 100%; 88 | z-index: 1000; 89 | } 90 | 91 | #blazor-error-ui .dismiss { 92 | cursor: pointer; 93 | position: absolute; 94 | right: 0.75rem; 95 | top: 0.5rem; 96 | } 97 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Infrastructure/Database/Repositories/PlayersBetsRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Players.Domain.Repositories; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace Euro2024Challenge.Backend.Modules.Players.Infrastructure.Database.Repositories 6 | { 7 | internal class PlayersBetsRepository : IPlayersBetsRepository 8 | { 9 | private readonly PlayersDbContext _context; 10 | private readonly DbSet _matchBets; 11 | private readonly DbSet _topScorerBets; 12 | private readonly DbSet _tournamentWinnerBets; 13 | 14 | public PlayersBetsRepository(PlayersDbContext context) 15 | { 16 | _context = context; 17 | _matchBets = _context.MatchBets; 18 | _topScorerBets = _context.TopScorerBets; 19 | _tournamentWinnerBets = _context.TournamentWinnerBets; 20 | } 21 | 22 | public async Task CreateMatchBetAsync(MatchBet matchBet) 23 | { 24 | await _matchBets.AddAsync(matchBet); 25 | await _context.SaveChangesAsync(); 26 | } 27 | 28 | public async Task UpdateMatchBetAsync(MatchBet matchBet) 29 | { 30 | _matchBets.Update(matchBet); 31 | await _context.SaveChangesAsync(); 32 | } 33 | 34 | public async Task CreateTopScorerBetAsync(TopScorerBet topScorerBet) 35 | { 36 | await _topScorerBets.AddAsync(topScorerBet); 37 | await _context.SaveChangesAsync(); 38 | } 39 | 40 | public async Task UpdateTopScorerBetAsync(TopScorerBet topScorerBet) 41 | { 42 | _topScorerBets.Update(topScorerBet); 43 | await _context.SaveChangesAsync(); 44 | } 45 | 46 | public async Task CreateTournamentWinnerBetAsync(TournamentWinnerBet tournamentWinnerBet) 47 | { 48 | await _tournamentWinnerBets.AddAsync(tournamentWinnerBet); 49 | await _context.SaveChangesAsync(); 50 | } 51 | 52 | public async Task UpdateTournamentWinnerBetAsync(TournamentWinnerBet tournamentWinnerBet) 53 | { 54 | _tournamentWinnerBets.Update(tournamentWinnerBet); 55 | await _context.SaveChangesAsync(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Backend/Modules/Classification/Euro2024Challenge.Backend.Modules.Classification.Infrastructure/Database/Repositories/PlayersClassificationRepository.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Entities; 2 | using Euro2024Challenge.Backend.Modules.Classification.Domain.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Settings; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Options; 6 | using MongoDB.Driver; 7 | 8 | namespace Euro2024Challenge.Backend.Modules.Classification.Infrastructure.Database.Repositories; 9 | 10 | public class PlayersClassificationRepository : IClassificationRepository 11 | { 12 | private readonly IMongoCollection _playersClassificationCollection; 13 | 14 | public PlayersClassificationRepository(IOptions options) 15 | { 16 | var mongoClient = new MongoClient(options.Value.ConnectionString); 17 | var mongoDatabase = mongoClient.GetDatabase(options.Value.DatabaseName); 18 | _playersClassificationCollection = mongoDatabase.GetCollection(options.Value.CollectionName); 19 | } 20 | 21 | public async Task> GetAll() 22 | { 23 | var result = await _playersClassificationCollection.Find(_ => true).ToListAsync(); 24 | 25 | return result; 26 | } 27 | 28 | public async Task Insert(PlayerBetPoints playerBetPoints) 29 | { 30 | await _playersClassificationCollection.InsertOneAsync(playerBetPoints); 31 | } 32 | 33 | public async Task Update(PlayerBetPoints playerBetPoints) 34 | { 35 | var builder = Builders.Filter; 36 | var filter = builder.Eq(x => x.PlayerId, playerBetPoints.PlayerId) & builder.Eq(x => x.BetId, playerBetPoints.BetId); 37 | 38 | var update = Builders.Update.Set(x => x.Points, playerBetPoints.Points); 39 | 40 | await _playersClassificationCollection.UpdateOneAsync(filter, update); 41 | } 42 | 43 | public async Task> Get(Guid playerId) 44 | { 45 | var filter = Builders.Filter.Eq("PlayerId", playerId); 46 | var result = (await _playersClassificationCollection.Find(filter).ToListAsync()).AsReadOnly(); 47 | 48 | return result; 49 | } 50 | 51 | public async Task GetBetPoints(Guid playerId, Guid betId) 52 | { 53 | var builder = Builders.Filter; 54 | var filter = builder.Eq("PlayerId", playerId) & builder.Eq("BetId", betId); 55 | 56 | return await _playersClassificationCollection.Find(filter).SingleOrDefaultAsync(); 57 | } 58 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/TeamService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Cache; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 4 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 5 | using Microsoft.Extensions.Caching.Memory; 6 | 7 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 8 | 9 | public class TeamService : ITeamService 10 | { 11 | private readonly ITeamRepository _teamRepository; 12 | private readonly ITeamsCache _cache; 13 | 14 | public TeamService(ITeamRepository teamRepository, ITeamsCache cache) 15 | { 16 | _teamRepository = teamRepository; 17 | _cache = cache; 18 | } 19 | 20 | public async Task> GetTeamsAsync(List ids) 21 | { 22 | SemaphoreSlim semaphore = new(1, 1); 23 | 24 | if(!_cache.TryGetValue(out Dictionary? allTeams)) 25 | { 26 | try 27 | { 28 | await semaphore.WaitAsync(); 29 | 30 | if(!_cache.TryGetValue(out allTeams)) 31 | { 32 | var teams = await _teamRepository.GetAllTeamsAsync(); 33 | 34 | _cache.Set(teams); 35 | 36 | var teamsDto = teams.ToTeamsResponse(); 37 | 38 | return teamsDto.Where(x => ids.Contains(x.Id)); 39 | } 40 | } 41 | finally 42 | { 43 | semaphore.Release(); 44 | } 45 | } 46 | 47 | var resultTeams = allTeams!.ToTeamsResponse(); 48 | 49 | return resultTeams.Where(x => ids.Contains(x.Id)); 50 | } 51 | 52 | public async Task GetTeamAsync(int id) 53 | { 54 | SemaphoreSlim semaphore = new(1, 1); 55 | 56 | if(!_cache.TryGetValue(out Dictionary? allTeams)) 57 | { 58 | try 59 | { 60 | await semaphore.WaitAsync(); 61 | if(!_cache.TryGetValue(out allTeams)) 62 | { 63 | var teams = await _teamRepository.GetAllTeamsAsync(); 64 | 65 | _cache.Set(teams); 66 | 67 | var teamsDto = teams.ToTeamsResponse(); 68 | 69 | return teamsDto.First(x => x.Id == id); 70 | } 71 | } 72 | finally 73 | { 74 | semaphore.Release(); 75 | } 76 | } 77 | 78 | return new TeamResponse(id, allTeams![id]); 79 | } 80 | } -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/wwwroot/app.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | } 4 | 5 | a, .btn-link { 6 | color: #006bb7; 7 | } 8 | 9 | .btn-primary { 10 | color: #fff; 11 | background-color: #1b6ec2; 12 | border-color: #1861ac; 13 | } 14 | 15 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 16 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 17 | } 18 | 19 | .content { 20 | padding-top: 1.1rem; 21 | } 22 | 23 | h1:focus { 24 | outline: none; 25 | } 26 | 27 | .valid.modified:not([type=checkbox]) { 28 | outline: 1px solid #26b050; 29 | } 30 | 31 | .invalid { 32 | outline: 1px solid #e50000; 33 | } 34 | 35 | .validation-message { 36 | color: #e50000; 37 | } 38 | 39 | .blazor-error-boundary { 40 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; 41 | padding: 1rem 1rem 1rem 3.7rem; 42 | color: white; 43 | } 44 | 45 | .blazor-error-boundary::after { 46 | content: "An error has occurred." 47 | } 48 | 49 | .darker-border-checkbox.form-check-input { 50 | border-color: #929292; 51 | } 52 | -------------------------------------------------------------------------------- /tests/Modules/Tournaments/Tournamnets.Core.Tests/Services/FootballerServiceTests.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 4 | using NSubstitute; 5 | 6 | namespace Modules.Tournamnets.Core.Tests.Services 7 | { 8 | public class FootballerServiceTests 9 | { 10 | private IFootballerRepository _footballerRepositorySubstitute; 11 | private FootballerService _footballerService; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _footballerRepositorySubstitute = Substitute.For(); 17 | } 18 | 19 | [Test] 20 | public async Task GetReturnsFootballerResponse() 21 | { 22 | //Arrange 23 | int id = 1; 24 | Footballer footballer = new() 25 | { 26 | Id = 1, 27 | FullName = "Test Name", 28 | Goals = 7, 29 | TeamId = 99, 30 | Team = new() 31 | { 32 | Name = "Poland" 33 | } 34 | }; 35 | 36 | _footballerRepositorySubstitute.Get(id).Returns(footballer); 37 | 38 | _footballerService = new FootballerService(_footballerRepositorySubstitute); 39 | 40 | //Act 41 | var result = await _footballerService.Get(id); 42 | 43 | //Assert 44 | Assert.Multiple(() => 45 | { 46 | Assert.That(result.FullName, Is.EqualTo(footballer.FullName)); 47 | Assert.That(result.Goals, Is.EqualTo(footballer.Goals)); 48 | Assert.That(result.Id, Is.EqualTo(footballer.Id)); 49 | Assert.That(result.TeamName, Is.EqualTo(footballer.Team.Name)); 50 | }); 51 | } 52 | 53 | [Test] 54 | public async Task UpdateGoalsCallsUpdateFootballerGoals() 55 | { 56 | //Arrange 57 | int id = 1; 58 | int goals = 3; 59 | Footballer footballer = new() 60 | { 61 | Id = 1, 62 | FullName = "Test Name", 63 | Goals = 1 64 | }; 65 | 66 | _footballerRepositorySubstitute.Get(id).Returns(footballer); 67 | 68 | _footballerService = new FootballerService(_footballerRepositorySubstitute); 69 | 70 | //Act 71 | await _footballerService.UpdateGoals(id, goals); 72 | 73 | //Assert 74 | await _footballerRepositorySubstitute.Received(1).UpdateAsync(Arg.Is(x => x.Goals == goals)); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Services/MatchService.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournament.Shared; 2 | using Euro2024Challenge.Backend.Modules.Tournament.Shared.DTO; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 4 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities; 5 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Extensions; 6 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Repositories; 7 | using Euro2024Challenge.Shared; 8 | 9 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 10 | 11 | public class MatchService : IMatchService 12 | { 13 | private readonly IMatchRepository _matchRepository; 14 | private readonly ITeamRepository _teamRepository; 15 | private readonly IEventBus _eventBus; 16 | 17 | public MatchService(IMatchRepository matchRepository, ITeamRepository teamRepository, IEventBus eventBus) 18 | { 19 | _matchRepository = matchRepository; 20 | _teamRepository = teamRepository; 21 | _eventBus = eventBus; 22 | } 23 | 24 | public async Task Add(AddMatchRequest matchToAdd) 25 | { 26 | var match = new Match 27 | { 28 | Number = matchToAdd.Number, 29 | GuestTeamId = matchToAdd.GuestTeamId, 30 | AwayTeamId = matchToAdd.AwayTeamId, 31 | GuestTeamGoals = matchToAdd.GuestTeamGoals, 32 | AwayTeamGoals = matchToAdd.AwayTeamGoals, 33 | StartHour = matchToAdd.StartHour 34 | }; 35 | 36 | await _matchRepository.AddAsync(match); 37 | } 38 | 39 | public async Task UpdateResult(int number, int guestTeamGoals, int awayTeamsGoals) 40 | { 41 | Match match = await _matchRepository.GetByNumber(number); 42 | match.GuestTeamGoals = guestTeamGoals; 43 | match.AwayTeamGoals = awayTeamsGoals; 44 | await _matchRepository.UpdateAsync(match); 45 | 46 | await _eventBus.PublishAsync(new MatchUpdated(number, guestTeamGoals, awayTeamsGoals)); 47 | } 48 | 49 | public async Task> GetAll() 50 | { 51 | var matches = await _matchRepository.GetAll(); 52 | var teams = await _teamRepository.GetAllTeamsAsync(); 53 | 54 | return matches.ToMatchesResponse(teams).ToList().AsReadOnly(); 55 | } 56 | 57 | public async Task GetByNumber(int number) 58 | { 59 | var teams = await _teamRepository.GetAllTeamsAsync(); 60 | return (await _matchRepository.GetByNumber(number)).ToMatchResponse(teams); 61 | } 62 | 63 | public async Task> GetByNumbers(int[] numbers) 64 | { 65 | var matches = await _matchRepository.GetByNumbers(numbers); 66 | var teams = await _teamRepository.GetAllTeamsAsync(); 67 | 68 | return matches.ToMatchesResponse(teams).ToList().AsReadOnly(); 69 | } 70 | } -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Presentation/TournamentsEndpoints.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.DTO; 2 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Services; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Routing; 7 | 8 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Presentation 9 | { 10 | public static class TournamentsEndpoints 11 | { 12 | public static void MapTournamentsEndpoints(this IEndpointRouteBuilder app) 13 | { 14 | var tournaments = app.MapGroup("tournaments-module/"); 15 | 16 | tournaments.MapPost("match", AddMatch) 17 | .Produces(200); 18 | tournaments.MapPut("match/{number:int}", UpdateMatchResult) 19 | .Produces(200); 20 | tournaments.MapGet("match/{number:int}", GetMatch) 21 | .Produces(200); 22 | tournaments.MapGet("matches", GetAllMatches) 23 | .Produces(200); 24 | 25 | tournaments.MapGet("teams/{ids}", GetTeams) 26 | .Produces(200); 27 | 28 | tournaments.MapPut("footballer/{id:int}", UpdateFootballerGoals) 29 | .Produces(200); 30 | tournaments.MapGet("footballer/{id:int}", GetFootballer) 31 | .Produces(200); 32 | } 33 | 34 | private static async Task AddMatch([FromServices] IMatchService matchService, AddMatchRequest request) 35 | { 36 | await matchService.Add(request); 37 | 38 | return Results.Ok(); 39 | } 40 | 41 | private static async Task UpdateMatchResult([FromServices] IMatchService matchService, int number, UpdateMatchResultRequest request) 42 | { 43 | await matchService.UpdateResult(number, request.GuestTeamGoals, request.AwayTeamGoals); 44 | 45 | return Results.Ok(); 46 | } 47 | 48 | private static async Task GetAllMatches([FromServices] IMatchService matchService) 49 | { 50 | var matches = await matchService.GetAll(); 51 | 52 | return Results.Ok(matches); 53 | } 54 | 55 | private static async Task GetMatch([FromServices] IMatchService matchService, int number) 56 | { 57 | var match = await matchService.GetByNumber(number); 58 | 59 | return Results.Ok(match); 60 | } 61 | 62 | private static async Task GetTeams([FromServices] ITeamService teamService, int[] ids) 63 | { 64 | var teams = await teamService.GetTeamsAsync(ids.ToList()); 65 | 66 | return Results.Ok(teams); 67 | } 68 | 69 | private static async Task GetFootballer([FromServices] IFootballerService footballerService, int id) 70 | { 71 | var result = await footballerService.Get(id); 72 | 73 | return result is null ? Results.NotFound() : Results.Ok(result); 74 | } 75 | 76 | private static async Task UpdateFootballerGoals([FromServices] IFootballerService footballerService, 77 | int id, [FromBody] UpdateFootballerGoalsRequest request) 78 | { 79 | await footballerService.UpdateGoals(id, request.Goals); 80 | 81 | return Results.Ok(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Backend/Modules/Players/Euro2024Challenge.Backend.Modules.Players.Presentation/PlayerBetsEndpoints.cs: -------------------------------------------------------------------------------- 1 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.Create; 2 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.Get; 3 | using Euro2024Challenge.Backend.Modules.Players.Application.Bets.Update; 4 | using MediatR; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.AspNetCore.Routing; 9 | 10 | namespace Euro2024Challenge.Backend.Modules.Players.Presentation 11 | { 12 | public static class PlayerBetsEndpoints 13 | { 14 | public static void MapPlayerBetsEndpoints(this IEndpointRouteBuilder app) 15 | { 16 | var playerBets = app.MapGroup("players-module/player-bets"); 17 | 18 | playerBets.MapGet("/{playerId}", GetPlayerBets) 19 | .Produces(200); 20 | 21 | playerBets.MapPost("/match-bet", CreateMatchBet) 22 | .Produces(201); 23 | 24 | playerBets.MapPost("/top-scorer", CreateTopScorerBet) 25 | .Produces(201); 26 | 27 | playerBets.MapPost("/tournament-winner", CreateTournamentWinnerBet) 28 | .Produces(201); 29 | 30 | playerBets.MapPut("/match-bet", UpdateMatchBet) 31 | .Produces(201); 32 | 33 | playerBets.MapPut("/top-scorer", UpdateTopScorerBet) 34 | .Produces(201); 35 | 36 | playerBets.MapPut("/tournament-winner", UpdateTournamentWinnerBet) 37 | .Produces(201); 38 | 39 | 40 | } 41 | 42 | private static async Task CreateMatchBet([FromServices] ISender sender, CreateMatchBetRequest request) 43 | { 44 | await sender.Send(new CreateMatchBetCommand(request.PlayerId, request.MatchId, request.Winner, request.HomeTeamGoals, request.AwayTeamGoals)); 45 | 46 | return Results.Ok(); 47 | } 48 | 49 | private static async Task CreateTopScorerBet([FromServices] ISender sender, CreateTopScorerBetRequest request) 50 | { 51 | await sender.Send(new CreateTopScorerBetCommand(request.PlayerId, request.FootballerId, request.Goals)); 52 | 53 | return Results.Ok(); 54 | } 55 | 56 | private static async Task CreateTournamentWinnerBet([FromServices] ISender sender, CreateTournamentWinnerBetRequest request) 57 | { 58 | await sender.Send(new CreateTournamentWinnerBetCommand(request.PlayerId, request.TeamId)); 59 | 60 | return Results.Ok(); 61 | } 62 | 63 | private static async Task UpdateMatchBet([FromServices] ISender sender, UpdateMatchBetRequest request) 64 | { 65 | await sender.Send(new UpdateMatchBetCommand(request.PlayerId, request.MatchId, request.Winner, request.HomeTeamGoals, request.AwayTeamGoals)); 66 | 67 | return Results.Ok(); 68 | } 69 | 70 | private static async Task UpdateTopScorerBet([FromServices] ISender sender, UpdateTopScorerBetRequest request) 71 | { 72 | await sender.Send(new UpdateTopScorerBetCommand(request.PlayerId, request.FootballerId, request.Goals)); 73 | 74 | return Results.Ok(); 75 | } 76 | 77 | private static async Task UpdateTournamentWinnerBet([FromServices] ISender sender, UpdateTournamentWinnerBetRequest request) 78 | { 79 | await sender.Send(new UpdateTournamentWinnerBetCommand(request.PlayerId, request.TeamId)); 80 | 81 | return Results.Ok(); 82 | } 83 | private static async Task GetPlayerBets([FromServices] ISender sender, Guid playerId) 84 | { 85 | var result = await sender.Send(new GetPlayerBetsQuery(playerId)); 86 | 87 | return Results.Ok(result); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Frontend/Euro2024Challange/Components/Layout/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | appearance: none; 3 | cursor: pointer; 4 | width: 3.5rem; 5 | height: 2.5rem; 6 | color: white; 7 | position: absolute; 8 | top: 0.5rem; 9 | right: 1rem; 10 | border: 1px solid rgba(255, 255, 255, 0.1); 11 | background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); 12 | } 13 | 14 | .navbar-toggler:checked { 15 | background-color: rgba(255, 255, 255, 0.5); 16 | } 17 | 18 | .top-row { 19 | height: 3.5rem; 20 | background-color: rgba(0,0,0,0.4); 21 | } 22 | 23 | .navbar-brand { 24 | font-size: 1.1rem; 25 | } 26 | 27 | .bi { 28 | display: inline-block; 29 | position: relative; 30 | width: 1.25rem; 31 | height: 1.25rem; 32 | margin-right: 0.75rem; 33 | top: -1px; 34 | background-size: cover; 35 | } 36 | 37 | .bi-house-door-fill-nav-menu { 38 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); 39 | } 40 | 41 | .bi-plus-square-fill-nav-menu { 42 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); 43 | } 44 | 45 | .bi-list-nested-nav-menu { 46 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); 47 | } 48 | 49 | .nav-item { 50 | font-size: 0.9rem; 51 | padding-bottom: 0.5rem; 52 | } 53 | 54 | .nav-item:first-of-type { 55 | padding-top: 1rem; 56 | } 57 | 58 | .nav-item:last-of-type { 59 | padding-bottom: 1rem; 60 | } 61 | 62 | .nav-item ::deep .nav-link { 63 | color: #d7d7d7; 64 | background: none; 65 | border: none; 66 | border-radius: 4px; 67 | height: 3rem; 68 | display: flex; 69 | align-items: center; 70 | line-height: 3rem; 71 | width: 100%; 72 | } 73 | 74 | .nav-item ::deep a.active { 75 | background-color: rgba(255,255,255,0.37); 76 | color: white; 77 | } 78 | 79 | .nav-item ::deep .nav-link:hover { 80 | background-color: rgba(255,255,255,0.1); 81 | color: white; 82 | } 83 | 84 | .nav-scrollable { 85 | display: none; 86 | } 87 | 88 | .navbar-toggler:checked ~ .nav-scrollable { 89 | display: block; 90 | } 91 | 92 | @media (min-width: 641px) { 93 | .navbar-toggler { 94 | display: none; 95 | } 96 | 97 | .nav-scrollable { 98 | /* Never collapse the sidebar for wide screens */ 99 | display: block; 100 | 101 | /* Allow sidebar to scroll for tall menus */ 102 | height: calc(100vh - 3.5rem); 103 | overflow-y: auto; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Migrations/TournamentDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 8 | 9 | #nullable disable 10 | 11 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Migrations 12 | { 13 | [DbContext(typeof(TournamentDbContext))] 14 | partial class TournamentDbContextModelSnapshot : ModelSnapshot 15 | { 16 | protected override void BuildModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasDefaultSchema("tournaments") 21 | .HasAnnotation("ProductVersion", "8.0.3") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 63); 23 | 24 | NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); 25 | 26 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 27 | { 28 | b.Property("Id") 29 | .ValueGeneratedOnAdd() 30 | .HasColumnType("integer"); 31 | 32 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 33 | 34 | b.Property("FullName") 35 | .IsRequired() 36 | .HasMaxLength(32) 37 | .HasColumnType("character varying(32)"); 38 | 39 | b.Property("Goals") 40 | .HasColumnType("integer"); 41 | 42 | b.Property("TeamId") 43 | .HasColumnType("integer"); 44 | 45 | b.HasKey("Id"); 46 | 47 | b.HasIndex("TeamId"); 48 | 49 | b.ToTable("Footballers", "tournaments"); 50 | }); 51 | 52 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Match", b => 53 | { 54 | b.Property("Id") 55 | .ValueGeneratedOnAdd() 56 | .HasColumnType("integer"); 57 | 58 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 59 | 60 | b.Property("AwayTeamGoals") 61 | .HasColumnType("integer"); 62 | 63 | b.Property("AwayTeamId") 64 | .HasColumnType("integer"); 65 | 66 | b.Property("GuestTeamGoals") 67 | .HasColumnType("integer"); 68 | 69 | b.Property("GuestTeamId") 70 | .HasColumnType("integer"); 71 | 72 | b.Property("Number") 73 | .HasColumnType("integer"); 74 | 75 | b.Property("StartHour") 76 | .HasColumnType("timestamp with time zone"); 77 | 78 | b.HasKey("Id"); 79 | 80 | b.ToTable("Matches", "tournaments"); 81 | }); 82 | 83 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 84 | { 85 | b.Property("Id") 86 | .ValueGeneratedOnAdd() 87 | .HasColumnType("integer"); 88 | 89 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 90 | 91 | b.Property("Name") 92 | .IsRequired() 93 | .HasMaxLength(16) 94 | .HasColumnType("character varying(16)"); 95 | 96 | b.HasKey("Id"); 97 | 98 | b.HasIndex("Name") 99 | .IsUnique(); 100 | 101 | b.ToTable("Teams", "tournaments"); 102 | }); 103 | 104 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 105 | { 106 | b.HasOne("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", "Team") 107 | .WithMany("Footballers") 108 | .HasForeignKey("TeamId") 109 | .OnDelete(DeleteBehavior.Cascade) 110 | .IsRequired(); 111 | 112 | b.Navigation("Team"); 113 | }); 114 | 115 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 116 | { 117 | b.Navigation("Footballers"); 118 | }); 119 | #pragma warning restore 612, 618 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Migrations/20240414180511_Initial.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 9 | 10 | #nullable disable 11 | 12 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Migrations 13 | { 14 | [DbContext(typeof(TournamentDbContext))] 15 | [Migration("20240414180511_Initial")] 16 | partial class Initial 17 | { 18 | /// 19 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 20 | { 21 | #pragma warning disable 612, 618 22 | modelBuilder 23 | .HasDefaultSchema("tournaments") 24 | .HasAnnotation("ProductVersion", "8.0.3") 25 | .HasAnnotation("Relational:MaxIdentifierLength", 63); 26 | 27 | NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); 28 | 29 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 30 | { 31 | b.Property("Id") 32 | .ValueGeneratedOnAdd() 33 | .HasColumnType("integer"); 34 | 35 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 36 | 37 | b.Property("FullName") 38 | .IsRequired() 39 | .HasMaxLength(32) 40 | .HasColumnType("character varying(32)"); 41 | 42 | b.Property("Golas") 43 | .HasColumnType("integer"); 44 | 45 | b.Property("TeamId") 46 | .HasColumnType("integer"); 47 | 48 | b.HasKey("Id"); 49 | 50 | b.HasIndex("TeamId"); 51 | 52 | b.ToTable("Footballers", "tournaments"); 53 | }); 54 | 55 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Match", b => 56 | { 57 | b.Property("Id") 58 | .ValueGeneratedOnAdd() 59 | .HasColumnType("integer"); 60 | 61 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 62 | 63 | b.Property("AwayTeamGoals") 64 | .HasColumnType("integer"); 65 | 66 | b.Property("AwayTeamId") 67 | .HasColumnType("integer"); 68 | 69 | b.Property("GuestTeamGoals") 70 | .HasColumnType("integer"); 71 | 72 | b.Property("GuestTeamId") 73 | .HasColumnType("integer"); 74 | 75 | b.Property("Number") 76 | .HasColumnType("integer"); 77 | 78 | b.Property("StartHour") 79 | .HasColumnType("timestamp with time zone"); 80 | 81 | b.HasKey("Id"); 82 | 83 | b.ToTable("Matches", "tournaments"); 84 | }); 85 | 86 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 87 | { 88 | b.Property("Id") 89 | .ValueGeneratedOnAdd() 90 | .HasColumnType("integer"); 91 | 92 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 93 | 94 | b.Property("Name") 95 | .IsRequired() 96 | .HasMaxLength(16) 97 | .HasColumnType("character varying(16)"); 98 | 99 | b.HasKey("Id"); 100 | 101 | b.HasIndex("Name") 102 | .IsUnique(); 103 | 104 | b.ToTable("Teams", "tournaments"); 105 | }); 106 | 107 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 108 | { 109 | b.HasOne("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", "Team") 110 | .WithMany("Footballers") 111 | .HasForeignKey("TeamId") 112 | .OnDelete(DeleteBehavior.Cascade) 113 | .IsRequired(); 114 | 115 | b.Navigation("Team"); 116 | }); 117 | 118 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 119 | { 120 | b.Navigation("Footballers"); 121 | }); 122 | #pragma warning restore 612, 618 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Backend/Modules/Tournaments/Euro2024Challenge.Backend.Modules.Tournaments.Core/Database/Migrations/20240522181806_ChangeColumnName.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Euro2024Challenge.Backend.Modules.Tournaments.Core.Database; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; 9 | 10 | #nullable disable 11 | 12 | namespace Euro2024Challenge.Backend.Modules.Tournaments.Core.Database.Migrations 13 | { 14 | [DbContext(typeof(TournamentDbContext))] 15 | [Migration("20240522181806_ChangeColumnName")] 16 | partial class ChangeColumnName 17 | { 18 | /// 19 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 20 | { 21 | #pragma warning disable 612, 618 22 | modelBuilder 23 | .HasDefaultSchema("tournaments") 24 | .HasAnnotation("ProductVersion", "8.0.3") 25 | .HasAnnotation("Relational:MaxIdentifierLength", 63); 26 | 27 | NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); 28 | 29 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 30 | { 31 | b.Property("Id") 32 | .ValueGeneratedOnAdd() 33 | .HasColumnType("integer"); 34 | 35 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 36 | 37 | b.Property("FullName") 38 | .IsRequired() 39 | .HasMaxLength(32) 40 | .HasColumnType("character varying(32)"); 41 | 42 | b.Property("Goals") 43 | .HasColumnType("integer"); 44 | 45 | b.Property("TeamId") 46 | .HasColumnType("integer"); 47 | 48 | b.HasKey("Id"); 49 | 50 | b.HasIndex("TeamId"); 51 | 52 | b.ToTable("Footballers", "tournaments"); 53 | }); 54 | 55 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Match", b => 56 | { 57 | b.Property("Id") 58 | .ValueGeneratedOnAdd() 59 | .HasColumnType("integer"); 60 | 61 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 62 | 63 | b.Property("AwayTeamGoals") 64 | .HasColumnType("integer"); 65 | 66 | b.Property("AwayTeamId") 67 | .HasColumnType("integer"); 68 | 69 | b.Property("GuestTeamGoals") 70 | .HasColumnType("integer"); 71 | 72 | b.Property("GuestTeamId") 73 | .HasColumnType("integer"); 74 | 75 | b.Property("Number") 76 | .HasColumnType("integer"); 77 | 78 | b.Property("StartHour") 79 | .HasColumnType("timestamp with time zone"); 80 | 81 | b.HasKey("Id"); 82 | 83 | b.ToTable("Matches", "tournaments"); 84 | }); 85 | 86 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 87 | { 88 | b.Property("Id") 89 | .ValueGeneratedOnAdd() 90 | .HasColumnType("integer"); 91 | 92 | NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); 93 | 94 | b.Property("Name") 95 | .IsRequired() 96 | .HasMaxLength(16) 97 | .HasColumnType("character varying(16)"); 98 | 99 | b.HasKey("Id"); 100 | 101 | b.HasIndex("Name") 102 | .IsUnique(); 103 | 104 | b.ToTable("Teams", "tournaments"); 105 | }); 106 | 107 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Footballer", b => 108 | { 109 | b.HasOne("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", "Team") 110 | .WithMany("Footballers") 111 | .HasForeignKey("TeamId") 112 | .OnDelete(DeleteBehavior.Cascade) 113 | .IsRequired(); 114 | 115 | b.Navigation("Team"); 116 | }); 117 | 118 | modelBuilder.Entity("Euro2024Challenge.Backend.Modules.Tournaments.Core.Entities.Team", b => 119 | { 120 | b.Navigation("Footballers"); 121 | }); 122 | #pragma warning restore 612, 618 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------