From 76094af15b5e8653470e129e85f79612611a099f Mon Sep 17 00:00:00 2001 From: Artemy <109195690+stalcker2288969@users.noreply.github.com> Date: Tue, 24 Jun 2025 21:20:43 +0700 Subject: [PATCH] Invitation globale work + tests + new services + InvitationDto and IInvitationReqest --- .../EF/Repositories/InvitesRepositoryTests.cs | 7 +- .../Validators/InvitationValidatorTests.cs | 7 +- .../UnitTests/Services/AuthServiceTests.cs | 14 +- .../AdminStuff/InviteUserController.cs | 77 ++++ .../{ => AdminStuff}/UsersController.cs | 8 +- Govor.API/Controllers/AuthController.cs | 14 +- .../ConfigurationProgramExtensions.cs | 2 + Govor.API/Govor.API.csproj | 1 + .../Interfaces/IInvitionGenerator.cs | 6 + .../AdminsStuff/InvitationGenerator.cs | 26 ++ .../Services/Authentication/AuthService.cs | 44 +- .../Authentication/Interfaces/IAuthService.cs | 2 +- .../Interfaces/IInvitesService.cs | 9 + .../Services/Authentication/InvitesService.cs | 52 +++ .../Services/Authentication/JwtService.cs | 9 +- Govor.Core/DTOs/InvitationDto.cs | 13 + .../Validators/InvitationValidator.cs | 8 +- Govor.Core/Models/Invitation.cs | 1 + .../Repositories/Invaites/IInvitesExist.cs | 1 + .../Requests/CreateInvitationRequest.cs | 9 + .../20250616151700_initial.Designer.cs | 129 ------ .../Migrations/20250616151700_initial.cs | 92 ----- ...18082839_AddPasswordHashColumn.Designer.cs | 129 ------ .../20250618082839_AddPasswordHashColumn.cs | 45 --- .../20250622044435_MessagesInit.Designer.cs | 310 --------------- ...0250624053837_FixAdminRelation.Designer.cs | 331 ---------------- .../20250624053837_FixAdminRelation.cs | 39 -- .../20250624071942_inviteAdd.Designer.cs | 375 ------------------ .../Migrations/20250624071942_inviteAdd.cs | 69 ---- .../Migrations/20250624072330_FixinviteAdd.cs | 22 - .../20250624072548_InitialCreate.cs | 22 - ... 20250624133431_InitialCreate.Designer.cs} | 10 +- ...nit.cs => 20250624133431_InitialCreate.cs} | 167 +++++++- ...50624141242_inviteAddIsActive.Designer.cs} | 15 +- .../20250624141242_inviteAddIsActive.cs | 29 ++ .../Migrations/GovorDbContextModelSnapshot.cs | 11 + .../Exceptions/AdditionException.cs | 10 +- Govor.Data/Repositories/InvitesRepository.cs | 8 + 38 files changed, 483 insertions(+), 1640 deletions(-) create mode 100644 Govor.API/Controllers/AdminStuff/InviteUserController.cs rename Govor.API/Controllers/{ => AdminStuff}/UsersController.cs (87%) create mode 100644 Govor.API/Services/AdminsStuff/Interfaces/IInvitionGenerator.cs create mode 100644 Govor.API/Services/AdminsStuff/InvitationGenerator.cs create mode 100644 Govor.API/Services/Authentication/Interfaces/IInvitesService.cs create mode 100644 Govor.API/Services/Authentication/InvitesService.cs create mode 100644 Govor.Core/DTOs/InvitationDto.cs create mode 100644 Govor.Core/Requests/CreateInvitationRequest.cs delete mode 100644 Govor.Data/Migrations/20250616151700_initial.Designer.cs delete mode 100644 Govor.Data/Migrations/20250616151700_initial.cs delete mode 100644 Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.Designer.cs delete mode 100644 Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.cs delete mode 100644 Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs delete mode 100644 Govor.Data/Migrations/20250624053837_FixAdminRelation.Designer.cs delete mode 100644 Govor.Data/Migrations/20250624053837_FixAdminRelation.cs delete mode 100644 Govor.Data/Migrations/20250624071942_inviteAdd.Designer.cs delete mode 100644 Govor.Data/Migrations/20250624071942_inviteAdd.cs delete mode 100644 Govor.Data/Migrations/20250624072330_FixinviteAdd.cs delete mode 100644 Govor.Data/Migrations/20250624072548_InitialCreate.cs rename Govor.Data/Migrations/{20250624072548_InitialCreate.Designer.cs => 20250624133431_InitialCreate.Designer.cs} (97%) rename Govor.Data/Migrations/{20250622044435_MessagesInit.cs => 20250624133431_InitialCreate.cs} (54%) rename Govor.Data/Migrations/{20250624072330_FixinviteAdd.Designer.cs => 20250624141242_inviteAddIsActive.Designer.cs} (96%) create mode 100644 Govor.Data/Migrations/20250624141242_inviteAddIsActive.cs diff --git a/Govor.API.Tests/IntegrationTests/EF/Repositories/InvitesRepositoryTests.cs b/Govor.API.Tests/IntegrationTests/EF/Repositories/InvitesRepositoryTests.cs index 59b18ee..a9569e7 100644 --- a/Govor.API.Tests/IntegrationTests/EF/Repositories/InvitesRepositoryTests.cs +++ b/Govor.API.Tests/IntegrationTests/EF/Repositories/InvitesRepositoryTests.cs @@ -204,12 +204,14 @@ public class InvitesRepositoryTests // Act var result = repository.Exist(Guid.NewGuid()); + var result2 = repository.Exist(_fixture.Create()); Assert.That(result, Is.False); + Assert.That(result2, Is.False); } [Test] - public async Task Given_ExistInvitesCode_When_Exist_Then_Returns_False() + public async Task Given_ExistInvites_When_Exist_Then_Returns_False() { // Arrange var invitation = _fixture.Create(); @@ -226,11 +228,14 @@ public class InvitesRepositoryTests // Act var result = repository.Exist(invitation.Id); var result2 = repository.Exist(invitation); + var result3 = repository.Exist(invitation.Code); Assert.That(result, Is.True); Assert.That(result2, Is.True); + Assert.That(result3, Is.True); } + [Test] public async Task Given_InvalidInvites_When_Exist_Then_Returns_False() { diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs index 68e71e5..78c3ef5 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs @@ -67,23 +67,24 @@ public class InvitationValidatorTests } [Test] - public void Given_InvalidEndDate_When_Exist_Then_Returns_False() + public void Given_InvalidEndDatesAndIsActive_When_Exist_Then_Returns_False() { // Arrange var invitation = _fixture.Create(); invitation.EndDate = invitation.DateCreated.AddDays(-1); - + invitation.IsActive = true; // Act & Assert Assert.Throws>( () => _messageValidator.Validate(invitation)); Assert.That(_messageValidator.TryValidate(invitation), Is.False); } [Test] - public void Given_InvalidMaxParticipants_When_Exist_Then_Returns_False() + public void Given_InvalidMaxParticipantsAndIsActive_When_Exist_Then_Returns_False() { // Arrange var invitation = _fixture.Create(); invitation.MaxParticipants = new Random().Next(-5, 0); + invitation.IsActive = true; // Act & Assert Assert.Throws>( () => _messageValidator.Validate(invitation)); diff --git a/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs b/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs index dc65d5e..24630d3 100644 --- a/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs +++ b/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs @@ -18,7 +18,6 @@ public class AuthServiceTests private Mock _jwtServiceMock; private Mock _usersRepositoryMock; private Mock _adminsRepositoryMock; - private Mock _invitesRepositoryMock; private IAccountService _accountService; @@ -27,15 +26,22 @@ public class AuthServiceTests { _fixture = new Fixture(); + _fixture.Behaviors + .OfType() + .ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _usersRepositoryMock = new Mock(); _passwordHasherMock = new Mock(); _jwtServiceMock = new Mock(); + _adminsRepositoryMock = new Mock(); _accountService = new AuthService( _usersRepositoryMock.Object, _jwtServiceMock.Object, _passwordHasherMock.Object, - _invitesRepositoryMock.Object, _adminsRepositoryMock.Object ); } @@ -48,7 +54,7 @@ public class AuthServiceTests // Act & Assert Assert.ThrowsAsync(async () => await _accountService.RegistrationAsync( - _fixture.Create(), _fixture.Create(), _fixture.Create())); + _fixture.Create(), _fixture.Create(), _fixture.Create())); } [Test] @@ -59,7 +65,7 @@ public class AuthServiceTests // Act & Assert Assert.DoesNotThrowAsync(async () => await _accountService.RegistrationAsync( - _fixture.Create(), _fixture.Create(), _fixture.Create())); + _fixture.Create(), _fixture.Create(), _fixture.Create())); } [Test] diff --git a/Govor.API/Controllers/AdminStuff/InviteUserController.cs b/Govor.API/Controllers/AdminStuff/InviteUserController.cs new file mode 100644 index 0000000..44d85c1 --- /dev/null +++ b/Govor.API/Controllers/AdminStuff/InviteUserController.cs @@ -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 _logger; + + public InviteUserController(IInvitationGenerator invitationGenerator, + IInvitesRepository repository, + ILogger logger) + { + _invitationGenerator = invitationGenerator; + _logger = logger; + _repository = repository; + } + + [HttpPost("[action]")] + public async Task 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 GetAllInvitations() + { + try + { + _logger.LogInformation("Getting all invitations by administrator"); + var read = await _repository.GetAllAsync(); + + List dto = new List(); + + 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}"); + } + } +} \ No newline at end of file diff --git a/Govor.API/Controllers/UsersController.cs b/Govor.API/Controllers/AdminStuff/UsersController.cs similarity index 87% rename from Govor.API/Controllers/UsersController.cs rename to Govor.API/Controllers/AdminStuff/UsersController.cs index b903e16..4a4ae04 100644 --- a/Govor.API/Controllers/UsersController.cs +++ b/Govor.API/Controllers/AdminStuff/UsersController.cs @@ -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 _logger; private readonly IUsersAdministration _users; - - public UsersController(ILogger logger, IUsersAdministration users) + + public UsersController(ILogger logger, IUsersAdministration users, IInvitationGenerator invitationGenerator) { _logger = logger; _users = users; } - + [HttpGet] public async Task AllUsers() { diff --git a/Govor.API/Controllers/AuthController.cs b/Govor.API/Controllers/AuthController.cs index b4aca2c..8e0ffe5 100644 --- a/Govor.API/Controllers/AuthController.cs +++ b/Govor.API/Controllers/AuthController.cs @@ -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 _logger; - public AuthController(IAccountService accountService, ILogger logger) + public AuthController(IAccountService accountService, IInvitesService invitesService, ILogger 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); diff --git a/Govor.API/Extensions/ConfigurationProgramExtensions.cs b/Govor.API/Extensions/ConfigurationProgramExtensions.cs index 0a59251..e05adca 100644 --- a/Govor.API/Extensions/ConfigurationProgramExtensions.cs +++ b/Govor.API/Extensions/ConfigurationProgramExtensions.cs @@ -25,6 +25,8 @@ public static class ConfigurationProgramExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void AddRepositories(this IServiceCollection services) diff --git a/Govor.API/Govor.API.csproj b/Govor.API/Govor.API.csproj index 94bf430..6a28550 100644 --- a/Govor.API/Govor.API.csproj +++ b/Govor.API/Govor.API.csproj @@ -7,6 +7,7 @@ + diff --git a/Govor.API/Services/AdminsStuff/Interfaces/IInvitionGenerator.cs b/Govor.API/Services/AdminsStuff/Interfaces/IInvitionGenerator.cs new file mode 100644 index 0000000..0c2f932 --- /dev/null +++ b/Govor.API/Services/AdminsStuff/Interfaces/IInvitionGenerator.cs @@ -0,0 +1,6 @@ +namespace Govor.API.Services.AdminsStuff.Interfaces; + +public interface IInvitationGenerator +{ + public Task GenerateInvitationCode(DateTime time, int maxUsers, bool isAdmin, string description = ""); +} \ No newline at end of file diff --git a/Govor.API/Services/AdminsStuff/InvitationGenerator.cs b/Govor.API/Services/AdminsStuff/InvitationGenerator.cs new file mode 100644 index 0000000..1b4dd8c --- /dev/null +++ b/Govor.API/Services/AdminsStuff/InvitationGenerator.cs @@ -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 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; + } +} \ No newline at end of file diff --git a/Govor.API/Services/Authentication/AuthService.cs b/Govor.API/Services/Authentication/AuthService.cs index 9ea80a5..17e4617 100644 --- a/Govor.API/Services/Authentication/AuthService.cs +++ b/Govor.API/Services/Authentication/AuthService.cs @@ -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 RegistrationAsync(string name, string password, string inviteCode) + public async Task 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 { } diff --git a/Govor.API/Services/Authentication/Interfaces/IAuthService.cs b/Govor.API/Services/Authentication/Interfaces/IAuthService.cs index ba95f13..df02845 100644 --- a/Govor.API/Services/Authentication/Interfaces/IAuthService.cs +++ b/Govor.API/Services/Authentication/Interfaces/IAuthService.cs @@ -4,6 +4,6 @@ namespace Govor.API.Services.Authentication.Interfaces; public interface IAccountService { - public Task RegistrationAsync(string name, string password, string inviteCode); + public Task RegistrationAsync(string name, string password, Invitation invitation); public Task LoginAsync(string name, string password); } \ No newline at end of file diff --git a/Govor.API/Services/Authentication/Interfaces/IInvitesService.cs b/Govor.API/Services/Authentication/Interfaces/IInvitesService.cs new file mode 100644 index 0000000..5643ea3 --- /dev/null +++ b/Govor.API/Services/Authentication/Interfaces/IInvitesService.cs @@ -0,0 +1,9 @@ +using Govor.Core.Models; + +namespace Govor.API.Services.Authentication.Interfaces; + +public interface IInvitesService +{ + public Task GetRole(User user); + public Invitation Validate(string inviteCode); +} \ No newline at end of file diff --git a/Govor.API/Services/Authentication/InvitesService.cs b/Govor.API/Services/Authentication/InvitesService.cs new file mode 100644 index 0000000..1f6d806 --- /dev/null +++ b/Govor.API/Services/Authentication/InvitesService.cs @@ -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 GetRole(User user) + { + try + { + var invitation = await _invitesRepository.FindByIdAsync(user.InviteId); + return invitation.IsAdmin ? "Admin" : "User"; + } + catch (NotFoundByKeyException) + { + 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}"); \ No newline at end of file diff --git a/Govor.API/Services/Authentication/JwtService.cs b/Govor.API/Services/Authentication/JwtService.cs index 9a62426..18d04d9 100644 --- a/Govor.API/Services/Authentication/JwtService.cs +++ b/Govor.API/Services/Authentication/JwtService.cs @@ -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 options) + public JwtService(IOptions 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( diff --git a/Govor.Core/DTOs/InvitationDto.cs b/Govor.Core/DTOs/InvitationDto.cs new file mode 100644 index 0000000..fd58a6c --- /dev/null +++ b/Govor.Core/DTOs/InvitationDto.cs @@ -0,0 +1,13 @@ +namespace Govor.Core.DTOs; + +public class InvitationDto +{ + public Guid Id { get; set; } + public bool IsAdmin { get; set; } + public bool IsActive { get; set; } + public string Code {get; set;} + public DateTime CreatedAt { get; set; } + public DateTime EndAt { get; set; } + public int MaxParticipants { get; set; } + public string Description { get; set; } +} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/InvitationValidator.cs b/Govor.Core/Infrastructure/Validators/InvitationValidator.cs index 069fe1d..ec8e36a 100644 --- a/Govor.Core/Infrastructure/Validators/InvitationValidator.cs +++ b/Govor.Core/Infrastructure/Validators/InvitationValidator.cs @@ -15,10 +15,10 @@ public class InvitationValidator : IObjectValidator throw new ArgumentException("Id cannot be empty", nameof(inv.Id)); if(inv.DateCreated == DateTime.MinValue) throw new ArgumentException("DateCreated cannot be empty", nameof(inv.DateCreated)); - if(inv.EndDate < inv.DateCreated) - throw new ArgumentException("EndDate cannot be less than StartDate", nameof(inv.EndDate)); - if(inv.MaxParticipants <= 0) - throw new ArgumentException("MaxParticipants cannot be less than 0", nameof(inv.MaxParticipants)); + if(inv.EndDate < inv.DateCreated && inv.IsActive) + throw new ArgumentException("EndDate cannot be less than StartDate when is active", nameof(inv.EndDate)); + if((inv.MaxParticipants <= 0 || inv.MaxParticipants <= inv.Users.Count) && inv.IsActive) + throw new ArgumentException("MaxParticipants cannot be less than 0 or users cannot be more then MaxParticipants when is active", nameof(inv.MaxParticipants)); if(inv.Code == string.Empty || inv.Code.Length < MIN_INVITATION_LENGTH) throw new ArgumentException($"Code cannot be empty or less then {MIN_INVITATION_LENGTH}", nameof(inv.Code)); } diff --git a/Govor.Core/Models/Invitation.cs b/Govor.Core/Models/Invitation.cs index a53c29e..adb0d90 100644 --- a/Govor.Core/Models/Invitation.cs +++ b/Govor.Core/Models/Invitation.cs @@ -4,6 +4,7 @@ public class Invitation { public Guid Id { get; set; } public bool IsAdmin { get; set; } + public bool IsActive { get; set; } = true; public string Code { get; set; } public string Description { get; set; } public DateTime DateCreated { get; set; } diff --git a/Govor.Core/Repositories/Invaites/IInvitesExist.cs b/Govor.Core/Repositories/Invaites/IInvitesExist.cs index f5d747b..e763d28 100644 --- a/Govor.Core/Repositories/Invaites/IInvitesExist.cs +++ b/Govor.Core/Repositories/Invaites/IInvitesExist.cs @@ -5,5 +5,6 @@ namespace Govor.Core.Repositories.Invaites; public interface IInvitesExist { bool Exist(Invitation invitation); + bool Exist(string code); bool Exist(Guid guid); } \ No newline at end of file diff --git a/Govor.Core/Requests/CreateInvitationRequest.cs b/Govor.Core/Requests/CreateInvitationRequest.cs new file mode 100644 index 0000000..861b460 --- /dev/null +++ b/Govor.Core/Requests/CreateInvitationRequest.cs @@ -0,0 +1,9 @@ +namespace Govor.Core.Requests; + +public class CreateInvitationRequest +{ + public DateTime EndDate { get; set; } + public int MaxParticipants { get; set; } + public bool IsAdmin { get; set; } + public string Description { get; set; } +} \ No newline at end of file diff --git a/Govor.Data/Migrations/20250616151700_initial.Designer.cs b/Govor.Data/Migrations/20250616151700_initial.Designer.cs deleted file mode 100644 index 3080a12..0000000 --- a/Govor.Data/Migrations/20250616151700_initial.Designer.cs +++ /dev/null @@ -1,129 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Govor.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Govor.Data.Migrations -{ - [DbContext(typeof(GovorDbContext))] - [Migration("20250616151700_initial")] - partial class initial - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Admins") - .IsRequired() - .HasColumnType("uuid[]"); - - b.PrimitiveCollection>("InviteCode") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("HashPassword") - .IsRequired() - .HasColumnType("text"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20250616151700_initial.cs b/Govor.Data/Migrations/20250616151700_initial.cs deleted file mode 100644 index 8957a2c..0000000 --- a/Govor.Data/Migrations/20250616151700_initial.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ChatGroups", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "text", nullable: false), - InviteCode = table.Column>(type: "text[]", nullable: false), - IsChannel = table.Column(type: "boolean", nullable: false), - IsPrivate = table.Column(type: "boolean", nullable: false), - Admins = table.Column>(type: "uuid[]", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ChatGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "GroupAdmins", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - GroupId = table.Column(type: "uuid", nullable: false), - UserId = table.Column(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_GroupAdmins", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "GroupMemberships", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - GroupId = table.Column(type: "uuid", nullable: false), - UserId = table.Column(type: "uuid", nullable: false), - IsBanned = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_GroupMemberships", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Users", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Username = table.Column(type: "text", nullable: false), - Description = table.Column(type: "text", nullable: false), - HashPassword = table.Column(type: "text", nullable: false), - IconId = table.Column(type: "uuid", nullable: false), - CreatedOn = table.Column(type: "timestamp with time zone", nullable: false), - WasOnline = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Users", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ChatGroups"); - - migrationBuilder.DropTable( - name: "GroupAdmins"); - - migrationBuilder.DropTable( - name: "GroupMemberships"); - - migrationBuilder.DropTable( - name: "Users"); - } - } -} diff --git a/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.Designer.cs b/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.Designer.cs deleted file mode 100644 index a20edbd..0000000 --- a/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.Designer.cs +++ /dev/null @@ -1,129 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Govor.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Govor.Data.Migrations -{ - [DbContext(typeof(GovorDbContext))] - [Migration("20250618082839_AddPasswordHashColumn")] - partial class AddPasswordHashColumn - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Admins") - .IsRequired() - .HasColumnType("uuid[]"); - - b.PrimitiveCollection>("InviteCode") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.cs b/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.cs deleted file mode 100644 index 82beab1..0000000 --- a/Govor.Data/Migrations/20250618082839_AddPasswordHashColumn.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class AddPasswordHashColumn : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.RenameColumn( - name: "HashPassword", - table: "Users", - newName: "PasswordHash"); - - migrationBuilder.AlterColumn( - name: "CreatedOn", - table: "Users", - type: "date", - nullable: false, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.RenameColumn( - name: "PasswordHash", - table: "Users", - newName: "HashPassword"); - - migrationBuilder.AlterColumn( - name: "CreatedOn", - table: "Users", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(DateOnly), - oldType: "date"); - } - } -} diff --git a/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs b/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs deleted file mode 100644 index 2fdacdc..0000000 --- a/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs +++ /dev/null @@ -1,310 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Govor.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Govor.Data.Migrations -{ - [DbContext(typeof(GovorDbContext))] - [Migration("20250622044435_MessagesInit")] - partial class MessagesInit - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Admins") - .IsRequired() - .HasColumnType("uuid[]"); - - b.PrimitiveCollection>("InviteCode") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EncryptedKey") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("FilePath") - .IsRequired() - .HasColumnType("text"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("MimeType") - .IsRequired() - .HasColumnType("text"); - - b.Property("Type") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("MessageId"); - - b.ToTable("MediaAttachments"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedContent") - .IsRequired() - .HasColumnType("text"); - - b.Property("IsEdited") - .HasColumnType("boolean"); - - b.Property("RecipientId") - .HasColumnType("uuid"); - - b.Property("RecipientType") - .HasColumnType("integer"); - - b.Property("ReplyToMessageId") - .HasColumnType("uuid"); - - b.Property("SenderId") - .HasColumnType("uuid"); - - b.Property("SentAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ReplyToMessageId"); - - b.ToTable("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("ReactedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReactionCode") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageReactions"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("ViewedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageViews"); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("MediaAttachments") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.HasOne("Govor.Core.Models.Message", "ReplyToMessage") - .WithMany() - .HasForeignKey("ReplyToMessageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("ReplyToMessage"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("Reactions") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.HasOne("Govor.Core.Models.Message", null) - .WithMany("MessageViews") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Navigation("MediaAttachments"); - - b.Navigation("MessageViews"); - - b.Navigation("Reactions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20250624053837_FixAdminRelation.Designer.cs b/Govor.Data/Migrations/20250624053837_FixAdminRelation.Designer.cs deleted file mode 100644 index c2d5107..0000000 --- a/Govor.Data/Migrations/20250624053837_FixAdminRelation.Designer.cs +++ /dev/null @@ -1,331 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Govor.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Govor.Data.Migrations -{ - [DbContext(typeof(GovorDbContext))] - [Migration("20250624053837_FixAdminRelation")] - partial class FixAdminRelation - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.Admin", b => - { - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("UserId"); - - b.ToTable("Admins"); - }); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Admins") - .IsRequired() - .HasColumnType("uuid[]"); - - b.PrimitiveCollection>("InviteCode") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EncryptedKey") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("FilePath") - .IsRequired() - .HasColumnType("text"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("MimeType") - .IsRequired() - .HasColumnType("text"); - - b.Property("Type") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("MessageId"); - - b.ToTable("MediaAttachments"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedContent") - .IsRequired() - .HasColumnType("text"); - - b.Property("IsEdited") - .HasColumnType("boolean"); - - b.Property("RecipientId") - .HasColumnType("uuid"); - - b.Property("RecipientType") - .HasColumnType("integer"); - - b.Property("ReplyToMessageId") - .HasColumnType("uuid"); - - b.Property("SenderId") - .HasColumnType("uuid"); - - b.Property("SentAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ReplyToMessageId"); - - b.ToTable("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("ReactedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReactionCode") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageReactions"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("ViewedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageViews"); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Admin", b => - { - b.HasOne("Govor.Core.Models.User", "User") - .WithOne() - .HasForeignKey("Govor.Core.Models.Admin", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("MediaAttachments") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.HasOne("Govor.Core.Models.Message", "ReplyToMessage") - .WithMany() - .HasForeignKey("ReplyToMessageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("ReplyToMessage"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("Reactions") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.HasOne("Govor.Core.Models.Message", null) - .WithMany("MessageViews") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Navigation("MediaAttachments"); - - b.Navigation("MessageViews"); - - b.Navigation("Reactions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20250624053837_FixAdminRelation.cs b/Govor.Data/Migrations/20250624053837_FixAdminRelation.cs deleted file mode 100644 index 09d1e2a..0000000 --- a/Govor.Data/Migrations/20250624053837_FixAdminRelation.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class FixAdminRelation : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Admins", - columns: table => new - { - UserId = table.Column(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Admins", x => x.UserId); - table.ForeignKey( - name: "FK_Admins_Users_UserId", - column: x => x.UserId, - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Admins"); - } - } -} diff --git a/Govor.Data/Migrations/20250624071942_inviteAdd.Designer.cs b/Govor.Data/Migrations/20250624071942_inviteAdd.Designer.cs deleted file mode 100644 index 4edcf15..0000000 --- a/Govor.Data/Migrations/20250624071942_inviteAdd.Designer.cs +++ /dev/null @@ -1,375 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Govor.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Govor.Data.Migrations -{ - [DbContext(typeof(GovorDbContext))] - [Migration("20250624071942_inviteAdd")] - partial class inviteAdd - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.Admin", b => - { - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("UserId"); - - b.ToTable("Admins"); - }); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Admins") - .IsRequired() - .HasColumnType("uuid[]"); - - b.PrimitiveCollection>("InviteCode") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); - - b.Property("IsAdmin") - .HasColumnType("boolean"); - - b.Property("MaxParticipants") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("Invitations"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EncryptedKey") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("FilePath") - .IsRequired() - .HasColumnType("text"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("MimeType") - .IsRequired() - .HasColumnType("text"); - - b.Property("Type") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("MessageId"); - - b.ToTable("MediaAttachments"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedContent") - .IsRequired() - .HasColumnType("text"); - - b.Property("IsEdited") - .HasColumnType("boolean"); - - b.Property("RecipientId") - .HasColumnType("uuid"); - - b.Property("RecipientType") - .HasColumnType("integer"); - - b.Property("ReplyToMessageId") - .HasColumnType("uuid"); - - b.Property("SenderId") - .HasColumnType("uuid"); - - b.Property("SentAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ReplyToMessageId"); - - b.ToTable("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("ReactedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReactionCode") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageReactions"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("ViewedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("MessageId", "UserId") - .IsUnique(); - - b.ToTable("MessageViews"); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("InviteId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("InviteId"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Admin", b => - { - b.HasOne("Govor.Core.Models.User", "User") - .WithOne() - .HasForeignKey("Govor.Core.Models.Admin", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("MediaAttachments") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.HasOne("Govor.Core.Models.Message", "ReplyToMessage") - .WithMany() - .HasForeignKey("ReplyToMessageId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("ReplyToMessage"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => - { - b.HasOne("Govor.Core.Models.Message", "Message") - .WithMany("Reactions") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.MessageView", b => - { - b.HasOne("Govor.Core.Models.Message", null) - .WithMany("MessageViews") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.User", b => - { - b.HasOne("Govor.Core.Models.Invitation", "Invite") - .WithMany("Users") - .HasForeignKey("InviteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Invite"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Navigation("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Message", b => - { - b.Navigation("MediaAttachments"); - - b.Navigation("MessageViews"); - - b.Navigation("Reactions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20250624071942_inviteAdd.cs b/Govor.Data/Migrations/20250624071942_inviteAdd.cs deleted file mode 100644 index b29ffe9..0000000 --- a/Govor.Data/Migrations/20250624071942_inviteAdd.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class inviteAdd : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "InviteId", - table: "Users", - type: "uuid", - nullable: false, - defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); - - migrationBuilder.CreateTable( - name: "Invitations", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - IsAdmin = table.Column(type: "boolean", nullable: false), - DateCreated = table.Column(type: "timestamp with time zone", nullable: false), - EndDate = table.Column(type: "timestamp with time zone", nullable: false), - MaxParticipants = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Invitations", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_Users_InviteId", - table: "Users", - column: "InviteId"); - - migrationBuilder.AddForeignKey( - name: "FK_Users_Invitations_InviteId", - table: "Users", - column: "InviteId", - principalTable: "Invitations", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Users_Invitations_InviteId", - table: "Users"); - - migrationBuilder.DropTable( - name: "Invitations"); - - migrationBuilder.DropIndex( - name: "IX_Users_InviteId", - table: "Users"); - - migrationBuilder.DropColumn( - name: "InviteId", - table: "Users"); - } - } -} diff --git a/Govor.Data/Migrations/20250624072330_FixinviteAdd.cs b/Govor.Data/Migrations/20250624072330_FixinviteAdd.cs deleted file mode 100644 index 342b753..0000000 --- a/Govor.Data/Migrations/20250624072330_FixinviteAdd.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class FixinviteAdd : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - - } - } -} diff --git a/Govor.Data/Migrations/20250624072548_InitialCreate.cs b/Govor.Data/Migrations/20250624072548_InitialCreate.cs deleted file mode 100644 index 5c791ea..0000000 --- a/Govor.Data/Migrations/20250624072548_InitialCreate.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class InitialCreate : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - - } - } -} diff --git a/Govor.Data/Migrations/20250624072548_InitialCreate.Designer.cs b/Govor.Data/Migrations/20250624133431_InitialCreate.Designer.cs similarity index 97% rename from Govor.Data/Migrations/20250624072548_InitialCreate.Designer.cs rename to Govor.Data/Migrations/20250624133431_InitialCreate.Designer.cs index f03fd47..a799edb 100644 --- a/Govor.Data/Migrations/20250624072548_InitialCreate.Designer.cs +++ b/Govor.Data/Migrations/20250624133431_InitialCreate.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Govor.Data.Migrations { [DbContext(typeof(GovorDbContext))] - [Migration("20250624072548_InitialCreate")] + [Migration("20250624133431_InitialCreate")] partial class InitialCreate { /// @@ -108,9 +108,17 @@ namespace Govor.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + b.Property("DateCreated") .HasColumnType("timestamp with time zone"); + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + b.Property("EndDate") .HasColumnType("timestamp with time zone"); diff --git a/Govor.Data/Migrations/20250622044435_MessagesInit.cs b/Govor.Data/Migrations/20250624133431_InitialCreate.cs similarity index 54% rename from Govor.Data/Migrations/20250622044435_MessagesInit.cs rename to Govor.Data/Migrations/20250624133431_InitialCreate.cs index 49ea51b..2b61e65 100644 --- a/Govor.Data/Migrations/20250622044435_MessagesInit.cs +++ b/Govor.Data/Migrations/20250624133431_InitialCreate.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable @@ -6,11 +7,71 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Govor.Data.Migrations { /// - public partial class MessagesInit : Migration + public partial class InitialCreate : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "ChatGroups", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: false), + InviteCode = table.Column>(type: "text[]", nullable: false), + IsChannel = table.Column(type: "boolean", nullable: false), + IsPrivate = table.Column(type: "boolean", nullable: false), + Admins = table.Column>(type: "uuid[]", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChatGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "GroupAdmins", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + GroupId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GroupAdmins", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "GroupMemberships", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + GroupId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + IsBanned = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GroupMemberships", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Invitations", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + IsAdmin = table.Column(type: "boolean", nullable: false), + Code = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: false), + DateCreated = table.Column(type: "timestamp with time zone", nullable: false), + EndDate = table.Column(type: "timestamp with time zone", nullable: false), + MaxParticipants = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Invitations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "Messages", columns: table => new @@ -36,6 +97,30 @@ namespace Govor.Data.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Username = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: false), + PasswordHash = table.Column(type: "text", nullable: false), + IconId = table.Column(type: "uuid", nullable: false), + CreatedOn = table.Column(type: "date", nullable: false), + WasOnline = table.Column(type: "timestamp with time zone", nullable: false), + InviteId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + table.ForeignKey( + name: "FK_Users_Invitations_InviteId", + column: x => x.InviteId, + principalTable: "Invitations", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "MediaAttachments", columns: table => new @@ -58,6 +143,43 @@ namespace Govor.Data.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "MessageViews", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + MessageId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ViewedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MessageViews", x => x.Id); + table.ForeignKey( + name: "FK_MessageViews_Messages_MessageId", + column: x => x.MessageId, + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Admins", + columns: table => new + { + UserId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Admins", x => x.UserId); + table.ForeignKey( + name: "FK_Admins_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "MessageReactions", columns: table => new @@ -85,26 +207,6 @@ namespace Govor.Data.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "MessageViews", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - MessageId = table.Column(type: "uuid", nullable: false), - UserId = table.Column(type: "uuid", nullable: false), - ViewedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MessageViews", x => x.Id); - table.ForeignKey( - name: "FK_MessageViews_Messages_MessageId", - column: x => x.MessageId, - principalTable: "Messages", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateIndex( name: "IX_MediaAttachments_MessageId", table: "MediaAttachments", @@ -131,11 +233,28 @@ namespace Govor.Data.Migrations table: "MessageViews", columns: new[] { "MessageId", "UserId" }, unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_InviteId", + table: "Users", + column: "InviteId"); } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "Admins"); + + migrationBuilder.DropTable( + name: "ChatGroups"); + + migrationBuilder.DropTable( + name: "GroupAdmins"); + + migrationBuilder.DropTable( + name: "GroupMemberships"); + migrationBuilder.DropTable( name: "MediaAttachments"); @@ -145,8 +264,14 @@ namespace Govor.Data.Migrations migrationBuilder.DropTable( name: "MessageViews"); + migrationBuilder.DropTable( + name: "Users"); + migrationBuilder.DropTable( name: "Messages"); + + migrationBuilder.DropTable( + name: "Invitations"); } } } diff --git a/Govor.Data/Migrations/20250624072330_FixinviteAdd.Designer.cs b/Govor.Data/Migrations/20250624141242_inviteAddIsActive.Designer.cs similarity index 96% rename from Govor.Data/Migrations/20250624072330_FixinviteAdd.Designer.cs rename to Govor.Data/Migrations/20250624141242_inviteAddIsActive.Designer.cs index 72cedce..bd2e361 100644 --- a/Govor.Data/Migrations/20250624072330_FixinviteAdd.Designer.cs +++ b/Govor.Data/Migrations/20250624141242_inviteAddIsActive.Designer.cs @@ -13,8 +13,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Govor.Data.Migrations { [DbContext(typeof(GovorDbContext))] - [Migration("20250624072330_FixinviteAdd")] - partial class FixinviteAdd + [Migration("20250624141242_inviteAddIsActive")] + partial class inviteAddIsActive { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -108,12 +108,23 @@ namespace Govor.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + b.Property("DateCreated") .HasColumnType("timestamp with time zone"); + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + b.Property("EndDate") .HasColumnType("timestamp with time zone"); + b.Property("IsActive") + .HasColumnType("boolean"); + b.Property("IsAdmin") .HasColumnType("boolean"); diff --git a/Govor.Data/Migrations/20250624141242_inviteAddIsActive.cs b/Govor.Data/Migrations/20250624141242_inviteAddIsActive.cs new file mode 100644 index 0000000..c43c141 --- /dev/null +++ b/Govor.Data/Migrations/20250624141242_inviteAddIsActive.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Govor.Data.Migrations +{ + /// + public partial class inviteAddIsActive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsActive", + table: "Invitations", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsActive", + table: "Invitations"); + } + } +} diff --git a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs b/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs index b00839f..cc407e7 100644 --- a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs +++ b/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs @@ -105,12 +105,23 @@ namespace Govor.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + b.Property("DateCreated") .HasColumnType("timestamp with time zone"); + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + b.Property("EndDate") .HasColumnType("timestamp with time zone"); + b.Property("IsActive") + .HasColumnType("boolean"); + b.Property("IsAdmin") .HasColumnType("boolean"); diff --git a/Govor.Data/Repositories/Exceptions/AdditionException.cs b/Govor.Data/Repositories/Exceptions/AdditionException.cs index d5501f6..46fa961 100644 --- a/Govor.Data/Repositories/Exceptions/AdditionException.cs +++ b/Govor.Data/Repositories/Exceptions/AdditionException.cs @@ -1,4 +1,10 @@ namespace Govor.Data.Repositories.Exceptions; -public class AdditionException(string s, Exception ex) - : Exception(s, ex); \ No newline at end of file +public class AdditionException : Exception +{ + public AdditionException(string s, Exception ex) : base(s, ex) + { + } + + public AdditionException(string s) : base(s) { } +} \ No newline at end of file diff --git a/Govor.Data/Repositories/InvitesRepository.cs b/Govor.Data/Repositories/InvitesRepository.cs index 374e697..5ae9da4 100644 --- a/Govor.Data/Repositories/InvitesRepository.cs +++ b/Govor.Data/Repositories/InvitesRepository.cs @@ -59,6 +59,9 @@ public class InvitesRepository : IInvitesRepository { _validator.Validate(invitation); + if(Exist(invitation.Code)) + throw new AdditionException("Invitation with given code already exists"); + _context.Invitations.Add(invitation); await _context.SaveChangesAsync(); } @@ -136,6 +139,11 @@ public class InvitesRepository : IInvitesRepository ); } + public bool Exist(string code) + { + return _context.Invitations.Any(i => i.Code == code); + } + public bool Exist(Guid guid) { return _context.Invitations.Any(i => i.Id == guid);