diff --git a/src/Admin.API/Controllers/ReportController.cs b/src/Admin.API/Controllers/ReportController.cs new file mode 100644 index 0000000..e96d329 --- /dev/null +++ b/src/Admin.API/Controllers/ReportController.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Application; +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>> GetAll() => Ok(await _reportsQueryService.GetAllAsync()); + + [HttpGet("{id:int}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> GetById(int id) => Ok(await _reportsQueryService.GetByIdAsync(id)); + + [HttpGet("getByTargetEntityId")] + [ProducesResponseType(StatusCodes.Status200OK)] + [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/DTO/ReportDTO.cs b/src/Application/DTO/ReportDTO.cs new file mode 100644 index 0000000..65e3fdb --- /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/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/Queries/IReportsQueryService.cs b/src/Application/Interfaces/Queries/IReportsQueryService.cs new file mode 100644 index 0000000..4b416e2 --- /dev/null +++ b/src/Application/Interfaces/Queries/IReportsQueryService.cs @@ -0,0 +1,10 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Queries; + +public interface IReportsQueryService +{ + public Task> GetAllAsync(); + public Task GetByIdAsync(int id); + public Task> GetByTargetEntityIdAsync(ReportTargetEntities entity); +} \ 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..ecc9d66 --- /dev/null +++ b/src/Application/Interfaces/Repositories/Admin/IReportCategoriesRepository.cs @@ -0,0 +1,9 @@ +using Domain.Entities.Admin; + +namespace Application.Interfaces.Repositories.Admin; + +public interface IReportCategoriesRepository : IRepository +{ + public Task GetByIdAsync(int id); + public Task CreateAsync(ReportCategory reportCategory); +} \ 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..0b31490 --- /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!.Value) is null) + throw new NotFoundException(nameof(ReportEntity), reportDTO.TargetEntityId.Value); + + var reportCategory = await _reportCategoriesRepository.GetByIdAsync(reportDTO.CategoryId!.Value); + if (reportCategory is null) + 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!.Value, + Description = reportDTO.Description, + IsActive = true + }; + + switch (reportDTO.TargetEntityId.Value) + { + case (int) ReportTargetEntities.Person: + 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!.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!.Value) is null) + throw new NotFoundException(nameof(PostModel), reportDTO.TargetId.Value); + 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..0cb2b4f --- /dev/null +++ b/src/Infrastructure/Persistence/Repositories/Admin/ReportCategoriesRepository.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; +using Domain.Entities.Admin; +using Application.Interfaces.Repositories.Admin; +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(); + } +} \ 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..ab0c650 --- /dev/null +++ b/src/Infrastructure/Services/Queries/ReportsQueryService.cs @@ -0,0 +1,46 @@ +using Application; +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; + } + + public async Task> GetByTargetEntityIdAsync(ReportTargetEntities entity) + { + ICollection reports = new List(); + switch (entity) + { + case ReportTargetEntities.Person: + reports = await _reports.Where(r => r.TargetPersonId != null).ToListAsync(); + break; + case ReportTargetEntities.Club: + 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