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 Govor.API.Controllers;
using Govor.API.Services.Authentication;
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.Requests;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
@@ -1,6 +1,6 @@
using AutoFixture;
using Govor.API.Services.AdminsStuff;
using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Application.Interfaces.AdminsStuff;
using Govor.Core.Models;
using Govor.Core.Repositories.Invaites;
using Moq;
@@ -1,11 +1,12 @@
using AutoFixture;
using Govor.API.Services.Authentication;
using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Models;
using Govor.Core.Repositories.Users;
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.Invaites;
using Moq;
namespace Govor.API.Tests.UnitTests.Services.Authentication;
@@ -1,7 +1,7 @@
using System.IdentityModel.Tokens.Jwt;
using AutoFixture;
using Govor.API.Services.Authentication;
using Govor.API.Services.Authentication.Interfaces;
using Govor.Application.Services;
using Govor.Core.Models;
using Microsoft.Extensions.Options;
using Moq;
@@ -1,5 +1,6 @@
using AutoFixture;
using Govor.API.Services;
using Govor.Application.Interfaces;
using Govor.Application.Services;
using Microsoft.AspNetCore.Hosting;
using Moq;
@@ -24,7 +25,7 @@ public class LocalStorageServiceTests
_webHostEnvironmentMock.Setup(w => w.ContentRootPath).Returns(_tempDirectory);
_service = new LocalStorageService(_webHostEnvironmentMock.Object);
_service = new LocalStorageService(_webHostEnvironmentMock.Object.ContentRootPath);
}
[TearDown]
@@ -1,5 +1,5 @@
using AutoFixture;
using Govor.API.Services;
using Govor.Application.Services;
using Govor.Core.Infrastructure.Extensions;
namespace Govor.API.Tests.UnitTests.Services;
@@ -1,8 +1,7 @@
using AutoMapper;
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.Requests;
using Microsoft.AspNetCore.Authorization;
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.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;
namespace Govor.API.Controllers;
+1 -2
View File
@@ -21,8 +21,7 @@ public class InviteController : ControllerBase
{
var group = _groupService.GetGroupByInvite(code);
if (group == null) return NotFound();
// Вернуть инфу, которая откроется в MAUI-клиенте
return Ok(new
{
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.Authentication;
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.Validators;
using Govor.Core.Models;
@@ -27,6 +28,12 @@ public static class ConfigurationProgramExtensions
services.AddScoped<IUsersAdministration, UsersService>();
services.AddScoped<IInvitesService, InvitesService>();
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)
+2
View File
@@ -22,6 +22,8 @@
</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.Data\Govor.Data.csproj" />
</ItemGroup>
+1 -17
View File
@@ -1,23 +1,7 @@
using System.Security.Cryptography;
using System.Text;
using Govor.API.Extensions;
using Govor.API.Hubs;
using Govor.API.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 Govor.Application.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
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.Repositories.Invaites;
namespace Govor.API.Services.AdminsStuff;
namespace Govor.Application.Interfaces.AdminsStuff;
public class InvitationGenerator(IInvitesRepository repository) : IInvitationGenerator
{
@@ -1,10 +1,9 @@
using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Core.Models;
using Govor.Core.Repositories.Users;
using Govor.Data.Repositories;
using Govor.Data.Repositories.Exceptions;
namespace Govor.API.Services.AdminsStuff;
namespace Govor.Application.Interfaces.AdminsStuff;
public class UsersService : IUsersAdministration
{
@@ -1,6 +1,6 @@
using Govor.Core.Models;
namespace Govor.API.Services.Authentication.Interfaces;
namespace Govor.Application.Interfaces.Authentication;
public interface IAccountService
{
@@ -1,6 +1,4 @@
using Microsoft.AspNetCore.Http; // для IFormFile
namespace Govor.API.Services;
namespace Govor.Application.Interfaces;
public interface IStorageService
{
@@ -1,15 +1,12 @@
using Govor.API.Services.Authentication.Interfaces;
using Govor.Core;
using Govor.Application.Exceptions.AuthService;
using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Models;
using Govor.Core.Repositories.Users;
using Govor.API.Services;
using Govor.API.Services.AdminsStuff.Interfaces;
using Govor.Application.Interfaces.Authentication;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
namespace Govor.API.Services.Authentication;
namespace Govor.Application.Services;
public class AuthService : IAccountService
{
@@ -75,10 +72,4 @@ public class AuthService : IAccountService
if(invitation.IsAdmin)
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.Core;
using Govor.Application.Exceptions.InvitesService;
using Govor.Core.Models;
using Govor.Core.Repositories.Invaites;
using Govor.Data.Repositories.Exceptions;
namespace Govor.API.Services.Authentication;
namespace Govor.Application.Services;
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 string SecretKeу {get; set;}
@@ -3,12 +3,10 @@ using System.Security.Claims;
using System.Text;
using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Models;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace Govor.API.Services.Authentication;
namespace Govor.Application.Services;
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
{
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))
{
@@ -1,6 +1,6 @@
using Govor.Core.Infrastructure.Extensions;
namespace Govor.API.Services;
namespace Govor.Application.Services;
public class PasswordHasher : IPasswordHasher
{
+1
View File
@@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Govor.Contracts\Govor.Contracts.csproj" />
<ProjectReference Include="..\Govor.Core\Govor.Core.csproj" />
</ItemGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.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
{
+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
{
@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
using Govor.Core.Infrastructure.Validators;
namespace Govor.Core.Requests;
namespace Govor.Contracts.Requests;
public class LoginRequest
{
@@ -1,8 +1,7 @@
using System.ComponentModel.DataAnnotations;
using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models;
namespace Govor.Core.Requests;
namespace Govor.Contracts.Requests;
public record RegistrationRequest
{
+14
View File
@@ -14,6 +14,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4ED5259A
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{114F53C1-B0AB-4BA0-9E36-0E811D1B3776}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(NestedProjects) = preSolution
{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}
{F7BB1EC7-63D6-4525-ADE4-E4AC937E219D} = {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
EndGlobal