mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 19:54:55 +00:00
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:
@@ -0,0 +1,75 @@
|
||||
using Govor.API.Services.Authentication.Interfaces;
|
||||
using Govor.Application.Exceptions.AuthService;
|
||||
using Govor.Core.Infrastructure.Extensions;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Repositories.Users;
|
||||
using Govor.Application.Interfaces.Authentication;
|
||||
using Govor.Core.Repositories.Admins;
|
||||
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class AuthService : IAccountService
|
||||
{
|
||||
private readonly IPasswordHasher _passwordHasher;
|
||||
private readonly IJwtService _jwtService;
|
||||
private readonly IUsersRepository _usersRepository;
|
||||
private readonly IAdminsRepository _adminsRepository;
|
||||
|
||||
public AuthService(IUsersRepository usersRepository,
|
||||
IJwtService jwtService,
|
||||
IPasswordHasher passwordHasher,
|
||||
IAdminsRepository adminsRepository
|
||||
)
|
||||
{
|
||||
_usersRepository = usersRepository;
|
||||
_jwtService = jwtService;
|
||||
_passwordHasher = passwordHasher;
|
||||
_adminsRepository = adminsRepository;
|
||||
}
|
||||
|
||||
public async Task<string> RegistrationAsync(string name, string password, Invitation invitation)
|
||||
{
|
||||
if (await _usersRepository.ExistsUsernameAsync(name))
|
||||
throw new UserAlreadyExistException(name);
|
||||
|
||||
var passwordHash = _passwordHasher.Hash(password);
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Username = name,
|
||||
PasswordHash = passwordHash,
|
||||
Description = string.Empty,
|
||||
CreatedOn = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||
IconId = Guid.NewGuid(),
|
||||
WasOnline = DateTime.UtcNow,
|
||||
InviteId = invitation.Id
|
||||
};
|
||||
|
||||
await _usersRepository.AddAsync(user);
|
||||
|
||||
SetRole(user, invitation);
|
||||
|
||||
return _jwtService.GenerateJwtToken(user);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> LoginAsync(string name, string password)
|
||||
{
|
||||
if (await _usersRepository.ExistsUsernameAsync(name) == false)
|
||||
throw new UserNotRegisteredException(name);
|
||||
|
||||
var user = await _usersRepository.FindByUsernameAsync(name);
|
||||
|
||||
if (_passwordHasher.Verify(password, user.PasswordHash) == false)
|
||||
throw new LoginUserException();
|
||||
|
||||
return _jwtService.GenerateJwtToken(user);
|
||||
}
|
||||
|
||||
private async void SetRole(User user, Invitation invitation)
|
||||
{
|
||||
if(invitation.IsAdmin)
|
||||
await _adminsRepository.AddAsync(new Admin() { UserId = user.Id });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Govor.API.Services.Authentication.Interfaces;
|
||||
using Govor.Application.Exceptions.InvitesService;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Repositories.Invaites;
|
||||
using Govor.Data.Repositories.Exceptions;
|
||||
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class InvitesService : IInvitesService
|
||||
{
|
||||
private readonly IInvitesRepository _invitesRepository;
|
||||
|
||||
public InvitesService(IInvitesRepository invitesRepository)
|
||||
{
|
||||
_invitesRepository = invitesRepository;
|
||||
}
|
||||
|
||||
public async Task<string> GetRole(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var invitation = await _invitesRepository.FindByIdAsync(user.InviteId);
|
||||
return invitation.IsAdmin ? "Admin" : "User";
|
||||
}
|
||||
catch (NotFoundByKeyException<Guid>)
|
||||
{
|
||||
return "User";
|
||||
}
|
||||
}
|
||||
|
||||
public Invitation Validate(string inviteCode)
|
||||
{
|
||||
var invite = _invitesRepository.FindByCodeAsync(inviteCode).Result;
|
||||
|
||||
if (invite.EndDate < DateTime.Now ||
|
||||
invite.MaxParticipants <= invite.Users.Count)
|
||||
{
|
||||
invite.IsActive = false;
|
||||
_invitesRepository.UpdateAsync(invite);
|
||||
throw new InviteLinkInvalidException(inviteCode);
|
||||
}
|
||||
|
||||
return invite;
|
||||
}
|
||||
|
||||
public string GenerateInvitationLink(Invitation invitation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Govor.Application.Services;
|
||||
public class JwtOption
|
||||
{
|
||||
public string SecretKeу {get; set;}
|
||||
public int Hours { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Govor.API.Services.Authentication.Interfaces;
|
||||
using Govor.Core.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class JwtService : IJwtService
|
||||
{
|
||||
private JwtOption _jwtOption;
|
||||
private IInvitesService _invitesService;
|
||||
|
||||
public JwtService(IOptions<JwtOption> options, IInvitesService invitesService)
|
||||
{
|
||||
_jwtOption = options.Value;
|
||||
_invitesService = invitesService;
|
||||
}
|
||||
|
||||
public string GenerateJwtToken(User user)
|
||||
{
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim("userID", user.Id.ToString()),
|
||||
new Claim(ClaimTypes.Role, _invitesService.GetRole(user).Result, ClaimValueTypes.String)
|
||||
};
|
||||
|
||||
var singing = new SigningCredentials(
|
||||
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOption.SecretKeу)),
|
||||
SecurityAlgorithms.HmacSha256Signature);
|
||||
|
||||
var token = new JwtSecurityToken(signingCredentials: singing,
|
||||
expires: DateTime.UtcNow.AddHours(_jwtOption.Hours),
|
||||
claims: claims);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Govor.Application.Interfaces;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class LocalStorageService : IStorageService
|
||||
{
|
||||
private readonly string _storagePath;
|
||||
|
||||
public LocalStorageService(string contentRootPath)
|
||||
{
|
||||
_storagePath = Path.Combine(contentRootPath, "uploads");
|
||||
|
||||
if (!Directory.Exists(_storagePath))
|
||||
{
|
||||
Directory.CreateDirectory(_storagePath);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> SaveAsync(byte[] data, string fileName)
|
||||
{
|
||||
if(data is null || data.Length == 0)
|
||||
throw new ArgumentException("Invalid file", nameof(data));
|
||||
|
||||
if(fileName is null || fileName.Length == 0)
|
||||
throw new ArgumentException("Invalid file name", nameof(fileName));
|
||||
|
||||
var date = DateTime.UtcNow.ToString("yyyy/MM");
|
||||
|
||||
var folder = Path.Combine(_storagePath, date);
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
var uniqueFileName = $"{Guid.NewGuid()}_{Path.GetFileName(fileName)}";
|
||||
var fullPath = Path.Combine(folder, uniqueFileName);
|
||||
|
||||
await using var stream = new FileStream(fullPath, FileMode.Create);
|
||||
stream.WriteAsync(data, 0, data.Length);
|
||||
|
||||
return Path.Combine(date, uniqueFileName);
|
||||
}
|
||||
|
||||
public async Task<Stream> LoadAsync(string url)
|
||||
{
|
||||
var filePath = Path.Combine(_storagePath, url);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
throw new FileNotFoundException("File not found.", filePath);
|
||||
|
||||
return new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public async Task RemoveAsync(string url)
|
||||
{
|
||||
var path = Path.Combine(_storagePath, url);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Govor.Core.Infrastructure.Extensions;
|
||||
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class PasswordHasher : IPasswordHasher
|
||||
{
|
||||
public string Hash(string password)
|
||||
{
|
||||
return BCrypt.Net.BCrypt.HashPassword(password);
|
||||
}
|
||||
|
||||
public bool Verify(string hashedPassword, string providedPassword)
|
||||
{
|
||||
return BCrypt.Net.BCrypt.Verify(hashedPassword, providedPassword);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user