From 55671154b6382180839d6c02cfa9bf459937ade9 Mon Sep 17 00:00:00 2001 From: Tomasz 'Tom' Kandula Date: Sun, 16 Jan 2022 11:48:17 +0100 Subject: [PATCH 1/5] feat: add new error/validation codes --- .../Resources/ErrorCodes.Designer.cs | 6 ++++++ .../EmailSender.Backend.Shared/Resources/ErrorCodes.resx | 3 +++ .../Resources/ValidationCodes.Designer.cs | 6 ++++++ .../Resources/ValidationCodes.resx | 3 +++ 4 files changed, 18 insertions(+) diff --git a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.Designer.cs b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.Designer.cs index d92afc7..97f47ea 100644 --- a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.Designer.cs +++ b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.Designer.cs @@ -110,5 +110,11 @@ public static string INVALID_API_VERSION { return ResourceManager.GetString("INVALID_API_VERSION", resourceCulture); } } + + public static string FILE_NOT_FOUND { + get { + return ResourceManager.GetString("FILE_NOT_FOUND", resourceCulture); + } + } } } diff --git a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.resx b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.resx index f587382..0994f39 100644 --- a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.resx +++ b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ErrorCodes.resx @@ -51,4 +51,7 @@ Provided API version seems to be invalid + + Cannot find file + \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.Designer.cs b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.Designer.cs index 21c8d91..b54e3ac 100644 --- a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.Designer.cs +++ b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.Designer.cs @@ -56,5 +56,11 @@ public static string INVALID_EMAIL_ADDRESS { return ResourceManager.GetString("INVALID_EMAIL_ADDRESS", resourceCulture); } } + + public static string NAME_TOO_LONG { + get { + return ResourceManager.GetString("NAME_TOO_LONG", resourceCulture); + } + } } } diff --git a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.resx b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.resx index 6df2090..645620e 100644 --- a/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.resx +++ b/EmailSender.Backend/EmailSender.Backend.Shared/Resources/ValidationCodes.resx @@ -24,4 +24,7 @@ Invalid email address + + The name is too long + \ No newline at end of file From a912f62bf28b12432c5f8bc65bcfdfb8b44033ae Mon Sep 17 00:00:00 2001 From: Tomasz 'Tom' Kandula Date: Sun, 16 Jan 2022 11:48:41 +0100 Subject: [PATCH 2/5] feat: map root path --- EmailSender.WebApi/Startup.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/EmailSender.WebApi/Startup.cs b/EmailSender.WebApi/Startup.cs index 2d2adf7..12e72c9 100644 --- a/EmailSender.WebApi/Startup.cs +++ b/EmailSender.WebApi/Startup.cs @@ -1,6 +1,7 @@ namespace EmailSender.WebApi; using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; @@ -56,7 +57,13 @@ public void Configure(IApplicationBuilder builder) builder.UseResponseCompression(); builder.UseRouting(); - builder.UseEndpoints(endpoints => endpoints.MapControllers()); + builder.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapGet("/", context + => context.Response.WriteAsync("Email Sender API")); + }); + builder.SetupSwaggerUi(_environment); } } \ No newline at end of file From 8202e84f51bac77a69b3c1eeefdf6e6bf58d49e1 Mon Sep 17 00:00:00 2001 From: Tomasz 'Tom' Kandula Date: Sun, 16 Jan 2022 11:48:55 +0100 Subject: [PATCH 3/5] feat: add cqrs for getting log files --- .../Queries/Logger/GetLogFileContentQuery.cs | 9 ++++++ .../Logger/GetLogFileContentQueryHandler.cs | 26 ++++++++++++++++ .../Logger/GetLogFileContentQueryValidator.cs | 18 +++++++++++ .../Queries/Logger/GetLogFilesListQuery.cs | 5 ++++ .../Logger/GetLogFilesListQueryHandler.cs | 30 +++++++++++++++++++ .../Logger/GetLogFilesListQueryResult.cs | 8 +++++ 6 files changed, 96 insertions(+) create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQuery.cs create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryHandler.cs create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryValidator.cs create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQuery.cs create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryHandler.cs create mode 100644 EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryResult.cs diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQuery.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQuery.cs new file mode 100644 index 0000000..7eaeb97 --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQuery.cs @@ -0,0 +1,9 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using Microsoft.AspNetCore.Mvc; +using MediatR; + +public class GetLogFileContentQuery : IRequest +{ + public string LogFileName { get; set; } +} \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryHandler.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryHandler.cs new file mode 100644 index 0000000..e454a6f --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryHandler.cs @@ -0,0 +1,26 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Core.Exceptions; +using Shared.Resources; + +public class GetLogFileContentQueryHandler : RequestHandler +{ + public override async Task Handle(GetLogFileContentQuery request, CancellationToken cancellationToken) + { + var pathToFolder = $"{AppDomain.CurrentDomain.BaseDirectory}logs"; + if (!Directory.Exists(pathToFolder)) + throw new BusinessException(nameof(ErrorCodes.ERROR_UNEXPECTED), ErrorCodes.ERROR_UNEXPECTED); + + var fullFilePath = $"{pathToFolder}{Path.DirectorySeparatorChar}{request.LogFileName}"; + if (!File.Exists(fullFilePath)) + throw new BusinessException(nameof(ErrorCodes.FILE_NOT_FOUND), ErrorCodes.FILE_NOT_FOUND); + + var fileContent = await File.ReadAllBytesAsync(fullFilePath, cancellationToken); + return new FileContentResult(fileContent, "text/plain"); + } +} \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryValidator.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryValidator.cs new file mode 100644 index 0000000..ba469ad --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFileContentQueryValidator.cs @@ -0,0 +1,18 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using FluentValidation; +using Shared.Resources; + +public class GetLogFileContentQueryValidator : AbstractValidator +{ + public GetLogFileContentQueryValidator() + { + RuleFor(query => query.LogFileName) + .NotEmpty() + .WithErrorCode(nameof(ValidationCodes.REQUIRED)) + .WithMessage(ValidationCodes.REQUIRED) + .MaximumLength(255) + .WithErrorCode(nameof(ValidationCodes.NAME_TOO_LONG)) + .WithMessage(ValidationCodes.NAME_TOO_LONG); + } +} \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQuery.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQuery.cs new file mode 100644 index 0000000..a69f1f2 --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQuery.cs @@ -0,0 +1,5 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using MediatR; + +public class GetLogFilesListQuery : IRequest { } \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryHandler.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryHandler.cs new file mode 100644 index 0000000..f6c3173 --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryHandler.cs @@ -0,0 +1,30 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +public class GetLogFilesListQueryHandler : RequestHandler +{ + public override async Task Handle(GetLogFilesListQuery request, CancellationToken cancellationToken) + { + var pathToFolder = $"{AppDomain.CurrentDomain.BaseDirectory}logs"; + if (!Directory.Exists(pathToFolder)) + return new GetLogFilesListQueryResult(); + + var fullPathFileList = Directory.EnumerateFiles(pathToFolder, "*.txt", SearchOption.TopDirectoryOnly); + var logFiles = new List(); + + foreach (var item in fullPathFileList) + { + logFiles.Add(Path.GetFileName(item)); + } + + return await Task.FromResult(new GetLogFilesListQueryResult + { + LogFiles = logFiles + }); + } +} \ No newline at end of file diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryResult.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryResult.cs new file mode 100644 index 0000000..e4024f3 --- /dev/null +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Logger/GetLogFilesListQueryResult.cs @@ -0,0 +1,8 @@ +namespace EmailSender.Backend.Cqrs.Handlers.Queries.Logger; + +using System.Collections.Generic; + +public class GetLogFilesListQueryResult +{ + public List LogFiles { get; set; } +} \ No newline at end of file From f8043c58ea756de1b71da7f98e5d8634e046a9a6 Mon Sep 17 00:00:00 2001 From: Tomasz 'Tom' Kandula Date: Sun, 16 Jan 2022 11:49:31 +0100 Subject: [PATCH 4/5] feat: add new endpoint for getting log files --- .../Controllers/LoggerController.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 EmailSender.WebApi/Controllers/LoggerController.cs diff --git a/EmailSender.WebApi/Controllers/LoggerController.cs b/EmailSender.WebApi/Controllers/LoggerController.cs new file mode 100644 index 0000000..10df9ad --- /dev/null +++ b/EmailSender.WebApi/Controllers/LoggerController.cs @@ -0,0 +1,23 @@ +namespace EmailSender.WebApi.Controllers; + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Backend.Cqrs.Handlers.Queries.Logger; +using MediatR; + +[ApiVersion("1.0")] +public class LoggerController : BaseController +{ + public LoggerController(IMediator mediator) : base(mediator) { } + + [HttpGet] + [ProducesResponseType(typeof(GetLogFilesListQueryResult), StatusCodes.Status200OK)] + public async Task GetLogFilesList([FromHeader(Name = HeaderName)] string privateKey) + => await Mediator.Send(new GetLogFilesListQuery()); + + [HttpGet("{fileName}")] + [ProducesResponseType(typeof(IActionResult), StatusCodes.Status200OK)] + public async Task GetLogFileContent([FromRoute] string fileName, [FromHeader(Name = HeaderName)] string privateKey) + => await Mediator.Send(new GetLogFileContentQuery { LogFileName = fileName }); +} \ No newline at end of file From 1ec90227048c8b29bd55db124ff5b02b218bec18 Mon Sep 17 00:00:00 2001 From: Tomasz 'Tom' Kandula Date: Sun, 16 Jan 2022 12:18:43 +0100 Subject: [PATCH 5/5] feat: add lgo information to handlers --- .../Handlers/Queries/Emails/GetEmailsHistoryQueryHandler.cs | 2 ++ .../Handlers/Queries/Users/GetUserDomainsQueryHandler.cs | 1 + .../Handlers/Queries/Users/GetUserEmailsQueryHandler.cs | 1 + 3 files changed, 4 insertions(+) diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Emails/GetEmailsHistoryQueryHandler.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Emails/GetEmailsHistoryQueryHandler.cs index 818517b..42fab6e 100644 --- a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Emails/GetEmailsHistoryQueryHandler.cs +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Emails/GetEmailsHistoryQueryHandler.cs @@ -68,6 +68,8 @@ public override async Task Handle(GetEmailsHistoryQ .Where(user => user.Id == userId) .FirstOrDefaultAsync(cancellationToken); + var wording = history.Count == 1 ? "entry" : "entries"; + _loggerService.LogInformation($"Found {history.Count} history {wording} for requested user"); return new GetEmailsHistoryQueryResult { AssociatedUser = associatedUser.UserAlias, diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserDomainsQueryHandler.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserDomainsQueryHandler.cs index bead643..38acde1 100644 --- a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserDomainsQueryHandler.cs +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserDomainsQueryHandler.cs @@ -57,6 +57,7 @@ public override async Task Handle(GetUserDomainsQuery .Select(allowDomain => allowDomain.Host) .ToListAsync(cancellationToken); + _loggerService.LogInformation($"Found {hosts.Count} host(s) for requested user"); return new GetUserDomainsQueryResult { Hosts = hosts diff --git a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserEmailsQueryHandler.cs b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserEmailsQueryHandler.cs index c490de5..2410871 100644 --- a/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserEmailsQueryHandler.cs +++ b/EmailSender.Backend/EmailSender.Backend.Cqrs/Handlers/Queries/Users/GetUserEmailsQueryHandler.cs @@ -63,6 +63,7 @@ public override async Task Handle(GetUserEmailsQuery r .Where(user => user.Id == userId) .FirstOrDefaultAsync(cancellationToken); + _loggerService.LogInformation($"Found {emails.Count} email(s) for requested user"); return new GetUserEmailsQueryResult { AssociatedUser = associatedUser.UserAlias,