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/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 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, 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 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 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