From 21b2c73cda32e25a6c9de741ffd1d329351244ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Tue, 3 Sep 2024 13:56:22 -0300 Subject: [PATCH 1/6] Criacao do EndPoint , do Logic e do Repositorie de Publication. --- src/Core/Application/DependencyInjection.cs | 1 + .../Publication/IPublicationBusinessLogic.cs | 9 +++++ .../Publication/PublicationBusinessLogic.cs | 15 ++++++++ .../Publication/CreatePublicationRequest.cs | 6 ++++ src/Core/Domain/Entities/Publication.cs | 10 ++++-- .../Repositories/IPublicationRepository.cs | 9 +++++ .../Infrastructure/DependencyInjection.cs | 1 + .../Repositories/PublicationRepository.cs | 19 ++++++++++ src/Core/Presentation/DependencyInjection.cs | 1 + .../EndPoints/PublicationEndPoints.cs | 36 +++++++++++++++++++ 10 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs create mode 100644 src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs create mode 100644 src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs create mode 100644 src/Core/Domain/Interfaces/Repositories/IPublicationRepository.cs create mode 100644 src/Core/Infrastructure/Repositories/PublicationRepository.cs create mode 100644 src/Core/Presentation/EndPoints/PublicationEndPoints.cs diff --git a/src/Core/Application/DependencyInjection.cs b/src/Core/Application/DependencyInjection.cs index 5635070f..9e96dc82 100644 --- a/src/Core/Application/DependencyInjection.cs +++ b/src/Core/Application/DependencyInjection.cs @@ -25,6 +25,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } } diff --git a/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs b/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs new file mode 100644 index 00000000..d6af1ba0 --- /dev/null +++ b/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs @@ -0,0 +1,9 @@ +using Domain.Contracts; +//using Domain.Entities; + +namespace Application.Logic; + +public interface IPublicationBusinessLogic +{ + public Task AddPublication(CreatePublicationRequest createPublicationRequest); +} diff --git a/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs new file mode 100644 index 00000000..165deff6 --- /dev/null +++ b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs @@ -0,0 +1,15 @@ +using Domain.Contracts; +using Domain.Entities; +using Domain.Repositories; + +namespace Application.Logic; + +public sealed class PublicationBusinessLogic(IPublicationRepository _repository) : IPublicationBusinessLogic +{ + public async Task AddPublication(CreatePublicationRequest createPublicationRequest) + { + var publication = Publication.Create(createPublicationRequest); + + await _repository.AddAsync(publication); + } +} \ No newline at end of file diff --git a/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs new file mode 100644 index 00000000..ceb0bca4 --- /dev/null +++ b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs @@ -0,0 +1,6 @@ +namespace Domain.Contracts; + +public record CreatePublicationRequest( + Guid PerfilId, + string Link +); diff --git a/src/Core/Domain/Entities/Publication.cs b/src/Core/Domain/Entities/Publication.cs index 9ff86d86..46505ce1 100644 --- a/src/Core/Domain/Entities/Publication.cs +++ b/src/Core/Domain/Entities/Publication.cs @@ -1,4 +1,5 @@ using Domain.Primitives; +using Domain.Contracts; namespace Domain.Entities; @@ -8,9 +9,14 @@ public sealed class Publication(Guid id, Guid perfilId, string link, bool isVali public string Link { get; private set; } = link; public bool IsValid { get; private set; } = isValid; - public static Publication Create(Guid perfilId, string link) + public static Publication Create(CreatePublicationRequest createPublicationRequest) { - return new Publication(Guid.NewGuid(), perfilId, link, true); + return new Publication( + Guid.NewGuid(), + createPublicationRequest.PerfilId, + createPublicationRequest.Link, + true + ); } public void NotValid() diff --git a/src/Core/Domain/Interfaces/Repositories/IPublicationRepository.cs b/src/Core/Domain/Interfaces/Repositories/IPublicationRepository.cs new file mode 100644 index 00000000..8e083cf9 --- /dev/null +++ b/src/Core/Domain/Interfaces/Repositories/IPublicationRepository.cs @@ -0,0 +1,9 @@ +using Domain.Entities; + +namespace Domain.Repositories +{ + public interface IPublicationRepository + { + public Task AddAsync(Publication publication); + } +} diff --git a/src/Core/Infrastructure/DependencyInjection.cs b/src/Core/Infrastructure/DependencyInjection.cs index df214505..e0aa42c4 100644 --- a/src/Core/Infrastructure/DependencyInjection.cs +++ b/src/Core/Infrastructure/DependencyInjection.cs @@ -274,6 +274,7 @@ public static IServiceCollection AddRepositories(this IServiceCollection service services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } } diff --git a/src/Core/Infrastructure/Repositories/PublicationRepository.cs b/src/Core/Infrastructure/Repositories/PublicationRepository.cs new file mode 100644 index 00000000..e767c58b --- /dev/null +++ b/src/Core/Infrastructure/Repositories/PublicationRepository.cs @@ -0,0 +1,19 @@ +using System; +using Domain.Entities; +using Domain.Repositories; +using Infrastructure.Contexts; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Repositories; + +public sealed class PublicationRepository(ApplicationDbContext context) + : GenericRepository(context), + IPublicationRepository +{ + + public async Task AddAsync(Publication publication) + { + await DbContext.Publications.AddAsync(publication); + await DbContext.SaveChangesAsync(); + } +} diff --git a/src/Core/Presentation/DependencyInjection.cs b/src/Core/Presentation/DependencyInjection.cs index 4c777110..75ba9369 100644 --- a/src/Core/Presentation/DependencyInjection.cs +++ b/src/Core/Presentation/DependencyInjection.cs @@ -316,6 +316,7 @@ public static IEndpointRouteBuilder AddEndPoints(this IEndpointRouteBuilder app) app.AddFollowEndPoints(); app.AddLikeEndPoints(); app.AddHelpResponseEndPoints(); + app.AddPublicationEndPoints(); return app; } diff --git a/src/Core/Presentation/EndPoints/PublicationEndPoints.cs b/src/Core/Presentation/EndPoints/PublicationEndPoints.cs new file mode 100644 index 00000000..8fd8460a --- /dev/null +++ b/src/Core/Presentation/EndPoints/PublicationEndPoints.cs @@ -0,0 +1,36 @@ +using Application.Logic; +using Domain.Contracts; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; + +namespace Presentation.EndPoints; + +public static class PublicationEndPoints +{ + public static void AddPublicationEndPoints(this IEndpointRouteBuilder app) + { + var group = app.MapGroup("api/publication"); + + group.WithOpenApi(); + + group.MapPost(string.Empty, Add); + } + + public static async Task Add( + [FromServices] IPublicationBusinessLogic _logic, + [FromBody] CreatePublicationRequest _request + ) + { + try + { + await _logic.AddPublication(_request); + return Results.Ok(); + } + catch (Exception ex) + { + return Results.BadRequest(ex.Message); + } + } +} From ea8000019ec97dc83912c0fd87668e7b6a5893bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Tue, 3 Sep 2024 20:24:00 -0300 Subject: [PATCH 2/6] Criacao da logica de validacao das URLs --- .../Publication/PublicationBusinessLogic.cs | 6 ++-- src/Core/Domain/Entities/Publication.cs | 30 ++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs index 165deff6..a90bdcab 100644 --- a/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs +++ b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs @@ -8,8 +8,10 @@ public sealed class PublicationBusinessLogic(IPublicationRepository _repository) { public async Task AddPublication(CreatePublicationRequest createPublicationRequest) { - var publication = Publication.Create(createPublicationRequest); - + var publication = + Publication.Create(createPublicationRequest) + ?? throw new UriFormatException("A URL fornecida é inválida!"); + await _repository.AddAsync(publication); } } \ No newline at end of file diff --git a/src/Core/Domain/Entities/Publication.cs b/src/Core/Domain/Entities/Publication.cs index 46505ce1..680a6e6f 100644 --- a/src/Core/Domain/Entities/Publication.cs +++ b/src/Core/Domain/Entities/Publication.cs @@ -9,8 +9,11 @@ public sealed class Publication(Guid id, Guid perfilId, string link, bool isVali public string Link { get; private set; } = link; public bool IsValid { get; private set; } = isValid; - public static Publication Create(CreatePublicationRequest createPublicationRequest) + public static Publication? Create(CreatePublicationRequest createPublicationRequest) { + if (!UrlIsValid(createPublicationRequest.Link)) + return null; + return new Publication( Guid.NewGuid(), createPublicationRequest.PerfilId, @@ -28,4 +31,29 @@ public void Valid() { IsValid = true; } + + public static bool UrlIsValid(string url) { + string[] allowedDomains = new[] + { + "linkedin.com", + "x.com", + "dev.to", + "tabnews.com.br", + "medium.com" + }; + + if (string.IsNullOrWhiteSpace(url)) + return false; + + Uri.TryCreate(url, UriKind.Absolute, out var uriResult); + + if ( + uriResult == null + || uriResult.Scheme != Uri.UriSchemeHttps + || !allowedDomains.Any(domain => uriResult.Host.EndsWith(domain, StringComparison.OrdinalIgnoreCase)) + ) + return false; + + return true; + } } From 0ddb32b88753d70f713a7103882a6dbb6b242132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Thu, 5 Sep 2024 02:47:20 -0300 Subject: [PATCH 3/6] Criacao do WebService no Core. Criacao da rota e do servico para adicionar publicacoes no App.Platform, com tratamento de excecoes. --- src/APP.Platform/Pages/Canal/Index.cshtml.cs | 22 ++++++++++++++++-- src/APP.Platform/Program.cs | 1 + .../Services/IPublicationService.cs | 10 ++++++++ .../Services/PublicationService.cs | 19 +++++++++++++++ .../WebServices/IPublicationWebService.cs | 11 +++++++++ .../Infrastructure/DependencyInjection.cs | 1 + .../WebServices/Core/PublicationWebService.cs | 23 +++++++++++++++++++ 7 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/APP.Platform/Services/IPublicationService.cs create mode 100644 src/APP.Platform/Services/PublicationService.cs create mode 100644 src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs create mode 100644 src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs diff --git a/src/APP.Platform/Pages/Canal/Index.cshtml.cs b/src/APP.Platform/Pages/Canal/Index.cshtml.cs index 7e308a6c..5e2549fb 100644 --- a/src/APP.Platform/Pages/Canal/Index.cshtml.cs +++ b/src/APP.Platform/Pages/Canal/Index.cshtml.cs @@ -3,6 +3,7 @@ using System.Text.Json; using Background; using ClassLib.Follow.Models.ViewModels; +using Domain.Contracts; using Domain.Entities; using Domain.Enums; using Domain.Models.ViewModels; @@ -22,6 +23,8 @@ namespace APP.Platform.Pages; public sealed class CanalIndexModel : CustomPageModel { + private readonly IPublicationService _publicationService; + [BindProperty] public JoinTime? JoinTime { get; set; } public Dictionary? MyEvents { get; set; } @@ -62,7 +65,8 @@ public CanalIndexModel( IMessagePublisher messagePublisher, Settings settings, IPerfilWebService perfilWebService, - ILiveService liveService + ILiveService liveService, + IPublicationService publicationService ) : base(context, httpClientFactory, httpContextAccessor, settings) { @@ -73,6 +77,7 @@ ILiveService liveService _context = context; _messagePublisher = messagePublisher; _liveService = liveService; + _publicationService = publicationService; } public async Task OnGetAsync(string usr) @@ -145,7 +150,7 @@ public async Task OnGetAfterloadCanal( { return BadRequest(); } - + var pagedPrivateLives = await _liveService.RenderPrivateLives( perfilOwner, UserProfile.Id, @@ -540,4 +545,17 @@ em receber mentoria {timeSelection.TituloTemporario} return Redirect("./?event=" + JoinTime.TimeSelectionId); } + + public async Task OnPostPublication([FromBody] CreatePublicationRequest reques) + { + try + { + await _publicationService.Add(reques); + return StatusCode(200, new { status = "OK", message = "Publicação adicionada com sucesso!" }); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } } diff --git a/src/APP.Platform/Program.cs b/src/APP.Platform/Program.cs index 192858ad..d40831a6 100644 --- a/src/APP.Platform/Program.cs +++ b/src/APP.Platform/Program.cs @@ -105,6 +105,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder .Services.AddDefaultIdentity(options => diff --git a/src/APP.Platform/Services/IPublicationService.cs b/src/APP.Platform/Services/IPublicationService.cs new file mode 100644 index 00000000..2d0dde46 --- /dev/null +++ b/src/APP.Platform/Services/IPublicationService.cs @@ -0,0 +1,10 @@ +using Domain.Contracts; + +namespace Platform.Services; + +public interface IPublicationService +{ + + public Task Add(CreatePublicationRequest request); + +} diff --git a/src/APP.Platform/Services/PublicationService.cs b/src/APP.Platform/Services/PublicationService.cs new file mode 100644 index 00000000..7c6298de --- /dev/null +++ b/src/APP.Platform/Services/PublicationService.cs @@ -0,0 +1,19 @@ +using Domain.Contracts; +using Domain.WebServices; + +namespace Platform.Services; + +public class PublicationService(IPublicationWebService _publicationWebService) : IPublicationService +{ + public async Task Add(CreatePublicationRequest request) { + + try + { + await _publicationWebService.Add(request); + } + catch + { + throw; + } + } +} \ No newline at end of file diff --git a/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs b/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs new file mode 100644 index 00000000..38521e66 --- /dev/null +++ b/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs @@ -0,0 +1,11 @@ +using Domain.Contracts; +using Domain.Entities; +using Microsoft.AspNetCore.Http; + +namespace Domain.WebServices; + +public interface IPublicationWebService +{ + public Task Add(CreatePublicationRequest request); + +} diff --git a/src/Core/Infrastructure/DependencyInjection.cs b/src/Core/Infrastructure/DependencyInjection.cs index e0aa42c4..bf40323e 100644 --- a/src/Core/Infrastructure/DependencyInjection.cs +++ b/src/Core/Infrastructure/DependencyInjection.cs @@ -217,6 +217,7 @@ IConfiguration configuration services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs b/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs new file mode 100644 index 00000000..6eeb8272 --- /dev/null +++ b/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs @@ -0,0 +1,23 @@ +using Domain.Contracts; +using Domain.WebServices; + +namespace Infrastructure.WebServices; + +public sealed class PublicationWebService(CoreClient client) : IPublicationWebService +{ + const string baseRoute = "api/publication"; + + public async Task Add(CreatePublicationRequest request) + { + var route = Path.Combine(baseRoute, string.Empty); + + try + { + await client.PostAsync(route, request); + } + catch + { + throw new Exception("Erro! Não foi possível adicionar sua publicação. Verifique a URL ou se o formato do arquivo JSON está correto."); + } + } +} \ No newline at end of file From d93c52d036a6f1b7ec8842a879a5d3e2ac2b1b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Thu, 5 Sep 2024 03:07:33 -0300 Subject: [PATCH 4/6] Execucao do comando dotnet csharpier . --- src/APP.Platform/Pages/Canal/Index.cshtml.cs | 9 ++++++--- .../Services/IPublicationService.cs | 2 -- src/APP.Platform/Services/PublicationService.cs | 10 +++++----- .../Publication/IPublicationBusinessLogic.cs | 1 + .../Publication/PublicationBusinessLogic.cs | 9 +++++---- .../Publication/CreatePublicationRequest.cs | 5 +---- src/Core/Domain/Entities/Publication.cs | 17 ++++++++++------- .../WebServices/IPublicationWebService.cs | 1 - .../Repositories/PublicationRepository.cs | 1 - .../WebServices/Core/PublicationWebService.cs | 8 +++++--- 10 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/APP.Platform/Pages/Canal/Index.cshtml.cs b/src/APP.Platform/Pages/Canal/Index.cshtml.cs index 5e2549fb..3ceede32 100644 --- a/src/APP.Platform/Pages/Canal/Index.cshtml.cs +++ b/src/APP.Platform/Pages/Canal/Index.cshtml.cs @@ -150,7 +150,7 @@ public async Task OnGetAfterloadCanal( { return BadRequest(); } - + var pagedPrivateLives = await _liveService.RenderPrivateLives( perfilOwner, UserProfile.Id, @@ -546,12 +546,15 @@ em receber mentoria {timeSelection.TituloTemporario} return Redirect("./?event=" + JoinTime.TimeSelectionId); } - public async Task OnPostPublication([FromBody] CreatePublicationRequest reques) + public async Task OnPostPublication([FromBody] CreatePublicationRequest reques) { try { await _publicationService.Add(reques); - return StatusCode(200, new { status = "OK", message = "Publicação adicionada com sucesso!" }); + return StatusCode( + 200, + new { status = "OK", message = "Publicação adicionada com sucesso!" } + ); } catch (Exception ex) { diff --git a/src/APP.Platform/Services/IPublicationService.cs b/src/APP.Platform/Services/IPublicationService.cs index 2d0dde46..ce4e723a 100644 --- a/src/APP.Platform/Services/IPublicationService.cs +++ b/src/APP.Platform/Services/IPublicationService.cs @@ -4,7 +4,5 @@ namespace Platform.Services; public interface IPublicationService { - public Task Add(CreatePublicationRequest request); - } diff --git a/src/APP.Platform/Services/PublicationService.cs b/src/APP.Platform/Services/PublicationService.cs index 7c6298de..9c819dd4 100644 --- a/src/APP.Platform/Services/PublicationService.cs +++ b/src/APP.Platform/Services/PublicationService.cs @@ -5,9 +5,9 @@ namespace Platform.Services; public class PublicationService(IPublicationWebService _publicationWebService) : IPublicationService { - public async Task Add(CreatePublicationRequest request) { - - try + public async Task Add(CreatePublicationRequest request) + { + try { await _publicationWebService.Add(request); } @@ -15,5 +15,5 @@ public async Task Add(CreatePublicationRequest request) { { throw; } - } -} \ No newline at end of file + } +} diff --git a/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs b/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs index d6af1ba0..57ae4889 100644 --- a/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs +++ b/src/Core/Application/Logic/Publication/IPublicationBusinessLogic.cs @@ -1,4 +1,5 @@ using Domain.Contracts; + //using Domain.Entities; namespace Application.Logic; diff --git a/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs index a90bdcab..b37cabcf 100644 --- a/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs +++ b/src/Core/Application/Logic/Publication/PublicationBusinessLogic.cs @@ -4,14 +4,15 @@ namespace Application.Logic; -public sealed class PublicationBusinessLogic(IPublicationRepository _repository) : IPublicationBusinessLogic +public sealed class PublicationBusinessLogic(IPublicationRepository _repository) + : IPublicationBusinessLogic { public async Task AddPublication(CreatePublicationRequest createPublicationRequest) { - var publication = + var publication = Publication.Create(createPublicationRequest) ?? throw new UriFormatException("A URL fornecida é inválida!"); - + await _repository.AddAsync(publication); } -} \ No newline at end of file +} diff --git a/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs index ceb0bca4..1a6cb777 100644 --- a/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs +++ b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs @@ -1,6 +1,3 @@ namespace Domain.Contracts; -public record CreatePublicationRequest( - Guid PerfilId, - string Link -); +public record CreatePublicationRequest(Guid PerfilId, string Link); diff --git a/src/Core/Domain/Entities/Publication.cs b/src/Core/Domain/Entities/Publication.cs index 680a6e6f..24fd841a 100644 --- a/src/Core/Domain/Entities/Publication.cs +++ b/src/Core/Domain/Entities/Publication.cs @@ -1,5 +1,5 @@ -using Domain.Primitives; using Domain.Contracts; +using Domain.Primitives; namespace Domain.Entities; @@ -32,28 +32,31 @@ public void Valid() IsValid = true; } - public static bool UrlIsValid(string url) { + public static bool UrlIsValid(string url) + { string[] allowedDomains = new[] { "linkedin.com", "x.com", "dev.to", "tabnews.com.br", - "medium.com" + "medium.com", }; if (string.IsNullOrWhiteSpace(url)) return false; - + Uri.TryCreate(url, UriKind.Absolute, out var uriResult); - + if ( uriResult == null || uriResult.Scheme != Uri.UriSchemeHttps - || !allowedDomains.Any(domain => uriResult.Host.EndsWith(domain, StringComparison.OrdinalIgnoreCase)) + || !allowedDomains.Any(domain => + uriResult.Host.EndsWith(domain, StringComparison.OrdinalIgnoreCase) ) + ) return false; - + return true; } } diff --git a/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs b/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs index 38521e66..c27e289d 100644 --- a/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs +++ b/src/Core/Domain/Interfaces/WebServices/IPublicationWebService.cs @@ -7,5 +7,4 @@ namespace Domain.WebServices; public interface IPublicationWebService { public Task Add(CreatePublicationRequest request); - } diff --git a/src/Core/Infrastructure/Repositories/PublicationRepository.cs b/src/Core/Infrastructure/Repositories/PublicationRepository.cs index e767c58b..3fd060bc 100644 --- a/src/Core/Infrastructure/Repositories/PublicationRepository.cs +++ b/src/Core/Infrastructure/Repositories/PublicationRepository.cs @@ -10,7 +10,6 @@ public sealed class PublicationRepository(ApplicationDbContext context) : GenericRepository(context), IPublicationRepository { - public async Task AddAsync(Publication publication) { await DbContext.Publications.AddAsync(publication); diff --git a/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs b/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs index 6eeb8272..c4d8008a 100644 --- a/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs +++ b/src/Core/Infrastructure/WebServices/Core/PublicationWebService.cs @@ -10,14 +10,16 @@ public sealed class PublicationWebService(CoreClient client) : IPublicationWebSe public async Task Add(CreatePublicationRequest request) { var route = Path.Combine(baseRoute, string.Empty); - + try { await client.PostAsync(route, request); } catch { - throw new Exception("Erro! Não foi possível adicionar sua publicação. Verifique a URL ou se o formato do arquivo JSON está correto."); + throw new Exception( + "Erro! Não foi possível adicionar sua publicação. Verifique a URL ou se o formato do arquivo JSON está correto." + ); } } -} \ No newline at end of file +} From 617e271f621b20bccd83bfb9e2cbc8680df08357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Sat, 7 Sep 2024 03:57:23 -0300 Subject: [PATCH 5/6] Correcoes e melhorias. Aprimoramento nas validacoes das URLs, eliminando vulnerabilidades, permitindo receber apenas o link do cliente, removendo a requisicao ao WebService do servico e fazendo diretamente pela rota POST do canal. --- src/APP.Platform/Models/PublicationModel.cs | 6 ++++ src/APP.Platform/Pages/Canal/Index.cshtml.cs | 27 ++++++--------- src/APP.Platform/Program.cs | 1 - .../Services/IPublicationService.cs | 8 ----- .../Services/PublicationService.cs | 19 ----------- .../Publication/CreatePublicationRequest.cs | 2 +- src/Core/Domain/Entities/Publication.cs | 34 +++++++------------ 7 files changed, 31 insertions(+), 66 deletions(-) create mode 100644 src/APP.Platform/Models/PublicationModel.cs delete mode 100644 src/APP.Platform/Services/IPublicationService.cs delete mode 100644 src/APP.Platform/Services/PublicationService.cs diff --git a/src/APP.Platform/Models/PublicationModel.cs b/src/APP.Platform/Models/PublicationModel.cs new file mode 100644 index 00000000..26066b70 --- /dev/null +++ b/src/APP.Platform/Models/PublicationModel.cs @@ -0,0 +1,6 @@ +namespace Domain.Models.ViewModels; + +public sealed class PublicationModel +{ + public string? Link { get; set; } +} diff --git a/src/APP.Platform/Pages/Canal/Index.cshtml.cs b/src/APP.Platform/Pages/Canal/Index.cshtml.cs index 3ceede32..4d59ab82 100644 --- a/src/APP.Platform/Pages/Canal/Index.cshtml.cs +++ b/src/APP.Platform/Pages/Canal/Index.cshtml.cs @@ -23,7 +23,7 @@ namespace APP.Platform.Pages; public sealed class CanalIndexModel : CustomPageModel { - private readonly IPublicationService _publicationService; + private readonly IPublicationWebService _publicationWebService; [BindProperty] public JoinTime? JoinTime { get; set; } @@ -66,7 +66,7 @@ public CanalIndexModel( Settings settings, IPerfilWebService perfilWebService, ILiveService liveService, - IPublicationService publicationService + IPublicationWebService publicationWebService ) : base(context, httpClientFactory, httpContextAccessor, settings) { @@ -77,7 +77,7 @@ IPublicationService publicationService _context = context; _messagePublisher = messagePublisher; _liveService = liveService; - _publicationService = publicationService; + _publicationWebService = publicationWebService; } public async Task OnGetAsync(string usr) @@ -546,19 +546,14 @@ em receber mentoria {timeSelection.TituloTemporario} return Redirect("./?event=" + JoinTime.TimeSelectionId); } - public async Task OnPostPublication([FromBody] CreatePublicationRequest reques) + public async Task OnPostPublication([FromBody] PublicationModel publicationModel) { - try - { - await _publicationService.Add(reques); - return StatusCode( - 200, - new { status = "OK", message = "Publicação adicionada com sucesso!" } - ); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + await _publicationWebService.Add(new CreatePublicationRequest( + UserProfile.Id, + publicationModel.Link + )); + + return Page(); + } } diff --git a/src/APP.Platform/Program.cs b/src/APP.Platform/Program.cs index d40831a6..192858ad 100644 --- a/src/APP.Platform/Program.cs +++ b/src/APP.Platform/Program.cs @@ -105,7 +105,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); builder .Services.AddDefaultIdentity(options => diff --git a/src/APP.Platform/Services/IPublicationService.cs b/src/APP.Platform/Services/IPublicationService.cs deleted file mode 100644 index ce4e723a..00000000 --- a/src/APP.Platform/Services/IPublicationService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Domain.Contracts; - -namespace Platform.Services; - -public interface IPublicationService -{ - public Task Add(CreatePublicationRequest request); -} diff --git a/src/APP.Platform/Services/PublicationService.cs b/src/APP.Platform/Services/PublicationService.cs deleted file mode 100644 index 9c819dd4..00000000 --- a/src/APP.Platform/Services/PublicationService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Domain.Contracts; -using Domain.WebServices; - -namespace Platform.Services; - -public class PublicationService(IPublicationWebService _publicationWebService) : IPublicationService -{ - public async Task Add(CreatePublicationRequest request) - { - try - { - await _publicationWebService.Add(request); - } - catch - { - throw; - } - } -} diff --git a/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs index 1a6cb777..159988b2 100644 --- a/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs +++ b/src/Core/Domain/Contracts/Publication/CreatePublicationRequest.cs @@ -1,3 +1,3 @@ namespace Domain.Contracts; -public record CreatePublicationRequest(Guid PerfilId, string Link); +public record CreatePublicationRequest(Guid PerfilId, string? Link); diff --git a/src/Core/Domain/Entities/Publication.cs b/src/Core/Domain/Entities/Publication.cs index 24fd841a..dd862d67 100644 --- a/src/Core/Domain/Entities/Publication.cs +++ b/src/Core/Domain/Entities/Publication.cs @@ -1,5 +1,6 @@ using Domain.Contracts; using Domain.Primitives; +using System.Text.RegularExpressions; namespace Domain.Entities; @@ -11,13 +12,14 @@ public sealed class Publication(Guid id, Guid perfilId, string link, bool isVali public static Publication? Create(CreatePublicationRequest createPublicationRequest) { - if (!UrlIsValid(createPublicationRequest.Link)) + string? url = createPublicationRequest.Link; + if (url == null || !UrlIsValid(url)) return null; return new Publication( Guid.NewGuid(), createPublicationRequest.PerfilId, - createPublicationRequest.Link, + url, true ); } @@ -34,29 +36,19 @@ public void Valid() public static bool UrlIsValid(string url) { - string[] allowedDomains = new[] - { - "linkedin.com", - "x.com", - "dev.to", - "tabnews.com.br", - "medium.com", + string[] allowedDomains = { + @"^https:\/\/(www\.)?linkedin\.com(\/.*)?$", + @"^https:\/\/x\.com(\/.*)?$", + @"^https:\/\/dev\.to(\/.*)?$", + @"^https:\/\/tabnews\.com\.br(\/.*)?$", + @"^https:\/\/medium\.com(\/.*)?$" }; - - if (string.IsNullOrWhiteSpace(url)) - return false; - - Uri.TryCreate(url, UriKind.Absolute, out var uriResult); - + if ( - uriResult == null - || uriResult.Scheme != Uri.UriSchemeHttps - || !allowedDomains.Any(domain => - uriResult.Host.EndsWith(domain, StringComparison.OrdinalIgnoreCase) + !allowedDomains.Any(domain => Regex.IsMatch(url, domain, RegexOptions.IgnoreCase)) ) - ) return false; - + return true; } } From 47a5126fad1072b007c8f2a7a8b6fb4b71dab785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Viana?= Date: Sat, 7 Sep 2024 09:51:59 -0300 Subject: [PATCH 6/6] Comando dotnet csharpier . --- src/APP.Platform/Pages/Canal/Index.cshtml.cs | 10 ++++----- src/Core/Domain/Entities/Publication.cs | 22 +++++++------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/APP.Platform/Pages/Canal/Index.cshtml.cs b/src/APP.Platform/Pages/Canal/Index.cshtml.cs index 4d59ab82..99de3ffc 100644 --- a/src/APP.Platform/Pages/Canal/Index.cshtml.cs +++ b/src/APP.Platform/Pages/Canal/Index.cshtml.cs @@ -548,12 +548,10 @@ em receber mentoria {timeSelection.TituloTemporario} public async Task OnPostPublication([FromBody] PublicationModel publicationModel) { - await _publicationWebService.Add(new CreatePublicationRequest( - UserProfile.Id, - publicationModel.Link - )); - + await _publicationWebService.Add( + new CreatePublicationRequest(UserProfile.Id, publicationModel.Link) + ); + return Page(); - } } diff --git a/src/Core/Domain/Entities/Publication.cs b/src/Core/Domain/Entities/Publication.cs index dd862d67..1a1ff8f6 100644 --- a/src/Core/Domain/Entities/Publication.cs +++ b/src/Core/Domain/Entities/Publication.cs @@ -1,6 +1,6 @@ +using System.Text.RegularExpressions; using Domain.Contracts; using Domain.Primitives; -using System.Text.RegularExpressions; namespace Domain.Entities; @@ -16,12 +16,7 @@ public sealed class Publication(Guid id, Guid perfilId, string link, bool isVali if (url == null || !UrlIsValid(url)) return null; - return new Publication( - Guid.NewGuid(), - createPublicationRequest.PerfilId, - url, - true - ); + return new Publication(Guid.NewGuid(), createPublicationRequest.PerfilId, url, true); } public void NotValid() @@ -36,19 +31,18 @@ public void Valid() public static bool UrlIsValid(string url) { - string[] allowedDomains = { + string[] allowedDomains = + { @"^https:\/\/(www\.)?linkedin\.com(\/.*)?$", @"^https:\/\/x\.com(\/.*)?$", @"^https:\/\/dev\.to(\/.*)?$", @"^https:\/\/tabnews\.com\.br(\/.*)?$", - @"^https:\/\/medium\.com(\/.*)?$" + @"^https:\/\/medium\.com(\/.*)?$", }; - - if ( - !allowedDomains.Any(domain => Regex.IsMatch(url, domain, RegexOptions.IgnoreCase)) - ) + + if (!allowedDomains.Any(domain => Regex.IsMatch(url, domain, RegexOptions.IgnoreCase))) return false; - + return true; } }