Refactor to introduce Govor.Application and Govor.Contracts layers

Moved service implementations and interfaces from Govor.API and Govor.Core to new Govor.Application and Govor.Contracts projects. Updated namespaces and references throughout the solution. Added custom exception classes for authentication and invite services. Adjusted dependency injection and project references to use the new structure. This refactor improves separation of concerns and prepares the codebase for better maintainability and scalability.
This commit is contained in:
Artemy
2025-06-25 15:16:14 +07:00
parent 5693190b1c
commit 4f3f4ec066
41 changed files with 126 additions and 75 deletions
@@ -1,9 +1,11 @@
using AutoFixture; using AutoFixture;
using Govor.API.Controllers; using Govor.API.Controllers;
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Application.Exceptions.AuthService;
using Govor.Application.Exceptions.InvitesService;
using Govor.Application.Interfaces.Authentication;
using Govor.Contracts.Requests;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Requests;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using Moq;
@@ -1,6 +1,6 @@
using AutoFixture; using AutoFixture;
using Govor.API.Services.AdminsStuff;
using Govor.API.Services.AdminsStuff.Interfaces; using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Application.Interfaces.AdminsStuff;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Invaites; using Govor.Core.Repositories.Invaites;
using Moq; using Moq;
@@ -1,11 +1,12 @@
using AutoFixture; using AutoFixture;
using Govor.API.Services.Authentication;
using Govor.Core.Infrastructure.Extensions; using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Users; using Govor.Core.Repositories.Users;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Application.Exceptions.AuthService;
using Govor.Application.Interfaces.Authentication;
using Govor.Application.Services;
using Govor.Core.Repositories.Admins; using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Moq; using Moq;
namespace Govor.API.Tests.UnitTests.Services.Authentication; namespace Govor.API.Tests.UnitTests.Services.Authentication;
@@ -1,7 +1,7 @@
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using AutoFixture; using AutoFixture;
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Application.Services;
using Govor.Core.Models; using Govor.Core.Models;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
@@ -1,5 +1,6 @@
using AutoFixture; using AutoFixture;
using Govor.API.Services; using Govor.Application.Interfaces;
using Govor.Application.Services;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Moq; using Moq;
@@ -24,7 +25,7 @@ public class LocalStorageServiceTests
_webHostEnvironmentMock.Setup(w => w.ContentRootPath).Returns(_tempDirectory); _webHostEnvironmentMock.Setup(w => w.ContentRootPath).Returns(_tempDirectory);
_service = new LocalStorageService(_webHostEnvironmentMock.Object); _service = new LocalStorageService(_webHostEnvironmentMock.Object.ContentRootPath);
} }
[TearDown] [TearDown]
@@ -1,5 +1,5 @@
using AutoFixture; using AutoFixture;
using Govor.API.Services; using Govor.Application.Services;
using Govor.Core.Infrastructure.Extensions; using Govor.Core.Infrastructure.Extensions;
namespace Govor.API.Tests.UnitTests.Services; namespace Govor.API.Tests.UnitTests.Services;
@@ -1,8 +1,7 @@
using AutoMapper;
using Govor.API.Services.AdminsStuff.Interfaces; using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Core.DTOs; using Govor.Contracts.DTOs;
using Govor.Contracts.Requests;
using Govor.Core.Repositories.Invaites; using Govor.Core.Repositories.Invaites;
using Govor.Core.Requests;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
+4 -2
View File
@@ -1,6 +1,8 @@
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Requests; using Govor.Application.Exceptions.AuthService;
using Govor.Application.Exceptions.InvitesService;
using Govor.Application.Interfaces.Authentication;
using Govor.Contracts.Requests;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Govor.API.Controllers; namespace Govor.API.Controllers;
@@ -22,7 +22,6 @@ public class InviteController : ControllerBase
var group = _groupService.GetGroupByInvite(code); var group = _groupService.GetGroupByInvite(code);
if (group == null) return NotFound(); if (group == null) return NotFound();
// Вернуть инфу, которая откроется в MAUI-клиенте
return Ok(new return Ok(new
{ {
groupId = group.Id, groupId = group.Id,
@@ -1,8 +1,9 @@
using Govor.API.Services;
using Govor.API.Services.AdminsStuff;
using Govor.API.Services.AdminsStuff.Interfaces; using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Application.Interfaces;
using Govor.Application.Interfaces.AdminsStuff;
using Govor.Application.Interfaces.Authentication;
using Govor.Application.Services;
using Govor.Core.Infrastructure.Extensions; using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Infrastructure.Validators; using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models; using Govor.Core.Models;
@@ -27,6 +28,12 @@ public static class ConfigurationProgramExtensions
services.AddScoped<IUsersAdministration, UsersService>(); services.AddScoped<IUsersAdministration, UsersService>();
services.AddScoped<IInvitesService, InvitesService>(); services.AddScoped<IInvitesService, InvitesService>();
services.AddScoped<IInvitationGenerator, InvitationGenerator>(); services.AddScoped<IInvitationGenerator, InvitationGenerator>();
services.AddScoped<IStorageService>(sp =>
{
var env = sp.GetRequiredService<IWebHostEnvironment>();
return new LocalStorageService(env.ContentRootPath);
});
} }
public static void AddRepositories(this IServiceCollection services) public static void AddRepositories(this IServiceCollection services)
+2
View File
@@ -22,6 +22,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Govor.Application\Govor.Application.csproj" />
<ProjectReference Include="..\Govor.Contracts\Govor.Contracts.csproj" />
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" /> <ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
<ProjectReference Include="..\Govor.Data\Govor.Data.csproj" /> <ProjectReference Include="..\Govor.Data\Govor.Data.csproj" />
</ItemGroup> </ItemGroup>
+1 -17
View File
@@ -1,23 +1,7 @@
using System.Security.Cryptography;
using System.Text; using System.Text;
using Govor.API.Extensions; using Govor.API.Extensions;
using Govor.API.Hubs; using Govor.API.Hubs;
using Govor.API.Services; using Govor.Application.Services;
using Govor.API.Services.AdminsStuff;
using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Govor.Core.Repositories.MediasAttachments;
using Govor.Core.Repositories.Messages;
using Govor.Core.Repositories.Users;
using Govor.Data;
using Govor.Data.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
@@ -0,0 +1,5 @@
using Govor.Core;
namespace Govor.Application.Exceptions.AuthService;
public class LoginUserException : GovorCoreException { }
@@ -0,0 +1,5 @@
using Govor.Core;
namespace Govor.Application.Exceptions.AuthService;
public class UserAlreadyExistException(string username) : GovorCoreException($"{username} is already exists!") { }
@@ -0,0 +1,5 @@
using Govor.Core;
namespace Govor.Application.Exceptions.AuthService;
public class UserNotRegisteredException(string username) : GovorCoreException($"{username} is not registered!") { }
@@ -0,0 +1,5 @@
using Govor.Core;
namespace Govor.Application.Exceptions.InvitesService;
public class InviteLinkInvalidException(string inviteCode) : GovorCoreException($"Invite link invalid: {inviteCode}");
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
<ProjectReference Include="..\Govor.Data\Govor.Data.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.3.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
</ItemGroup>
</Project>
@@ -2,7 +2,7 @@ using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Invaites; using Govor.Core.Repositories.Invaites;
namespace Govor.API.Services.AdminsStuff; namespace Govor.Application.Interfaces.AdminsStuff;
public class InvitationGenerator(IInvitesRepository repository) : IInvitationGenerator public class InvitationGenerator(IInvitesRepository repository) : IInvitationGenerator
{ {
@@ -1,10 +1,9 @@
using Govor.API.Services.AdminsStuff.Interfaces; using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Users; using Govor.Core.Repositories.Users;
using Govor.Data.Repositories;
using Govor.Data.Repositories.Exceptions; using Govor.Data.Repositories.Exceptions;
namespace Govor.API.Services.AdminsStuff; namespace Govor.Application.Interfaces.AdminsStuff;
public class UsersService : IUsersAdministration public class UsersService : IUsersAdministration
{ {
@@ -1,6 +1,6 @@
using Govor.Core.Models; using Govor.Core.Models;
namespace Govor.API.Services.Authentication.Interfaces; namespace Govor.Application.Interfaces.Authentication;
public interface IAccountService public interface IAccountService
{ {
@@ -1,6 +1,4 @@
using Microsoft.AspNetCore.Http; // для IFormFile namespace Govor.Application.Interfaces;
namespace Govor.API.Services;
public interface IStorageService public interface IStorageService
{ {
@@ -1,15 +1,12 @@
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Core; using Govor.Application.Exceptions.AuthService;
using Govor.Core.Infrastructure.Extensions; using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Users; using Govor.Core.Repositories.Users;
using Govor.API.Services; using Govor.Application.Interfaces.Authentication;
using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Core.Repositories.Admins; using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
namespace Govor.Application.Services;
namespace Govor.API.Services.Authentication;
public class AuthService : IAccountService public class AuthService : IAccountService
{ {
@@ -76,9 +73,3 @@ public class AuthService : IAccountService
await _adminsRepository.AddAsync(new Admin() { UserId = user.Id }); await _adminsRepository.AddAsync(new Admin() { UserId = user.Id });
} }
} }
public class LoginUserException : GovorCoreException { }
public class UserAlreadyExistException(string username) : GovorCoreException($"{username} is already exists!") { }
public class UserNotRegisteredException(string username) : GovorCoreException($"{username} is not registered!") { }
@@ -1,10 +1,10 @@
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Core; using Govor.Application.Exceptions.InvitesService;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Invaites; using Govor.Core.Repositories.Invaites;
using Govor.Data.Repositories.Exceptions; using Govor.Data.Repositories.Exceptions;
namespace Govor.API.Services.Authentication; namespace Govor.Application.Services;
public class InvitesService : IInvitesService public class InvitesService : IInvitesService
{ {
@@ -49,4 +49,3 @@ public class InvitesService : IInvitesService
} }
} }
public class InviteLinkInvalidException(string inviteCode) : GovorCoreException($"Invite link invalid: {inviteCode}");
@@ -1,5 +1,4 @@
namespace Govor.API.Services.Authentication; namespace Govor.Application.Services;
public class JwtOption public class JwtOption
{ {
public string SecretKeу {get; set;} public string SecretKeу {get; set;}
@@ -3,12 +3,10 @@ using System.Security.Claims;
using System.Text; using System.Text;
using Govor.API.Services.Authentication.Interfaces; using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Models; using Govor.Core.Models;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
namespace Govor.API.Services.Authentication; namespace Govor.Application.Services;
public class JwtService : IJwtService public class JwtService : IJwtService
{ {
@@ -1,12 +1,14 @@
namespace Govor.API.Services; using Govor.Application.Interfaces;
using Microsoft.AspNetCore.Hosting;
namespace Govor.Application.Services;
public class LocalStorageService : IStorageService public class LocalStorageService : IStorageService
{ {
private readonly string _storagePath; private readonly string _storagePath;
public LocalStorageService(IWebHostEnvironment hostingEnvironment) public LocalStorageService(string contentRootPath)
{ {
_storagePath = Path.Combine(hostingEnvironment.ContentRootPath, "uploads"); _storagePath = Path.Combine(contentRootPath, "uploads");
if (!Directory.Exists(_storagePath)) if (!Directory.Exists(_storagePath))
{ {
@@ -1,6 +1,6 @@
using Govor.Core.Infrastructure.Extensions; using Govor.Core.Infrastructure.Extensions;
namespace Govor.API.Services; namespace Govor.Application.Services;
public class PasswordHasher : IPasswordHasher public class PasswordHasher : IPasswordHasher
{ {
+1
View File
@@ -15,6 +15,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Govor.Contracts\Govor.Contracts.csproj" />
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" /> <ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
</ItemGroup> </ItemGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json; using System.Text.Json;
using Govor.Core.Requests; using Govor.Contracts.Requests;
/*==================================== /*====================================
@@ -1,4 +1,4 @@
namespace Govor.Core.DTOs; namespace Govor.Contracts.DTOs;
public class InvitationDto public class InvitationDto
{ {
+13
View File
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,4 +1,4 @@
namespace Govor.Core.Requests; namespace Govor.Contracts.Requests;
public class CreateInvitationRequest public class CreateInvitationRequest
{ {
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Govor.Core.Infrastructure.Validators; using Govor.Core.Infrastructure.Validators;
namespace Govor.Core.Requests; namespace Govor.Contracts.Requests;
public class LoginRequest public class LoginRequest
{ {
@@ -1,8 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Govor.Core.Infrastructure.Validators; using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models;
namespace Govor.Core.Requests; namespace Govor.Contracts.Requests;
public record RegistrationRequest public record RegistrationRequest
{ {
+14
View File
@@ -14,6 +14,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4ED5259A
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{114F53C1-B0AB-4BA0-9E36-0E811D1B3776}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{114F53C1-B0AB-4BA0-9E36-0E811D1B3776}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Contracts", "Govor.Contracts\Govor.Contracts.csproj", "{4E94907F-BE20-42A6-AB15-637850FEAD11}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Application", "Govor.Application\Govor.Application.csproj", "{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -40,6 +44,14 @@ Global
{F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Release|Any CPU.Build.0 = Release|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Release|Any CPU.Build.0 = Release|Any CPU
{4E94907F-BE20-42A6-AB15-637850FEAD11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E94907F-BE20-42A6-AB15-637850FEAD11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E94907F-BE20-42A6-AB15-637850FEAD11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E94907F-BE20-42A6-AB15-637850FEAD11}.Release|Any CPU.Build.0 = Release|Any CPU
{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{15031CBD-F319-4755-BA91-B86F20BD8E37} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4} {15031CBD-F319-4755-BA91-B86F20BD8E37} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4}
@@ -47,5 +59,7 @@ Global
{F4535DC3-BDFB-4EB2-B259-F92B6BBB535B} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776}
{F7BB1EC7-63D6-4525-ADE4-E4AC937E219D} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776}
{E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776}
{4E94907F-BE20-42A6-AB15-637850FEAD11} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776}
{FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal