mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
Invitation globale work
+ tests + new services + InvitationDto and IInvitationReqest
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using AutoMapper;
|
||||
using Govor.API.Services.AdminsStuff.Interfaces;
|
||||
using Govor.Core.DTOs;
|
||||
using Govor.Core.Repositories.Invaites;
|
||||
using Govor.Core.Requests;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Govor.API.Controllers.AdminStuff;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
public class InviteUserController : Controller
|
||||
{
|
||||
private readonly IInvitesRepository _repository;
|
||||
private readonly IInvitationGenerator _invitationGenerator;
|
||||
private readonly ILogger<InviteUserController> _logger;
|
||||
|
||||
public InviteUserController(IInvitationGenerator invitationGenerator,
|
||||
IInvitesRepository repository,
|
||||
ILogger<InviteUserController> logger)
|
||||
{
|
||||
_invitationGenerator = invitationGenerator;
|
||||
_logger = logger;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> Invitation([FromBody] CreateInvitationRequest createInvitation)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _invitationGenerator.GenerateInvitationCode(createInvitation.EndDate,
|
||||
createInvitation.MaxParticipants,
|
||||
createInvitation.IsAdmin,
|
||||
createInvitation.Description);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return BadRequest($"An error occured: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAllInvitations()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Getting all invitations by administrator");
|
||||
var read = await _repository.GetAllAsync();
|
||||
|
||||
List<InvitationDto> dto = new List<InvitationDto>();
|
||||
|
||||
foreach (var inv in read)
|
||||
{
|
||||
dto.Add(new InvitationDto(){
|
||||
Id = inv.Id,
|
||||
Description = inv.Description,
|
||||
IsAdmin = inv.IsAdmin,
|
||||
MaxParticipants = inv.MaxParticipants,
|
||||
Code = inv.Code,
|
||||
CreatedAt = inv.DateCreated,
|
||||
EndAt = inv.EndDate,
|
||||
IsActive = inv.IsActive,
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(dto);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return BadRequest($"An error occured: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -2,7 +2,7 @@ using Govor.API.Services.AdminsStuff.Interfaces;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Govor.API.Controllers;
|
||||
namespace Govor.API.Controllers.AdminStuff;
|
||||
|
||||
|
||||
[ApiController]
|
||||
@@ -12,13 +12,13 @@ public class UsersController : Controller
|
||||
{
|
||||
private readonly ILogger<UsersController> _logger;
|
||||
private readonly IUsersAdministration _users;
|
||||
|
||||
public UsersController(ILogger<UsersController> logger, IUsersAdministration users)
|
||||
|
||||
public UsersController(ILogger<UsersController> logger, IUsersAdministration users, IInvitationGenerator invitationGenerator)
|
||||
{
|
||||
_logger = logger;
|
||||
_users = users;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> AllUsers()
|
||||
{
|
||||
@@ -1,3 +1,4 @@
|
||||
using Govor.API.Services;
|
||||
using Govor.API.Services.Authentication;
|
||||
using Govor.Core.DTOs;
|
||||
using Govor.API.Services.Authentication.Interfaces;
|
||||
@@ -9,12 +10,14 @@ namespace Govor.API.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class AuthController : Controller
|
||||
{
|
||||
private IInvitesService _invitesService;
|
||||
private IAccountService _accountService;
|
||||
private ILogger<AuthController> _logger;
|
||||
|
||||
public AuthController(IAccountService accountService, ILogger<AuthController> logger)
|
||||
public AuthController(IAccountService accountService, IInvitesService invitesService, ILogger<AuthController> logger)
|
||||
{
|
||||
_accountService = accountService;
|
||||
_invitesService = invitesService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -29,7 +32,9 @@ public class AuthController : Controller
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var token = await _accountService.RegistrationAsync(registrationDto.Name, registrationDto.Password, registrationDto.InviteLink);
|
||||
var invite = _invitesService.Validate(registrationDto.InviteLink);
|
||||
|
||||
var token = await _accountService.RegistrationAsync(registrationDto.Name, registrationDto.Password, invite);
|
||||
_logger.LogInformation($"Register request for {registrationDto.Name}");
|
||||
return Ok(new { token });
|
||||
}
|
||||
@@ -38,6 +43,11 @@ public class AuthController : Controller
|
||||
_logger.LogWarning(ex, $"Registration failed for user {registrationDto.Name}");
|
||||
return BadRequest("Registration failed: user already exists.");
|
||||
}
|
||||
catch (InviteLinkInvalidException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, $"Invite link invalid: {registrationDto.InviteLink}");
|
||||
return BadRequest("Invite link invalid.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error during registration for user {Name}", registrationDto.Name);
|
||||
|
||||
@@ -25,6 +25,8 @@ public static class ConfigurationProgramExtensions
|
||||
services.AddScoped<IJwtService, JwtService>();
|
||||
services.AddScoped<IAccountService, AuthService>();
|
||||
services.AddScoped<IUsersAdministration, UsersService>();
|
||||
services.AddScoped<IInvitesService, InvitesService>();
|
||||
services.AddScoped<IInvitationGenerator, InvitationGenerator>();
|
||||
}
|
||||
|
||||
public static void AddRepositories(this IServiceCollection services)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Govor.API.Services.AdminsStuff.Interfaces;
|
||||
|
||||
public interface IInvitationGenerator
|
||||
{
|
||||
public Task<string> GenerateInvitationCode(DateTime time, int maxUsers, bool isAdmin, string description = "");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Govor.API.Services.AdminsStuff.Interfaces;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Repositories.Invaites;
|
||||
|
||||
namespace Govor.API.Services.AdminsStuff;
|
||||
|
||||
public class InvitationGenerator(IInvitesRepository repository) : IInvitationGenerator
|
||||
{
|
||||
public async Task<string> GenerateInvitationCode(DateTime time, int maxUsers, bool isAdmin, string description = "")
|
||||
{
|
||||
Invitation newInvitation = new Invitation()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Description = description,
|
||||
MaxParticipants = maxUsers,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
EndDate = time.ToUniversalTime(),
|
||||
Code = Guid.NewGuid().ToString("N"),
|
||||
IsAdmin = isAdmin
|
||||
};
|
||||
|
||||
await repository.AddAsync(newInvitation);
|
||||
|
||||
return newInvitation.Code;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ 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.Core.Repositories.Admins;
|
||||
using Govor.Core.Repositories.Invaites;
|
||||
|
||||
@@ -15,35 +16,27 @@ public class AuthService : IAccountService
|
||||
private readonly IPasswordHasher _passwordHasher;
|
||||
private readonly IJwtService _jwtService;
|
||||
private readonly IUsersRepository _usersRepository;
|
||||
private readonly IInvitesRepository _invitesRepository;
|
||||
private readonly IAdminsRepository _adminsRepository;
|
||||
|
||||
public AuthService(IUsersRepository usersRepository,
|
||||
IJwtService jwtService,
|
||||
IPasswordHasher passwordHasher,
|
||||
IInvitesRepository invitesRepository,
|
||||
IAdminsRepository adminsRepository)
|
||||
IAdminsRepository adminsRepository
|
||||
)
|
||||
{
|
||||
_usersRepository = usersRepository;
|
||||
_jwtService = jwtService;
|
||||
_passwordHasher = passwordHasher;
|
||||
_invitesRepository = invitesRepository;
|
||||
_adminsRepository = adminsRepository;
|
||||
}
|
||||
|
||||
public async Task<string> RegistrationAsync(string name, string password, string inviteCode)
|
||||
public async Task<string> RegistrationAsync(string name, string password, Invitation invitation)
|
||||
{
|
||||
// 1. Проверка существования имени
|
||||
if (await _usersRepository.ExistsUsernameAsync(name))
|
||||
throw new UserAlreadyExistException(name);
|
||||
|
||||
// 2. Проверка валидности инвайта
|
||||
var invite = await _invitesRepository.FindByCodeAsync(inviteCode);
|
||||
|
||||
// 3. Генерация пароля
|
||||
|
||||
var passwordHash = _passwordHasher.Hash(password);
|
||||
|
||||
// 4. Создание пользователя
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -53,22 +46,13 @@ public class AuthService : IAccountService
|
||||
CreatedOn = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||
IconId = Guid.NewGuid(),
|
||||
WasOnline = DateTime.UtcNow,
|
||||
InviteId = invite.Id
|
||||
InviteId = invitation.Id
|
||||
};
|
||||
|
||||
// 5. Добавление пользователя
|
||||
|
||||
await _usersRepository.AddAsync(user);
|
||||
|
||||
// 6. Назначение роли, если инвайт — админский
|
||||
if (invite.IsAdmin)
|
||||
{
|
||||
await _adminsRepository.AddAsync(new Admin
|
||||
{
|
||||
UserId = user.Id
|
||||
});
|
||||
}
|
||||
|
||||
// 7. Генерация токена
|
||||
|
||||
SetRole(user, invitation);
|
||||
|
||||
return _jwtService.GenerateJwtToken(user);
|
||||
}
|
||||
|
||||
@@ -85,6 +69,12 @@ public class AuthService : IAccountService
|
||||
|
||||
return _jwtService.GenerateJwtToken(user);
|
||||
}
|
||||
|
||||
private async void SetRole(User user, Invitation invitation)
|
||||
{
|
||||
if(invitation.IsAdmin)
|
||||
await _adminsRepository.AddAsync(new Admin() { UserId = user.Id });
|
||||
}
|
||||
}
|
||||
|
||||
public class LoginUserException : GovorCoreException { }
|
||||
|
||||
@@ -4,6 +4,6 @@ namespace Govor.API.Services.Authentication.Interfaces;
|
||||
|
||||
public interface IAccountService
|
||||
{
|
||||
public Task<string> RegistrationAsync(string name, string password, string inviteCode);
|
||||
public Task<string> RegistrationAsync(string name, string password, Invitation invitation);
|
||||
public Task<string> LoginAsync(string name, string password);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Govor.Core.Models;
|
||||
|
||||
namespace Govor.API.Services.Authentication.Interfaces;
|
||||
|
||||
public interface IInvitesService
|
||||
{
|
||||
public Task<string> GetRole(User user);
|
||||
public Invitation Validate(string inviteCode);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Govor.API.Services.Authentication.Interfaces;
|
||||
using Govor.Core;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Repositories.Invaites;
|
||||
using Govor.Data.Repositories.Exceptions;
|
||||
|
||||
namespace Govor.API.Services.Authentication;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public class InviteLinkInvalidException(string inviteCode) : GovorCoreException($"Invite link invalid: {inviteCode}");
|
||||
@@ -13,21 +13,20 @@ namespace Govor.API.Services.Authentication;
|
||||
public class JwtService : IJwtService
|
||||
{
|
||||
private JwtOption _jwtOption;
|
||||
private IInvitesRepository _invitesRepository;
|
||||
private IInvitesService _invitesService;
|
||||
|
||||
public JwtService(IOptions<JwtOption> options)
|
||||
public JwtService(IOptions<JwtOption> options, IInvitesService invitesService)
|
||||
{
|
||||
_jwtOption = options.Value;
|
||||
_invitesService = invitesService;
|
||||
}
|
||||
|
||||
public string GenerateJwtToken(User user)
|
||||
{
|
||||
var invite = _invitesRepository.FindByIdAsync(user.InviteId).Result;
|
||||
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim("userID", user.Id.ToString()),
|
||||
new Claim(ClaimTypes.Role, invite.IsAdmin ? "Admin" : "User", ClaimValueTypes.String)
|
||||
new Claim(ClaimTypes.Role, _invitesService.GetRole(user).Result, ClaimValueTypes.String)
|
||||
};
|
||||
|
||||
var singing = new SigningCredentials(
|
||||
|
||||
Reference in New Issue
Block a user