From 96c8102d33149cd08e8c64aca1f24f641ce2305c Mon Sep 17 00:00:00 2001 From: Valentin Virot Date: Sun, 20 Jul 2025 12:41:15 +0200 Subject: [PATCH 1/2] Added new tournament logo mecanism --- .../UpdateTournamentPictureCommand.cs | 29 +++++++++ .../UpdateTournamentPictureCommandHandler.cs | 64 +++++++++++++++++++ .../GetTournamentLogoQuery.cs | 20 ++++++ .../GetTournamentLogoQueryHandler.cs | 61 ++++++++++++++++++ GameOn.Common/DTOs/TournamentLogoDto.cs | 24 +++++++ 5 files changed, 198 insertions(+) create mode 100644 GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs create mode 100644 GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs create mode 100644 GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs create mode 100644 GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs create mode 100644 GameOn.Common/DTOs/TournamentLogoDto.cs diff --git a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs new file mode 100644 index 0000000..af149f7 --- /dev/null +++ b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) LeadOn's Corp'. All rights reserved. +// + +namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture +{ + using GameOn.Common.DTOs; + using GameOn.Domain; + using MediatR; + using Microsoft.AspNetCore.Http; + + /// + /// UpdatePlayerProfilePictureCommand class. + /// + public class UpdatePlayerProfilePictureCommand : IRequest + { + /// + /// Gets or sets Player ID. + /// + public int PlayerId { get; set; } + + /// + /// Gets or sets File. + /// +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + public IFormFile File { get; set; } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + } +} diff --git a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs new file mode 100644 index 0000000..bd586d0 --- /dev/null +++ b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs @@ -0,0 +1,64 @@ +// +// Copyright (c) LeadOn's Corp'. All rights reserved. +// + +namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture +{ + using GameOn.Application.Common.Players.Queries.GetPlayerById; + using GameOn.Common.Exceptions; + using GameOn.Common.Interfaces; + using GameOn.Domain; + using GameOn.External.NetworkStorage.Interfaces; + using MediatR; + using Microsoft.EntityFrameworkCore; + + /// + /// UpdatePlayerProfilePictureCommandHandler class. + /// + public class UpdatePlayerProfilePictureCommandHandler : IRequestHandler + { + private readonly IMediator mediator; + private readonly IApplicationDbContext context; + private readonly INetworkStorageService nsService; + private readonly string bucketName = Environment.GetEnvironmentVariable("S3_BUCKET_NAME") ?? throw new MissingEnvironmentVariableException("S3_BUCKET_NAME"); + private readonly string ppBasePath = Environment.GetEnvironmentVariable("S3_PP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_PP_BASE_PATH"); + + /// + /// Initializes a new instance of the class. + /// + /// DbContext, injected. + /// NetworkStorageService, injected. + /// Mediator, injected. + public UpdatePlayerProfilePictureCommandHandler(IApplicationDbContext context, INetworkStorageService nsService, IMediator mediator) + { + this.context = context; + this.nsService = nsService; + this.mediator = mediator; + } + + /// + public async Task Handle(UpdatePlayerProfilePictureCommand request, CancellationToken cancellationToken) + { + try + { + await this.nsService.UploadFile(this.bucketName, this.ppBasePath + "/" + request.PlayerId + Path.GetExtension(request.File.FileName), request.File); + + // now that file is uploaded, updating user + var playerInDb = await this.mediator.Send(new GetPlayerByIdQuery { PlayerId = request.PlayerId }, cancellationToken); + + if (playerInDb is not null) + { + playerInDb.ProfilePictureUrl = request.PlayerId + Path.GetExtension(request.File.FileName); + this.context.Players.Update(playerInDb); + await this.context.SaveChangesAsync(cancellationToken); + } + + return true; + } + catch + { + return false; + } + } + } +} diff --git a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs new file mode 100644 index 0000000..9628fe3 --- /dev/null +++ b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) LeadOn's Corp'. All rights reserved. +// + +namespace GameOn.Application.Common.Players.Queries.GetProfilePicture +{ + using GameOn.Common.DTOs; + using MediatR; + + /// + /// GetProfilePictureQuery class. + /// + public class GetProfilePictureQuery : IRequest + { + /// + /// Gets or sets Player ID. + /// + public int PlayerId { get; set; } + } +} diff --git a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs new file mode 100644 index 0000000..d9f75c7 --- /dev/null +++ b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs @@ -0,0 +1,61 @@ +// +// Copyright (c) LeadOn's Corp'. All rights reserved. +// + +namespace GameOn.Application.Common.Players.Queries.GetProfilePicture +{ + using GameOn.Application.Common.Players.Queries.GetPlayerById; + using GameOn.Common.DTOs; + using GameOn.Common.Exceptions; + using GameOn.External.NetworkStorage.Interfaces; + using MediatR; + + /// + /// GetProfilePictureQueryHandler class. + /// + public class GetProfilePictureQueryHandler : IRequestHandler + { + private readonly IMediator mediator; + private readonly INetworkStorageService nsService; + private readonly string bucketName = Environment.GetEnvironmentVariable("S3_BUCKET_NAME") ?? throw new MissingEnvironmentVariableException("S3_BUCKET_NAME"); + private readonly string ppBasePath = Environment.GetEnvironmentVariable("S3_PP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_PP_BASE_PATH"); + + /// + /// Initializes a new instance of the class. + /// + /// NetworkStorageService, injected. + /// Mediator, injected. + public GetProfilePictureQueryHandler(INetworkStorageService nsService, IMediator mediator) + { + this.nsService = nsService; + this.mediator = mediator; + } + + /// + public async Task Handle(GetProfilePictureQuery request, CancellationToken cancellationToken) + { + var ppDto = new ProfilePictureDto(); + + // First, getting player + var playerInDb = await this.mediator.Send(new GetPlayerByIdQuery { PlayerId = request.PlayerId }, cancellationToken); + + if (playerInDb is null) + { + return ppDto; + } + + if (playerInDb.ProfilePictureUrl is null || playerInDb.ProfilePictureUrl == string.Empty) + { + ppDto.FileName = Environment.GetEnvironmentVariable("DEFAULT_PROFILE_PIC") ?? throw new MissingEnvironmentVariableException("DEFAULT_PROFILE_PIC"); + } + else + { + ppDto.FileName = playerInDb.ProfilePictureUrl; + } + + // Getting profile picture + ppDto.FileStream = await this.nsService.GetFile(this.bucketName, this.ppBasePath + "/" + ppDto.FileName); + return ppDto; + } + } +} diff --git a/GameOn.Common/DTOs/TournamentLogoDto.cs b/GameOn.Common/DTOs/TournamentLogoDto.cs new file mode 100644 index 0000000..1e04b1a --- /dev/null +++ b/GameOn.Common/DTOs/TournamentLogoDto.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) LeadOn's Corp'. All rights reserved. +// + +namespace GameOn.Common.DTOs +{ + using GameOn.Domain; + + /// + /// ProfilePictureDto class. + /// + public class ProfilePictureDto + { + /// + /// Gets or sets File Stream. + /// + public Stream? FileStream { get; set; } + + /// + /// Gets or sets File name. + /// + public string FileName { get; set; } = string.Empty; + } +} \ No newline at end of file From 80ad2f8411c64078f320ef2a8d34091438e3c862 Mon Sep 17 00:00:00 2001 From: Valentin Virot Date: Sun, 20 Jul 2025 12:41:16 +0200 Subject: [PATCH 2/2] Added new tournament logo mecanism --- .../UpdateTournamentPictureCommand.cs | 12 ++-- .../UpdateTournamentPictureCommandHandler.cs | 28 ++++---- .../GetTournamentLogoQuery.cs | 12 ++-- .../GetTournamentLogoQueryHandler.cs | 38 ++++++----- GameOn.Application/GameOn.Application.csproj | 3 +- GameOn.Common/DTOs/TournamentLogoDto.cs | 8 +-- GameOn.Common/GameOn.Common.csproj | 3 +- GameOn.Domain/GameOn.Domain.csproj | 3 +- GameOn.External/GameOn.External.csproj | 3 +- GameOn.Persistence/GameOn.Persistence.csproj | 3 +- .../Controllers/FIFA/TournamentController.cs | 68 ++++++++++++++++++- .../GameOn.Presentation.csproj | 3 +- .../Properties/launchSettings.json | 1 + README.md | 1 + 14 files changed, 131 insertions(+), 55 deletions(-) diff --git a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs index af149f7..6f4ae1c 100644 --- a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs +++ b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommand.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) LeadOn's Corp'. All rights reserved. // -namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture +namespace GameOn.Application.FIFA.Tournaments.Commands.UpdateTournamentPicture { using GameOn.Common.DTOs; using GameOn.Domain; @@ -10,14 +10,14 @@ namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture using Microsoft.AspNetCore.Http; /// - /// UpdatePlayerProfilePictureCommand class. + /// UpdateTournamentPictureCommand class. /// - public class UpdatePlayerProfilePictureCommand : IRequest + public class UpdateTournamentPictureCommand : IRequest { /// - /// Gets or sets Player ID. + /// Gets or sets Tournament ID. /// - public int PlayerId { get; set; } + public int TournamentId { get; set; } /// /// Gets or sets File. diff --git a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs index bd586d0..b884ccf 100644 --- a/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs +++ b/GameOn.Application/FIFA/Tournaments/Commands/UpdateTournamentPicture/UpdateTournamentPictureCommandHandler.cs @@ -1,8 +1,10 @@ -// +// // Copyright (c) LeadOn's Corp'. All rights reserved. // -namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture +using GameOn.Application.FIFA.Tournaments.Queries.GetTournamentById; + +namespace GameOn.Application.FIFA.Tournaments.Commands.UpdateTournamentPicture { using GameOn.Application.Common.Players.Queries.GetPlayerById; using GameOn.Common.Exceptions; @@ -13,23 +15,23 @@ namespace GameOn.Application.Common.Players.Commands.UpdatePlayerProfilePicture using Microsoft.EntityFrameworkCore; /// - /// UpdatePlayerProfilePictureCommandHandler class. + /// UpdateTournamentPictureCommandHandler class. /// - public class UpdatePlayerProfilePictureCommandHandler : IRequestHandler + public class UpdateTournamentPictureCommandHandler : IRequestHandler { private readonly IMediator mediator; private readonly IApplicationDbContext context; private readonly INetworkStorageService nsService; private readonly string bucketName = Environment.GetEnvironmentVariable("S3_BUCKET_NAME") ?? throw new MissingEnvironmentVariableException("S3_BUCKET_NAME"); - private readonly string ppBasePath = Environment.GetEnvironmentVariable("S3_PP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_PP_BASE_PATH"); + private readonly string tpBasePath = Environment.GetEnvironmentVariable("S3_TP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_TP_BASE_PATH"); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// DbContext, injected. /// NetworkStorageService, injected. /// Mediator, injected. - public UpdatePlayerProfilePictureCommandHandler(IApplicationDbContext context, INetworkStorageService nsService, IMediator mediator) + public UpdateTournamentPictureCommandHandler(IApplicationDbContext context, INetworkStorageService nsService, IMediator mediator) { this.context = context; this.nsService = nsService; @@ -37,19 +39,19 @@ public UpdatePlayerProfilePictureCommandHandler(IApplicationDbContext context, I } /// - public async Task Handle(UpdatePlayerProfilePictureCommand request, CancellationToken cancellationToken) + public async Task Handle(UpdateTournamentPictureCommand request, CancellationToken cancellationToken) { try { - await this.nsService.UploadFile(this.bucketName, this.ppBasePath + "/" + request.PlayerId + Path.GetExtension(request.File.FileName), request.File); + await this.nsService.UploadFile(this.bucketName, this.tpBasePath + "/" + request.TournamentId + Path.GetExtension(request.File.FileName), request.File); // now that file is uploaded, updating user - var playerInDb = await this.mediator.Send(new GetPlayerByIdQuery { PlayerId = request.PlayerId }, cancellationToken); + var tournamentInDb = await this.context.Tournaments.FirstOrDefaultAsync(x => x.Id == request.TournamentId, cancellationToken); - if (playerInDb is not null) + if (tournamentInDb is not null) { - playerInDb.ProfilePictureUrl = request.PlayerId + Path.GetExtension(request.File.FileName); - this.context.Players.Update(playerInDb); + tournamentInDb.LogoUrl = request.TournamentId + Path.GetExtension(request.File.FileName); + this.context.Tournaments.Update(tournamentInDb); await this.context.SaveChangesAsync(cancellationToken); } diff --git a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs index 9628fe3..27c305a 100644 --- a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs +++ b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQuery.cs @@ -1,20 +1,20 @@ -// +// // Copyright (c) LeadOn's Corp'. All rights reserved. // -namespace GameOn.Application.Common.Players.Queries.GetProfilePicture +namespace GameOn.Application.FIFA.Tournaments.Queries.GetTournamentLogo { using GameOn.Common.DTOs; using MediatR; /// - /// GetProfilePictureQuery class. + /// GetTournamentLogoQuery class. /// - public class GetProfilePictureQuery : IRequest + public class GetTournamentLogoQuery : IRequest { /// - /// Gets or sets Player ID. + /// Gets or sets Tournament ID. /// - public int PlayerId { get; set; } + public int TournamentId { get; set; } } } diff --git a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs index d9f75c7..a00e01f 100644 --- a/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs +++ b/GameOn.Application/FIFA/Tournaments/Queries/GetTournamentLogo/GetTournamentLogoQueryHandler.cs @@ -1,8 +1,10 @@ -// +// // Copyright (c) LeadOn's Corp'. All rights reserved. // -namespace GameOn.Application.Common.Players.Queries.GetProfilePicture +using GameOn.Application.FIFA.Tournaments.Queries.GetTournamentById; + +namespace GameOn.Application.FIFA.Tournaments.Queries.GetTournamentLogo { using GameOn.Application.Common.Players.Queries.GetPlayerById; using GameOn.Common.DTOs; @@ -11,51 +13,51 @@ namespace GameOn.Application.Common.Players.Queries.GetProfilePicture using MediatR; /// - /// GetProfilePictureQueryHandler class. + /// GetTournamentLogoQueryHandler class. /// - public class GetProfilePictureQueryHandler : IRequestHandler + public class GetTournamentLogoQueryHandler : IRequestHandler { private readonly IMediator mediator; private readonly INetworkStorageService nsService; private readonly string bucketName = Environment.GetEnvironmentVariable("S3_BUCKET_NAME") ?? throw new MissingEnvironmentVariableException("S3_BUCKET_NAME"); - private readonly string ppBasePath = Environment.GetEnvironmentVariable("S3_PP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_PP_BASE_PATH"); + private readonly string tpBasePath = Environment.GetEnvironmentVariable("S3_TP_BASE_PATH") ?? throw new MissingEnvironmentVariableException("S3_TP_BASE_PATH"); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// NetworkStorageService, injected. /// Mediator, injected. - public GetProfilePictureQueryHandler(INetworkStorageService nsService, IMediator mediator) + public GetTournamentLogoQueryHandler(INetworkStorageService nsService, IMediator mediator) { this.nsService = nsService; this.mediator = mediator; } /// - public async Task Handle(GetProfilePictureQuery request, CancellationToken cancellationToken) + public async Task Handle(GetTournamentLogoQuery request, CancellationToken cancellationToken) { - var ppDto = new ProfilePictureDto(); + var tpDto = new TournamentLogoDto(); - // First, getting player - var playerInDb = await this.mediator.Send(new GetPlayerByIdQuery { PlayerId = request.PlayerId }, cancellationToken); + // First, getting tournament + var tournamentInDb = await this.mediator.Send(new GetTournamentByIdQuery { TournamentId = request.TournamentId }, cancellationToken); - if (playerInDb is null) + if (tournamentInDb is null) { - return ppDto; + return tpDto; } - if (playerInDb.ProfilePictureUrl is null || playerInDb.ProfilePictureUrl == string.Empty) + if (tournamentInDb.LogoUrl is null || tournamentInDb.LogoUrl == string.Empty) { - ppDto.FileName = Environment.GetEnvironmentVariable("DEFAULT_PROFILE_PIC") ?? throw new MissingEnvironmentVariableException("DEFAULT_PROFILE_PIC"); + tpDto.FileName = Environment.GetEnvironmentVariable("DEFAULT_PROFILE_PIC") ?? throw new MissingEnvironmentVariableException("DEFAULT_PROFILE_PIC"); } else { - ppDto.FileName = playerInDb.ProfilePictureUrl; + tpDto.FileName = tournamentInDb.LogoUrl; } // Getting profile picture - ppDto.FileStream = await this.nsService.GetFile(this.bucketName, this.ppBasePath + "/" + ppDto.FileName); - return ppDto; + tpDto.FileStream = await this.nsService.GetFile(this.bucketName, this.tpBasePath + "/" + tpDto.FileName); + return tpDto; } } } diff --git a/GameOn.Application/GameOn.Application.csproj b/GameOn.Application/GameOn.Application.csproj index c4ae6e0..96277df 100644 --- a/GameOn.Application/GameOn.Application.csproj +++ b/GameOn.Application/GameOn.Application.csproj @@ -9,13 +9,14 @@ Game On! Application LeadOn LeadOn's Corp - Application layer of the Game On! project. + Application layer of the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr gameon-icon.png README.md https://github.com/LeadOn/GameOn-API git + 6.0.0 diff --git a/GameOn.Common/DTOs/TournamentLogoDto.cs b/GameOn.Common/DTOs/TournamentLogoDto.cs index 1e04b1a..8f48bcb 100644 --- a/GameOn.Common/DTOs/TournamentLogoDto.cs +++ b/GameOn.Common/DTOs/TournamentLogoDto.cs @@ -1,15 +1,13 @@ -// +// // Copyright (c) LeadOn's Corp'. All rights reserved. // namespace GameOn.Common.DTOs { - using GameOn.Domain; - /// - /// ProfilePictureDto class. + /// TournamentLogoDto class. /// - public class ProfilePictureDto + public class TournamentLogoDto { /// /// Gets or sets File Stream. diff --git a/GameOn.Common/GameOn.Common.csproj b/GameOn.Common/GameOn.Common.csproj index 8ef22a6..c8ad082 100644 --- a/GameOn.Common/GameOn.Common.csproj +++ b/GameOn.Common/GameOn.Common.csproj @@ -7,7 +7,7 @@ true GameOn! Common LeadOn's Corp - Common utilities used in the GameOn! project. + Common utilities used in the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr LeadOn's Corp @@ -16,6 +16,7 @@ https://github.com/LeadOn/GameOn-API git gameon-icon.ico + 6.0.0 diff --git a/GameOn.Domain/GameOn.Domain.csproj b/GameOn.Domain/GameOn.Domain.csproj index 91f4fbc..60c5ad7 100644 --- a/GameOn.Domain/GameOn.Domain.csproj +++ b/GameOn.Domain/GameOn.Domain.csproj @@ -9,13 +9,14 @@ GameOn! Domain LeadOn LeadOn's Corp - Domain layer of the GameOn! project. + Domain layer of the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr gameon-icon.png README.md https://github.com/LeadOn/GameOn-API git + 6.0.0 diff --git a/GameOn.External/GameOn.External.csproj b/GameOn.External/GameOn.External.csproj index 56bc8b1..f22390b 100644 --- a/GameOn.External/GameOn.External.csproj +++ b/GameOn.External/GameOn.External.csproj @@ -9,13 +9,14 @@ GameOn! External LeadOn LeadOn's Corp - External layer of the GameOn! project. + External layer of the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr gameon-icon.png README.md https://github.com/LeadOn/GameOn-API git + 6.0.0 diff --git a/GameOn.Persistence/GameOn.Persistence.csproj b/GameOn.Persistence/GameOn.Persistence.csproj index 9aa8847..c4471fc 100644 --- a/GameOn.Persistence/GameOn.Persistence.csproj +++ b/GameOn.Persistence/GameOn.Persistence.csproj @@ -9,13 +9,14 @@ GameOn! Persistence LeadOn LeadOn's Corp - Persistance layer of the GameOn! Project + Persistance layer of the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr gameon-icon.png README.md https://github.com/LeadOn/GameOn-API git + 6.0.0 diff --git a/GameOn.Presentation/Controllers/FIFA/TournamentController.cs b/GameOn.Presentation/Controllers/FIFA/TournamentController.cs index c2968bb..bbbc4fd 100644 --- a/GameOn.Presentation/Controllers/FIFA/TournamentController.cs +++ b/GameOn.Presentation/Controllers/FIFA/TournamentController.cs @@ -13,12 +13,15 @@ namespace GameOn.Presentation.Controllers.FIFA using GameOn.Application.FIFA.Tournaments.Commands.SavePhase1Score; using GameOn.Application.FIFA.Tournaments.Commands.SubscribeTournament; using GameOn.Application.FIFA.Tournaments.Commands.UpdateTournament; + using GameOn.Application.FIFA.Tournaments.Commands.UpdateTournamentPicture; using GameOn.Application.FIFA.Tournaments.Queries.CheckTournamentSubscription; using GameOn.Application.FIFA.Tournaments.Queries.GetAllTournaments; using GameOn.Application.FIFA.Tournaments.Queries.GetFeaturedTournaments; using GameOn.Application.FIFA.Tournaments.Queries.GetTournamentById; + using GameOn.Application.FIFA.Tournaments.Queries.GetTournamentLogo; using GameOn.Common.DTOs; using GameOn.Domain; + using GameOn.External.NetworkStorage.Interfaces; using GameOn.Presentation.Classes; using MediatR; using Microsoft.AspNetCore.Authorization; @@ -33,14 +36,17 @@ namespace GameOn.Presentation.Controllers.FIFA public class TournamentController : ControllerBase { private readonly ISender mediator; + private readonly INetworkStorageService nsService; /// /// Initializes a new instance of the class. /// /// MediatR interface, injected. - public TournamentController(ISender mediator) + /// NetworkStorage interface, injected. + public TournamentController(ISender mediator, INetworkStorageService nsService) { this.mediator = mediator; + this.nsService = nsService; } /// @@ -331,5 +337,65 @@ public async Task Delete(int id) return this.NoContent(); } } + + /// + /// Upload tournament picture. + /// + /// Tournament ID. + /// Tournament picture file. + /// IActionResult. + [HttpPost] + [Authorize(Roles = "gameon_admin")] + [Route("{tournamentId}/logo")] + [SwaggerOperation(Summary = "Updates tournament picture.")] + [SwaggerResponse(201, "Tournament's picture created on the server.")] + [SwaggerResponse(401, "Unauthorized.")] + [SwaggerResponse(406, "Wrong file format.")] + [SwaggerResponse(404, "No profile picture found.")] + [SwaggerResponse(500, "Unknown error happened.")] + public async Task UpdateTournamentPicture(int tournamentId, IFormFile tournamentPicture) + { + if (!CheckIfPictureFormatIsAuthorized(tournamentPicture.ContentType)) + { + return this.StatusCode(406); + } + + var currentPlayer = await this.mediator.Send(new UpdateTournamentPictureCommand { TournamentId = tournamentId, File = tournamentPicture }); + + return currentPlayer ? this.Created() : this.Problem(); + } + + /// + /// Gets tournament logo from network attached storage. + /// + /// Tournament ID. + /// File. + [HttpGet] + [Route("{tournamentId}/logo")] + [SwaggerOperation(Summary = "Get tournament logo from server.")] + [SwaggerResponse(200, "Tournament logo from server.", typeof(FileStreamResult))] + [SwaggerResponse(404, "No tournament logo found.")] + [SwaggerResponse(500, "Unknown error happened.")] + public async Task GetTournamentLogo(int tournamentId) + { + var tpDto = await this.mediator.Send(new GetTournamentLogoQuery { TournamentId = tournamentId }); + + if (tpDto.FileStream is null) + { + return this.NotFound(); + } + + return this.File(tpDto.FileStream, this.nsService.GetContentType(tpDto.FileName)); + } + + /// + /// Checks if file type is valid. + /// + /// File content type. + /// True if valid, false if not. + private static bool CheckIfPictureFormatIsAuthorized(string contentType) + { + return contentType is "image/jpeg" or "image/png" or "image/gif" or "image/webp"; + } } } diff --git a/GameOn.Presentation/GameOn.Presentation.csproj b/GameOn.Presentation/GameOn.Presentation.csproj index 19cd582..f0c0258 100644 --- a/GameOn.Presentation/GameOn.Presentation.csproj +++ b/GameOn.Presentation/GameOn.Presentation.csproj @@ -9,13 +9,14 @@ GameOn! API LeadOn LeadOn's Corp - Back-end of the GameOn! project. + Back-end of the GameOn! app. LeadOn's Corp https://www.valentinvirot.fr gameon-icon.png README.md https://github.com/LeadOn/GameOn-API git + 6.0.0 diff --git a/GameOn.Presentation/Properties/launchSettings.json b/GameOn.Presentation/Properties/launchSettings.json index 0796a9d..2a35ae1 100644 --- a/GameOn.Presentation/Properties/launchSettings.json +++ b/GameOn.Presentation/Properties/launchSettings.json @@ -20,6 +20,7 @@ "S3_SECRET_KEY": "", "S3_BUCKET_NAME": "", "S3_PP_BASE_PATH": "", + "S3_TP_BASE_PATH": "", "DEFAULT_PROFILE_PIC": "" }, "dotnetRunMessages": true, diff --git a/README.md b/README.md index 60b0c03..38e3b6d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Here are all of the environment variables currently used :
  • S3_SECRET_KEY: S3 Bucket Secret key.
  • S3_BUCKET_NAME: S3 Bucket Name.
  • S3_PP_BASE_PATH: Base path to profile pictures in S3 bucket.
  • +
  • S3_TP_BASE_PATH: Base path to tournament pictures in S3 bucket.
  • DEFAULT_PROFILE_PIC: Default profile picture name.