From 41f2dd3972c2898e31b2a58b285246853ac0da6a Mon Sep 17 00:00:00 2001 From: dotReboot Date: Fri, 21 Feb 2025 11:13:48 +0300 Subject: [PATCH 01/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20Serilog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/API/API.csproj | 4 ++++ src/API/Program.cs | 6 ++++++ src/API/appsettings.Development.json | 22 ++++++++++++++++++---- src/API/appsettings.json | 23 ++++++++++++++++++----- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/API/API.csproj b/src/API/API.csproj index 78b9659..c825d32 100644 --- a/src/API/API.csproj +++ b/src/API/API.csproj @@ -10,6 +10,10 @@ + + + + diff --git a/src/API/Program.cs b/src/API/Program.cs index aec095c..1e8118c 100644 --- a/src/API/Program.cs +++ b/src/API/Program.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.FileProviders; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; +using Serilog; using Infrastructure.Extensions; using Infrastructure.Services; using API.Extensions; @@ -13,6 +14,10 @@ public class Program public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); + builder.Host.UseSerilog((context, configuration) => + { + configuration.ReadFrom.Configuration(context.Configuration); + }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(); builder.Configuration.AddEnvironmentVariables(); @@ -66,6 +71,7 @@ public static void Main(string[] args) }; }); var app = builder.Build(); + app.UseSerilogRequestLogging(); app.UseCors(); app.UseExceptionHandler(); app.UseOpenApi(options => diff --git a/src/API/appsettings.Development.json b/src/API/appsettings.Development.json index 0c208ae..e3255cc 100644 --- a/src/API/appsettings.Development.json +++ b/src/API/appsettings.Development.json @@ -1,8 +1,22 @@ { - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Override": { + "API": "Debug", + "Microsoft.AspNetCore": "Warning" + } + }, + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "Logs/Development/DevLog-.txt", + "rollingInterval": "Day" + } + } + ] } } diff --git a/src/API/appsettings.json b/src/API/appsettings.json index 15b1a81..c812aeb 100644 --- a/src/API/appsettings.json +++ b/src/API/appsettings.json @@ -1,9 +1,22 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Serilog": { + "MinimumLevel": { + "Default": "Warning", + "Override": { + "API": "Information" + } + }, + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "Logs/Log-.txt", + "rollingInterval": "Day" + } + } + ] }, "AllowedHosts": "*", "JWTKey": "9>I4=o8{AG\\Nh{`I7m*={tP:Gs)dsXxNw.Hj92]dQSO", From 70e98113fe60531ca5569a85bc094afa62e1a68c Mon Sep 17 00:00:00 2001 From: dotReboot Date: Mon, 25 Aug 2025 01:47:15 +0300 Subject: [PATCH 02/30] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=D0=B4?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=B8=D1=8F=20=D1=81=D0=BB=D0=B8=D1=8F=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=81=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Program.cs | 6 ------ src/Platform.API/Program.cs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Admin.API/Program.cs b/src/Admin.API/Program.cs index b9b303c..fa7fd8b 100644 --- a/src/Admin.API/Program.cs +++ b/src/Admin.API/Program.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; -using Serilog; using Application.Interfaces.Services; using Infrastructure.Extensions; using Admin.API.Extensions; @@ -13,10 +12,6 @@ public class Program public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); - builder.Host.UseSerilog((context, configuration) => - { - configuration.ReadFrom.Configuration(context.Configuration); - }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(); builder.Configuration.AddEnvironmentVariables(); @@ -72,7 +67,6 @@ public static void Main(string[] args) }; }); var app = builder.Build(); - app.UseSerilogRequestLogging(); app.UseCors(); app.UseExceptionHandler(); app.UseOpenApi(options => diff --git a/src/Platform.API/Program.cs b/src/Platform.API/Program.cs index 25b1267..e6500d3 100644 --- a/src/Platform.API/Program.cs +++ b/src/Platform.API/Program.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.FileProviders; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; +using Serilog; using Application.Interfaces.Services; using Infrastructure.Extensions; using Platform.API.Extensions; @@ -14,6 +15,10 @@ public class Program public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); + builder.Host.UseSerilog((context, configuration) => + { + configuration.ReadFrom.Configuration(context.Configuration); + }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(); builder.Configuration.AddEnvironmentVariables(); @@ -78,6 +83,7 @@ public static void Main(string[] args) options.Secure = CookieSecurePolicy.Always; }); var app = builder.Build(); + app.UseSerilogRequestLogging(); app.UseCors(); app.UseExceptionHandler(); app.UseOpenApi(options => From b9a5e4541affe90ea652c44968280ce004625004 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Mon, 25 Aug 2025 18:17:46 +0300 Subject: [PATCH 03/30] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3?= =?UTF-8?q?=D1=83=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20Serilog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Platform.API/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Platform.API/appsettings.json b/src/Platform.API/appsettings.json index 5281fd3..355bed1 100644 --- a/src/Platform.API/appsettings.json +++ b/src/Platform.API/appsettings.json @@ -3,7 +3,7 @@ "MinimumLevel": { "Default": "Warning", "Override": { - "API": "Information" + "Platform.API": "Information" } }, "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], From ad9fe8b465570526e1bbc41b4bfd8ff1c179a195 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Sun, 7 Sep 2025 22:07:24 +0300 Subject: [PATCH 04/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=20PersonId=20=D0=B2=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2=20=D0=BA=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D1=83=20-=20=D0=98=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D1=80=D1=8B=20MinimumLevel=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?Serilog=20=D0=B2=20appsettings.Development.json=20-=20=D0=94?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20ApplicationA?= =?UTF-8?q?uthorizationException=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=B1=D0=BE?= =?UTF-8?q?=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BE=D0=BA=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D0=B8,=20=D0=BF=D1=80=D0=BE=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D1=88=D0=B5=D0=B4=D1=88=D0=B8=D1=85=20=D0=B2=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B5=D0=BC=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B8=20-=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=B2=D1=80=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D1=80=D0=B5=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5=D0=BC?= =?UTF-8?q?=D1=8B=20=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=BE=D0=B2=20=D0=BE?= =?UTF-8?q?=D0=B1=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=D1=85=20=D0=BF=D1=80=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20Except?= =?UTF-8?q?ionHandlerMiddleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApplicationAuthorizationException.cs | 3 +++ src/Application/Services/ClubAdminsService.cs | 4 ++-- src/Application/Services/PersonsService.cs | 6 ++++-- src/Application/Services/PostsService.cs | 6 +++--- ...> ApplicationAuthorizationExceptionHandler.cs} | 14 ++++++++++++-- .../AuthenticationExceptionHandler.cs | 9 +++++++++ .../BadRequestExceptionHandler.cs | 9 +++++++++ .../ExceptionHandlers/GlobalExceptionHandler.cs | 9 +++++++++ .../InvalidOperationExceptionHandler.cs | 9 +++++++++ .../ExceptionHandlers/NotFoundExceptionHandler.cs | 9 +++++++++ .../Extensions/ServiceCollectionExtensions.cs | 2 +- src/Platform.API/Program.cs | 15 ++++++++++++++- src/Platform.API/appsettings.Development.json | 5 ++--- 13 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 src/Application/Exceptions/ApplicationAuthorizationException.cs rename src/Platform.API/ExceptionHandlers/{AuthorizationExceptionHandler.cs => ApplicationAuthorizationExceptionHandler.cs} (62%) diff --git a/src/Application/Exceptions/ApplicationAuthorizationException.cs b/src/Application/Exceptions/ApplicationAuthorizationException.cs new file mode 100644 index 0000000..862c995 --- /dev/null +++ b/src/Application/Exceptions/ApplicationAuthorizationException.cs @@ -0,0 +1,3 @@ +namespace Application.Exceptions; + +public class ApplicationAuthorizationException(string? message) : UnauthorizedAccessException(message); \ No newline at end of file diff --git a/src/Application/Services/ClubAdminsService.cs b/src/Application/Services/ClubAdminsService.cs index a6a6a19..34f0e67 100644 --- a/src/Application/Services/ClubAdminsService.cs +++ b/src/Application/Services/ClubAdminsService.cs @@ -32,7 +32,7 @@ public async Task GrantAdminRights(int personId, int clubId) if (person is null) throw new NotFoundException(nameof(PersonModel), personId); if (_sessionService.PersonId != club.OwnerId) - throw new UnauthorizedAccessException("Пользователь должен являться владельцем клуба, чтобы назначить администратора"); + throw new ApplicationAuthorizationException("Пользователь должен являться владельцем клуба, чтобы назначить администратора"); if (await _clubAdminsRepository.CheckIfContainsAsync(personId, clubId) || club.OwnerId == personId) throw new InvalidOperationException("Пользователь уже является администратором или владельцем данного клуба"); var clubAdmin = new ClubAdmin { PersonId = personId, ClubId = clubId }; @@ -48,7 +48,7 @@ public async Task RevokeAdminRights(int personId, int clubId) if (person is null) throw new NotFoundException(nameof(PersonModel), personId); if (_sessionService.PersonId != club.OwnerId) - throw new UnauthorizedAccessException("Пользователь должен являться владельцем клуба, чтобы разжаловать администратора"); + throw new ApplicationAuthorizationException("Пользователь должен являться владельцем клуба, чтобы разжаловать администратора"); if (!await _clubAdminsRepository.CheckIfContainsAsync(personId, clubId)) throw new InvalidOperationException("Пользователь не является администратором данного клуба"); var id = (await _clubAdminsRepository.GetByClubIdAsync(clubId)).First(c => c.ClubId == clubId diff --git a/src/Application/Services/PersonsService.cs b/src/Application/Services/PersonsService.cs index 7af208f..c848d2e 100644 --- a/src/Application/Services/PersonsService.cs +++ b/src/Application/Services/PersonsService.cs @@ -28,7 +28,8 @@ public async Task CreateAsync(PersonDTO personDTO) public async Task UpdateAsync(PersonDTO personDTO, int id) { - if (_sessionService.PersonId != id) throw new UnauthorizedAccessException(); + if (_sessionService.PersonId != id) + throw new ApplicationAuthorizationException("Только владелец записи пользователя может её изменить"); var person = await _personsRepository.GetByIdAsync(id); if (person is null) throw new NotFoundException(nameof(PersonModel), id); person = _mapper.Map(personDTO, person); @@ -37,7 +38,8 @@ public async Task UpdateAsync(PersonDTO personDTO, int id) public async Task DeleteByIdAsync(int id) { - if (_sessionService.PersonId != id) throw new UnauthorizedAccessException(); + if (_sessionService.PersonId != id) + throw new ApplicationAuthorizationException("Только владелец записи пользователя может её удалить"); await _personsRepository.DeleteByIdAsync(id); } } \ No newline at end of file diff --git a/src/Application/Services/PostsService.cs b/src/Application/Services/PostsService.cs index a44e519..ff07d61 100644 --- a/src/Application/Services/PostsService.cs +++ b/src/Application/Services/PostsService.cs @@ -35,7 +35,7 @@ public async Task CreateAsync(PostDTO postDTO) var ownerId = (await _clubsRepository.GetByIdAsync(postDTO.ClubId!.Value))!.OwnerId; if (ownerId != _sessionService.PersonId && !await _clubAdminsRepository.CheckIfContainsAsync(_sessionService.PersonId, postDTO.ClubId!.Value)) - throw new UnauthorizedAccessException("Создавать посты могут только администраторы и владелец клуба"); + throw new ApplicationAuthorizationException("Создавать посты могут только администраторы и владелец клуба"); var post = _mapper.Map(postDTO); await _postsRepository.CreateAsync(post); return post.Id; @@ -48,7 +48,7 @@ public async Task UpdateAsync(PostDTO postDTO, int postId) var ownerId = (await _clubsRepository.GetByIdAsync(postDTO.ClubId!.Value))!.OwnerId; if (ownerId != _sessionService.PersonId && !await _clubAdminsRepository.CheckIfContainsAsync(_sessionService.PersonId, postDTO.ClubId!.Value)) - throw new UnauthorizedAccessException("Изменять посты могут только администраторы и владелец клуба"); + throw new ApplicationAuthorizationException("Изменять посты могут только администраторы и владелец клуба"); post = _mapper.Map(postDTO, post); await _postsRepository.UpdateAsync(post); } @@ -61,7 +61,7 @@ public async Task DeleteByIdAsync(int postId) var ownerId = (await _clubsRepository.GetByIdAsync(clubId))!.OwnerId; if (ownerId != _sessionService.PersonId && !await _clubAdminsRepository.CheckIfContainsAsync(_sessionService.PersonId, clubId)) - throw new UnauthorizedAccessException("Удалять посты могут только администраторы и владелец клуба"); + throw new ApplicationAuthorizationException("Удалять посты могут только администраторы и владелец клуба"); await _postsRepository.DeleteByIdAsync(postId); } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/AuthorizationExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs similarity index 62% rename from src/Platform.API/ExceptionHandlers/AuthorizationExceptionHandler.cs rename to src/Platform.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs index 2fc4ab2..d1a81c3 100644 --- a/src/Platform.API/ExceptionHandlers/AuthorizationExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs @@ -1,16 +1,25 @@ +using Application.Exceptions; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; -public class AuthorizationExceptionHandler : IExceptionHandler +public class ApplicationAuthorizationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Доступ запрещён"; private const int StatusCode = StatusCodes.Status403Forbidden; + private readonly ILogger _logger; + + public ApplicationAuthorizationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { - if (exception is not UnauthorizedAccessException) + if (exception is not ApplicationAuthorizationException) { return false; } @@ -23,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/AuthenticationExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/AuthenticationExceptionHandler.cs index ac44437..a6c552b 100644 --- a/src/Platform.API/ExceptionHandlers/AuthenticationExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/AuthenticationExceptionHandler.cs @@ -1,6 +1,7 @@ using System.Security.Authentication; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class AuthenticationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "При аутентификации произошла ошибка"; private const int StatusCode = StatusCodes.Status401Unauthorized; + private readonly ILogger _logger; + + public AuthenticationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/BadRequestExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/BadRequestExceptionHandler.cs index ce7561d..c12e946 100644 --- a/src/Platform.API/ExceptionHandlers/BadRequestExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/BadRequestExceptionHandler.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; @@ -7,6 +8,13 @@ public class BadRequestExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Некорректный запрос"; private const int StatusCode = StatusCodes.Status400BadRequest; + private readonly ILogger _logger; + + public BadRequestExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -23,6 +31,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/GlobalExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/GlobalExceptionHandler.cs index 7692133..fa14194 100644 --- a/src/Platform.API/ExceptionHandlers/GlobalExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/GlobalExceptionHandler.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; @@ -7,6 +8,13 @@ public class GlobalExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Произошла ошибка на стороне сервера"; private const int StatusCode = StatusCodes.Status500InternalServerError; + private readonly ILogger _logger; + + public GlobalExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -19,6 +27,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Error(exception, ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs index 76a6547..91e569c 100644 --- a/src/Platform.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class InvalidOperationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Недопустимая операция"; private const int StatusCode = StatusCodes.Status409Conflict; + private readonly ILogger _logger; + + public InvalidOperationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/ExceptionHandlers/NotFoundExceptionHandler.cs b/src/Platform.API/ExceptionHandlers/NotFoundExceptionHandler.cs index d284aee..7c5bc7d 100644 --- a/src/Platform.API/ExceptionHandlers/NotFoundExceptionHandler.cs +++ b/src/Platform.API/ExceptionHandlers/NotFoundExceptionHandler.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; using Application.Exceptions; +using ILogger = Serilog.ILogger; namespace Platform.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class NotFoundExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Запрашиваемый ресурс отсутствует на сервере"; private const int StatusCode = StatusCodes.Status404NotFound; + private readonly ILogger _logger; + + public NotFoundExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Platform.API/Extensions/ServiceCollectionExtensions.cs b/src/Platform.API/Extensions/ServiceCollectionExtensions.cs index 459d0b0..9fa18c9 100644 --- a/src/Platform.API/Extensions/ServiceCollectionExtensions.cs +++ b/src/Platform.API/Extensions/ServiceCollectionExtensions.cs @@ -10,7 +10,7 @@ public static IServiceCollection AddExceptionHandlers(this IServiceCollection se services.AddExceptionHandler(); services.AddExceptionHandler(); services.AddExceptionHandler(); - services.AddExceptionHandler(); + services.AddExceptionHandler(); services.AddExceptionHandler(); return services; } diff --git a/src/Platform.API/Program.cs b/src/Platform.API/Program.cs index a760cc0..fd75d76 100644 --- a/src/Platform.API/Program.cs +++ b/src/Platform.API/Program.cs @@ -1,9 +1,11 @@ +using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.CookiePolicy; using Microsoft.Extensions.FileProviders; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; using Serilog; +using Serilog.Filters; using Application.Interfaces.Services; using Infrastructure.Extensions; using Platform.API.Extensions; @@ -18,6 +20,9 @@ public static void Main(string[] args) builder.Host.UseSerilog((context, configuration) => { configuration.ReadFrom.Configuration(context.Configuration); + // Временное решение, дублирование логов при использовании ExceptionHandlerMiddleware исправлено в .NET 10 + configuration.Filter.ByExcluding(Matching + .FromSource()); }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApiDocument(); @@ -83,7 +88,15 @@ public static void Main(string[] args) options.Secure = CookieSecurePolicy.Always; }); var app = builder.Build(); - app.UseSerilogRequestLogging(); + app.UseSerilogRequestLogging(options => + { + options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => + { + var personId = httpContext.User.FindFirstValue("personId") ?? "Undefined"; + diagnosticContext.Set("PersonId", personId); + }; + options.MessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000}ms for PersonId {PersonId}"; + }); app.UseCors(); app.UseExceptionHandler(); app.UseOpenApi(options => diff --git a/src/Platform.API/appsettings.Development.json b/src/Platform.API/appsettings.Development.json index e3255cc..e8d4cb0 100644 --- a/src/Platform.API/appsettings.Development.json +++ b/src/Platform.API/appsettings.Development.json @@ -1,10 +1,9 @@ { "Serilog": { "MinimumLevel": { - "Default": "Information", + "Default": "Debug", "Override": { - "API": "Debug", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Information" } }, "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], From 8ec48deda325e478055833d89b9c4c3da1b352a6 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Sun, 7 Sep 2025 22:59:39 +0300 Subject: [PATCH 05/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B0=20Admin.API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Admin.API.csproj | 4 ++++ ...=> ApplicationAuthorizationExceptionHandler.cs} | 14 ++++++++++++-- .../AuthenticationExceptionHandler.cs | 9 +++++++++ .../BadRequestExceptionHandler.cs | 9 +++++++++ .../ExceptionHandlers/GlobalExceptionHandler.cs | 9 +++++++++ .../InvalidOperationExceptionHandler.cs | 9 +++++++++ .../ExceptionHandlers/NotFoundExceptionHandler.cs | 9 +++++++++ .../Extensions/ServiceCollectionExtensions.cs | 2 +- 8 files changed, 62 insertions(+), 3 deletions(-) rename src/Admin.API/ExceptionHandlers/{AuthorizationExceptionHandler.cs => ApplicationAuthorizationExceptionHandler.cs} (62%) diff --git a/src/Admin.API/Admin.API.csproj b/src/Admin.API/Admin.API.csproj index a16c169..1948653 100644 --- a/src/Admin.API/Admin.API.csproj +++ b/src/Admin.API/Admin.API.csproj @@ -15,6 +15,10 @@ + + + + diff --git a/src/Admin.API/ExceptionHandlers/AuthorizationExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs similarity index 62% rename from src/Admin.API/ExceptionHandlers/AuthorizationExceptionHandler.cs rename to src/Admin.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs index 9d294e2..9c1c74e 100644 --- a/src/Admin.API/ExceptionHandlers/AuthorizationExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/ApplicationAuthorizationExceptionHandler.cs @@ -1,16 +1,25 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using Application.Exceptions; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; -public class AuthorizationExceptionHandler : IExceptionHandler +public class ApplicationAuthorizationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Доступ запрещён"; private const int StatusCode = StatusCodes.Status403Forbidden; + private readonly ILogger _logger; + + public ApplicationAuthorizationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { - if (exception is not UnauthorizedAccessException) + if (exception is not ApplicationAuthorizationException) { return false; } @@ -23,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/ExceptionHandlers/AuthenticationExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/AuthenticationExceptionHandler.cs index 24b67fa..55069a5 100644 --- a/src/Admin.API/ExceptionHandlers/AuthenticationExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/AuthenticationExceptionHandler.cs @@ -1,6 +1,7 @@ using System.Security.Authentication; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class AuthenticationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "При аутентификации произошла ошибка"; private const int StatusCode = StatusCodes.Status401Unauthorized; + private readonly ILogger _logger; + + public AuthenticationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/ExceptionHandlers/BadRequestExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/BadRequestExceptionHandler.cs index d850610..6417cfa 100644 --- a/src/Admin.API/ExceptionHandlers/BadRequestExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/BadRequestExceptionHandler.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; @@ -7,6 +8,13 @@ public class BadRequestExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Некорректный запрос"; private const int StatusCode = StatusCodes.Status400BadRequest; + private readonly ILogger _logger; + + public BadRequestExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -23,6 +31,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/ExceptionHandlers/GlobalExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/GlobalExceptionHandler.cs index 2cba8d8..eb4df35 100644 --- a/src/Admin.API/ExceptionHandlers/GlobalExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/GlobalExceptionHandler.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; @@ -7,6 +8,13 @@ public class GlobalExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Произошла ошибка на стороне сервера"; private const int StatusCode = StatusCodes.Status500InternalServerError; + private readonly ILogger _logger; + + public GlobalExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -19,6 +27,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Error(exception, ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs index cfa7cb1..bbab133 100644 --- a/src/Admin.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/InvalidOperationExceptionHandler.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class InvalidOperationExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Недопустимая операция"; private const int StatusCode = StatusCodes.Status409Conflict; + private readonly ILogger _logger; + + public InvalidOperationExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/ExceptionHandlers/NotFoundExceptionHandler.cs b/src/Admin.API/ExceptionHandlers/NotFoundExceptionHandler.cs index 5a95095..ab2ee88 100644 --- a/src/Admin.API/ExceptionHandlers/NotFoundExceptionHandler.cs +++ b/src/Admin.API/ExceptionHandlers/NotFoundExceptionHandler.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; using Application.Exceptions; +using ILogger = Serilog.ILogger; namespace Admin.API.ExceptionHandlers; @@ -8,6 +9,13 @@ public class NotFoundExceptionHandler : IExceptionHandler { private const string ResponseTitle = "Запрашиваемый ресурс отсутствует на сервере"; private const int StatusCode = StatusCodes.Status404NotFound; + private readonly ILogger _logger; + + public NotFoundExceptionHandler(ILogger logger) + { + _logger = logger; + } + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { @@ -24,6 +32,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e Detail = exception.Message }; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + _logger.Warning(exception, "Исключение обработано: {ResponseTitle}", ResponseTitle); return true; } } \ No newline at end of file diff --git a/src/Admin.API/Extensions/ServiceCollectionExtensions.cs b/src/Admin.API/Extensions/ServiceCollectionExtensions.cs index b14f38a..ca65408 100644 --- a/src/Admin.API/Extensions/ServiceCollectionExtensions.cs +++ b/src/Admin.API/Extensions/ServiceCollectionExtensions.cs @@ -10,7 +10,7 @@ public static IServiceCollection AddExceptionHandlers(this IServiceCollection se services.AddExceptionHandler(); services.AddExceptionHandler(); services.AddExceptionHandler(); - services.AddExceptionHandler(); + services.AddExceptionHandler(); services.AddExceptionHandler(); return services; } From aaccc5a87e17b7e3e9e1b3b237a7584f1a0ff85b Mon Sep 17 00:00:00 2001 From: dotReboot Date: Mon, 8 Sep 2025 05:02:50 +0300 Subject: [PATCH 06/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?ResponseCookiesExtensions=20-=20=D0=97=D0=B0=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20Serilog,=20Serilog.Sinks?= =?UTF-8?q?.Console=20=D0=B8=20Serilog.Sinks.File=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20Application.csproj=20-=20?= =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B=20MinimumLevel=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20Serilog=20=D0=B2=20appsettings.json=20?= =?UTF-8?q?=D0=B8=20appsettings.Development.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Admin.API.csproj | 5 +---- src/Application/Application.csproj | 3 +++ src/Platform.API/Extensions/ResponseCookiesExtensions.cs | 6 ++++++ src/Platform.API/Platform.API.csproj | 3 --- src/Platform.API/appsettings.Development.json | 3 ++- src/Platform.API/appsettings.json | 5 +---- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Admin.API/Admin.API.csproj b/src/Admin.API/Admin.API.csproj index 1948653..baf4193 100644 --- a/src/Admin.API/Admin.API.csproj +++ b/src/Admin.API/Admin.API.csproj @@ -15,10 +15,7 @@ - - - - + diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj index d1ca462..a262b2f 100644 --- a/src/Application/Application.csproj +++ b/src/Application/Application.csproj @@ -12,6 +12,9 @@ + + + diff --git a/src/Platform.API/Extensions/ResponseCookiesExtensions.cs b/src/Platform.API/Extensions/ResponseCookiesExtensions.cs index 3c729f2..03c9a12 100644 --- a/src/Platform.API/Extensions/ResponseCookiesExtensions.cs +++ b/src/Platform.API/Extensions/ResponseCookiesExtensions.cs @@ -1,9 +1,13 @@ +using Serilog; +using ILogger = Serilog.ILogger; using Infrastructure.Identity.Models.DTO; namespace Platform.API.Extensions; public static class ResponseCookiesExtensions { + private static readonly ILogger _logger = Log.Logger; + public static void UpdateTokenCookies(this IResponseCookies cookies, TokenModel tokens) { cookies.DeleteTokenCookies(); @@ -14,11 +18,13 @@ public static void UpdateTokenCookies(this IResponseCookies cookies, TokenModel }; cookies.Append("AccessToken", tokens.AccessToken, cookieOptions); cookies.Append("RefreshToken", tokens.RefreshToken, cookieOptions); + _logger.Verbose("Обновлены Cookie файлы Access и Refresh токенов"); } public static void DeleteTokenCookies(this IResponseCookies cookies) { cookies.Delete("AccessToken"); cookies.Delete("RefreshToken"); + _logger.Verbose("Удалены Cookie файлы Access и Refresh токенов"); } } \ No newline at end of file diff --git a/src/Platform.API/Platform.API.csproj b/src/Platform.API/Platform.API.csproj index ed49e68..383b8a2 100644 --- a/src/Platform.API/Platform.API.csproj +++ b/src/Platform.API/Platform.API.csproj @@ -12,9 +12,6 @@ - - - diff --git a/src/Platform.API/appsettings.Development.json b/src/Platform.API/appsettings.Development.json index e8d4cb0..ad551c3 100644 --- a/src/Platform.API/appsettings.Development.json +++ b/src/Platform.API/appsettings.Development.json @@ -1,8 +1,9 @@ { "Serilog": { "MinimumLevel": { - "Default": "Debug", + "Default": "Verbose", "Override": { + "Microsoft.EntityFrameworkCore": "Information", "Microsoft.AspNetCore": "Information" } }, diff --git a/src/Platform.API/appsettings.json b/src/Platform.API/appsettings.json index 355bed1..8c341fb 100644 --- a/src/Platform.API/appsettings.json +++ b/src/Platform.API/appsettings.json @@ -1,10 +1,7 @@ { "Serilog": { "MinimumLevel": { - "Default": "Warning", - "Override": { - "Platform.API": "Information" - } + "Default": "Warning" }, "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "WriteTo": [ From a7de6f4aa5d1e8e7103935e3d8443168087dfcd1 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Mon, 8 Sep 2025 05:27:39 +0300 Subject: [PATCH 07/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D0=BA=D0=BB=D0=B0=D0=B4=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=81=D0=BB=D0=BE=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/Services/ClubAdminsService.cs | 11 ++++++++--- .../Services/ClubCreationRequestsService.cs | 13 ++++++++++--- src/Application/Services/ClubsService.cs | 15 ++++++++++++--- src/Application/Services/PersonsService.cs | 8 +++++++- src/Application/Services/PostsService.cs | 8 +++++++- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/Application/Services/ClubAdminsService.cs b/src/Application/Services/ClubAdminsService.cs index 34f0e67..42856dd 100644 --- a/src/Application/Services/ClubAdminsService.cs +++ b/src/Application/Services/ClubAdminsService.cs @@ -1,4 +1,5 @@ -using Domain.Entities.Club; +using ILogger = Serilog.ILogger; +using Domain.Entities.Club; using Domain.Entities.Person; using Application.Exceptions; using Application.Interfaces.Repositories.Club; @@ -13,16 +14,18 @@ public class ClubAdminsService : IClubAdminsService private readonly IPersonsRepository _personsRepository; private readonly IClubsRepository _clubsRepository; private readonly ISessionService _sessionService; + private readonly ILogger _logger; public ClubAdminsService(IClubAdminsRepository clubAdminsRepository, IClubsRepository clubsRepository, - ISessionService sessionService, IPersonsRepository personsRepository) + ISessionService sessionService, IPersonsRepository personsRepository, ILogger logger) { _clubAdminsRepository = clubAdminsRepository; _clubsRepository = clubsRepository; _sessionService = sessionService; _personsRepository = personsRepository; + _logger = logger; } - + public async Task GrantAdminRights(int personId, int clubId) { var club = await _clubsRepository.GetByIdAsync(clubId); @@ -37,6 +40,7 @@ public async Task GrantAdminRights(int personId, int clubId) throw new InvalidOperationException("Пользователь уже является администратором или владельцем данного клуба"); var clubAdmin = new ClubAdmin { PersonId = personId, ClubId = clubId }; await _clubAdminsRepository.CreateAsync(clubAdmin); + _logger.Information("Пользователь с Id ({PersonId}) назначен администратором клуба с Id ({ClubId})", personId, clubId); } public async Task RevokeAdminRights(int personId, int clubId) @@ -54,5 +58,6 @@ public async Task RevokeAdminRights(int personId, int clubId) var id = (await _clubAdminsRepository.GetByClubIdAsync(clubId)).First(c => c.ClubId == clubId && c.PersonId == personId).Id; await _clubAdminsRepository.DeleteByIdAsync(id); + _logger.Information("Пользователь с Id ({PersonId}) лишён прав администратора клуба с Id ({ClubId})", personId, clubId); } } \ No newline at end of file diff --git a/src/Application/Services/ClubCreationRequestsService.cs b/src/Application/Services/ClubCreationRequestsService.cs index 4196238..edbd928 100644 --- a/src/Application/Services/ClubCreationRequestsService.cs +++ b/src/Application/Services/ClubCreationRequestsService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ILogger = Serilog.ILogger; using Domain.Entities.Admin; using Domain.Entities.Club; using Application.DTO; @@ -14,20 +15,23 @@ public class ClubCreationRequestsService : IClubCreationRequestsService private readonly IClubCreationRequestsRepository _clubCreationRequestsRepository; private readonly IClubsRepository _clubsRepository; private readonly IMapper _mapper; - + private readonly ILogger _logger; + public ClubCreationRequestsService(IClubCreationRequestsRepository clubCreationRequestsRepository, - IClubsRepository clubsRepository, IMapper mapper) + IClubsRepository clubsRepository, IMapper mapper, ILogger logger) { _clubCreationRequestsRepository = clubCreationRequestsRepository; _clubsRepository = clubsRepository; _mapper = mapper; + _logger = logger; } - + public async Task CreateAsync(ClubCreationRequestDTO clubCreationRequestDTO) { var clubCreationRequest = _mapper.Map(clubCreationRequestDTO); clubCreationRequest.IsActive = true; await _clubCreationRequestsRepository.CreateAsync(clubCreationRequest); + _logger.Information("Добавлена заявка на создание клуба с Id ({ClubCreationRequestId})", clubCreationRequest.Id); } public async Task AcceptRequest(int requestId) @@ -47,7 +51,9 @@ public async Task AcceptRequest(int requestId) await _clubsRepository.CreateAsync(club); clubCreationRequest.IsActive = false; await _clubCreationRequestsRepository.UpdateAsync(clubCreationRequest); + _logger.Information("Заявка на создание клуба с Id ({RequestId}) одобрена", requestId); } + public async Task DeclineRequest(int requestId) { var clubCreationRequest = await _clubCreationRequestsRepository.GetByIdAsync(requestId); @@ -56,5 +62,6 @@ public async Task DeclineRequest(int requestId) throw new InvalidOperationException("Заявка на создание клуба уже была рассмотрена"); clubCreationRequest.IsActive = false; await _clubCreationRequestsRepository.UpdateAsync(clubCreationRequest); + _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена)", requestId); } } \ No newline at end of file diff --git a/src/Application/Services/ClubsService.cs b/src/Application/Services/ClubsService.cs index 30a4643..0ff55e1 100644 --- a/src/Application/Services/ClubsService.cs +++ b/src/Application/Services/ClubsService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ILogger = Serilog.ILogger; using Domain.Entities.Club; using Application.DTO; using Application.Exceptions; @@ -13,16 +14,18 @@ public class ClubsService : IClubsService private readonly IPersonsClubsRepository _personsClubsRepository; private readonly ISessionService _sessionService; private readonly IMapper _mapper; + private readonly ILogger _logger; public ClubsService(IClubsRepository clubsRepository, IPersonsClubsRepository personsClubsRepository, - ISessionService sessionService, IMapper mapper) + ISessionService sessionService, IMapper mapper, ILogger logger) { _clubsRepository = clubsRepository; _personsClubsRepository = personsClubsRepository; _sessionService = sessionService; _mapper = mapper; + _logger = logger; } - + public async Task ToggleSubscription(int id) { if (await _clubsRepository.GetByIdAsync(id) is null) throw new NotFoundException(nameof(ClubModel), id); @@ -46,6 +49,7 @@ public async Task CreateAsync(ClubDTO clubDTO) { var club = _mapper.Map(clubDTO); await _clubsRepository.CreateAsync(club); + _logger.Information("Создан клуб с Id ({ClubId}), принадлежащий пользователю с Id ({OwnerId})", club.Id, club.OwnerId); } public async Task UpdateAsync(ClubDTO clubDTO, int clubId) @@ -54,7 +58,12 @@ public async Task UpdateAsync(ClubDTO clubDTO, int clubId) if (club is null) throw new NotFoundException(nameof(ClubModel), clubId); club = _mapper.Map(clubDTO, club); await _clubsRepository.UpdateAsync(club); + _logger.Information("Обновлена информация о клубе с Id ({ClubId})", club.Id); } - public async Task DeleteByIdAsync(int id) => await _clubsRepository.DeleteByIdAsync(id); + public async Task DeleteByIdAsync(int id) + { + await _clubsRepository.DeleteByIdAsync(id); + _logger.Information("Удалён клуб с Id ({ClubId})", id); + } } \ No newline at end of file diff --git a/src/Application/Services/PersonsService.cs b/src/Application/Services/PersonsService.cs index c848d2e..8123740 100644 --- a/src/Application/Services/PersonsService.cs +++ b/src/Application/Services/PersonsService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ILogger = Serilog.ILogger; using Domain.Entities.Person; using Application.DTO; using Application.Exceptions; @@ -12,18 +13,21 @@ public class PersonsService : IPersonsService private readonly IPersonsRepository _personsRepository; private readonly ISessionService _sessionService; private readonly IMapper _mapper; + private readonly ILogger _logger; - public PersonsService(IPersonsRepository personsRepository, ISessionService sessionService, IMapper mapper) + public PersonsService(IPersonsRepository personsRepository, ISessionService sessionService, IMapper mapper, ILogger logger) { _personsRepository = personsRepository; _sessionService = sessionService; _mapper = mapper; + _logger = logger; } public async Task CreateAsync(PersonDTO personDTO) { var person = _mapper.Map(personDTO); await _personsRepository.CreateAsync(person); + _logger.Information("Создан пользователь с Id ({PersonId})", person.Id); } public async Task UpdateAsync(PersonDTO personDTO, int id) @@ -34,6 +38,7 @@ public async Task UpdateAsync(PersonDTO personDTO, int id) if (person is null) throw new NotFoundException(nameof(PersonModel), id); person = _mapper.Map(personDTO, person); await _personsRepository.UpdateAsync(person); + _logger.Information("Обновлена информация о пользователе с Id ({PersonId})", person.Id); } public async Task DeleteByIdAsync(int id) @@ -41,5 +46,6 @@ public async Task DeleteByIdAsync(int id) if (_sessionService.PersonId != id) throw new ApplicationAuthorizationException("Только владелец записи пользователя может её удалить"); await _personsRepository.DeleteByIdAsync(id); + _logger.Information("Удалён пользователь с Id ({PersonId})", id); } } \ No newline at end of file diff --git a/src/Application/Services/PostsService.cs b/src/Application/Services/PostsService.cs index ff07d61..ed9f053 100644 --- a/src/Application/Services/PostsService.cs +++ b/src/Application/Services/PostsService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using ILogger = Serilog.ILogger; using Domain.Entities.Post; using Application.DTO; using Application.Exceptions; @@ -17,9 +18,10 @@ public class PostsService : IPostsService private readonly IClubAdminsRepository _clubAdminsRepository; private readonly IClubsRepository _clubsRepository; private readonly IMapper _mapper; + private readonly ILogger _logger; public PostsService(IPostsRepository postsRepository, IClubsQueryService clubsQueryService, IMapper mapper, - IClubAdminsRepository clubAdminsRepository, IClubsRepository clubsRepository, ISessionService sessionService) + IClubAdminsRepository clubAdminsRepository, IClubsRepository clubsRepository, ISessionService sessionService, ILogger logger) { _postsRepository = postsRepository; _clubsQueryService = clubsQueryService; @@ -27,6 +29,7 @@ public PostsService(IPostsRepository postsRepository, IClubsQueryService clubsQu _clubsRepository = clubsRepository; _sessionService = sessionService; _mapper = mapper; + _logger = logger; } public async Task CreateAsync(PostDTO postDTO) @@ -38,6 +41,7 @@ public async Task CreateAsync(PostDTO postDTO) throw new ApplicationAuthorizationException("Создавать посты могут только администраторы и владелец клуба"); var post = _mapper.Map(postDTO); await _postsRepository.CreateAsync(post); + _logger.Information("Создан пост с Id ({PostId}) пользователем с Id ({PersonId})", post.Id, _sessionService.PersonId); return post.Id; } @@ -51,6 +55,7 @@ public async Task UpdateAsync(PostDTO postDTO, int postId) throw new ApplicationAuthorizationException("Изменять посты могут только администраторы и владелец клуба"); post = _mapper.Map(postDTO, post); await _postsRepository.UpdateAsync(post); + _logger.Information("Изменён пост с Id ({PostId}) пользователем с Id ({PersonId})", post.Id, _sessionService.PersonId); } public async Task DeleteByIdAsync(int postId) @@ -63,5 +68,6 @@ public async Task DeleteByIdAsync(int postId) !await _clubAdminsRepository.CheckIfContainsAsync(_sessionService.PersonId, clubId)) throw new ApplicationAuthorizationException("Удалять посты могут только администраторы и владелец клуба"); await _postsRepository.DeleteByIdAsync(postId); + _logger.Information("Удалён пост с Id ({PostId}) пользователем с Id ({PersonId})", post.Id, _sessionService.PersonId); } } \ No newline at end of file From 6c8aacd2519d8ffb6d80b13490bff5a35f82f802 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 06:47:28 +0300 Subject: [PATCH 08/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=84=D1=80=D0=B0=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=81=D0=BB=D0=BE?= =?UTF-8?q?=D1=8F=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=B0=20AuthService=20-=20=D0=94?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81=D0=B0=20SessionService=20-=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=20ImagesService=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=BE=D0=B3=D0=B8=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2=20=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D0=B5=D0=B2=20-=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B?= =?UTF-8?q?=20MinimumLevel=20=D0=B4=D0=BB=D1=8F=20Serilog=20=D0=B2=20appse?= =?UTF-8?q?ttings.json=20=D0=B8=20appsettings.Development.json=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20Platform.API=20=D0=B8=20Admin.API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/appsettings.Development.json | 24 +++++++++++++++---- src/Admin.API/appsettings.json | 22 +++++++++++++---- .../Extensions/ServiceCollectionExtensions.cs | 10 ++++++++ .../Identity/Services/AuthService.cs | 23 ++++++++++++++---- src/Infrastructure/Services/ImagesService.cs | 16 ++++++++++++- src/Infrastructure/Services/SessionService.cs | 9 +++++++ src/Platform.API/appsettings.Development.json | 2 +- src/Platform.API/appsettings.json | 6 ++++- 8 files changed, 95 insertions(+), 17 deletions(-) diff --git a/src/Admin.API/appsettings.Development.json b/src/Admin.API/appsettings.Development.json index 0c208ae..e04fcfb 100644 --- a/src/Admin.API/appsettings.Development.json +++ b/src/Admin.API/appsettings.Development.json @@ -1,8 +1,22 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft.EntityFrameworkCore": "Information", + "Microsoft.AspNetCore": "Information" + } + }, + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "Logs/Development/DevLog-.txt", + "rollingInterval": "Day" + } + } + ] } } diff --git a/src/Admin.API/appsettings.json b/src/Admin.API/appsettings.json index a71e7cf..b935137 100644 --- a/src/Admin.API/appsettings.json +++ b/src/Admin.API/appsettings.json @@ -1,9 +1,23 @@ { - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Override": { + "Microsoft.EntityFrameworkCore": "Warning", + "Microsoft.AspNetCore": "Warning" + } + }, + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "Logs/Log-.txt", + "rollingInterval": "Day" + } + } + ] }, "Domain": "admin.setka-rtu.ru", "AllowedHosts": "*", diff --git a/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs b/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs index 886a632..6cd4205 100644 --- a/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs +++ b/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Serilog; using Application.Interfaces.Repositories; using Application.Interfaces.Services; using Application.Interfaces.Queries; @@ -14,8 +15,11 @@ namespace Infrastructure.Extensions; public static class ServiceCollectionExtensions { + private static readonly ILogger _logger = Log.Logger; + public static IServiceCollection AddStudHubServices(this IServiceCollection services, string connectionString) { + _logger.Debug("Начата регистрация сервисов платформы"); services.AddDbContext(dbContextOptions => dbContextOptions.UseNpgsql(connectionString)); services.AddIdentityServices(connectionString); @@ -38,18 +42,22 @@ public static IServiceCollection AddStudHubServices(this IServiceCollection serv services.AddTransient(); services.AddScoped(); services.AddStudHubRepositories(); + _logger.Debug("Завершена регистрация сервисов платформы"); return services; } public static IServiceCollection AddAdminServices(this IServiceCollection services) { + _logger.Debug("Начата регистрация сервисов панели администрирования"); services.AddTransient(); services.AddTransient(); + _logger.Debug("Завершена регистрация сервисов панели администрирования"); return services; } public static IServiceCollection AddStudHubRepositories(this IServiceCollection services) { + _logger.Debug("Начата регистрация репозиториев"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes() .Where(type => type is { IsClass: true, IsAbstract: false } && type.GetInterfaces().Contains(typeof(IRepository)))) @@ -62,8 +70,10 @@ public static IServiceCollection AddStudHubRepositories(this IServiceCollection else { services.AddTransient(type); + _logger.Warning("Для репозитория {ServiceType} не найден подходящий интерфейс", type); } } + _logger.Debug("Завершена регистрация репозиториев"); return services; } } \ No newline at end of file diff --git a/src/Infrastructure/Identity/Services/AuthService.cs b/src/Infrastructure/Identity/Services/AuthService.cs index dd97014..524f0d2 100644 --- a/src/Infrastructure/Identity/Services/AuthService.cs +++ b/src/Infrastructure/Identity/Services/AuthService.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; +using ILogger = Serilog.ILogger; using Domain.Entities.Person; using Application.DTO; using Application.Interfaces.Repositories.Person; @@ -21,20 +22,24 @@ public class AuthService private readonly IConfiguration _configuration; private readonly RefreshTokensRepository _refreshTokensRepository; private readonly IPersonsRepository _personsRepository; + private readonly ILogger _logger; - public AuthService(UserManager userManager, IConfiguration configuration, RefreshTokensRepository refreshTokensRepository, IPersonsRepository personsRepository) + public AuthService(UserManager userManager, IConfiguration configuration, + RefreshTokensRepository refreshTokensRepository, IPersonsRepository personsRepository, ILogger logger) { _userManager = userManager; _configuration = configuration; _refreshTokensRepository = refreshTokensRepository; _personsRepository = personsRepository; + _logger = logger; } - + public async Task Login(LoginDTO loginDTO) { var account = await _userManager.FindByEmailAsync(loginDTO.Email); if (account is null || !await _userManager.CheckPasswordAsync(account, loginDTO.Password)) throw new InvalidCredentialException("Неверный email или пароль"); + _logger.Information("Произведён вход в систему пользователем {Email}", account.Email); return await GetTokensAsync(account); } @@ -69,6 +74,8 @@ public async Task Register(RegisterDTO registerDTO) "и включает в себя как минимум одну цифру, символ нижнего и верхнего регистра, специальный символ, " + "затем повторите попытку"); } + _logger.Information("Произведена регистрация пользователя {Email} с Id ({PersonId})", + account.Email, person.Id); } public async Task RefreshTokensAsync(TokenModel tokenModel) @@ -85,9 +92,11 @@ public async Task RefreshTokensAsync(TokenModel tokenModel) var account = await _userManager.FindByIdAsync(refreshToken.AccountId); if (account is null) throw new AuthenticationException("Пользователь не найден"); await RevokeRefreshTokenAsync(tokenModel.RefreshToken); - return await GetTokensAsync(account); + tokenModel = await GetTokensAsync(account); + _logger.Information("Токены аутентификации обновлены для пользователя с Id ({PersonId})", account.PersonId); + return tokenModel; } - + private async Task GetTokensAsync(Account account) { var person = (await _personsRepository.GetByIdAsync(account.PersonId))!; @@ -117,10 +126,14 @@ private async Task GetTokensAsync(Account account) ExpiresAt = DateTime.Now.AddMonths(1) }; await _refreshTokensRepository.AddAsync(refreshToken); + _logger.Debug("Создана новая пара токенов аутентификации для пользователя с Id ({PersonId})", person.Id); TokenModel tokenModel = new TokenModel(accessTokenValue, refreshTokenValue); return tokenModel; } - public async Task RevokeRefreshTokenAsync(string refreshTokenValue) => + public async Task RevokeRefreshTokenAsync(string refreshTokenValue) + { await _refreshTokensRepository.RemoveByValueAsync(refreshTokenValue); + _logger.Debug("Аннулирован токен со значением ({RefreshTokenValue})", refreshTokenValue); + } } \ No newline at end of file diff --git a/src/Infrastructure/Services/ImagesService.cs b/src/Infrastructure/Services/ImagesService.cs index 4905603..8372a17 100644 --- a/src/Infrastructure/Services/ImagesService.cs +++ b/src/Infrastructure/Services/ImagesService.cs @@ -1,3 +1,4 @@ +using ILogger = Serilog.ILogger; using Domain.Entities; using Application.Exceptions; using Application.Interfaces.Repositories; @@ -8,11 +9,13 @@ namespace Infrastructure.Services; public class ImagesService : IImagesService { private readonly IImagesRepository _imagesRepository; + private readonly ILogger _logger; private readonly string[] _availableImageExtensions = new[] { ".png", ".jpg", ".jpeg" }; - public ImagesService(IImagesRepository imagesRepository) + public ImagesService(IImagesRepository imagesRepository, ILogger logger) { _imagesRepository = imagesRepository; + _logger = logger; } public async Task GetPathByIdAsync(int id) @@ -25,27 +28,38 @@ public async Task GetPathByIdAsync(int id) public async Task CreateAsync(Stream stream, string extension) { if (!_availableImageExtensions.Contains(extension)) + { + _logger.Warning("Загрузка файла с расширением {FileExtension} прервана", extension); throw new ArgumentException("Расширение файла не поддерживается"); + } var image = new Image { Path = Guid.NewGuid() + extension, CreatedAt = DateTime.Now }; + _logger.Information("Начата загрузка изображения {Image}", image); using (var fileStream = File.Create(Path.Combine("/StudHubImages", image.Path))) { await stream.CopyToAsync(fileStream); } + _logger.Debug("Изображение {Image} сохранено на диск", image); await _imagesRepository.CreateAsync(image); + _logger.Information("Изображение {Image} успешно загружено", image); return image.Id; } public async Task DeleteImageFileByIdAsync(int id) { var filePath = Path.Combine("/StudHubImages", await GetPathByIdAsync(id)); + _logger.Information("Начато удаление изображения с Id ({ImageId})", id); await _imagesRepository.DeleteByIdAsync(id); + _logger.Debug("Изображение с Id ({ImageId}) успешно удалено из базы данных", id); if (File.Exists(filePath)) { File.Delete(filePath); + _logger.Information("Изображение с Id ({ImageId}) успешно удалено", id); + return; } + _logger.Warning("Не удалось найти изображение по пути ({FilePath}) при удалении", filePath); } } \ No newline at end of file diff --git a/src/Infrastructure/Services/SessionService.cs b/src/Infrastructure/Services/SessionService.cs index a706972..f9d2d30 100644 --- a/src/Infrastructure/Services/SessionService.cs +++ b/src/Infrastructure/Services/SessionService.cs @@ -1,12 +1,20 @@ using System.Security.Authentication; using System.Security.Claims; +using ILogger = Serilog.ILogger; using Application.Interfaces.Services; namespace Infrastructure.Services; public class SessionService : ISessionService { + private readonly ILogger _logger; private int? _personId; + + public SessionService(ILogger logger) + { + _logger = logger; + } + public int PersonId { get => _personId ?? throw new AuthenticationException("Сессия не инициализирована"); @@ -17,5 +25,6 @@ public void Initialise(ClaimsPrincipal claimsPrincipal) { PersonId = int.Parse(claimsPrincipal.FindFirstValue("personId") ?? throw new AuthenticationException("При инициализации использован недействительный ClaimsPrincipal")); + _logger.Debug("Инициализирована сессия для пользователя с Id ({PersonId})", PersonId); } } \ No newline at end of file diff --git a/src/Platform.API/appsettings.Development.json b/src/Platform.API/appsettings.Development.json index ad551c3..e04fcfb 100644 --- a/src/Platform.API/appsettings.Development.json +++ b/src/Platform.API/appsettings.Development.json @@ -1,7 +1,7 @@ { "Serilog": { "MinimumLevel": { - "Default": "Verbose", + "Default": "Debug", "Override": { "Microsoft.EntityFrameworkCore": "Information", "Microsoft.AspNetCore": "Information" diff --git a/src/Platform.API/appsettings.json b/src/Platform.API/appsettings.json index 8c341fb..6aca759 100644 --- a/src/Platform.API/appsettings.json +++ b/src/Platform.API/appsettings.json @@ -1,7 +1,11 @@ { "Serilog": { "MinimumLevel": { - "Default": "Warning" + "Default": "Information", + "Override": { + "Microsoft.EntityFrameworkCore": "Warning", + "Microsoft.AspNetCore": "Warning" + } }, "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "WriteTo": [ From 60a14e5587861528ce78da0704f8fd989f9b70e7 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 18:12:37 +0300 Subject: [PATCH 09/30] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80?= =?UTF-8?q?=D1=8B=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20Scalar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Platform.API/Program.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Platform.API/Program.cs b/src/Platform.API/Program.cs index d122b3a..f128103 100644 --- a/src/Platform.API/Program.cs +++ b/src/Platform.API/Program.cs @@ -92,7 +92,9 @@ public static void Main(string[] args) options.Title = app.Environment.IsDevelopment() ? "StudHub API [DEV]" : "StudHub API"; options.Servers = new List { - new ScalarServer("https://dev-api.setka-rtu.ru") + new ScalarServer(app.Environment.IsDevelopment() + ? "https://dev-api.setka-rtu.ru" + : "https://api.setka-rtu.ru") }; if (app.Environment.IsDevelopment()) { From 6ec2c0cf37945e3ab5ec7f1369c1a0664eddb254 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 18:37:44 +0300 Subject: [PATCH 10/30] =?UTF-8?q?[SN-48]=20=D0=9D=D0=B5=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Platform.API/Extensions/ResponseCookiesExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Platform.API/Extensions/ResponseCookiesExtensions.cs b/src/Platform.API/Extensions/ResponseCookiesExtensions.cs index 03c9a12..ae0e229 100644 --- a/src/Platform.API/Extensions/ResponseCookiesExtensions.cs +++ b/src/Platform.API/Extensions/ResponseCookiesExtensions.cs @@ -18,13 +18,13 @@ public static void UpdateTokenCookies(this IResponseCookies cookies, TokenModel }; cookies.Append("AccessToken", tokens.AccessToken, cookieOptions); cookies.Append("RefreshToken", tokens.RefreshToken, cookieOptions); - _logger.Verbose("Обновлены Cookie файлы Access и Refresh токенов"); + _logger.Debug("Обновлены Cookie файлы Access и Refresh токенов"); } public static void DeleteTokenCookies(this IResponseCookies cookies) { cookies.Delete("AccessToken"); cookies.Delete("RefreshToken"); - _logger.Verbose("Удалены Cookie файлы Access и Refresh токенов"); + _logger.Debug("Удалены Cookie файлы Access и Refresh токенов"); } } \ No newline at end of file From 02d21fd0151b8491f29c40d79dc8d9eee4665eb2 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 18:53:39 +0300 Subject: [PATCH 11/30] =?UTF-8?q?[SN-48]=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=BB=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BB=D0=BE=D0=B3=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20Platform.API?= =?UTF-8?q?=20=D0=B8=20Admin.API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/appsettings.Development.json | 2 +- src/Admin.API/appsettings.json | 2 +- src/Platform.API/appsettings.Development.json | 2 +- src/Platform.API/appsettings.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Admin.API/appsettings.Development.json b/src/Admin.API/appsettings.Development.json index e04fcfb..8fc50b9 100644 --- a/src/Admin.API/appsettings.Development.json +++ b/src/Admin.API/appsettings.Development.json @@ -13,7 +13,7 @@ { "Name": "File", "Args": { - "path": "Logs/Development/DevLog-.txt", + "path": "/Logs/Admin.API/Development/DevLog-.txt", "rollingInterval": "Day" } } diff --git a/src/Admin.API/appsettings.json b/src/Admin.API/appsettings.json index b935137..e388758 100644 --- a/src/Admin.API/appsettings.json +++ b/src/Admin.API/appsettings.json @@ -13,7 +13,7 @@ { "Name": "File", "Args": { - "path": "Logs/Log-.txt", + "path": "/Logs/Admin.API/Production/Log-.txt", "rollingInterval": "Day" } } diff --git a/src/Platform.API/appsettings.Development.json b/src/Platform.API/appsettings.Development.json index e04fcfb..9f81c7e 100644 --- a/src/Platform.API/appsettings.Development.json +++ b/src/Platform.API/appsettings.Development.json @@ -13,7 +13,7 @@ { "Name": "File", "Args": { - "path": "Logs/Development/DevLog-.txt", + "path": "/Logs/Platform.API/Development/DevLog-.txt", "rollingInterval": "Day" } } diff --git a/src/Platform.API/appsettings.json b/src/Platform.API/appsettings.json index 6aca759..9648d0a 100644 --- a/src/Platform.API/appsettings.json +++ b/src/Platform.API/appsettings.json @@ -13,7 +13,7 @@ { "Name": "File", "Args": { - "path": "Logs/Log-.txt", + "path": "/Logs/Platform.API/Production/Log-.txt", "rollingInterval": "Day" } } From ce32051f755841a9c7c068e48ebe3262bf42ab18 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 19:01:07 +0300 Subject: [PATCH 12/30] =?UTF-8?q?[SN-48]=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BB=D0=B8=D1=88=D0=BD=D1=8F=D1=8F=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82?= =?UTF-8?q?=D0=B0=20Scalar.AspNetCore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Platform.API/Platform.API.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Platform.API/Platform.API.csproj b/src/Platform.API/Platform.API.csproj index 383b8a2..89d0fc0 100644 --- a/src/Platform.API/Platform.API.csproj +++ b/src/Platform.API/Platform.API.csproj @@ -10,7 +10,6 @@ - From 56a75c35ee1e5da0fa4fba22ac01926097578f71 Mon Sep 17 00:00:00 2001 From: c23p1 <162514537+c23p1@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:02:11 +0300 Subject: [PATCH 13/30] =?UTF-8?q?[SN-48]=20=D0=9D=D0=B5=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D0=BE=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/Application/Services/ClubCreationRequestsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/Services/ClubCreationRequestsService.cs b/src/Application/Services/ClubCreationRequestsService.cs index edbd928..8306210 100644 --- a/src/Application/Services/ClubCreationRequestsService.cs +++ b/src/Application/Services/ClubCreationRequestsService.cs @@ -62,6 +62,6 @@ public async Task DeclineRequest(int requestId) throw new InvalidOperationException("Заявка на создание клуба уже была рассмотрена"); clubCreationRequest.IsActive = false; await _clubCreationRequestsRepository.UpdateAsync(clubCreationRequest); - _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена)", requestId); + _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена", requestId); } } \ No newline at end of file From 1e2db351ca87e8badef0621099a723876341f366 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 19:18:30 +0300 Subject: [PATCH 14/30] =?UTF-8?q?[SN-48]=20=D0=9D=D0=B5=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/Services/ClubAdminsService.cs | 2 +- src/Application/Services/ClubCreationRequestsService.cs | 4 ++-- src/Application/Services/ClubsService.cs | 2 +- src/Application/Services/PersonsService.cs | 2 +- src/Application/Services/PostsService.cs | 2 +- src/Infrastructure/Identity/Services/AuthService.cs | 2 +- src/Infrastructure/Services/ImagesService.cs | 2 +- src/Infrastructure/Services/SessionService.cs | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Application/Services/ClubAdminsService.cs b/src/Application/Services/ClubAdminsService.cs index 42856dd..2b19cfb 100644 --- a/src/Application/Services/ClubAdminsService.cs +++ b/src/Application/Services/ClubAdminsService.cs @@ -1,4 +1,4 @@ -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Club; using Domain.Entities.Person; using Application.Exceptions; diff --git a/src/Application/Services/ClubCreationRequestsService.cs b/src/Application/Services/ClubCreationRequestsService.cs index 8306210..191d5b7 100644 --- a/src/Application/Services/ClubCreationRequestsService.cs +++ b/src/Application/Services/ClubCreationRequestsService.cs @@ -1,5 +1,5 @@ using AutoMapper; -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Admin; using Domain.Entities.Club; using Application.DTO; @@ -62,6 +62,6 @@ public async Task DeclineRequest(int requestId) throw new InvalidOperationException("Заявка на создание клуба уже была рассмотрена"); clubCreationRequest.IsActive = false; await _clubCreationRequestsRepository.UpdateAsync(clubCreationRequest); - _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена", requestId); + _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена)", requestId); } } \ No newline at end of file diff --git a/src/Application/Services/ClubsService.cs b/src/Application/Services/ClubsService.cs index 0ff55e1..36731a0 100644 --- a/src/Application/Services/ClubsService.cs +++ b/src/Application/Services/ClubsService.cs @@ -1,5 +1,5 @@ using AutoMapper; -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Club; using Application.DTO; using Application.Exceptions; diff --git a/src/Application/Services/PersonsService.cs b/src/Application/Services/PersonsService.cs index 8123740..be6f578 100644 --- a/src/Application/Services/PersonsService.cs +++ b/src/Application/Services/PersonsService.cs @@ -1,5 +1,5 @@ using AutoMapper; -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Person; using Application.DTO; using Application.Exceptions; diff --git a/src/Application/Services/PostsService.cs b/src/Application/Services/PostsService.cs index ed9f053..e60addb 100644 --- a/src/Application/Services/PostsService.cs +++ b/src/Application/Services/PostsService.cs @@ -1,5 +1,5 @@ using AutoMapper; -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Post; using Application.DTO; using Application.Exceptions; diff --git a/src/Infrastructure/Identity/Services/AuthService.cs b/src/Infrastructure/Identity/Services/AuthService.cs index 524f0d2..da73895 100644 --- a/src/Infrastructure/Identity/Services/AuthService.cs +++ b/src/Infrastructure/Identity/Services/AuthService.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities.Person; using Application.DTO; using Application.Interfaces.Repositories.Person; diff --git a/src/Infrastructure/Services/ImagesService.cs b/src/Infrastructure/Services/ImagesService.cs index 8372a17..747e39a 100644 --- a/src/Infrastructure/Services/ImagesService.cs +++ b/src/Infrastructure/Services/ImagesService.cs @@ -1,4 +1,4 @@ -using ILogger = Serilog.ILogger; +using Serilog; using Domain.Entities; using Application.Exceptions; using Application.Interfaces.Repositories; diff --git a/src/Infrastructure/Services/SessionService.cs b/src/Infrastructure/Services/SessionService.cs index f9d2d30..6b61264 100644 --- a/src/Infrastructure/Services/SessionService.cs +++ b/src/Infrastructure/Services/SessionService.cs @@ -1,6 +1,6 @@ using System.Security.Authentication; using System.Security.Claims; -using ILogger = Serilog.ILogger; +using Serilog; using Application.Interfaces.Services; namespace Infrastructure.Services; From fbadf7cd8891495d0d96261258fa7db0766626bd Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 20:51:37 +0300 Subject: [PATCH 15/30] =?UTF-8?q?[SN-48]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20Admin.API=20-=20?= =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=91=D0=BD=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=20Program.cs=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B0=20Admin.API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Program.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Admin.API/Program.cs b/src/Admin.API/Program.cs index fa7fd8b..b1c4b32 100644 --- a/src/Admin.API/Program.cs +++ b/src/Admin.API/Program.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; +using Serilog; +using Serilog.Filters; using Application.Interfaces.Services; using Infrastructure.Extensions; using Admin.API.Extensions; @@ -12,8 +14,18 @@ public class Program public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); + builder.Host.UseSerilog((context, configuration) => + { + configuration.ReadFrom.Configuration(context.Configuration); + // Временное решение, дублирование логов при использовании ExceptionHandlerMiddleware исправлено в .NET 10 + configuration.Filter.ByExcluding(Matching + .FromSource()); + }); builder.Services.AddEndpointsApiExplorer(); - builder.Services.AddOpenApiDocument(); + builder.Services.AddOpenApiDocument(options => + { + options.Title = builder.Environment.IsDevelopment() ? "StudHub Admin API [DEV]" : "StudHub Admin API"; + }); builder.Configuration.AddEnvironmentVariables(); builder.Services.AddStudHubServices(builder.Configuration.GetConnectionString("Default")!); builder.Services.AddAdminServices(); @@ -67,6 +79,7 @@ public static void Main(string[] args) }; }); var app = builder.Build(); + app.UseSerilogRequestLogging(); app.UseCors(); app.UseExceptionHandler(); app.UseOpenApi(options => @@ -75,7 +88,9 @@ public static void Main(string[] args) }); app.MapScalarApiReference(options => { - options.Title = "StudHub.Admin API"; + options.Title = app.Environment.IsDevelopment() + ? "StudHub Admin API [DEV]" + : "StudHub Admin API"; options.Servers = new List { new ScalarServer("https://api.admin.setka-rtu.ru") From a5cf38a2227e45bbc7d470caafc3355ee3c23bf8 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 9 Sep 2025 20:59:15 +0300 Subject: [PATCH 16/30] =?UTF-8?q?[SN-48]=20=D0=92=D0=BD=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BD=D0=B5=D0=B7=D0=BD=D0=B0=D1=87=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D0=BE=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/Services/ClubCreationRequestsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/Services/ClubCreationRequestsService.cs b/src/Application/Services/ClubCreationRequestsService.cs index 191d5b7..b3f7913 100644 --- a/src/Application/Services/ClubCreationRequestsService.cs +++ b/src/Application/Services/ClubCreationRequestsService.cs @@ -62,6 +62,6 @@ public async Task DeclineRequest(int requestId) throw new InvalidOperationException("Заявка на создание клуба уже была рассмотрена"); clubCreationRequest.IsActive = false; await _clubCreationRequestsRepository.UpdateAsync(clubCreationRequest); - _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена)", requestId); + _logger.Information("Заявка на создание клуба с Id ({RequestId}) отклонена", requestId); } } \ No newline at end of file From 795a5c467c6a6967c1c0a11d43b2ffe4247e3983 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Sat, 13 Sep 2025 19:46:04 +0300 Subject: [PATCH 17/30] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=B0=D0=B4=D1=80=D0=B5=D1=81=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0=20=D0=BF=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Admin.API/Program.cs b/src/Admin.API/Program.cs index b1c4b32..b2ca618 100644 --- a/src/Admin.API/Program.cs +++ b/src/Admin.API/Program.cs @@ -93,7 +93,7 @@ public static void Main(string[] args) : "StudHub Admin API"; options.Servers = new List { - new ScalarServer("https://api.admin.setka-rtu.ru") + new ScalarServer("https://api-admin.setka-rtu.ru") }; if (app.Environment.IsDevelopment()) { From 1457f35a009e55defcc4381cf33ebb92fe411f0f Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Sun, 21 Sep 2025 21:20:38 +0300 Subject: [PATCH 18/30] =?UTF-8?q?[SN-142]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC?= =?UTF-8?q?=D0=B0=20=D0=B6=D0=B0=D0=BB=D0=BE=D0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Controllers/ReportController.cs | 42 ++++++++++ src/Application/DTO/ReportDTO.cs | 14 ++++ .../Queries/IReportsQueryService.cs | 9 +++ .../Admin/IReportCategoriesRepository.cs | 10 +++ .../Admin/IReportEntitiesRepository.cs | 8 ++ .../Repositories/Admin/IReportsRepository.cs | 10 +++ .../Interfaces/Services/IReportsService.cs | 8 ++ src/Application/Services/ReportsService.cs | 80 +++++++++++++++++++ src/Domain/Entities/Admin/Report.cs | 13 +++ src/Domain/Entities/Admin/ReportCategory.cs | 8 ++ src/Domain/Entities/Admin/ReportEntity.cs | 7 ++ .../Extensions/ServiceCollectionExtensions.cs | 2 + .../Persistence/Data/ApplicationDbContext.cs | 3 + .../Admin/ReportCategoriesRepository.cs | 36 +++++++++ .../Admin/ReportEntitiesRepository.cs | 20 +++++ .../Repositories/Admin/ReportsRepository.cs | 32 ++++++++ .../Services/Queries/ReportsQueryService.cs | 27 +++++++ 17 files changed, 329 insertions(+) create mode 100644 src/Admin.API/Controllers/ReportController.cs create mode 100644 src/Application/DTO/ReportDTO.cs create mode 100644 src/Application/Interfaces/Queries/IReportsQueryService.cs create mode 100644 src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs create mode 100644 src/Application/Interfaces/Repositories/Admin/IReportEntitiesRepository.cs create mode 100644 src/Application/Interfaces/Repositories/Admin/IReportsRepository.cs create mode 100644 src/Application/Interfaces/Services/IReportsService.cs create mode 100644 src/Application/Services/ReportsService.cs create mode 100644 src/Domain/Entities/Admin/Report.cs create mode 100644 src/Domain/Entities/Admin/ReportCategory.cs create mode 100644 src/Domain/Entities/Admin/ReportEntity.cs create mode 100644 src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs create mode 100644 src/Infrastructure/Persistence/Repositories/Admin/ReportEntitiesRepository.cs create mode 100644 src/Infrastructure/Persistence/Repositories/Admin/ReportsRepository.cs create mode 100644 src/Infrastructure/Services/Queries/ReportsQueryService.cs diff --git a/src/Admin.API/Controllers/ReportController.cs b/src/Admin.API/Controllers/ReportController.cs new file mode 100644 index 0000000..bfdad55 --- /dev/null +++ b/src/Admin.API/Controllers/ReportController.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Application.DTO; +using Application.Interfaces.Queries; +using Application.Interfaces.Services; +using Domain.Entities.Admin; + +namespace Admin.API.Controllers; + +[Authorize] +[ApiController] +[Route("reports")] +public class ReportController : ControllerBase +{ + private readonly IReportsService _reportsService; + private readonly IReportsQueryService _reportsQueryService; + + public ReportController(IReportsService reportsService, IReportsQueryService reportsQueryService) + { + _reportsService = reportsService; + _reportsQueryService = reportsQueryService; + } + + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task Create(ReportDTO reportDTO) + { + await _reportsService.CreateReport(reportDTO); + return new StatusCodeResult(StatusCodes.Status201Created); + } + + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task>> GetReports() => Ok(await _reportsQueryService.GetAllAsync()); + + [HttpGet("{id:int}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> GetReport(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); +} \ No newline at end of file diff --git a/src/Application/DTO/ReportDTO.cs b/src/Application/DTO/ReportDTO.cs new file mode 100644 index 0000000..28a0112 --- /dev/null +++ b/src/Application/DTO/ReportDTO.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Application.DTO; + +public record ReportDTO +{ + [Required] + public int TargetId { get; init; } + [Required] + public int TargetEntityId { get; init; } + [Required] + public int CategoryId { get; init; } + public string? Description { get; init; } +} \ No newline at end of file diff --git a/src/Application/Interfaces/Queries/IReportsQueryService.cs b/src/Application/Interfaces/Queries/IReportsQueryService.cs new file mode 100644 index 0000000..5bb53cd --- /dev/null +++ b/src/Application/Interfaces/Queries/IReportsQueryService.cs @@ -0,0 +1,9 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Queries; + +public interface IReportsQueryService +{ + public Task> GetAllAsync(); + public Task GetByIdAsync(int id); +} \ No newline at end of file diff --git a/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs b/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs new file mode 100644 index 0000000..7d6a1c6 --- /dev/null +++ b/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs @@ -0,0 +1,10 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Repositories.Admin; + +public interface IReportCategoriesRepository : IRepository +{ + public Task GetByIdAsync(int id); + public Task CreateAsync(ReportCategory reportCategory); + public Task DeleteByIdAsync(int id); +} \ No newline at end of file diff --git a/src/Application/Interfaces/Repositories/Admin/IReportEntitiesRepository.cs b/src/Application/Interfaces/Repositories/Admin/IReportEntitiesRepository.cs new file mode 100644 index 0000000..70bbc5d --- /dev/null +++ b/src/Application/Interfaces/Repositories/Admin/IReportEntitiesRepository.cs @@ -0,0 +1,8 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Repositories.Admin; + +public interface IReportEntitiesRepository : IRepository +{ + public Task GetByIdAsync(int id); +} \ No newline at end of file diff --git a/src/Application/Interfaces/Repositories/Admin/IReportsRepository.cs b/src/Application/Interfaces/Repositories/Admin/IReportsRepository.cs new file mode 100644 index 0000000..16e3940 --- /dev/null +++ b/src/Application/Interfaces/Repositories/Admin/IReportsRepository.cs @@ -0,0 +1,10 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Repositories.Admin; + +public interface IReportsRepository : IRepository +{ + public Task GetByIdAsync(int id); + public Task CreateAsync(Report report); + public Task UpdateAsync(Report report); +} \ No newline at end of file diff --git a/src/Application/Interfaces/Services/IReportsService.cs b/src/Application/Interfaces/Services/IReportsService.cs new file mode 100644 index 0000000..bc86fa2 --- /dev/null +++ b/src/Application/Interfaces/Services/IReportsService.cs @@ -0,0 +1,8 @@ +using Application.DTO; + +namespace Application.Interfaces.Services; + +public interface IReportsService +{ + public Task CreateReport(ReportDTO report); +} \ No newline at end of file diff --git a/src/Application/Services/ReportsService.cs b/src/Application/Services/ReportsService.cs new file mode 100644 index 0000000..2411a56 --- /dev/null +++ b/src/Application/Services/ReportsService.cs @@ -0,0 +1,80 @@ +using Domain.Entities.Admin; +using Domain.Entities.Club; +using Domain.Entities.Person; +using Domain.Entities.Post; +using Application.DTO; +using Application.Exceptions; +using Application.Interfaces.Repositories.Admin; +using Application.Interfaces.Repositories.Club; +using Application.Interfaces.Repositories.Person; +using Application.Interfaces.Repositories.Post; +using Application.Interfaces.Services; + +namespace Application.Services; + +public class ReportsService : IReportsService +{ + private readonly IReportsRepository _reportsRepository; + private readonly IReportCategoriesRepository _reportCategoriesRepository; + private readonly IReportEntitiesRepository _reportEntitiesRepository; + private readonly IPersonsRepository _personsRepository; + private readonly IPostsRepository _postsRepository; + private readonly IClubsRepository _clubsRepository; + private readonly ISessionService _sessionService; + + public ReportsService(IReportsRepository reportsRepository, IReportCategoriesRepository reportCategoriesRepository, + IReportEntitiesRepository reportEntitiesRepository, IPersonsRepository personsRepository, + IPostsRepository postsRepository, IClubsRepository clubsRepository, ISessionService sessionService) + { + _reportsRepository = reportsRepository; + _reportCategoriesRepository = reportCategoriesRepository; + _reportEntitiesRepository = reportEntitiesRepository; + _personsRepository = personsRepository; + _postsRepository = postsRepository; + _clubsRepository = clubsRepository; + _sessionService = sessionService; + } + + public async Task CreateReport(ReportDTO reportDTO) + { + if (await _reportEntitiesRepository.GetByIdAsync(reportDTO.TargetEntityId) is null) + throw new NotFoundException(nameof(ReportEntity), reportDTO.TargetEntityId); + + var reportCategory = await _reportCategoriesRepository.GetByIdAsync(reportDTO.CategoryId); + if (reportCategory is null) + throw new NotFoundException(nameof(ReportCategory), reportDTO.CategoryId); + if (reportCategory.ReportEntityId != reportDTO.TargetEntityId) + throw new ArgumentException("Некорректная категория"); + + var report = new Report + { + ReporterId = _sessionService.PersonId, + CategoryId = reportDTO.CategoryId, + Description = reportDTO.Description, + IsActive = true + }; + + switch (reportDTO.TargetEntityId) + { + case 1: + if (await _personsRepository.GetByIdAsync(reportDTO.TargetId) is null) + throw new NotFoundException(nameof(PersonModel), reportDTO.TargetId); + report.TargetPersonId = reportDTO.TargetId; + break; + case 2: + if (await _clubsRepository.GetByIdAsync(reportDTO.TargetId) is null) + throw new NotFoundException(nameof(ClubModel), reportDTO.TargetId); + report.TargetClubId = reportDTO.TargetId; + break; + case 3: + if (await _postsRepository.GetByIdAsync(reportDTO.TargetId) is null) + throw new NotFoundException(nameof(PostModel), reportDTO.TargetId); + report.TargetPostId = reportDTO.TargetId; + break; + default: + throw new ArgumentException("Некорректная сущность для репорта"); + } + + await _reportsRepository.CreateAsync(report); + } +} \ No newline at end of file diff --git a/src/Domain/Entities/Admin/Report.cs b/src/Domain/Entities/Admin/Report.cs new file mode 100644 index 0000000..a05c01d --- /dev/null +++ b/src/Domain/Entities/Admin/Report.cs @@ -0,0 +1,13 @@ +namespace Domain.Entities.Admin; + +public class Report +{ + public int Id { get; set; } + public int ReporterId { get; set; } + public int? TargetPersonId { get; set; } + public int? TargetClubId { get; set; } + public int? TargetPostId { get; set; } + public int CategoryId { get; set; } + public string? Description { get; set; } + public bool IsActive { get; set; } +} \ No newline at end of file diff --git a/src/Domain/Entities/Admin/ReportCategory.cs b/src/Domain/Entities/Admin/ReportCategory.cs new file mode 100644 index 0000000..a4c69fd --- /dev/null +++ b/src/Domain/Entities/Admin/ReportCategory.cs @@ -0,0 +1,8 @@ +namespace Domain.Entities.Admin; + +public class ReportCategory +{ + public int Id { get; set; } + public int ReportEntityId { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/Domain/Entities/Admin/ReportEntity.cs b/src/Domain/Entities/Admin/ReportEntity.cs new file mode 100644 index 0000000..5ad11e3 --- /dev/null +++ b/src/Domain/Entities/Admin/ReportEntity.cs @@ -0,0 +1,7 @@ +namespace Domain.Entities.Admin; + +public class ReportEntity +{ + public int Id { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs b/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs index 6cd4205..87cf9a0 100644 --- a/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs +++ b/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs @@ -51,6 +51,8 @@ public static IServiceCollection AddAdminServices(this IServiceCollection servic _logger.Debug("Начата регистрация сервисов панели администрирования"); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); _logger.Debug("Завершена регистрация сервисов панели администрирования"); return services; } diff --git a/src/Infrastructure/Persistence/Data/ApplicationDbContext.cs b/src/Infrastructure/Persistence/Data/ApplicationDbContext.cs index ca317a2..4ead819 100644 --- a/src/Infrastructure/Persistence/Data/ApplicationDbContext.cs +++ b/src/Infrastructure/Persistence/Data/ApplicationDbContext.cs @@ -35,6 +35,9 @@ public class ApplicationDbContext : DbContext public DbSet v_PostDetails { get; set; } public DbSet v_CommentDetails { get; set; } public DbSet v_ClubCreationRequestDetails { get; set; } + public DbSet t_ReportEntities { get; set; } + public DbSet t_ReportCategories { get; set; } + public DbSet t_Reports { get; set; } public ApplicationDbContext(DbContextOptions options) : base(options) { diff --git a/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs b/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs new file mode 100644 index 0000000..0e79850 --- /dev/null +++ b/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using Domain.Entities.Admin; +using Application.Interfaces.Repositories.Admin; +using Application.Exceptions; +using Infrastructure.Persistence.Data; + +namespace Infrastructure.Persistence.Repositories.Admin; + +public class ReportCategoriesRepository : IReportCategoriesRepository +{ + private readonly ApplicationDbContext _applicationDbContext; + private readonly DbSet _reportCategories; + + public ReportCategoriesRepository(ApplicationDbContext applicationDbContext) + { + _applicationDbContext = applicationDbContext; + _reportCategories = _applicationDbContext.Set(); + } + + public async Task GetByIdAsync(int id) => await _reportCategories.FindAsync(id); + + public async Task CreateAsync(ReportCategory reportCategory) + { + _reportCategories.Add(reportCategory); + await _applicationDbContext.SaveChangesAsync(); + } + + public async Task DeleteByIdAsync(int id) + { + var reportCategory = await GetByIdAsync(id); + if (reportCategory is null) + throw new NotFoundException(nameof(ReportCategory), id); + _reportCategories.Remove(reportCategory); + await _applicationDbContext.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/src/Infrastructure/Persistence/Repositories/Admin/ReportEntitiesRepository.cs b/src/Infrastructure/Persistence/Repositories/Admin/ReportEntitiesRepository.cs new file mode 100644 index 0000000..51b4f31 --- /dev/null +++ b/src/Infrastructure/Persistence/Repositories/Admin/ReportEntitiesRepository.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using Domain.Entities.Admin; +using Application.Interfaces.Repositories.Admin; +using Infrastructure.Persistence.Data; + +namespace Infrastructure.Persistence.Repositories.Admin; + +public class ReportEntitiesRepository : IReportEntitiesRepository +{ + private readonly DbSet _reportEntities; + private readonly ApplicationDbContext _applicationDbContext; + + public ReportEntitiesRepository(ApplicationDbContext applicationDbContext) + { + _applicationDbContext = applicationDbContext; + _reportEntities = _applicationDbContext.Set(); + } + + public async Task GetByIdAsync(int id) => await _reportEntities.FindAsync(id); +} \ No newline at end of file diff --git a/src/Infrastructure/Persistence/Repositories/Admin/ReportsRepository.cs b/src/Infrastructure/Persistence/Repositories/Admin/ReportsRepository.cs new file mode 100644 index 0000000..9fb4880 --- /dev/null +++ b/src/Infrastructure/Persistence/Repositories/Admin/ReportsRepository.cs @@ -0,0 +1,32 @@ +using Application.Interfaces.Repositories.Admin; +using Domain.Entities.Admin; +using Infrastructure.Persistence.Data; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Persistence.Repositories.Admin; + +public class ReportsRepository : IReportsRepository +{ + private readonly ApplicationDbContext _applicationDbContext; + private readonly DbSet _reports; + + public ReportsRepository(ApplicationDbContext applicationDbContext) + { + _applicationDbContext = applicationDbContext; + _reports = _applicationDbContext.Set(); + } + + public async Task GetByIdAsync(int id) => await _reports.FindAsync(id); + + public async Task CreateAsync(Report report) + { + _reports.Add(report); + await _applicationDbContext.SaveChangesAsync(); + } + + public async Task UpdateAsync(Report report) + { + _reports.Update(report); + await _applicationDbContext.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/src/Infrastructure/Services/Queries/ReportsQueryService.cs b/src/Infrastructure/Services/Queries/ReportsQueryService.cs new file mode 100644 index 0000000..519f40c --- /dev/null +++ b/src/Infrastructure/Services/Queries/ReportsQueryService.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Domain.Entities.Admin; +using Application.Exceptions; +using Application.Interfaces.Queries; +using Infrastructure.Persistence.Data; + +namespace Infrastructure.Services.Queries; + +public class ReportsQueryService : IReportsQueryService +{ + private readonly DbSet _reports; + + public ReportsQueryService(ApplicationDbContext context) + { + _reports = context.t_Reports; + } + + public async Task> GetAllAsync() => await _reports.ToListAsync(); + + public async Task GetByIdAsync(int id) + { + var report = await _reports.FindAsync(id); + if (report is null) + throw new NotFoundException(nameof(Report), id); + return report; + } +} \ No newline at end of file From d7043cb693613646967afd57fde387493d3e66b0 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 23 Sep 2025 22:26:44 +0300 Subject: [PATCH 19/30] =?UTF-8?q?[SN-148]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=B7=D0=BA=D0=B8=20=D0=B8=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BF=D1=80=D0=B8=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=BF=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=20-=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=91=D0=BD?= =?UTF-8?q?=20PostDTO,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=20=D1=81=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20Id=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/DTO/PostDTO.cs | 4 +++- src/Application/Services/PostsService.cs | 12 ++++++++++- .../Controllers/PostsController.cs | 20 ++++++++++++++++--- src/Platform.API/Models/CreatePostRequest.cs | 17 ++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/Platform.API/Models/CreatePostRequest.cs diff --git a/src/Application/DTO/PostDTO.cs b/src/Application/DTO/PostDTO.cs index de0bf82..74f7392 100644 --- a/src/Application/DTO/PostDTO.cs +++ b/src/Application/DTO/PostDTO.cs @@ -12,7 +12,9 @@ public record PostDTO [MaxLength(500)] public required string Content { get; init; } [Required] - public int? ClubId { get; set; } + public int? ClubId { get; init; } + [MaxLength(5)] + public List PostImagesIds { get; init; } = new List(); } public record PostDetailDTO diff --git a/src/Application/Services/PostsService.cs b/src/Application/Services/PostsService.cs index e60addb..843cfe2 100644 --- a/src/Application/Services/PostsService.cs +++ b/src/Application/Services/PostsService.cs @@ -13,6 +13,7 @@ namespace Application.Services; public class PostsService : IPostsService { private readonly IPostsRepository _postsRepository; + private readonly IPostsImagesRepository _postsImagesRepository; private readonly IClubsQueryService _clubsQueryService; private readonly ISessionService _sessionService; private readonly IClubAdminsRepository _clubAdminsRepository; @@ -20,10 +21,11 @@ public class PostsService : IPostsService private readonly IMapper _mapper; private readonly ILogger _logger; - public PostsService(IPostsRepository postsRepository, IClubsQueryService clubsQueryService, IMapper mapper, + public PostsService(IPostsRepository postsRepository, IPostsImagesRepository postsImagesRepository, IClubsQueryService clubsQueryService, IMapper mapper, IClubAdminsRepository clubAdminsRepository, IClubsRepository clubsRepository, ISessionService sessionService, ILogger logger) { _postsRepository = postsRepository; + _postsImagesRepository = postsImagesRepository; _clubsQueryService = clubsQueryService; _clubAdminsRepository = clubAdminsRepository; _clubsRepository = clubsRepository; @@ -41,6 +43,14 @@ public async Task CreateAsync(PostDTO postDTO) throw new ApplicationAuthorizationException("Создавать посты могут только администраторы и владелец клуба"); var post = _mapper.Map(postDTO); await _postsRepository.CreateAsync(post); + foreach (var imageId in postDTO.PostImagesIds) + { + await _postsImagesRepository.CreateAsync(new PostsImages + { + PostId = post.Id, + ImageId = imageId + }); + } _logger.Information("Создан пост с Id ({PostId}) пользователем с Id ({PersonId})", post.Id, _sessionService.PersonId); return post.Id; } diff --git a/src/Platform.API/Controllers/PostsController.cs b/src/Platform.API/Controllers/PostsController.cs index 0721050..a982e61 100644 --- a/src/Platform.API/Controllers/PostsController.cs +++ b/src/Platform.API/Controllers/PostsController.cs @@ -3,6 +3,7 @@ using Application.DTO; using Application.Interfaces.Queries; using Application.Interfaces.Services; +using Platform.API.Models; namespace Platform.API.Controllers { @@ -12,11 +13,13 @@ public class PostsController : ControllerBase { private readonly IPostsQueryService _postsQueryService; private readonly IPostsService _postsService; + private readonly IImagesService _imagesService; - public PostsController(IPostsQueryService postsQueryService, IPostsService postsService) + public PostsController(IPostsQueryService postsQueryService, IPostsService postsService, IImagesService imagesService) { _postsQueryService = postsQueryService; _postsService = postsService; + _imagesService = imagesService; } [ProducesResponseType(StatusCodes.Status200OK)] @@ -45,9 +48,20 @@ public async Task> GetById(int id) [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [HttpPost] - public async Task> Create(PostDTO post) + public async Task> Create(CreatePostRequest request) { - var id = await _postsService.CreateAsync(post); + var postDTO = new PostDTO + { + Title = request.Title, + Content = request.Content, + ClubId = request.ClubId + }; + foreach (var image in request.PostImages) + { + var imageExtension = Path.GetExtension(image.FileName); + postDTO.PostImagesIds.Add(await _imagesService.CreateAsync(image.OpenReadStream(), imageExtension)); + } + var id = await _postsService.CreateAsync(postDTO); return CreatedAtAction(nameof(GetById), new { id }, await _postsQueryService.GetDetailByIdAsync(id)); } diff --git a/src/Platform.API/Models/CreatePostRequest.cs b/src/Platform.API/Models/CreatePostRequest.cs new file mode 100644 index 0000000..281a6f8 --- /dev/null +++ b/src/Platform.API/Models/CreatePostRequest.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Platform.API.Models; + +public record CreatePostRequest +{ + [Required] + [MaxLength(50)] + public required string Title { get; init; } + [Required] + [MaxLength(500)] + public required string Content { get; init; } + [Required] + public int? ClubId { get; init; } + [MaxLength(5)] + public List PostImages { get; init; } = new List(); +} \ No newline at end of file From 10ea7bfba331f803c7c19e9fd8d26eb012c0262f Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Wed, 24 Sep 2025 16:01:42 +0300 Subject: [PATCH 20/30] =?UTF-8?q?[SN-142]=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=B2=20?= =?UTF-8?q?ReportController,=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=20enum?= =?UTF-8?q?=20ReportTargetEntities,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D0=B0=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=B1=D1=83=D1=82=D1=8B=20Required,=20=D1=83=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20Del?= =?UTF-8?q?eteByIdAsync=20=D0=B8=D0=B7=20ReportCategoriesRepository,=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=BE=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=20=D1=83=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B6=D0=B0=D0=BB=D0=BE=D0=B1=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Controllers/ReportController.cs | 4 ++-- src/Application/DTO/ReportDTO.cs | 7 +------ src/Application/Enums/ReportTargetEntities.cs | 8 ++++++++ .../Repositories/Admin/IReportCategoriesRepository.cs | 1 - src/Application/Services/ReportsService.cs | 8 ++++---- .../Repositories/Admin/ReportCategoriesRepository.cs | 10 ---------- 6 files changed, 15 insertions(+), 23 deletions(-) create mode 100644 src/Application/Enums/ReportTargetEntities.cs diff --git a/src/Admin.API/Controllers/ReportController.cs b/src/Admin.API/Controllers/ReportController.cs index bfdad55..a46f474 100644 --- a/src/Admin.API/Controllers/ReportController.cs +++ b/src/Admin.API/Controllers/ReportController.cs @@ -33,10 +33,10 @@ public async Task Create(ReportDTO reportDTO) [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetReports() => Ok(await _reportsQueryService.GetAllAsync()); + public async Task>> GetAll() => Ok(await _reportsQueryService.GetAllAsync()); [HttpGet("{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetReport(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); + public async Task> GetById(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); } \ No newline at end of file diff --git a/src/Application/DTO/ReportDTO.cs b/src/Application/DTO/ReportDTO.cs index 28a0112..463e0ee 100644 --- a/src/Application/DTO/ReportDTO.cs +++ b/src/Application/DTO/ReportDTO.cs @@ -1,14 +1,9 @@ -using System.ComponentModel.DataAnnotations; - -namespace Application.DTO; +namespace Application.DTO; public record ReportDTO { - [Required] public int TargetId { get; init; } - [Required] public int TargetEntityId { get; init; } - [Required] public int CategoryId { get; init; } public string? Description { get; init; } } \ No newline at end of file diff --git a/src/Application/Enums/ReportTargetEntities.cs b/src/Application/Enums/ReportTargetEntities.cs new file mode 100644 index 0000000..082197a --- /dev/null +++ b/src/Application/Enums/ReportTargetEntities.cs @@ -0,0 +1,8 @@ +namespace Application; + +public enum ReportTargetEntities +{ + Person = 1, + Club = 2, + Post = 3 +} \ No newline at end of file diff --git a/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs b/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs index 7d6a1c6..ecc9d66 100644 --- a/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs +++ b/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs @@ -6,5 +6,4 @@ public interface IReportCategoriesRepository : IRepository { public Task GetByIdAsync(int id); public Task CreateAsync(ReportCategory reportCategory); - public Task DeleteByIdAsync(int id); } \ No newline at end of file diff --git a/src/Application/Services/ReportsService.cs b/src/Application/Services/ReportsService.cs index 2411a56..e72feb0 100644 --- a/src/Application/Services/ReportsService.cs +++ b/src/Application/Services/ReportsService.cs @@ -56,23 +56,23 @@ public async Task CreateReport(ReportDTO reportDTO) switch (reportDTO.TargetEntityId) { - case 1: + case (int) ReportTargetEntities.Person: if (await _personsRepository.GetByIdAsync(reportDTO.TargetId) is null) throw new NotFoundException(nameof(PersonModel), reportDTO.TargetId); report.TargetPersonId = reportDTO.TargetId; break; - case 2: + case (int) ReportTargetEntities.Club: if (await _clubsRepository.GetByIdAsync(reportDTO.TargetId) is null) throw new NotFoundException(nameof(ClubModel), reportDTO.TargetId); report.TargetClubId = reportDTO.TargetId; break; - case 3: + case (int) ReportTargetEntities.Post: if (await _postsRepository.GetByIdAsync(reportDTO.TargetId) is null) throw new NotFoundException(nameof(PostModel), reportDTO.TargetId); report.TargetPostId = reportDTO.TargetId; break; default: - throw new ArgumentException("Некорректная сущность для репорта"); + throw new ArgumentException("Указана некорректная сущность при создании жалобы"); } await _reportsRepository.CreateAsync(report); diff --git a/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs b/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs index 0e79850..0cb2b4f 100644 --- a/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs +++ b/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs @@ -1,7 +1,6 @@ using Microsoft.EntityFrameworkCore; using Domain.Entities.Admin; using Application.Interfaces.Repositories.Admin; -using Application.Exceptions; using Infrastructure.Persistence.Data; namespace Infrastructure.Persistence.Repositories.Admin; @@ -24,13 +23,4 @@ public async Task CreateAsync(ReportCategory reportCategory) _reportCategories.Add(reportCategory); await _applicationDbContext.SaveChangesAsync(); } - - public async Task DeleteByIdAsync(int id) - { - var reportCategory = await GetByIdAsync(id); - if (reportCategory is null) - throw new NotFoundException(nameof(ReportCategory), id); - _reportCategories.Remove(reportCategory); - await _applicationDbContext.SaveChangesAsync(); - } } \ No newline at end of file From 2e58dbb75c75adede4ce71451086597c5f4e9c6f Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Wed, 24 Sep 2025 17:22:24 +0300 Subject: [PATCH 21/30] =?UTF-8?q?[SN-142]=20=D0=92=D0=BD=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=B5=D0=B7=D0=BD=D0=B0=D1=87=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/DTO/ReportDTO.cs | 13 +++++++---- src/Application/Services/ReportsService.cs | 26 +++++++++++----------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/Application/DTO/ReportDTO.cs b/src/Application/DTO/ReportDTO.cs index 463e0ee..65e3fdb 100644 --- a/src/Application/DTO/ReportDTO.cs +++ b/src/Application/DTO/ReportDTO.cs @@ -1,9 +1,14 @@ -namespace Application.DTO; +using System.ComponentModel.DataAnnotations; + +namespace Application.DTO; public record ReportDTO { - public int TargetId { get; init; } - public int TargetEntityId { get; init; } - public int CategoryId { get; init; } + [Required] + public int? TargetId { get; init; } + [Required] + public int? TargetEntityId { get; init; } + [Required] + public int? CategoryId { get; init; } public string? Description { get; init; } } \ No newline at end of file diff --git a/src/Application/Services/ReportsService.cs b/src/Application/Services/ReportsService.cs index e72feb0..0b31490 100644 --- a/src/Application/Services/ReportsService.cs +++ b/src/Application/Services/ReportsService.cs @@ -37,38 +37,38 @@ public ReportsService(IReportsRepository reportsRepository, IReportCategoriesRep public async Task CreateReport(ReportDTO reportDTO) { - if (await _reportEntitiesRepository.GetByIdAsync(reportDTO.TargetEntityId) is null) - throw new NotFoundException(nameof(ReportEntity), reportDTO.TargetEntityId); + if (await _reportEntitiesRepository.GetByIdAsync(reportDTO.TargetEntityId!.Value) is null) + throw new NotFoundException(nameof(ReportEntity), reportDTO.TargetEntityId.Value); - var reportCategory = await _reportCategoriesRepository.GetByIdAsync(reportDTO.CategoryId); + var reportCategory = await _reportCategoriesRepository.GetByIdAsync(reportDTO.CategoryId!.Value); if (reportCategory is null) - throw new NotFoundException(nameof(ReportCategory), reportDTO.CategoryId); - if (reportCategory.ReportEntityId != reportDTO.TargetEntityId) + throw new NotFoundException(nameof(ReportCategory), reportDTO.CategoryId.Value); + if (reportCategory.ReportEntityId != reportDTO.TargetEntityId.Value) throw new ArgumentException("Некорректная категория"); var report = new Report { ReporterId = _sessionService.PersonId, - CategoryId = reportDTO.CategoryId, + CategoryId = reportDTO.CategoryId!.Value, Description = reportDTO.Description, IsActive = true }; - switch (reportDTO.TargetEntityId) + switch (reportDTO.TargetEntityId.Value) { case (int) ReportTargetEntities.Person: - if (await _personsRepository.GetByIdAsync(reportDTO.TargetId) is null) - throw new NotFoundException(nameof(PersonModel), reportDTO.TargetId); + if (await _personsRepository.GetByIdAsync(reportDTO.TargetId!.Value) is null) + throw new NotFoundException(nameof(PersonModel), reportDTO.TargetId.Value); report.TargetPersonId = reportDTO.TargetId; break; case (int) ReportTargetEntities.Club: - if (await _clubsRepository.GetByIdAsync(reportDTO.TargetId) is null) - throw new NotFoundException(nameof(ClubModel), reportDTO.TargetId); + if (await _clubsRepository.GetByIdAsync(reportDTO.TargetId!.Value) is null) + throw new NotFoundException(nameof(ClubModel), reportDTO.TargetId.Value); report.TargetClubId = reportDTO.TargetId; break; case (int) ReportTargetEntities.Post: - if (await _postsRepository.GetByIdAsync(reportDTO.TargetId) is null) - throw new NotFoundException(nameof(PostModel), reportDTO.TargetId); + if (await _postsRepository.GetByIdAsync(reportDTO.TargetId!.Value) is null) + throw new NotFoundException(nameof(PostModel), reportDTO.TargetId.Value); report.TargetPostId = reportDTO.TargetId; break; default: From 896db6e2af7d752bd3b6286e9b5a9fd4a33ca1ee Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Wed, 24 Sep 2025 17:52:30 +0300 Subject: [PATCH 22/30] =?UTF-8?q?[SN-149]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=83=D1=82=D1=8C=20=D0=BA=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC=20=D0=B4=D0=BB=D1=8F=20=D0=B7=D0=B0=D1=8F=D0=B2=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=BD=D0=B0=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BA=D0=BB=D1=83=D0=B1=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application/DTO/ClubCreationRequestDTO.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application/DTO/ClubCreationRequestDTO.cs b/src/Application/DTO/ClubCreationRequestDTO.cs index f94ba30..ab4c3e5 100644 --- a/src/Application/DTO/ClubCreationRequestDTO.cs +++ b/src/Application/DTO/ClubCreationRequestDTO.cs @@ -27,8 +27,8 @@ public record ClubCreationRequestDetailsDTO public string ClubName { get; init; } public string? ClubAbout { get; init; } [Required] - public int ImageId { get; init; } - public int? BannerId { get; init; } + public string ImagePath { get; init; } + public string? BannerPath { get; init; } [Required] public bool IsActive { get; init; } [Required] From 65cd336a8fdc85bcf73ff7f131773fdfd61f4a86 Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Wed, 24 Sep 2025 21:14:25 +0300 Subject: [PATCH 23/30] =?UTF-8?q?[SN-142]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B6=D0=B0=D0=BB=D0=BE=D0=B1=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Controllers/ReportController.cs | 6 ++++++ .../Interfaces/Queries/IReportsQueryService.cs | 1 + .../Services/Queries/ReportsQueryService.cs | 16 +++++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Admin.API/Controllers/ReportController.cs b/src/Admin.API/Controllers/ReportController.cs index a46f474..d66867f 100644 --- a/src/Admin.API/Controllers/ReportController.cs +++ b/src/Admin.API/Controllers/ReportController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Application; using Application.DTO; using Application.Interfaces.Queries; using Application.Interfaces.Services; @@ -39,4 +40,9 @@ public async Task Create(ReportDTO reportDTO) [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetById(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); + + [HttpGet("getByEntityId")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status409Conflict)] + public async Task>> GetByEntityId(ReportTargetEntities entity) => Ok(await _reportsQueryService.GetByEntityIdAsync(entity)); } \ No newline at end of file diff --git a/src/Application/Interfaces/Queries/IReportsQueryService.cs b/src/Application/Interfaces/Queries/IReportsQueryService.cs index 5bb53cd..2c435ac 100644 --- a/src/Application/Interfaces/Queries/IReportsQueryService.cs +++ b/src/Application/Interfaces/Queries/IReportsQueryService.cs @@ -6,4 +6,5 @@ public interface IReportsQueryService { public Task> GetAllAsync(); public Task GetByIdAsync(int id); + public Task> GetByEntityIdAsync(ReportTargetEntities entity); } \ No newline at end of file diff --git a/src/Infrastructure/Services/Queries/ReportsQueryService.cs b/src/Infrastructure/Services/Queries/ReportsQueryService.cs index 519f40c..bfb9cde 100644 --- a/src/Infrastructure/Services/Queries/ReportsQueryService.cs +++ b/src/Infrastructure/Services/Queries/ReportsQueryService.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using Application; +using Microsoft.EntityFrameworkCore; using Domain.Entities.Admin; using Application.Exceptions; using Application.Interfaces.Queries; @@ -24,4 +25,17 @@ public async Task GetByIdAsync(int id) throw new NotFoundException(nameof(Report), id); return report; } + + public async Task> GetByEntityIdAsync(ReportTargetEntities entity) + { + switch (entity) + { + case ReportTargetEntities.Person: + return await _reports.Where(r => r.TargetPersonId != null).ToListAsync(); + case ReportTargetEntities.Club: + return await _reports.Where(r => r.TargetClubId != null).ToListAsync(); + default: + return await _reports.Where(r => r.TargetPostId != null).ToListAsync(); + } + } } \ No newline at end of file From 3120bdc33bfd23ca10a8f027a589c124cbef29e4 Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Thu, 25 Sep 2025 14:48:40 +0300 Subject: [PATCH 24/30] =?UTF-8?q?[SN-142]=20GetByEntityId=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=20=D0=BD=D0=B0=20GetByTargetEnti?= =?UTF-8?q?tyId,=20=D0=BD=D0=B5=D0=B7=D0=BD=D0=B0=D1=87=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/Controllers/ReportController.cs | 7 ++++--- .../Interfaces/Queries/IReportsQueryService.cs | 2 +- .../Services/Queries/ReportsQueryService.cs | 15 ++++++++++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Admin.API/Controllers/ReportController.cs b/src/Admin.API/Controllers/ReportController.cs index d66867f..e96d329 100644 --- a/src/Admin.API/Controllers/ReportController.cs +++ b/src/Admin.API/Controllers/ReportController.cs @@ -41,8 +41,9 @@ public async Task Create(ReportDTO reportDTO) [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetById(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); - [HttpGet("getByEntityId")] + [HttpGet("getByTargetEntityId")] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - public async Task>> GetByEntityId(ReportTargetEntities entity) => Ok(await _reportsQueryService.GetByEntityIdAsync(entity)); + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task>> GetByTargetEntityId(ReportTargetEntities entity) + => Ok(await _reportsQueryService.GetByTargetEntityIdAsync(entity)); } \ No newline at end of file diff --git a/src/Application/Interfaces/Queries/IReportsQueryService.cs b/src/Application/Interfaces/Queries/IReportsQueryService.cs index 2c435ac..4b416e2 100644 --- a/src/Application/Interfaces/Queries/IReportsQueryService.cs +++ b/src/Application/Interfaces/Queries/IReportsQueryService.cs @@ -6,5 +6,5 @@ public interface IReportsQueryService { public Task> GetAllAsync(); public Task GetByIdAsync(int id); - public Task> GetByEntityIdAsync(ReportTargetEntities entity); + public Task> GetByTargetEntityIdAsync(ReportTargetEntities entity); } \ No newline at end of file diff --git a/src/Infrastructure/Services/Queries/ReportsQueryService.cs b/src/Infrastructure/Services/Queries/ReportsQueryService.cs index bfb9cde..ab0c650 100644 --- a/src/Infrastructure/Services/Queries/ReportsQueryService.cs +++ b/src/Infrastructure/Services/Queries/ReportsQueryService.cs @@ -26,16 +26,21 @@ public async Task GetByIdAsync(int id) return report; } - public async Task> GetByEntityIdAsync(ReportTargetEntities entity) + public async Task> GetByTargetEntityIdAsync(ReportTargetEntities entity) { + ICollection reports = new List(); switch (entity) { case ReportTargetEntities.Person: - return await _reports.Where(r => r.TargetPersonId != null).ToListAsync(); + reports = await _reports.Where(r => r.TargetPersonId != null).ToListAsync(); + break; case ReportTargetEntities.Club: - return await _reports.Where(r => r.TargetClubId != null).ToListAsync(); - default: - return await _reports.Where(r => r.TargetPostId != null).ToListAsync(); + reports = await _reports.Where(r => r.TargetClubId != null).ToListAsync(); + break; + case ReportTargetEntities.Post: + reports = await _reports.Where(r => r.TargetPostId != null).ToListAsync(); + break; } + return reports; } } \ No newline at end of file From 1eabc315ca425f6c28c0a943d5c01c7724cb9f6f Mon Sep 17 00:00:00 2001 From: dotReboot Date: Fri, 17 Oct 2025 16:33:35 +0300 Subject: [PATCH 25/30] =?UTF-8?q?[SN-127]=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- StudHub.Server.sln | 6 ++++++ test/Unit/Unit.csproj | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/Unit/Unit.csproj diff --git a/StudHub.Server.sln b/StudHub.Server.sln index ec49472..f1e5bae 100644 --- a/StudHub.Server.sln +++ b/StudHub.Server.sln @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Platform.API", "src\Platfor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.API", "src\Admin.API\Admin.API.csproj", "{781F6E4E-FC3B-46E4-895A-F27A4310CF42}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit", "test\Unit\Unit.csproj", "{3558A138-C00A-4857-93E5-3ECCB5CD873C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,5 +38,9 @@ Global {781F6E4E-FC3B-46E4-895A-F27A4310CF42}.Debug|Any CPU.Build.0 = Debug|Any CPU {781F6E4E-FC3B-46E4-895A-F27A4310CF42}.Release|Any CPU.ActiveCfg = Release|Any CPU {781F6E4E-FC3B-46E4-895A-F27A4310CF42}.Release|Any CPU.Build.0 = Release|Any CPU + {3558A138-C00A-4857-93E5-3ECCB5CD873C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3558A138-C00A-4857-93E5-3ECCB5CD873C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3558A138-C00A-4857-93E5-3ECCB5CD873C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3558A138-C00A-4857-93E5-3ECCB5CD873C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/test/Unit/Unit.csproj b/test/Unit/Unit.csproj new file mode 100644 index 0000000..1047410 --- /dev/null +++ b/test/Unit/Unit.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + From af787ab1503e006bf2b6052dfed25967698169c4 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Sat, 18 Oct 2025 03:40:04 +0300 Subject: [PATCH 26/30] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=20Create=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=20ClubCreationRequestsService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Unit/ClubCreationRequestsServiceTests.cs | 163 ++++++++++++++++++ test/Unit/Unit.csproj | 4 + 2 files changed, 167 insertions(+) create mode 100644 test/Unit/ClubCreationRequestsServiceTests.cs diff --git a/test/Unit/ClubCreationRequestsServiceTests.cs b/test/Unit/ClubCreationRequestsServiceTests.cs new file mode 100644 index 0000000..ee93d1b --- /dev/null +++ b/test/Unit/ClubCreationRequestsServiceTests.cs @@ -0,0 +1,163 @@ +using System.ComponentModel.DataAnnotations; +using Application.DTO; + +namespace Unit; + +public class ClubCreationRequestsServiceTests +{ + #region CreateRequest + [Fact] + public void CreateRequest_WithValidData_Succeeds() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = "Новый клуб для тестирования функциональности", + PersonId = 0, + ImageId = 0, + BannerId = 0, + ClubAbout = "Описание клуба для создания" + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.True(isValid); + } + + [Fact] + public void CreateRequest_WithEmptyClubName_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + Comment = "Новый клуб для тестирования функциональности", + PersonId = 0, + ImageId = 0, + BannerId = 0, + ClubAbout = new string('0', 100) + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("ClubName") && r.ErrorMessage!.Contains("required")); + } + + [Fact] + public void CreateRequest_WithLongClubName_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = new string('0', 64), + Comment = "Новый клуб для тестирования функциональности", + PersonId = 0, + ImageId = 0, + BannerId = 0, + ClubAbout = new string('0', 100) + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("ClubName") && r.ErrorMessage!.Contains("maximum length")); + } + + [Fact] + public void CreateRequest_WithEmptyImageId_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = "Новый клуб для тестирования функциональности", + PersonId = 0 + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("ImageId") && r.ErrorMessage!.Contains("required")); + } + + [Fact] + public void CreateRequest_WithEmptyPersonId_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = "Новый клуб для тестирования функциональности", + ImageId = 0 + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("PersonId") && r.ErrorMessage!.Contains("required")); + } + + [Fact] + public void CreateRequest_WithLongClubAbout_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = "Новый клуб для тестирования функциональности", + PersonId = 0, + ImageId = 0, + BannerId = 0, + ClubAbout = new string('0', 256) + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("ClubAbout") && r.ErrorMessage!.Contains("maximum length")); + } + + [Fact] + public void CreateRequest_WithEmptyComment_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = "", + PersonId = 0 + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("Comment") && r.ErrorMessage!.Contains("required")); + } + + [Fact] + public void CreateRequest_WithLongComment_ValidationFails() + { + var clubCreationRequest = new ClubCreationRequestDTO + { + ClubName = "Новый клуб", + Comment = new string('0', 1001), + PersonId = 0 + }; + var context = new ValidationContext(clubCreationRequest); + var results = new List(); + + var isValid = Validator.TryValidateObject(clubCreationRequest, context, results, true); + + Assert.False(isValid); + Assert.Contains(results, r => r.MemberNames.Contains("Comment") && r.ErrorMessage!.Contains("maximum length")); + } + #endregion +} \ No newline at end of file diff --git a/test/Unit/Unit.csproj b/test/Unit/Unit.csproj index 1047410..e4ef3e5 100644 --- a/test/Unit/Unit.csproj +++ b/test/Unit/Unit.csproj @@ -18,4 +18,8 @@ + + + + From ca9c0ef41bc1d98b6d56a390668713a5f9354f7c Mon Sep 17 00:00:00 2001 From: c23p1 <162514537+c23p1@users.noreply.github.com> Date: Sat, 18 Oct 2025 04:21:34 +0300 Subject: [PATCH 27/30] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20=D0=B2=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a91ffed..68e56a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,3 +22,5 @@ jobs: run: dotnet restore - name: Build run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build From af5db2533a8a1439420b8adfb24da872e14f85b6 Mon Sep 17 00:00:00 2001 From: Vladimir Arkhipenkov Date: Sat, 18 Oct 2025 07:30:44 +0300 Subject: [PATCH 28/30] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=20AcceptRequest=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81=D0=B0=20ClubCreationRequestsService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Unit/ClubCreationRequestsServiceTests.cs | 94 +++++++++++++++++++ test/Unit/Unit.csproj | 1 + 2 files changed, 95 insertions(+) diff --git a/test/Unit/ClubCreationRequestsServiceTests.cs b/test/Unit/ClubCreationRequestsServiceTests.cs index ee93d1b..fc6e0ae 100644 --- a/test/Unit/ClubCreationRequestsServiceTests.cs +++ b/test/Unit/ClubCreationRequestsServiceTests.cs @@ -1,10 +1,33 @@ using System.ComponentModel.DataAnnotations; +using AutoMapper; +using Moq; +using Serilog; +using Domain.Entities.Admin; +using Domain.Entities.Club; using Application.DTO; +using Application.Exceptions; +using Application.Interfaces.Repositories.Admin; +using Application.Interfaces.Repositories.Club; +using Application.Services; namespace Unit; public class ClubCreationRequestsServiceTests { + private readonly Mock _requestsRepoMock; + private readonly Mock _clubsRepoMock; + private readonly Mock _loggerMock; + private readonly Mock _mapperMock; + private readonly ClubCreationRequestsService _clubCreationRequestsService; + public ClubCreationRequestsServiceTests() + { + _requestsRepoMock = new Mock(); + _clubsRepoMock = new Mock(); + _loggerMock = new Mock(); + _mapperMock = new Mock(); + _clubCreationRequestsService = new ClubCreationRequestsService(_requestsRepoMock.Object, _clubsRepoMock.Object, + _mapperMock.Object, _loggerMock.Object); + } #region CreateRequest [Fact] public void CreateRequest_WithValidData_Succeeds() @@ -159,5 +182,76 @@ public void CreateRequest_WithLongComment_ValidationFails() Assert.False(isValid); Assert.Contains(results, r => r.MemberNames.Contains("Comment") && r.ErrorMessage!.Contains("maximum length")); } + [Fact] + public async Task AcceptRequest_WhenRequestNotFound_ThrowsNotFoundException() + { + var requestId = 1; + _requestsRepoMock + .Setup(r => r.GetByIdAsync(requestId)) + .ReturnsAsync((ClubCreationRequest)null); + + await Assert.ThrowsAsync(() => _clubCreationRequestsService.AcceptRequest(requestId)); + } + + [Fact] + public async Task AcceptRequest_WhenRequestIsNotActive_ThrowsInvalidOperationException() + { + var requestId = 1; + var inactiveRequest = new ClubCreationRequest { IsActive = false }; + _requestsRepoMock + .Setup(r => r.GetByIdAsync(requestId)) + .ReturnsAsync(inactiveRequest); + + var exception = await Assert.ThrowsAsync( + () => _clubCreationRequestsService.AcceptRequest(requestId)); + Assert.Equal("Заявка на создание клуба уже была рассмотрена", exception.Message); + } + + [Fact] + public async Task AcceptRequest_WhenValidRequest_CreatesClubAndUpdatesRequest() + { + var requestId = 1; + var activeRequest = new ClubCreationRequest + { + Id = requestId, + ClubName = "Test Club", + ClubAbout = "About club", + ImageId = 1, + BannerId = 2, + PersonId = 3, + IsActive = true + }; + + _requestsRepoMock + .Setup(r => r.GetByIdAsync(requestId)) + .ReturnsAsync(activeRequest); + + ClubModel createdClub = null; + _clubsRepoMock + .Setup(r => r.CreateAsync(It.IsAny())) + .Callback(club => createdClub = club) + .Returns(Task.CompletedTask); + + _requestsRepoMock + .Setup(r => r.UpdateAsync(activeRequest)) + .Returns(Task.CompletedTask); + + await _clubCreationRequestsService.AcceptRequest(requestId); + + _clubsRepoMock.Verify(r => r.CreateAsync(It.IsAny()), Times.Once); + _requestsRepoMock.Verify(r => r.UpdateAsync(activeRequest), Times.Once); + + Assert.NotNull(createdClub); + Assert.Equal(activeRequest.ClubName, createdClub.Name); + Assert.Equal(activeRequest.ClubAbout, createdClub.About); + Assert.Equal(activeRequest.ImageId, createdClub.ImageId); + Assert.Equal(activeRequest.BannerId, createdClub.BannerId); + Assert.Equal(activeRequest.PersonId, createdClub.OwnerId); + Assert.False(activeRequest.IsActive); + + _loggerMock.Verify(l => l.Information( + "Заявка на создание клуба с Id ({RequestId}) одобрена", requestId), + Times.Once); + } #endregion } \ No newline at end of file diff --git a/test/Unit/Unit.csproj b/test/Unit/Unit.csproj index e4ef3e5..3285fca 100644 --- a/test/Unit/Unit.csproj +++ b/test/Unit/Unit.csproj @@ -11,6 +11,7 @@ + From 87dcdeeaf0449ae96141fcbbe78983147b8ad1ea Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 25 Nov 2025 13:24:44 +0300 Subject: [PATCH 29/30] =?UTF-8?q?=D0=92=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BD=D0=B5=D0=B7=D0=BD=D0=B0=D1=87=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Platform.API/appsettings.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Platform.API/appsettings.json b/src/Platform.API/appsettings.json index 9648d0a..876b1c3 100644 --- a/src/Platform.API/appsettings.json +++ b/src/Platform.API/appsettings.json @@ -20,9 +20,5 @@ ] }, "Domain": ".setka-rtu.ru", - "AllowedHosts": "*", - "JWTKey": "9>I4=o8{AG\\Nh{`I7m*={tP:Gs)dsXxNw.Hj92]dQSO", - "ConnectionStrings": { - "Default": "Host=31.128.38.159;Port=5432;User ID=admin-setka;Password=P1{Hg?:(~jLfDNrp!W9QkF?bO;Database=SetkaDB" - } + "AllowedHosts": "*" } \ No newline at end of file From a65c2b3c5296ab23a4d71cacd5573ac071f7a881 Mon Sep 17 00:00:00 2001 From: dotReboot Date: Tue, 25 Nov 2025 13:40:36 +0300 Subject: [PATCH 30/30] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BF=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Admin.API/appsettings.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Admin.API/appsettings.json b/src/Admin.API/appsettings.json index 3d9a13a..1d121cd 100644 --- a/src/Admin.API/appsettings.json +++ b/src/Admin.API/appsettings.json @@ -20,9 +20,5 @@ ] }, "Domain": "setka-rtu.ru", - "AllowedHosts": "*", - "JWTKey": "9>I4=o8{AG\\Nh{`I7m*={tP:Gs)dsXxNw.Hj92]dQSO", - "ConnectionStrings": { - "Default": "Host=31.128.38.159;Port=5432;User ID=admin-setka;Password=P1{Hg?:(~jLfDNrp!W9QkF?bO;Database=SetkaDB" - } + "AllowedHosts": "*" }