diff --git a/Govor.API.Tests/Controllers/SessionControllerTests.cs b/Govor.API.Tests/Controllers/SessionControllerTests.cs index f3190db..c7d22d5 100644 --- a/Govor.API.Tests/Controllers/SessionControllerTests.cs +++ b/Govor.API.Tests/Controllers/SessionControllerTests.cs @@ -3,7 +3,7 @@ using Govor.API.Controllers; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Application.Interfaces.UserSession; using Govor.Contracts.DTOs; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; diff --git a/Govor.API.Tests/Govor.API.Tests.csproj b/Govor.API.Tests/Govor.API.Tests.csproj index 26fdd64..da8779c 100644 --- a/Govor.API.Tests/Govor.API.Tests.csproj +++ b/Govor.API.Tests/Govor.API.Tests.csproj @@ -27,6 +27,5 @@ - diff --git a/Govor.API.Tests/Hubs/PresenceHubTests.cs b/Govor.API.Tests/Hubs/PresenceHubTests.cs index 8318c70..99ddc91 100644 --- a/Govor.API.Tests/Hubs/PresenceHubTests.cs +++ b/Govor.API.Tests/Hubs/PresenceHubTests.cs @@ -2,8 +2,8 @@ using AutoFixture; using Govor.API.Common.SignalR.Helpers; using Govor.API.Hubs; using Govor.Application.Interfaces.UserOnlineStatus; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Users; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs index d216655..54f4953 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs @@ -1,12 +1,12 @@ using AutoFixture; using Govor.API.Controllers.Authentication; -using Govor.Application.Exceptions.AuthService; +using Govor.Application.Authentication.Exceptions; using Govor.Application.Exceptions.InvitesService; using Govor.Application.Interfaces.Authentication; using Govor.Application.Interfaces.UserSession; using Govor.Contracts.Requests; -using Govor.Core.Models; -using Govor.Core.Models.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/ChatLoadControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/ChatLoadControllerTests.cs index bc5fb08..cfaf2bd 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/ChatLoadControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/ChatLoadControllerTests.cs @@ -3,9 +3,10 @@ using AutoMapper; using Govor.API.Controllers; using Govor.Application.Interfaces; using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Messages; using Govor.Contracts.Requests; using Govor.Contracts.Responses; -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/FriendsRequestQueryControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/FriendsRequestQueryControllerTests.cs index 1d2b6c1..2f9b8a1 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/FriendsRequestQueryControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/FriendsRequestQueryControllerTests.cs @@ -4,7 +4,7 @@ using Govor.API.Controllers.Friends; using Govor.Application.Interfaces.Friends; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Contracts.DTOs; -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/FriendshipControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/FriendshipControllerTests.cs index 6d712fb..98eb09e 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/FriendshipControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/FriendshipControllerTests.cs @@ -5,7 +5,7 @@ using Govor.Application.Exceptions.FriendsService; using Govor.Application.Interfaces.Friends; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Contracts.DTOs; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/MediaControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/MediaControllerTests.cs index 0cf8f7e..3e74058 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/MediaControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/MediaControllerTests.cs @@ -4,7 +4,7 @@ using Govor.API.Controllers; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Application.Interfaces.Medias; using Govor.Contracts.Requests; -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/OnlinePingingControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/OnlinePingingControllerTests.cs index 0133572..d99c066 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/OnlinePingingControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/OnlinePingingControllerTests.cs @@ -1,6 +1,7 @@ using Govor.API.Controllers; using Govor.Application.Interfaces; using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.PingHandler; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.API.Tests/IntegrationTests/Controllers/ProfileControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/ProfileControllerTests.cs index 1e73e2d..83653e8 100644 --- a/Govor.API.Tests/IntegrationTests/Controllers/ProfileControllerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Controllers/ProfileControllerTests.cs @@ -8,8 +8,8 @@ using Govor.Application.Interfaces.Medias; using Govor.Application.Profiles; using Govor.Contracts.DTOs; using Govor.Contracts.Requests; -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/Govor.API.Tests/IntegrationTests/Hubs/FriendsHubTests.cs b/Govor.API.Tests/IntegrationTests/Hubs/FriendsHubTests.cs index e0ee94d..c5a2bd0 100644 --- a/Govor.API.Tests/IntegrationTests/Hubs/FriendsHubTests.cs +++ b/Govor.API.Tests/IntegrationTests/Hubs/FriendsHubTests.cs @@ -7,7 +7,7 @@ using Govor.Application.Interfaces.Friends; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Contracts.DTOs; using Govor.Contracts.Responses.SignalR; -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.API.Tests/IntegrationTests/Hubs/Infrastructure/PrivateChatGroupManagerTests.cs b/Govor.API.Tests/IntegrationTests/Hubs/Infrastructure/PrivateChatGroupManagerTests.cs index bf931f4..57c69cc 100644 --- a/Govor.API.Tests/IntegrationTests/Hubs/Infrastructure/PrivateChatGroupManagerTests.cs +++ b/Govor.API.Tests/IntegrationTests/Hubs/Infrastructure/PrivateChatGroupManagerTests.cs @@ -1,7 +1,8 @@ using Govor.API.Hubs; using Govor.API.Hubs.Infrastructure; +using Govor.Application.Infrastructure.Extensions; using Govor.Application.Interfaces; -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.AspNetCore.SignalR; using Moq; diff --git a/Govor.API.Tests/LocalStorageServiceTests.cs b/Govor.API.Tests/LocalStorageServiceTests.cs index aff7ac8..f6be86e 100644 --- a/Govor.API.Tests/LocalStorageServiceTests.cs +++ b/Govor.API.Tests/LocalStorageServiceTests.cs @@ -1,6 +1,5 @@ using AutoFixture; using Govor.Application.Interfaces; -using Govor.Application.Services; using Microsoft.AspNetCore.Hosting; using Moq; diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/ChatGroupValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/ChatGroupValidatorTests.cs index 42986c0..57a0afe 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/ChatGroupValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/ChatGroupValidatorTests.cs @@ -1,6 +1,6 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/FriendshipValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/FriendshipValidatorTests.cs index 2b49311..5d8bf0a 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/FriendshipValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/FriendshipValidatorTests.cs @@ -1,6 +1,6 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationConstantsTests.cs similarity index 94% rename from Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs rename to Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationConstantsTests.cs index 38a7775..bb787f7 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/InvitationConstantsTests.cs @@ -1,18 +1,18 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; [TestFixture] -public class InvitationValidatorTests +public class InvitationConstantsTests { private IObjectValidator _messageValidator; private Fixture _fixture; - public InvitationValidatorTests() + public InvitationConstantsTests() { - _messageValidator = new InvitationValidator(); + _messageValidator = new InvitationConstants(); _fixture = new Fixture(); diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs index 8472243..aa9fb94 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs @@ -1,7 +1,7 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/PrivateChatValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/PrivateChatValidatorTests.cs index 43d54d1..f38c98e 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/PrivateChatValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/PrivateChatValidatorTests.cs @@ -1,6 +1,6 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/UserValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/UserConstantsTests.cs similarity index 96% rename from Govor.API.Tests/UnitTests/Infrastructure/Validators/UserValidatorTests.cs rename to Govor.API.Tests/UnitTests/Infrastructure/Validators/UserConstantsTests.cs index c7d9162..487d1ec 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/UserValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/UserConstantsTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; +using Govor.Domain.Common.Constants; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; namespace Govor.API.Tests.UnitTests.Infrastructure.Validators; [TestFixture] -public class UserValidatorTests +public class UserConstantsTests { private IObjectValidator _userValidator; private Fixture _fixture; @@ -14,7 +14,7 @@ public class UserValidatorTests [SetUp] public void SetUp() { - _userValidator = new UserValidator(); + _userValidator = new UserConstants(); _fixture = new Fixture(); diff --git a/Govor.API/Common/Extensions/AddOptionExtensions.cs b/Govor.API/Common/Extensions/AddOptionExtensions.cs index 060de2b..b31b5cf 100644 --- a/Govor.API/Common/Extensions/AddOptionExtensions.cs +++ b/Govor.API/Common/Extensions/AddOptionExtensions.cs @@ -1,4 +1,4 @@ -using Govor.Application.Services.Authentication; +using Govor.Application.Authentication.JWT; namespace Govor.API.Common.Extensions; diff --git a/Govor.API/Common/Extensions/ConfigurationProgramExtensions.cs b/Govor.API/Common/Extensions/ConfigurationProgramExtensions.cs index 6de6259..f79650d 100644 --- a/Govor.API/Common/Extensions/ConfigurationProgramExtensions.cs +++ b/Govor.API/Common/Extensions/ConfigurationProgramExtensions.cs @@ -1,46 +1,27 @@ using Govor.API.Common.Mapping; using Govor.API.Common.SignalR.Helpers; using Govor.API.Hubs.Infrastructure; +using Govor.Application.Authentication; +using Govor.Application.Authentication.JWT; +using Govor.Application.Friends; +using Govor.Application.Groups; using Govor.Application.Infrastructure.AdminsStuff; using Govor.Application.Infrastructure.Extensions; using Govor.Application.Infrastructure.Validators; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Authentication; -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.Medias; -using Govor.Application.Interfaces.Messages; -using Govor.Application.Interfaces.PushNotifications; -using Govor.Application.Interfaces.UserOnlineStatus; -using Govor.Application.Interfaces.UserSession; -using Govor.Application.Interfaces.UserSession.Crypto; -using Govor.Application.Services; -using Govor.Application.Services.Authentication; -using Govor.Application.Services.Friends; -using Govor.Application.Services.Medias; -using Govor.Application.Services.Messages; -using Govor.Application.Services.PushNotifications; -using Govor.Application.Services.PushNotifications.Providers; -using Govor.Application.Services.UserOnlineStatus; -using Govor.Application.Services.UserSessions; -using Govor.Application.Services.UserSessions.Crypto; -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Admins; -using Govor.Core.Repositories.Friendships; -using Govor.Core.Repositories.Groups; -using Govor.Core.Repositories.Invaites; -using Govor.Core.Repositories.MediasAttachments; -using Govor.Core.Repositories.Messages; -using Govor.Core.Repositories.PrivateChats; -using Govor.Core.Repositories.PushTokens; -using Govor.Core.Repositories.Users; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data; -using Govor.Data.Repositories; +using Govor.Application.Medias; +using Govor.Application.Messages; +using Govor.Application.PingHandler; +using Govor.Application.PrivateUserChats; +using Govor.Application.Profiles; +using Govor.Application.PushNotifications; +using Govor.Application.PushNotifications.Providers; +using Govor.Application.Storage; +using Govor.Application.Synching; +using Govor.Application.Users; +using Govor.Application.Users.UserOnlineStatus; +using Govor.Application.Users.UserSessions; +using Govor.Application.Users.UserSessions.Crypto; +using Govor.Domain; using Microsoft.EntityFrameworkCore; namespace Govor.API.Common.Extensions; @@ -56,6 +37,7 @@ public static class ConfigurationProgramExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -80,7 +62,10 @@ public static class ConfigurationProgramExtensions services.AddScoped(); - services.AddScoped(); + //services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -88,6 +73,9 @@ public static class ConfigurationProgramExtensions services.AddScoped(); services.AddScoped(); + // User + services.AddScoped(); + // UserSession services.AddScoped(); services.AddScoped(); @@ -104,6 +92,7 @@ public static class ConfigurationProgramExtensions services.AddSingleton(); // Pushs + services.AddScoped(); services.AddScoped(); services.AddSingleton(); @@ -122,34 +111,7 @@ public static class ConfigurationProgramExtensions services.AddScoped(); } - - public static void AddRepositories(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - // other - } - - public static void AddValidators(this IServiceCollection services) - { - services.AddScoped, UserValidator>(); - services.AddScoped, MessageValidator>(); - services.AddScoped, MediaAttachmentsValidator>(); - services.AddScoped, AdminValidator>(); - services.AddScoped, InvitationValidator>(); - services.AddScoped, FriendshipValidator>(); - services.AddScoped, PrivateChatValidator>(); - services.AddScoped, ChatGroupValidator>(); - } - + public static void AddGovorDbContext(this IServiceCollection services, IConfiguration configuration) { var useMySql = configuration.GetValue("UseMySql"); diff --git a/Govor.API/Common/Mapping/MappingProfile.cs b/Govor.API/Common/Mapping/MappingProfile.cs index 4ad619d..0921426 100644 --- a/Govor.API/Common/Mapping/MappingProfile.cs +++ b/Govor.API/Common/Mapping/MappingProfile.cs @@ -1,11 +1,10 @@ using AutoMapper; -using Govor.API.Extensions.Mapping; using Govor.Application.Profiles; using Govor.Contracts.DTOs; using Govor.Contracts.Responses; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Models.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain.Models.Users; namespace Govor.API.Common.Mapping; diff --git a/Govor.API/Common/Mapping/UserProfileToUserProfileDtoMappingAction.cs b/Govor.API/Common/Mapping/UserProfileToUserProfileDtoMappingAction.cs index 2a7be87..01d57e1 100644 --- a/Govor.API/Common/Mapping/UserProfileToUserProfileDtoMappingAction.cs +++ b/Govor.API/Common/Mapping/UserProfileToUserProfileDtoMappingAction.cs @@ -1,8 +1,7 @@ using AutoMapper; -using Govor.Application.Interfaces.UserOnlineStatus; using Govor.Application.Profiles; +using Govor.Application.Users.UserOnlineStatus; using Govor.Contracts.DTOs; -using Govor.Core.Models.Users; namespace Govor.API.Common.Mapping; diff --git a/Govor.API/Common/Mapping/UserToUserDtoMappingAction.cs b/Govor.API/Common/Mapping/UserToUserDtoMappingAction.cs index c915fb3..c90ee9b 100644 --- a/Govor.API/Common/Mapping/UserToUserDtoMappingAction.cs +++ b/Govor.API/Common/Mapping/UserToUserDtoMappingAction.cs @@ -1,9 +1,9 @@ using AutoMapper; -using Govor.Application.Interfaces.UserOnlineStatus; +using Govor.Application.Users.UserOnlineStatus; using Govor.Contracts.DTOs; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.API.Extensions.Mapping; +namespace Govor.API.Common.Mapping; public class UserToUserDtoMappingAction : IMappingAction { diff --git a/Govor.API/Controllers/AdminStuff/FriendshipsController.cs b/Govor.API/Controllers/AdminStuff/FriendshipsController.cs index 94b5225..2a0e85b 100644 --- a/Govor.API/Controllers/AdminStuff/FriendshipsController.cs +++ b/Govor.API/Controllers/AdminStuff/FriendshipsController.cs @@ -1,8 +1,3 @@ -using Govor.Contracts.DTOs; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Friendships; -using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -14,14 +9,8 @@ namespace Govor.API.Controllers.AdminStuff; public class FriendshipsController : Controller { private readonly ILogger _logger; - private readonly IFriendshipsRepository _friendshipsRepository; - public FriendshipsController(ILogger logger, IFriendshipsRepository friendshipsRepository) - { - _logger = logger; - _friendshipsRepository = friendshipsRepository; - } - + /* [HttpGet] public async Task Get() { @@ -88,5 +77,5 @@ public class FriendshipsController : Controller _logger.LogError(ex, ex.Message); return StatusCode(500, new { error = "Internal server error." }); } - } + }*/ } \ No newline at end of file diff --git a/Govor.API/Controllers/AdminStuff/InviteUserController.cs b/Govor.API/Controllers/AdminStuff/InviteUserController.cs index 204ae79..d55043f 100644 --- a/Govor.API/Controllers/AdminStuff/InviteUserController.cs +++ b/Govor.API/Controllers/AdminStuff/InviteUserController.cs @@ -1,8 +1,6 @@ -using Govor.Application.Interfaces; +using Govor.Application.Infrastructure.AdminsStuff; using Govor.Contracts.DTOs; using Govor.Contracts.Requests; -using Govor.Core.Repositories.Invaites; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Govor.API.Controllers.AdminStuff; @@ -12,17 +10,17 @@ namespace Govor.API.Controllers.AdminStuff; //[Authorize(Roles = "Admin")] public class InviteUserController : Controller { - private readonly IInvitesRepository _repository; + private readonly IInvitationGetter _invitationGetter; private readonly IInvitationGenerator _invitationGenerator; private readonly ILogger _logger; public InviteUserController(IInvitationGenerator invitationGenerator, - IInvitesRepository repository, + IInvitationGetter invitationGetter, ILogger logger) { _invitationGenerator = invitationGenerator; _logger = logger; - _repository = repository; + _invitationGetter = invitationGetter; } [HttpPost("[action]")] @@ -51,7 +49,7 @@ public class InviteUserController : Controller { _logger.LogInformation("Getting all active invitations by administrator"); - var read = await _repository.GetAllAsync(); + var read = await _invitationGetter.GetAllAsync(); var result = read.Where(x => x.IsActive).ToList(); List dtos = new List(); @@ -86,7 +84,7 @@ public class InviteUserController : Controller try { _logger.LogInformation("Getting all invitations by administrator"); - var read = await _repository.GetAllAsync(); + var read = await _invitationGetter.GetAllAsync(); List dtos = new List(); @@ -120,18 +118,22 @@ public class InviteUserController : Controller try { _logger.LogInformation("Getting invitations {id} by administrator"); - var read = await _repository.FindByIdAsync(id); + var read = await _invitationGetter.FindByIdAsync(id); + + if(read.IsFailure) + return NotFound(read.Error); + var dto = read.Value; var response = new InvitationResponses(){ - Id = read.Id, - Description = read.Description, - IsAdmin = read.IsAdmin, - MaxParticipants = read.MaxParticipants, - Code = read.Code, - CreatedAt = read.DateCreated, - EndAt = read.EndDate, - IsActive = read.IsActive, - ParticipantCount = read.Users.Count, + Id = dto.Id, + Description = dto.Description, + IsAdmin = dto.IsAdmin, + MaxParticipants = dto.MaxParticipants, + Code = dto.Code, + CreatedAt = dto.DateCreated, + EndAt = dto.EndDate, + IsActive = dto.IsActive, + ParticipantCount = dto.Users.Count, }; return Ok(response); diff --git a/Govor.API/Controllers/AdminStuff/UsersController.cs b/Govor.API/Controllers/AdminStuff/UsersController.cs index 7440264..0a60b3d 100644 --- a/Govor.API/Controllers/AdminStuff/UsersController.cs +++ b/Govor.API/Controllers/AdminStuff/UsersController.cs @@ -1,10 +1,7 @@ -using Govor.Application.Interfaces; +using Govor.Application.Infrastructure.AdminsStuff; using Govor.Contracts.Responses.Admins; -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Models.Users; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Models.Users; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace Govor.API.Controllers.AdminStuff; @@ -54,11 +51,6 @@ public class UsersController : Controller var read = await _users.GetUserById(id); return Ok(BuildUserDtos([read]).First()); } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(ex.Message); - } catch (Exception e) { _logger.LogError(e, e.Message); diff --git a/Govor.API/Controllers/Authentication/AuthController.cs b/Govor.API/Controllers/Authentication/AuthController.cs index 897803f..f1c7fa8 100644 --- a/Govor.API/Controllers/Authentication/AuthController.cs +++ b/Govor.API/Controllers/Authentication/AuthController.cs @@ -1,7 +1,6 @@ -using Govor.Application.Exceptions.AuthService; -using Govor.Application.Exceptions.InvitesService; -using Govor.Application.Interfaces.Authentication; -using Govor.Application.Interfaces.UserSession; +using Govor.Application.Authentication; +using Govor.Application.Authentication.Exceptions; +using Govor.Application.Users.UserSessions; using Govor.Contracts.Requests; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -29,83 +28,84 @@ public class AuthController : Controller _invitesService = invitesService; _logger = logger; } - - //[RequireHttps] - [HttpPost("register")]// api/auth/register + + [HttpPost("register")] // api/auth/register public async Task Register([FromBody] RegistrationRequest registrationRequest) { - try + + var inviteResult = await _invitesService.ValidateAsync(registrationRequest.InviteLink); + if (!inviteResult.IsSuccess) { - if (!ModelState.IsValid) - return BadRequest(ModelState); + _logger.LogWarning("Invite link invalid: {InviteLink}. Error: {Error}", registrationRequest.InviteLink, + inviteResult.Error); + return BadRequest($"Invite link invalid: {inviteResult.Error.Message}"); + } + + var userResult = await _accountService.RegistrationAsync( + registrationRequest.Name, + registrationRequest.Password, + inviteResult.Value); - var invite = await _invitesService.ValidateAsync(registrationRequest.InviteLink); + if (userResult.IsFailure) + { + _logger.LogWarning("Registration failed for user {Name}. Error: {Error}", registrationRequest.Name, + userResult.Error); + + return userResult.Error.Code switch + { + nameof(UserAlreadyExistException) => BadRequest($"Registration failed: {userResult.Error.Message}"), + nameof(InvalidUsernameException) => BadRequest($"Invalid username: {userResult.Error.Message}"), + _ => BadRequest($"Registration failed: {userResult.Error.Message}") + }; + } - var user = await _accountService.RegistrationAsync(registrationRequest.Name, registrationRequest.Password, - invite); - - _logger.LogInformation($"Register request for {user.Username} with id {user.Id} processed successfully"); + var user = userResult.Value; + _logger.LogInformation("Register request for {Username} with id {Id} processed successfully", user.Username, + user.Id); + + var sessionResult = await _userSession.OpenSessionAsync(user, registrationRequest.DeviceInfo); + if (sessionResult.IsFailure) + { + _logger.LogError("Failed to open session for user {Username}. Error: {Error}", user.Username, + sessionResult.Error.Message); + return StatusCode(500, "An error occurred while creating the session."); + } - var tokens = await _userSession.OpenSessionAsync(user, registrationRequest.DeviceInfo); - - _logger.LogInformation($"Session for user {user.Username} with id {user.Id} has been opened"); - - return Ok(tokens); - } - catch (UserAlreadyExistException ex) - { - _logger.LogWarning(ex, $"Registration failed for user {registrationRequest.Name}"); - return BadRequest("Registration failed: user already exists."); - } - catch (InviteLinkInvalidException ex) - { - _logger.LogWarning(ex, $"Invite link invalid: {registrationRequest.InviteLink}"); - return BadRequest("Invite link invalid."); - } - catch (InvalidUsernameException ex) - { - _logger.LogWarning(ex, $"Invalid username: {registrationRequest.Name}"); - return BadRequest($"Invalid username: {ex.Message}"); - } - catch (Exception ex) - { - _logger.LogError(ex, "Unexpected error during registration for user {Name}", registrationRequest.Name); - return StatusCode(500, "An unexpected error occurred. Please try again later."); - } + _logger.LogInformation("Session for user {Username} with id {Id} has been opened", user.Username, user.Id); + return Ok(sessionResult.Value); } + - //[RequireHttps] - [HttpPost("login")]// api/auth/login + [HttpPost("login")] // api/auth/login public async Task Login([FromBody] LoginRequest loginRequest) { - try + var userResult = await _accountService.LoginAsync(loginRequest.Name, loginRequest.Password); + + if (userResult.IsFailure) { - if (!ModelState.IsValid) - return BadRequest(ModelState); - - var user = await _accountService.LoginAsync(loginRequest.Name, loginRequest.Password); - _logger.LogInformation($"Login request for {user.Username} with id {user.Id} processed successfully"); + _logger.LogWarning("Login failed for user {Name}. Error: {Code}", loginRequest.Name, userResult.Error); - var tokens = await _userSession.OpenSessionAsync(user, loginRequest.DeviceInfo); - - _logger.LogInformation($"Session for user {user.Username} with id {user.Id} has been opened"); - - return Ok(tokens); + return userResult.Error.Code switch + { + nameof(UserNotRegisteredException) => BadRequest("Login failed: user does not exist."), + nameof(InvalidOperationException) => BadRequest("Login failed: username or password is incorrect."), + _ => BadRequest($"Login failed: {userResult.Error.Message}") + }; } - catch (UserNotRegisteredException ex) + + var user = userResult.Value; + _logger.LogInformation("Login request for {Username} with id {Id} processed successfully", user.Username, user.Id); + + var sessionResult = await _userSession.OpenSessionAsync(user, loginRequest.DeviceInfo); + + if (sessionResult.IsFailure) { - _logger.LogWarning(ex, "Login failed for user {Name}", loginRequest.Name); - return BadRequest("Login failed: user does not exist."); - } - catch (LoginUserException ex) - { - _logger.LogWarning(ex, "Login failed for user {Name}", loginRequest.Name); - return BadRequest("Login failed: username or password is incorrect."); - } - catch (Exception ex) - { - _logger.LogError(ex, "Unexpected error during login for user {Name}", loginRequest.Name); - return StatusCode(500, "An unexpected error occurred. Please try again later."); + _logger.LogError("Failed to open session for user {Username}. Error: {Error}", user.Username, sessionResult.Error); + return StatusCode(500, "An error occurred while creating the session."); } + + _logger.LogInformation("Session for user {Username} with id {Id} has been opened", user.Username, user.Id); + + return Ok(sessionResult.Value); } } \ No newline at end of file diff --git a/Govor.API/Controllers/Authentication/RefreshController.cs b/Govor.API/Controllers/Authentication/RefreshController.cs index ebf95c1..68e81fd 100644 --- a/Govor.API/Controllers/Authentication/RefreshController.cs +++ b/Govor.API/Controllers/Authentication/RefreshController.cs @@ -1,4 +1,4 @@ -using Govor.Application.Interfaces.UserSession; +using Govor.Application.Users.UserSessions; using Govor.Contracts.Requests; using Govor.Contracts.Responses; using Microsoft.AspNetCore.Authorization; @@ -13,7 +13,7 @@ public class RefreshController : Controller { private readonly ILogger _logger; private readonly IUserSessionRefresher _userSession; - + public RefreshController( ILogger logger, IUserSessionRefresher userSession) @@ -21,41 +21,35 @@ public class RefreshController : Controller _logger = logger; _userSession = userSession; } - + //[RequireHttps] [HttpPost("refresh")] // api/auth/token/refresh public async Task Refresh([FromBody] RefreshTokenRequest refreshRequest) { - try + if (string.IsNullOrWhiteSpace(refreshRequest.RefreshToken)) { - if (!ModelState.IsValid) - return BadRequest(ModelState); - - if (string.IsNullOrEmpty(refreshRequest.RefreshToken)) - throw new InvalidOperationException("Refresh token cant be empty."); - - var result = await _userSession.RefreshTokenAsync(refreshRequest.RefreshToken); + _logger.LogWarning("Refresh request failed: token is empty."); + return BadRequest("Refresh token can't be empty."); + } + + var result = await _userSession.RefreshTokenAsync(refreshRequest.RefreshToken); - return Ok(new RefreshTokenResponse() - { - AccessToken = result.accessToken, - RefreshToken = result.refreshToken - }); - } - catch (InvalidOperationException ex) + if (result.IsFailure) { - _logger.LogWarning(ex, "Invalid refresh token."); - return BadRequest(ex.Message); + _logger.LogWarning("Refresh token failed. Error Code: {Code}", result.Error.Code); + + return result.Error.Code switch + { + "Auth.EmptyToken" => BadRequest(result.Error.Message), + "Auth.InvalidToken" => Unauthorized(result.Error.Message), + _ => BadRequest($"Refresh failed: {result.Error.Message}") + }; } - catch (UnauthorizedAccessException ex) + + return Ok(new RefreshTokenResponse { - _logger.LogWarning(ex, "Refresh token failed."); - return Unauthorized("Invalid refresh token"); - } - catch (Exception ex) - { - _logger.LogError(ex, ex.Message); - return StatusCode(500, "An unexpected error occurred."); - } + AccessToken = result.Value.accessToken, + RefreshToken = result.Value.refreshToken + }); } } \ No newline at end of file diff --git a/Govor.API/Controllers/Authentication/SessionKeysController.cs b/Govor.API/Controllers/Authentication/SessionKeysController.cs index 77929ec..4f6558e 100644 --- a/Govor.API/Controllers/Authentication/SessionKeysController.cs +++ b/Govor.API/Controllers/Authentication/SessionKeysController.cs @@ -1,7 +1,6 @@ -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserSession; -using Govor.Application.Interfaces.UserSession.Crypto; +using Govor.Application.Friends; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.Users.UserSessions.Crypto; using Govor.Contracts.Requests; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/Govor.API/Controllers/ChatLoadController.cs b/Govor.API/Controllers/ChatLoadController.cs index e4be8b9..550a8ce 100644 --- a/Govor.API/Controllers/ChatLoadController.cs +++ b/Govor.API/Controllers/ChatLoadController.cs @@ -1,9 +1,8 @@ using AutoMapper; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.Messages; using Govor.Contracts.Requests; using Govor.Contracts.Responses; -using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -52,16 +51,6 @@ public class ChatLoadController : Controller return Ok(response); } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex.Message); - return Forbid(ex.Message); - } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return BadRequest(ex.Message); - } catch (ArgumentException ex) { _logger.LogWarning(ex, ex.Message); @@ -95,21 +84,6 @@ public class ChatLoadController : Controller return Ok(response); } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, ex.Message); - return BadRequest(ex.Message); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex.Message); - return Forbid(ex.Message); - } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return BadRequest(ex.Message); - } catch (ArgumentException ex) { _logger.LogWarning(ex, ex.Message); diff --git a/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs b/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs index 542ee89..2d1d367 100644 --- a/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs +++ b/Govor.API/Controllers/Friends/FriendsRequestQueryController.cs @@ -1,8 +1,7 @@ using AutoMapper; -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Friends; +using Govor.Application.Infrastructure.Extensions; using Govor.Contracts.DTOs; -using Govor.Core.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -41,16 +40,6 @@ public class FriendsRequestQueryController : Controller return Ok(response); } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, ex.Message); - return Ok(new List()); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex, ex.Message); - return Forbid(ex.Message); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); @@ -72,16 +61,6 @@ public class FriendsRequestQueryController : Controller return Ok(response); } - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, ex.Message); - return Ok(new List()); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogWarning(ex, ex.Message); - return Forbid(ex.Message); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); diff --git a/Govor.API/Controllers/Friends/FriendshipController.cs b/Govor.API/Controllers/Friends/FriendshipController.cs index 25c0065..d375717 100644 --- a/Govor.API/Controllers/Friends/FriendshipController.cs +++ b/Govor.API/Controllers/Friends/FriendshipController.cs @@ -1,9 +1,7 @@ using AutoMapper; -using Govor.Application.Exceptions.FriendsService; -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Friends; +using Govor.Application.Infrastructure.Extensions; using Govor.Contracts.DTOs; -using Govor.Core.Models.Users; using Microsoft.AspNetCore.Mvc; namespace Govor.API.Controllers.Friends; diff --git a/Govor.API/Controllers/InviteController.cs b/Govor.API/Controllers/InviteController.cs index 26ff900..e7de645 100644 --- a/Govor.API/Controllers/InviteController.cs +++ b/Govor.API/Controllers/InviteController.cs @@ -1,5 +1,5 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Groups; +using Govor.Application.Infrastructure.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/Govor.API/Controllers/MediaController.cs b/Govor.API/Controllers/MediaController.cs index 6c0a870..d6ab259 100644 --- a/Govor.API/Controllers/MediaController.cs +++ b/Govor.API/Controllers/MediaController.cs @@ -1,7 +1,7 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.Medias; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.Medias; using Govor.Contracts.Requests; -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/Govor.API/Controllers/OnlinePingingController.cs b/Govor.API/Controllers/OnlinePingingController.cs index 0a58dfc..001ce34 100644 --- a/Govor.API/Controllers/OnlinePingingController.cs +++ b/Govor.API/Controllers/OnlinePingingController.cs @@ -1,6 +1,6 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserOnlineStatus; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.PingHandler; +using Govor.Application.Users.UserOnlineStatus; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -40,16 +40,6 @@ public class OnlinePingingController : Controller _logger.LogInformation($"Ping from user {id} processed successfully"); return Ok(); } - catch (InvalidOperationException e) - { - _logger.LogError(e, e.Message); - return BadRequest("User can't be found in our database."); - } - catch (UnauthorizedAccessException e) - { - _logger.LogError(e, e.Message); - return Forbid(e.Message); - } catch (Exception e) { _logger.LogError(e, e.Message); diff --git a/Govor.API/Controllers/PrivateChatController.cs b/Govor.API/Controllers/PrivateChatController.cs index 7efc26f..da3873f 100644 --- a/Govor.API/Controllers/PrivateChatController.cs +++ b/Govor.API/Controllers/PrivateChatController.cs @@ -1,10 +1,9 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Exceptions.VerifyFriendship; +using Govor.Application.Friends; +using Govor.Application.Infrastructure.AdminsStuff; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.PrivateUserChats; using Govor.Contracts.DTOs; -using Govor.Core.Models; -using Govor.Core.Repositories.PrivateChats; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -16,7 +15,6 @@ namespace Govor.API.Controllers; public class PrivateChatController : Controller { private readonly ICurrentUserService _currentUser; - private readonly IUsersRepository _usersRepository; private readonly IVerifyFriendship _verifyFriendship; private readonly IUserPrivateChatsCreator _userPrivateChatsCreator; private readonly IUserPrivateChatsGetterService _privateChatsGetter; @@ -24,15 +22,12 @@ public class PrivateChatController : Controller public PrivateChatController( ICurrentUserService currentUser, - IUsersRepository usersRepository, IVerifyFriendship verifyFriendship, - IPrivateChatsRepository privateChats, IUserPrivateChatsCreator userPrivateChatsCreator, IUserPrivateChatsGetterService userPrivateChatsGetterService, ILogger logger) { _currentUser = currentUser; - _usersRepository = usersRepository; _verifyFriendship = verifyFriendship; _userPrivateChatsCreator = userPrivateChatsCreator; _privateChatsGetter = userPrivateChatsGetterService; @@ -46,14 +41,8 @@ public class PrivateChatController : Controller { var currentId = _currentUser.GetCurrentUserId(); - if (!await _usersRepository.ExistsByIdAsync(friendId)) - { - _logger.LogWarning("User not exist {0}", friendId); - return NotFound("User not exist."); - } - await _verifyFriendship.VerifyAsync(currentId, friendId); - + var chat = await _userPrivateChatsCreator.CreateAsync(currentId, friendId); return Ok(chat.Id); } @@ -62,16 +51,16 @@ public class PrivateChatController : Controller _logger.LogWarning(ex.Message); return Forbid(ex.Message); } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return BadRequest(ex.Message); - } catch (ArgumentException ex) { _logger.LogWarning(ex, ex.Message); return BadRequest(ex.Message); } + catch (FriendshipException ex) + { + _logger.LogWarning(ex, ex.Message); + return Forbid(ex.Message); + } catch (Exception ex) { _logger.LogError(ex, ex.Message); diff --git a/Govor.API/Controllers/ProfileController.cs b/Govor.API/Controllers/ProfileController.cs index a58f72e..0f45836 100644 --- a/Govor.API/Controllers/ProfileController.cs +++ b/Govor.API/Controllers/ProfileController.cs @@ -1,12 +1,11 @@ using AutoMapper; using Govor.API.Hubs; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.Medias; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.Medias; +using Govor.Application.Profiles; using Govor.Contracts.DTOs; using Govor.Contracts.Requests; -using Govor.Core.Models; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; @@ -91,8 +90,12 @@ public class ProfileController : ControllerBase try { var userId = _currentUserService.GetCurrentUserId(); - var user = await _profileService.GetUserProfileAsync(userId); + var result = await _profileService.GetUserProfileAsync(userId); + if(result.IsFailure) + return NotFound(result.Error); + + var user = result.Value; var dto = _mapper.Map(user); return Ok(dto); } @@ -101,11 +104,6 @@ public class ProfileController : ControllerBase _logger.LogWarning(ex.Message); return Forbid(ex.Message); } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound("Profile not found"); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); @@ -128,11 +126,6 @@ public class ProfileController : ControllerBase _logger.LogWarning(ex.Message); return Forbid(ex.Message); } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound("Profile not found"); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); diff --git a/Govor.API/Controllers/PushTokensController.cs b/Govor.API/Controllers/PushTokensController.cs index 9577d29..2b53ae4 100644 --- a/Govor.API/Controllers/PushTokensController.cs +++ b/Govor.API/Controllers/PushTokensController.cs @@ -1,6 +1,6 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.PushNotifications; using Govor.Contracts.Requests; -using Govor.Core.Repositories.PushTokens; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -13,15 +13,15 @@ public class PushTokensController : Controller { private readonly ICurrentUserService _currentUser; private readonly ICurrentUserSessionService _currentSession; - private readonly IPushTokenRepository _pushTokenRepo; + private readonly IPushTokenService _pushTokenService; public PushTokensController( + IPushTokenService pushTokenService, ICurrentUserService currentUser, - ICurrentUserSessionService currentSession, - IPushTokenRepository pushTokenRepository) + ICurrentUserSessionService currentSession) { + _pushTokenService = pushTokenService; _currentUser = currentUser; - _pushTokenRepo = pushTokenRepository; _currentSession = currentSession; } @@ -39,7 +39,7 @@ public class PushTokensController : Controller var currentId = _currentUser.GetCurrentUserId(); var currentSessionId = _currentSession.GetUserSessionId(); - await _pushTokenRepo.AddOrUpdateTokenAsync( + await _pushTokenService.AddOrUpdateTokenAsync( userId: currentId, sessionId: currentSessionId, token: req.Token, diff --git a/Govor.API/Controllers/SessionController.cs b/Govor.API/Controllers/SessionController.cs index f68b91b..7aacee4 100644 --- a/Govor.API/Controllers/SessionController.cs +++ b/Govor.API/Controllers/SessionController.cs @@ -1,9 +1,7 @@ using AutoMapper; -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserSession; +using Govor.Application.Infrastructure.Extensions; +using Govor.Application.Users.UserSessions; using Govor.Contracts.DTOs; -using Govor.Core.Repositories.PushTokens; -using Govor.Data.Repositories.Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -43,7 +41,11 @@ public class SessionController : Controller try { var sessions = await _userSessionReader.GetAllSessionsAsync(_currentUserService.GetCurrentUserId()); - return Ok(_mapper.Map>(sessions)); + + if(sessions.IsFailure) + return NotFound(sessions.Error); + + return Ok(_mapper.Map>(sessions.Value)); } catch (UnauthorizedAccessException ex) { @@ -65,8 +67,12 @@ public class SessionController : Controller if (sessionId == Guid.Empty) return BadRequest("Invalid sessionId."); - await _userSessionRevoker.CloseSessionByIdAsync(sessionId, + var res = await _userSessionRevoker.CloseSessionByIdAsync(sessionId, _currentUserService.GetCurrentUserId()); + + if (res.IsFailure) + return BadRequest(res.Error); + return Ok(); } catch (InvalidOperationException ex) @@ -79,11 +85,6 @@ public class SessionController : Controller _logger.LogWarning(ex, ex.Message); return Forbid(ex.Message); } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(ex.Message); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); @@ -96,11 +97,14 @@ public class SessionController : Controller { try { - await _userSessionRevoker.CloseSessionByIdAsync( + var res = await _userSessionRevoker.CloseSessionByIdAsync( _currentUserSessionService.GetUserSessionId(), _currentUserService.GetCurrentUserId()); - - return Ok(); + + if(res.IsFailure) + return NotFound(res.Error); + + return Ok(); } catch (InvalidOperationException ex) { @@ -112,11 +116,6 @@ public class SessionController : Controller _logger.LogWarning(ex, ex.Message); return Forbid(ex.Message); } - catch (NotFoundException ex) - { - _logger.LogWarning(ex, ex.Message); - return NotFound(ex.Message); - } catch (Exception ex) { _logger.LogError(ex, ex.Message); @@ -129,7 +128,11 @@ public class SessionController : Controller { try { - await _userSessionRevoker.CloseAllSessionsAsync(_currentUserService.GetCurrentUserId()); + var res = await _userSessionRevoker.CloseAllSessionsAsync(_currentUserService.GetCurrentUserId()); + + if(res.IsFailure) + return NotFound(res.Error); + return Ok(); } catch (UnauthorizedAccessException ex) diff --git a/Govor.API/Filters/HubExceptionFilter.cs b/Govor.API/Filters/HubExceptionFilter.cs index fa814fb..f11b6ef 100644 --- a/Govor.API/Filters/HubExceptionFilter.cs +++ b/Govor.API/Filters/HubExceptionFilter.cs @@ -70,7 +70,6 @@ public class HubExceptionFilter : IHubFilter } } - // Ничего не возвращаем, если не поддерживается return null; } } \ No newline at end of file diff --git a/Govor.API/Govor.API.csproj b/Govor.API/Govor.API.csproj index 76f5525..c109986 100644 --- a/Govor.API/Govor.API.csproj +++ b/Govor.API/Govor.API.csproj @@ -24,10 +24,7 @@ - - - - + diff --git a/Govor.API/Hubs/ChatsHub.cs b/Govor.API/Hubs/ChatsHub.cs index e9136fa..02bb92c 100644 --- a/Govor.API/Hubs/ChatsHub.cs +++ b/Govor.API/Hubs/ChatsHub.cs @@ -1,11 +1,11 @@ using Govor.API.Common.SignalR.Helpers; using Govor.API.Hubs.Infrastructure; using Govor.Application.Exceptions.VerifyFriendship; -using Govor.Application.Interfaces.Messages; -using Govor.Application.Interfaces.Messages.Parameters; +using Govor.Application.Messages; +using Govor.Application.Messages.Parameters; using Govor.Contracts.Requests.SignalR; using Govor.Contracts.Responses.SignalR; -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; @@ -15,20 +15,24 @@ namespace Govor.API.Hubs; public class ChatsHub : Hub { private readonly ILogger _logger; - private readonly IMessageCommandService _commandService; + private readonly IMessageSendingService _messageSendingService; + private readonly IMessageEditingService _messageEditingService; + private readonly IMessageRemovingService _messageRemovingService; private readonly IHubUserAccessor _userAccessor; private readonly IChatNotificationService _notifier; private readonly IConnectionManager _connectionManager; - public ChatsHub( - ILogger logger, - IMessageCommandService commandService, + + public ChatsHub(ILogger logger, + IMessageSendingService messageSendingService, + IMessageEditingService messageEditingService, IHubUserAccessor userAccessor, IChatNotificationService notifier, IConnectionManager connectionManager) { _logger = logger; - _commandService = commandService; + _messageSendingService = messageSendingService; + _messageEditingService = messageEditingService; _userAccessor = userAccessor; _notifier = notifier; _connectionManager = connectionManager; @@ -69,7 +73,7 @@ public class ChatsHub : Hub ValidateMessageRequest(request); var sendParams = MapToSendMessage(request, userId); - var result = await _commandService.SendMessageAsync(sendParams); + var result = await _messageSendingService.SendMessageAsync(sendParams); if (!result.IsSuccess) throw new InvalidOperationException(result.Exception.Message ?? "Failed to send message"); @@ -87,7 +91,7 @@ public class ChatsHub : Hub { return await SafeExecute(async (userId) => { - var result = await _commandService.DeleteMessageAsync(new DeleteMessage(userId, request.MessageId)); + var result = await _messageRemovingService.DeleteMessageAsync(new DeleteMessage(userId, request.MessageId)); if (!result.IsSuccess || result.OriginalMessage == null) throw new InvalidOperationException("Message deletion failed"); @@ -112,7 +116,7 @@ public class ChatsHub : Hub return await SafeExecute(async (userId) => { var editParams = new EditMessage(userId, request.MessageId, request.NewEncryptedContent, DateTime.UtcNow); - var result = await _commandService.EditMessageAsync(editParams); + var result = await _messageEditingService.EditMessageAsync(editParams); if (!result.IsSuccess || result.OriginalMessage == null) throw new InvalidOperationException("Edit message error"); diff --git a/Govor.API/Hubs/FriendsHub.cs b/Govor.API/Hubs/FriendsHub.cs index 87b1a36..9871926 100644 --- a/Govor.API/Hubs/FriendsHub.cs +++ b/Govor.API/Hubs/FriendsHub.cs @@ -1,7 +1,7 @@ using AutoMapper; using Govor.API.Common.SignalR.Helpers; using Govor.Application.Exceptions.FriendsService; -using Govor.Application.Interfaces.Friends; +using Govor.Application.Friends; using Govor.Contracts.DTOs; using Govor.Contracts.Responses.SignalR; using Microsoft.AspNetCore.SignalR; @@ -76,7 +76,12 @@ public class FriendsHub : Hub try { var userId = _userAccessor.GetUserId(Context); - var friendship = await _friendRequestService.SendAsync(userId, targetUserId); + var result = await _friendRequestService.SendAsync(userId, targetUserId); + + if(result.IsFailure) + return HubResult.Error(result.Error.ToString()); + + var friendship = result.Value; var dto = _mapper.Map(friendship); await Clients.Group(targetUserId.ToString()) @@ -115,7 +120,13 @@ public class FriendsHub : Hub try { var userId = _userAccessor.GetUserId(Context); - var friendship = await _friendRequestService.AcceptAsync(friendshipId, userId); + var result = await _friendRequestService.AcceptAsync(friendshipId, userId); + + if(result.IsFailure) + return HubResult.BadRequest(result.Error.ToString()); + + var friendship = result.Value; + var dto = _mapper.Map(friendship); await Clients.Group(userId.ToString()) @@ -149,7 +160,13 @@ public class FriendsHub : Hub try { var userId = _userAccessor.GetUserId(Context); - var friendship = await _friendRequestService.RejectAsync(friendshipId, userId); + var result = await _friendRequestService.RejectAsync(friendshipId, userId); + + if(result.IsFailure) + return HubResult.BadRequest(result.Error.ToString()); + + var friendship = result.Value; + var dto = _mapper.Map(friendship); await Clients.Group(userId.ToString()) diff --git a/Govor.API/Hubs/Infrastructure/ChatNotificationService.cs b/Govor.API/Hubs/Infrastructure/ChatNotificationService.cs index fa0cf3e..b9a2428 100644 --- a/Govor.API/Hubs/Infrastructure/ChatNotificationService.cs +++ b/Govor.API/Hubs/Infrastructure/ChatNotificationService.cs @@ -1,9 +1,8 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.PushNotifications; +using Govor.Application.PrivateUserChats; +using Govor.Application.Profiles; +using Govor.Application.PushNotifications; using Govor.Contracts.Responses.SignalR; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.PrivateChats; -using Govor.Core.Repositories.PushTokens; +using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.SignalR; namespace Govor.API.Hubs.Infrastructure; @@ -11,19 +10,20 @@ namespace Govor.API.Hubs.Infrastructure; public class ChatNotificationService : IChatNotificationService { private readonly IHubContext _hubContext; - private readonly IPrivateChatsRepository _privateChatsRepository; private readonly IPushNotificationService _notificationService; + private readonly IUserPrivateChatsGetterService _userPrivateChatsGetterService; private readonly IProfileService _profileService; + public ChatNotificationService( - IProfileService profileService, - IHubContext hubContext, + IHubContext hubContext, IPushNotificationService notificationService, - IPrivateChatsRepository privateChatsRepository) + IUserPrivateChatsGetterService userPrivateChatsGetterService, + IProfileService profileService) { _hubContext = hubContext; - _profileService = profileService; _notificationService = notificationService; - _privateChatsRepository = privateChatsRepository; + _userPrivateChatsGetterService = userPrivateChatsGetterService; + _profileService = profileService; } public async Task NotifyMessageSentAsync(UserMessageResponse message) @@ -47,12 +47,22 @@ public class ChatNotificationService : IChatNotificationService private async Task NotifyMessageReceivedInPrivateChatAsync(UserMessageResponse message) { - var privateChat = await _privateChatsRepository.GetByIdAsync(message.RecipientId); - + + var result = await _userPrivateChatsGetterService.GetPrivateChatAsync(message.RecipientId); + + if(result.IsFailure) + return; + var privateChat = result.Value; + var text = message.EncryptedContent.Substring(0, Math.Min(40, message.EncryptedContent.Length)); var userId = message.SenderId == privateChat.UserAId ? privateChat.UserBId : privateChat.UserAId; - var profile = await _profileService.GetUserProfileAsync(message.SenderId); + var resultProf = await _profileService.GetUserProfileAsync(message.SenderId); + + if(resultProf.IsFailure) + return; + var profile = resultProf.Value; + var title = profile.Username; Dictionary data = new Dictionary(); diff --git a/Govor.API/Hubs/Infrastructure/ConnectionManager.cs b/Govor.API/Hubs/Infrastructure/ConnectionManager.cs index e70b353..834a177 100644 --- a/Govor.API/Hubs/Infrastructure/ConnectionManager.cs +++ b/Govor.API/Hubs/Infrastructure/ConnectionManager.cs @@ -1,5 +1,8 @@ using System.Collections.Concurrent; +using Govor.Application.Groups; +using Govor.Application.Infrastructure.Extensions; using Govor.Application.Interfaces; +using Govor.Application.PrivateUserChats; using Microsoft.AspNetCore.SignalR; namespace Govor.API.Hubs.Infrastructure; diff --git a/Govor.API/Hubs/Infrastructure/ConnectionStore.cs b/Govor.API/Hubs/Infrastructure/ConnectionStore.cs index 3e93fa3..d6af509 100644 --- a/Govor.API/Hubs/Infrastructure/ConnectionStore.cs +++ b/Govor.API/Hubs/Infrastructure/ConnectionStore.cs @@ -1,5 +1,5 @@ using System.Collections.Concurrent; -using Govor.Application.Interfaces; +using Govor.Application.Infrastructure.Extensions; namespace Govor.API.Hubs.Infrastructure; diff --git a/Govor.API/Hubs/Infrastructure/PrivateChatGroupManager.cs b/Govor.API/Hubs/Infrastructure/PrivateChatGroupManager.cs index 16714ab..7939c1d 100644 --- a/Govor.API/Hubs/Infrastructure/PrivateChatGroupManager.cs +++ b/Govor.API/Hubs/Infrastructure/PrivateChatGroupManager.cs @@ -1,7 +1,9 @@ using Govor.API.Hubs; using Govor.API.Hubs.Infrastructure; +using Govor.Application.Infrastructure.Extensions; using Govor.Application.Interfaces; -using Govor.Core.Models; +using Govor.Application.PrivateUserChats; +using Govor.Domain.Models; using Microsoft.AspNetCore.SignalR; namespace Govor.API.Hubs.Infrastructure; diff --git a/Govor.API/Hubs/PresenceHub.cs b/Govor.API/Hubs/PresenceHub.cs index 33dadb6..60e825a 100644 --- a/Govor.API/Hubs/PresenceHub.cs +++ b/Govor.API/Hubs/PresenceHub.cs @@ -1,6 +1,5 @@ using Govor.API.Common.SignalR.Helpers; -using Govor.Application.Interfaces.UserOnlineStatus; -using Govor.Core.Repositories.Users; +using Govor.Application.Users.UserOnlineStatus; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.SignalR; @@ -15,17 +14,14 @@ public class PresenceHub : Hub private readonly IUserNotificationScopeService _scopeService; private readonly IOnlineUserStore _onlineUserStore; private readonly IHubUserAccessor _userAccessor; - private readonly IUsersRepository _users; public PresenceHub( ILogger logger, IUserNotificationScopeService scopeService, IOnlineUserStore onlineUserStore, - IHubUserAccessor userAccessor, - IUsersRepository users) + IHubUserAccessor userAccessor) { _logger = logger; - _users = users; _scopeService = scopeService; _onlineUserStore = onlineUserStore; _userAccessor = userAccessor; @@ -79,32 +75,9 @@ public class PresenceHub : Hub if (isLastConnection) { - _ = Task.Run(async () => - { - await Task.Delay(TimeSpan.FromSeconds(5)); - - var currentConnections = _onlineUserStore.GetConnections(userId); - if (currentConnections == null || !currentConnections.Any()) - { - var friends = await _scopeService.GetNotifiedUsers(userId); - await Clients.Groups(friends.Select(f => f.ToString()).ToList()) - .SendAsync("UserOffline", userId); - - try - { - var user = await _users.FindByIdAsync(userId); - if (user != null) - { - user.WasOnline = DateTime.UtcNow; - await _users.UpdateAsync(user); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error updating WasOnline for {UserId}", userId); - } - } - }); + var friends = await _scopeService.GetNotifiedUsers(userId); + await Clients.Groups(friends.Select(f => f.ToString()).ToList()) + .SendAsync("UserOffline", userId); } await base.OnDisconnectedAsync(exception); diff --git a/Govor.API/Hubs/ProfileHub.cs b/Govor.API/Hubs/ProfileHub.cs index 27d1918..024f840 100644 --- a/Govor.API/Hubs/ProfileHub.cs +++ b/Govor.API/Hubs/ProfileHub.cs @@ -1,10 +1,10 @@ using Govor.API.Common.SignalR.Helpers; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.Medias; +using Govor.Application.Friends; +using Govor.Application.Medias; +using Govor.Application.Profiles; +using Govor.Application.Synching; using Govor.Contracts.DTOs; using Govor.Contracts.Responses.SignalR; -using Govor.Core.Repositories.Groups; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; @@ -13,7 +13,6 @@ namespace Govor.API.Hubs; [Authorize] public class ProfileHub : Hub { - private readonly IGroupsRepository _groupsRepository; private readonly IFriendshipService _friendsService; private readonly IProfileService _profileService; private readonly IHubUserAccessor _userAccessor; @@ -22,7 +21,6 @@ public class ProfileHub : Hub private readonly IMediaService _mediaService; public ProfileHub( - IGroupsRepository groupsRepository, IFriendshipService friendsService, IProfileService profileService, IHubUserAccessor userAccessor, @@ -30,7 +28,6 @@ public class ProfileHub : Hub IMediaService mediaService, ILogger logger) { - _groupsRepository = groupsRepository; _friendsService = friendsService; _profileService = profileService; _userAccessor = userAccessor; diff --git a/Govor.API/Program.cs b/Govor.API/Program.cs index 4c8663f..1ee5ad4 100644 --- a/Govor.API/Program.cs +++ b/Govor.API/Program.cs @@ -3,7 +3,7 @@ using FirebaseAdmin; using Google.Apis.Auth.OAuth2; using Govor.API.Common.Extensions; using Govor.API.Hubs; -using Govor.Application.Services.Authentication; +using Govor.Application.Authentication.JWT; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; @@ -29,7 +29,6 @@ builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnC FirebaseApp.Create(new AppOptions() { Credential = GoogleCredential.FromFile("secrets/firebase-adminsdk.json") - // или FromStream(File.OpenRead("firebase-adminsdk.json")) }); builder.Services.AddCors(options => @@ -81,9 +80,6 @@ builder.Services.AddControllers(); // Init DI builder.Services.AddServices(); -builder.Services.AddRepositories(); -builder.Services.AddValidators(); - builder.Services.AddOptionsConfiguration(configuration); builder.Services.AddGovorDbContext(configuration); // GovorDbContext init @@ -125,6 +121,7 @@ if (!app.Environment.IsDevelopment()) { //app.MapOpenApi(); builder.WebHost.UseUrls("http://0.0.0.0:8080"); + builder.WebHost.UseUrls("http://10.8.0.5:5000"); //builder.WebHost.UseUrls("http://192.168.1.107:8080"); } @@ -142,7 +139,7 @@ app.UseAuthorization(); app.MapControllers(); -app.Map("/server/ping", +app.MapGet("/server/ping", () => new OkResult()); app.MapHub("/hubs/chats"); diff --git a/Govor.API/Properties/launchSettings.json b/Govor.API/Properties/launchSettings.json index bdcb24a..83eb278 100644 --- a/Govor.API/Properties/launchSettings.json +++ b/Govor.API/Properties/launchSettings.json @@ -5,7 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "http://0.0.0.0:8080;http://localhost:7155", + "applicationUrl": "http://0.0.0.0:8080;http://localhost:7155;http://10.8.0.5:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/Govor.API/appsettings.Development.json b/Govor.API/appsettings.Development.json index c2959b4..61c97cc 100644 --- a/Govor.API/appsettings.Development.json +++ b/Govor.API/appsettings.Development.json @@ -6,7 +6,7 @@ } }, "ConnectionStrings": { - "GovorDbContext": "Host=46.19.68.182;Port=5432;Database=default_db;Username=main;Password=1M^rf!1JKL:y,w;" + "GovorDbContext": "Host=localhost;Port=5432;Database=GovorDb;Username=postgres;Password=stalcker;" }, "UseMySql": false, "AllowedHosts": "*", diff --git a/Govor.API/appsettings.json b/Govor.API/appsettings.json index c2959b4..70d9f3e 100644 --- a/Govor.API/appsettings.json +++ b/Govor.API/appsettings.json @@ -6,7 +6,7 @@ } }, "ConnectionStrings": { - "GovorDbContext": "Host=46.19.68.182;Port=5432;Database=default_db;Username=main;Password=1M^rf!1JKL:y,w;" + "GovorDbContext": "Host=localhost;Port=5432;Database=GovorDb;Username=postgres;Password=stalcker;" }, "UseMySql": false, "AllowedHosts": "*", @@ -18,6 +18,6 @@ "RefreshTokenLifetimeDays": 30 }, "EncryptionOption": { - "Secret": "8B2j9kkw9xP5m7nQwE2zY3A-=Q8zP7C4+TqLZpg" + "Secret": "8B2j9kkw9xP5m7nQwE2zY3A-=Q8zP7C4+TqLZpg" } } diff --git a/Govor.Application.Tests/Infrastructure/AdminsStuff/InvitationGeneratorTests.cs b/Govor.Application.Tests/Infrastructure/AdminsStuff/InvitationGeneratorTests.cs index 698b6ed..e295386 100644 --- a/Govor.Application.Tests/Infrastructure/AdminsStuff/InvitationGeneratorTests.cs +++ b/Govor.Application.Tests/Infrastructure/AdminsStuff/InvitationGeneratorTests.cs @@ -1,8 +1,8 @@ using AutoFixture; using Govor.Application.Infrastructure.AdminsStuff; using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.Invaites; +using Govor.Domain.Models; +using Govor.Domain.Repositories.Invaites; using Moq; namespace Govor.Application.Tests.Infrastructure.AdminsStuff; diff --git a/Govor.Application.Tests/Infrastructure/Validators/UsernameValidatorTests.cs b/Govor.Application.Tests/Infrastructure/Validators/UsernameValidatorTests.cs index 8d9d865..2a99dd8 100644 --- a/Govor.Application.Tests/Infrastructure/Validators/UsernameValidatorTests.cs +++ b/Govor.Application.Tests/Infrastructure/Validators/UsernameValidatorTests.cs @@ -1,4 +1,4 @@ -using Govor.Application.Exceptions.AuthService; +using Govor.Application.Authentication.Exceptions; using Govor.Application.Infrastructure.Validators; using Microsoft.Extensions.Configuration; diff --git a/Govor.Application.Tests/Services/Authentication/AuthServiceTests.cs b/Govor.Application.Tests/Services/Authentication/AuthServiceTests.cs index ee3964a..71287df 100644 --- a/Govor.Application.Tests/Services/Authentication/AuthServiceTests.cs +++ b/Govor.Application.Tests/Services/Authentication/AuthServiceTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Models; -using Govor.Core.Repositories.Users; -using Govor.Application.Exceptions.AuthService; +using Govor.Domain.Infrastructure.Extensions; +using Govor.Domain.Models; +using Govor.Domain.Repositories.Users; +using Govor.Application.Authentication.Exceptions; using Govor.Application.Interfaces.Authentication; using Govor.Application.Services.Authentication; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Admins; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Admins; using Moq; namespace Govor.Application.Tests.Services.Authentication; diff --git a/Govor.Application.Tests/Services/Authentication/JwtServiceTests.cs b/Govor.Application.Tests/Services/Authentication/JwtServiceTests.cs index 777e876..d6dd2ff 100644 --- a/Govor.Application.Tests/Services/Authentication/JwtServiceTests.cs +++ b/Govor.Application.Tests/Services/Authentication/JwtServiceTests.cs @@ -4,7 +4,7 @@ using System.Text; using AutoFixture; using Govor.Application.Interfaces.Authentication; using Govor.Application.Services.Authentication; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Moq; diff --git a/Govor.Application.Tests/Services/Friends/FriendRequestCommandServiceTests.cs b/Govor.Application.Tests/Services/Friends/FriendRequestCommandServiceTests.cs index 9d7a389..d0fa9d2 100644 --- a/Govor.Application.Tests/Services/Friends/FriendRequestCommandServiceTests.cs +++ b/Govor.Application.Tests/Services/Friends/FriendRequestCommandServiceTests.cs @@ -2,10 +2,11 @@ using AutoFixture; using Govor.Application.Exceptions.FriendsService; using Govor.Application.Interfaces; using Govor.Application.Interfaces.Friends; +using Govor.Application.PrivateUserChats; using Govor.Application.Services.Friends; -using Govor.Core.Models; -using Govor.Core.Repositories.Friendships; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models; +using Govor.Domain.Repositories.Friendships; +using Govor.Domain.Repositories.Users; using Govor.Data.Repositories.Exceptions; using Moq; diff --git a/Govor.Application.Tests/Services/Friends/FriendRequestQueryServiceTests.cs b/Govor.Application.Tests/Services/Friends/FriendRequestQueryServiceTests.cs index 56029ec..aa627aa 100644 --- a/Govor.Application.Tests/Services/Friends/FriendRequestQueryServiceTests.cs +++ b/Govor.Application.Tests/Services/Friends/FriendRequestQueryServiceTests.cs @@ -1,10 +1,10 @@ using AutoFixture; using Govor.Application.Interfaces.Friends; using Govor.Application.Services.Friends; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Friendships; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Friendships; +using Govor.Domain.Repositories.Users; using Govor.Data.Repositories.Exceptions; using Moq; diff --git a/Govor.Application.Tests/Services/Friends/FriendshipServiceTests.cs b/Govor.Application.Tests/Services/Friends/FriendshipServiceTests.cs index acd7d08..1653ef5 100644 --- a/Govor.Application.Tests/Services/Friends/FriendshipServiceTests.cs +++ b/Govor.Application.Tests/Services/Friends/FriendshipServiceTests.cs @@ -1,10 +1,10 @@ using AutoFixture; using Govor.Application.Interfaces.Friends; using Govor.Application.Services.Friends; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Friendships; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Friendships; +using Govor.Domain.Repositories.Users; using Govor.Data.Repositories.Exceptions; using Moq; diff --git a/Govor.Application.Tests/Services/Medias/AccesserToDownloadMediaServiceTests.cs b/Govor.Application.Tests/Services/Medias/AccesserToDownloadMediaServiceTests.cs index 8c45613..3a6054a 100644 --- a/Govor.Application.Tests/Services/Medias/AccesserToDownloadMediaServiceTests.cs +++ b/Govor.Application.Tests/Services/Medias/AccesserToDownloadMediaServiceTests.cs @@ -1,6 +1,6 @@ using Govor.Application.Services.Medias; -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; using Govor.Data; using Microsoft.EntityFrameworkCore; diff --git a/Govor.Application.Tests/Services/Messages/MessageCommandServiceTests.cs b/Govor.Application.Tests/Services/Messages/MessageCommandServiceTests.cs index 40a4327..5cc7e2d 100644 --- a/Govor.Application.Tests/Services/Messages/MessageCommandServiceTests.cs +++ b/Govor.Application.Tests/Services/Messages/MessageCommandServiceTests.cs @@ -2,13 +2,14 @@ using Govor.Application.Interfaces; using Govor.Application.Interfaces.Medias; using Govor.Application.Interfaces.Messages.Parameters; +using Govor.Application.PrivateUserChats; using Govor.Application.Services.Messages; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.Groups; -using Govor.Core.Repositories.Messages; -using Govor.Core.Repositories.PrivateChats; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain.Repositories.Groups; +using Govor.Domain.Repositories.Messages; +using Govor.Domain.Repositories.PrivateChats; +using Govor.Domain.Repositories.Users; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/Messages/MessagesLoaderTests.cs b/Govor.Application.Tests/Services/Messages/MessagesLoaderTests.cs index 0cfa9d9..03b4f94 100644 --- a/Govor.Application.Tests/Services/Messages/MessagesLoaderTests.cs +++ b/Govor.Application.Tests/Services/Messages/MessagesLoaderTests.cs @@ -1,9 +1,10 @@ using Govor.Application.Interfaces; +using Govor.Application.Messages; using Govor.Application.Services.Messages; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.Groups; -using Govor.Core.Repositories.PrivateChats; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain.Repositories.Groups; +using Govor.Domain.Repositories.PrivateChats; using Govor.Data; using Microsoft.EntityFrameworkCore; using Moq; diff --git a/Govor.Application.Tests/Services/PasswordHasherTests.cs b/Govor.Application.Tests/Services/PasswordHasherTests.cs index a0e4074..cb6b195 100644 --- a/Govor.Application.Tests/Services/PasswordHasherTests.cs +++ b/Govor.Application.Tests/Services/PasswordHasherTests.cs @@ -1,6 +1,6 @@ using AutoFixture; using Govor.Application.Services.Authentication; -using Govor.Core.Infrastructure.Extensions; +using Govor.Domain.Infrastructure.Extensions; namespace Govor.Application.Tests.Services; diff --git a/Govor.Application.Tests/Services/PingHandlerServiceTests.cs b/Govor.Application.Tests/Services/PingHandlerServiceTests.cs index 09762ad..cd68952 100644 --- a/Govor.Application.Tests/Services/PingHandlerServiceTests.cs +++ b/Govor.Application.Tests/Services/PingHandlerServiceTests.cs @@ -1,5 +1,5 @@ -using Govor.Application.Services; -using Govor.Core.Models.Users; +using Govor.Application.PingHandler; +using Govor.Domain.Models.Users; using Govor.Data; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; diff --git a/Govor.Application.Tests/Services/ProfileServiceTests.cs b/Govor.Application.Tests/Services/ProfileServiceTests.cs index 45e14a6..39ebd90 100644 --- a/Govor.Application.Tests/Services/ProfileServiceTests.cs +++ b/Govor.Application.Tests/Services/ProfileServiceTests.cs @@ -1,6 +1,5 @@ -using Govor.Application.Services; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Users; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/PushNotifications/PushNotificationServiceTests.cs b/Govor.Application.Tests/Services/PushNotifications/PushNotificationServiceTests.cs index dcf2f1a..fd1707f 100644 --- a/Govor.Application.Tests/Services/PushNotifications/PushNotificationServiceTests.cs +++ b/Govor.Application.Tests/Services/PushNotifications/PushNotificationServiceTests.cs @@ -1,7 +1,8 @@ using Govor.Application.Interfaces.PushNotifications; using Govor.Application.Interfaces.PushNotifications.Models; +using Govor.Application.PushNotifications; using Govor.Application.Services.PushNotifications; -using Govor.Core.Repositories.PushTokens; +using Govor.Domain.Repositories.PushTokens; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/SynchingServiceTests.cs b/Govor.Application.Tests/Services/SynchingServiceTests.cs index e18e30e..31f68b5 100644 --- a/Govor.Application.Tests/Services/SynchingServiceTests.cs +++ b/Govor.Application.Tests/Services/SynchingServiceTests.cs @@ -1,4 +1,4 @@ -using Govor.Application.Services; +using Govor.Application.Synching; namespace Govor.Application.Tests.Services; diff --git a/Govor.Application.Tests/Services/UserGroupsGetterServiceTests.cs b/Govor.Application.Tests/Services/UserGroupsGetterServiceTests.cs index 83af882..3b4702b 100644 --- a/Govor.Application.Tests/Services/UserGroupsGetterServiceTests.cs +++ b/Govor.Application.Tests/Services/UserGroupsGetterServiceTests.cs @@ -1,8 +1,8 @@ using AutoFixture; +using Govor.Application.Groups; using Govor.Application.Interfaces; -using Govor.Application.Services; -using Govor.Core.Models; -using Govor.Core.Repositories.Groups; +using Govor.Domain.Models; +using Govor.Domain.Repositories.Groups; using Govor.Data.Repositories.Exceptions; using Moq; diff --git a/Govor.Application.Tests/Services/UserOnlineStatus/UserNotificationScopeServiceTests.cs b/Govor.Application.Tests/Services/UserOnlineStatus/UserNotificationScopeServiceTests.cs index 1eb0eb7..d031e73 100644 --- a/Govor.Application.Tests/Services/UserOnlineStatus/UserNotificationScopeServiceTests.cs +++ b/Govor.Application.Tests/Services/UserOnlineStatus/UserNotificationScopeServiceTests.cs @@ -2,8 +2,8 @@ using AutoFixture; using Govor.Application.Interfaces.Friends; using Govor.Application.Interfaces.UserOnlineStatus; using Govor.Application.Services.UserOnlineStatus; -using Govor.Core.Models; -using Govor.Core.Models.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/UserPrivateChatsCreatorTests.cs b/Govor.Application.Tests/Services/UserPrivateChatsCreatorTests.cs index 147b9ed..ad06d25 100644 --- a/Govor.Application.Tests/Services/UserPrivateChatsCreatorTests.cs +++ b/Govor.Application.Tests/Services/UserPrivateChatsCreatorTests.cs @@ -1,8 +1,8 @@ using AutoFixture; using Govor.Application.Interfaces; -using Govor.Application.Services; -using Govor.Core.Models; -using Govor.Core.Repositories.PrivateChats; +using Govor.Application.PrivateUserChats; +using Govor.Domain.Models; +using Govor.Domain.Repositories.PrivateChats; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/UserSessions/UserSessionOpenerTests.cs b/Govor.Application.Tests/Services/UserSessions/UserSessionOpenerTests.cs index e09c519..396e1a9 100644 --- a/Govor.Application.Tests/Services/UserSessions/UserSessionOpenerTests.cs +++ b/Govor.Application.Tests/Services/UserSessions/UserSessionOpenerTests.cs @@ -1,6 +1,6 @@ using Govor.Application.Services.UserSessions; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.UserSessionsRepository; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.UserSessionsRepository; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; diff --git a/Govor.Application.Tests/Services/UserSessions/UserSessionReaderTests.cs b/Govor.Application.Tests/Services/UserSessions/UserSessionReaderTests.cs index cc660fa..159278d 100644 --- a/Govor.Application.Tests/Services/UserSessions/UserSessionReaderTests.cs +++ b/Govor.Application.Tests/Services/UserSessions/UserSessionReaderTests.cs @@ -1,9 +1,9 @@ using AutoFixture; using Govor.Application.Interfaces.UserSession; using Govor.Application.Services.UserSessions; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.UserSessionsRepository; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.UserSessionsRepository; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/UserSessions/UserSessionRefresherTests.cs b/Govor.Application.Tests/Services/UserSessions/UserSessionRefresherTests.cs index b717f9f..1dfb754 100644 --- a/Govor.Application.Tests/Services/UserSessions/UserSessionRefresherTests.cs +++ b/Govor.Application.Tests/Services/UserSessions/UserSessionRefresherTests.cs @@ -1,10 +1,10 @@ using Govor.Application.Interfaces.Authentication; using Govor.Application.Services.Authentication; using Govor.Application.Services.UserSessions; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; -using Govor.Core.Repositories.UserSessionsRepository; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.Users; +using Govor.Domain.Repositories.UserSessionsRepository; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/Govor.Application.Tests/Services/UserSessions/UserSessionRevokerTests.cs b/Govor.Application.Tests/Services/UserSessions/UserSessionRevokerTests.cs index 289a82e..240f48d 100644 --- a/Govor.Application.Tests/Services/UserSessions/UserSessionRevokerTests.cs +++ b/Govor.Application.Tests/Services/UserSessions/UserSessionRevokerTests.cs @@ -1,8 +1,8 @@ using Govor.Application.Services.UserSessions; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.PushTokens; -using Govor.Core.Repositories.UserSessionsRepository; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories.PushTokens; +using Govor.Domain.Repositories.UserSessionsRepository; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application.Tests/Services/VerifyFriendshipTests.cs b/Govor.Application.Tests/Services/VerifyFriendshipTests.cs index a4a396d..cd3628e 100644 --- a/Govor.Application.Tests/Services/VerifyFriendshipTests.cs +++ b/Govor.Application.Tests/Services/VerifyFriendshipTests.cs @@ -1,8 +1,7 @@ using AutoFixture; using Govor.Application.Exceptions.VerifyFriendship; -using Govor.Application.Services; -using Govor.Core.Models; -using Govor.Core.Repositories.Friendships; +using Govor.Domain.Models; +using Govor.Domain.Repositories.Friendships; using Govor.Data.Repositories.Exceptions; using Microsoft.Extensions.Logging; using Moq; diff --git a/Govor.Application/Authentication/AuthService.cs b/Govor.Application/Authentication/AuthService.cs new file mode 100644 index 0000000..2f9df25 --- /dev/null +++ b/Govor.Application/Authentication/AuthService.cs @@ -0,0 +1,101 @@ +using Govor.Application.Authentication.Exceptions; +using Govor.Application.Infrastructure.Validators; +using Govor.Application.Users; +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Authentication; + +public class AuthService : IAccountService +{ + private readonly GovorDbContext _context; + private readonly IPasswordHasher _passwordHasher; + private readonly IUserNameExistValidator _userNameExistValidator; + private readonly IUsernameValidator _usernameValidator; + + public AuthService( + GovorDbContext context, + IUserNameExistValidator existValidator, + IPasswordHasher passwordHasher, + IUsernameValidator usernameValidator) + { + _context = context; + _userNameExistValidator = existValidator; + _passwordHasher = passwordHasher; + _usernameValidator = usernameValidator; + } + + public async Task> RegistrationAsync(string name, string password, Invitation invitation) + { + + var validationResult = _usernameValidator.Validate(name); + if (validationResult.IsFailure) + { + return Result.Failure(validationResult.Error); + } + + if (await _userNameExistValidator.IsUsernameExistsAsync(name)) + { + return Result.Failure(new Error( + nameof(UserAlreadyExistException), + $"User with username '{name}' already exists.")); + } + + 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.Empty, + WasOnline = DateTime.UtcNow, + InviteId = invitation.Id + }; + + + await _context.Users.AddAsync(user); + + await SetRoleAsync(user, invitation); + + await _context.SaveChangesAsync(); + + return user; // Success + } + + public async Task> LoginAsync(string name, string password) + { + var user = await _context.Users + .AsNoTracking() + .FirstOrDefaultAsync(u => u.Username == name); + + if (user is null) + { + return Result.Failure(new Error( + nameof(UserNotRegisteredException), + $"User '{name}' is not registered.")); + } + + if (!_passwordHasher.Verify(password, user.PasswordHash)) + { + return Result.Failure(new Error( + nameof(InvalidOperationException), + "The password provided is incorrect.")); + } + + return user; // Success + } + + private async Task SetRoleAsync(User user, Invitation invitation) + { + if (invitation.IsAdmin) + { + await _context.Admins.AddAsync(new Admin { UserId = user.Id }); + } + } +} diff --git a/Govor.Application/Exceptions/AuthService/InvalidUsernameException.cs b/Govor.Application/Authentication/Exceptions/InvalidUsernameException.cs similarity index 55% rename from Govor.Application/Exceptions/AuthService/InvalidUsernameException.cs rename to Govor.Application/Authentication/Exceptions/InvalidUsernameException.cs index 9824b86..435a509 100644 --- a/Govor.Application/Exceptions/AuthService/InvalidUsernameException.cs +++ b/Govor.Application/Authentication/Exceptions/InvalidUsernameException.cs @@ -1,6 +1,6 @@ -using Govor.Core; +using Govor.Domain; -namespace Govor.Application.Exceptions.AuthService; +namespace Govor.Application.Authentication.Exceptions; public class InvalidUsernameException(string message) : GovorCoreException(message) { diff --git a/Govor.Application/Authentication/Exceptions/LoginUserException.cs b/Govor.Application/Authentication/Exceptions/LoginUserException.cs new file mode 100644 index 0000000..1926fcc --- /dev/null +++ b/Govor.Application/Authentication/Exceptions/LoginUserException.cs @@ -0,0 +1,5 @@ +using Govor.Domain; + +namespace Govor.Application.Authentication.Exceptions; + +public class LoginUserException : GovorCoreException { } \ No newline at end of file diff --git a/Govor.Application/Authentication/Exceptions/UserAlreadyExistException.cs b/Govor.Application/Authentication/Exceptions/UserAlreadyExistException.cs new file mode 100644 index 0000000..40701c2 --- /dev/null +++ b/Govor.Application/Authentication/Exceptions/UserAlreadyExistException.cs @@ -0,0 +1,5 @@ +using Govor.Domain; + +namespace Govor.Application.Authentication.Exceptions; + +public class UserAlreadyExistException(string username) : GovorCoreException($"{username} is already exists!") { } \ No newline at end of file diff --git a/Govor.Application/Authentication/Exceptions/UserNotRegisteredException.cs b/Govor.Application/Authentication/Exceptions/UserNotRegisteredException.cs new file mode 100644 index 0000000..a1c82ec --- /dev/null +++ b/Govor.Application/Authentication/Exceptions/UserNotRegisteredException.cs @@ -0,0 +1,5 @@ +using Govor.Domain; + +namespace Govor.Application.Authentication.Exceptions; + +public class UserNotRegisteredException(string username) : GovorCoreException($"{username} is not registered!") { } \ No newline at end of file diff --git a/Govor.Application/Authentication/IAuthService.cs b/Govor.Application/Authentication/IAuthService.cs new file mode 100644 index 0000000..48816d1 --- /dev/null +++ b/Govor.Application/Authentication/IAuthService.cs @@ -0,0 +1,11 @@ +using Govor.Domain.Common; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; + +namespace Govor.Application.Authentication; + +public interface IAccountService +{ + 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.Application/Authentication/IInvitesService.cs b/Govor.Application/Authentication/IInvitesService.cs new file mode 100644 index 0000000..18e030a --- /dev/null +++ b/Govor.Application/Authentication/IInvitesService.cs @@ -0,0 +1,12 @@ +using Govor.Domain.Common; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; + +namespace Govor.Application.Authentication; + +public interface IInvitesService +{ + public Task GetRoleNameAsync(User user); + public Task GetRoleNameAsync(Guid sessionId); + public Task> ValidateAsync(string inviteCode); +} \ No newline at end of file diff --git a/Govor.Application/Interfaces/IPasswordHasher.cs b/Govor.Application/Authentication/IPasswordHasher.cs similarity index 73% rename from Govor.Application/Interfaces/IPasswordHasher.cs rename to Govor.Application/Authentication/IPasswordHasher.cs index c6253c9..a549102 100644 --- a/Govor.Application/Interfaces/IPasswordHasher.cs +++ b/Govor.Application/Authentication/IPasswordHasher.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Infrastructure.Extensions; +namespace Govor.Application.Authentication; public interface IPasswordHasher { diff --git a/Govor.Application/Authentication/InvitesService.cs b/Govor.Application/Authentication/InvitesService.cs new file mode 100644 index 0000000..1d2a70c --- /dev/null +++ b/Govor.Application/Authentication/InvitesService.cs @@ -0,0 +1,56 @@ +using Govor.Application.Exceptions.InvitesService; +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Authentication; + +public class InvitesService : IInvitesService +{ + private readonly GovorDbContext _context; + + public InvitesService(GovorDbContext context) + { + _context = context; + } + + public async Task GetRoleNameAsync(User user) + { + return await GetRoleNameAsync(user.InviteId); + } + + public async Task GetRoleNameAsync(Guid sessionId) + { + var invitation = await _context.Invitations.FirstOrDefaultAsync(s => s.Id == sessionId); + + if (invitation == null) + return "User"; + + return invitation.IsAdmin ? "Admin" : "User"; + } + + public async Task> ValidateAsync(string inviteCode) + { + var invite = await _context.Invitations + .Include(s => s.Users) + .FirstOrDefaultAsync(s => s.Code == inviteCode); + + if (invite == null) + return Result.Failure(Error.Null); + + if (invite.EndDate < DateTime.Now || invite.MaxParticipants <= invite.Users.Count) + { + invite.IsActive = false; + await _context.SaveChangesAsync(); + + return Result.Failure(new Error( + "Auth.InviteLinkInvalid", $"Invite link invalid: {inviteCode}") + ); + } + + return invite; + } +} + diff --git a/Govor.Application/Interfaces/Authentication/IJwtService.cs b/Govor.Application/Authentication/JWT/IJwtService.cs similarity index 74% rename from Govor.Application/Interfaces/Authentication/IJwtService.cs rename to Govor.Application/Authentication/JWT/IJwtService.cs index d5d54ad..74d581d 100644 --- a/Govor.Application/Interfaces/Authentication/IJwtService.cs +++ b/Govor.Application/Authentication/JWT/IJwtService.cs @@ -1,7 +1,7 @@ using System.Security.Claims; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Application.Interfaces.Authentication; +namespace Govor.Application.Authentication.JWT; public interface IJwtService { diff --git a/Govor.Application/Interfaces/Authentication/IJwtTokenHasher.cs b/Govor.Application/Authentication/JWT/IJwtTokenHasher.cs similarity index 69% rename from Govor.Application/Interfaces/Authentication/IJwtTokenHasher.cs rename to Govor.Application/Authentication/JWT/IJwtTokenHasher.cs index 439e87b..7823e04 100644 --- a/Govor.Application/Interfaces/Authentication/IJwtTokenHasher.cs +++ b/Govor.Application/Authentication/JWT/IJwtTokenHasher.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.Authentication; +namespace Govor.Application.Authentication.JWT; public interface IJwtTokenHasher { diff --git a/Govor.Application/Services/Authentication/JwtAccessOption.cs b/Govor.Application/Authentication/JWT/JwtAccessOption.cs similarity index 66% rename from Govor.Application/Services/Authentication/JwtAccessOption.cs rename to Govor.Application/Authentication/JWT/JwtAccessOption.cs index a898c5e..b6dda6f 100644 --- a/Govor.Application/Services/Authentication/JwtAccessOption.cs +++ b/Govor.Application/Authentication/JWT/JwtAccessOption.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Services.Authentication; +namespace Govor.Application.Authentication.JWT; public class JwtAccessOption { public string SecretKey {get; set;} diff --git a/Govor.Application/Services/Authentication/JwtRefreshOption.cs b/Govor.Application/Authentication/JWT/JwtRefreshOption.cs similarity index 62% rename from Govor.Application/Services/Authentication/JwtRefreshOption.cs rename to Govor.Application/Authentication/JWT/JwtRefreshOption.cs index 51db7ad..482ab96 100644 --- a/Govor.Application/Services/Authentication/JwtRefreshOption.cs +++ b/Govor.Application/Authentication/JWT/JwtRefreshOption.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Services.Authentication; +namespace Govor.Application.Authentication.JWT; public class JwtRefreshOption { diff --git a/Govor.Application/Services/Authentication/JwtService.cs b/Govor.Application/Authentication/JWT/JwtService.cs similarity index 94% rename from Govor.Application/Services/Authentication/JwtService.cs rename to Govor.Application/Authentication/JWT/JwtService.cs index 764ded3..609eddf 100644 --- a/Govor.Application/Services/Authentication/JwtService.cs +++ b/Govor.Application/Authentication/JWT/JwtService.cs @@ -1,12 +1,11 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; -using Govor.Application.Interfaces.Authentication; -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; -namespace Govor.Application.Services.Authentication; +namespace Govor.Application.Authentication.JWT; public class JwtService : IJwtService { @@ -27,7 +26,7 @@ public class JwtService : IJwtService { new Claim("userId", user.Id.ToString()), new Claim("sid", sessionId.ToString()), - new Claim(ClaimTypes.Role, await _invitesService.GetRoleAsync(user), ClaimValueTypes.String) + new Claim(ClaimTypes.Role, await _invitesService.GetRoleNameAsync(user), ClaimValueTypes.String) }; var singing = new SigningCredentials( diff --git a/Govor.Application/Services/Authentication/JwtTokenHasher.cs b/Govor.Application/Authentication/JWT/JwtTokenHasher.cs similarity index 91% rename from Govor.Application/Services/Authentication/JwtTokenHasher.cs rename to Govor.Application/Authentication/JWT/JwtTokenHasher.cs index 90154d8..d2595d9 100644 --- a/Govor.Application/Services/Authentication/JwtTokenHasher.cs +++ b/Govor.Application/Authentication/JWT/JwtTokenHasher.cs @@ -1,9 +1,8 @@ using System.Security.Cryptography; using System.Text; -using Govor.Application.Interfaces.Authentication; using Microsoft.Extensions.Configuration; -namespace Govor.Application.Services.Authentication; +namespace Govor.Application.Authentication.JWT; public class JwtTokenHasher : IJwtTokenHasher { diff --git a/Govor.Application/Services/Authentication/PasswordHasher.cs b/Govor.Application/Authentication/PasswordHasher.cs similarity index 76% rename from Govor.Application/Services/Authentication/PasswordHasher.cs rename to Govor.Application/Authentication/PasswordHasher.cs index 99003ef..65e2f2d 100644 --- a/Govor.Application/Services/Authentication/PasswordHasher.cs +++ b/Govor.Application/Authentication/PasswordHasher.cs @@ -1,6 +1,6 @@ -using Govor.Core.Infrastructure.Extensions; +using Govor.Domain.Common.Extensions; -namespace Govor.Application.Services.Authentication; +namespace Govor.Application.Authentication; public class PasswordHasher : IPasswordHasher { diff --git a/Govor.Application/Exceptions/AuthService/LoginUserException.cs b/Govor.Application/Exceptions/AuthService/LoginUserException.cs deleted file mode 100644 index 7ad1d60..0000000 --- a/Govor.Application/Exceptions/AuthService/LoginUserException.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Govor.Core; - -namespace Govor.Application.Exceptions.AuthService; - -public class LoginUserException : GovorCoreException { } \ No newline at end of file diff --git a/Govor.Application/Exceptions/AuthService/UserAlreadyExistException.cs b/Govor.Application/Exceptions/AuthService/UserAlreadyExistException.cs deleted file mode 100644 index 14827f5..0000000 --- a/Govor.Application/Exceptions/AuthService/UserAlreadyExistException.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Govor.Core; - -namespace Govor.Application.Exceptions.AuthService; - -public class UserAlreadyExistException(string username) : GovorCoreException($"{username} is already exists!") { } \ No newline at end of file diff --git a/Govor.Application/Exceptions/AuthService/UserNotRegisteredException.cs b/Govor.Application/Exceptions/AuthService/UserNotRegisteredException.cs deleted file mode 100644 index 51f35b3..0000000 --- a/Govor.Application/Exceptions/AuthService/UserNotRegisteredException.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Govor.Core; - -namespace Govor.Application.Exceptions.AuthService; - -public class UserNotRegisteredException(string username) : GovorCoreException($"{username} is not registered!") { } \ No newline at end of file diff --git a/Govor.Application/Exceptions/FriendsService/RequestAlreadySentException.cs b/Govor.Application/Exceptions/FriendsService/RequestAlreadySentException.cs index 97f85d0..7b30c17 100644 --- a/Govor.Application/Exceptions/FriendsService/RequestAlreadySentException.cs +++ b/Govor.Application/Exceptions/FriendsService/RequestAlreadySentException.cs @@ -1,4 +1,4 @@ -using Govor.Core; +using Govor.Domain; namespace Govor.Application.Exceptions.FriendsService; diff --git a/Govor.Application/Exceptions/FriendsService/SearchUsersException.cs b/Govor.Application/Exceptions/FriendsService/SearchUsersException.cs index f51ebce..4a14f83 100644 --- a/Govor.Application/Exceptions/FriendsService/SearchUsersException.cs +++ b/Govor.Application/Exceptions/FriendsService/SearchUsersException.cs @@ -1,4 +1,4 @@ -using Govor.Core; +using Govor.Domain; namespace Govor.Application.Exceptions.FriendsService; diff --git a/Govor.Application/Exceptions/FriendsService/SendFriendRequestException.cs b/Govor.Application/Exceptions/FriendsService/SendFriendRequestException.cs index 0e0b78f..5b1c900 100644 --- a/Govor.Application/Exceptions/FriendsService/SendFriendRequestException.cs +++ b/Govor.Application/Exceptions/FriendsService/SendFriendRequestException.cs @@ -1,4 +1,4 @@ -using Govor.Core; +using Govor.Domain; namespace Govor.Application.Exceptions.FriendsService; diff --git a/Govor.Application/Exceptions/InvitesService/InviteLinkInvalidException.cs b/Govor.Application/Exceptions/InvitesService/InviteLinkInvalidException.cs index 4180c9d..ffe6847 100644 --- a/Govor.Application/Exceptions/InvitesService/InviteLinkInvalidException.cs +++ b/Govor.Application/Exceptions/InvitesService/InviteLinkInvalidException.cs @@ -1,4 +1,4 @@ -using Govor.Core; +using Govor.Domain; namespace Govor.Application.Exceptions.InvitesService; diff --git a/Govor.Application/Exceptions/VerifyFriendship/FriendshipException.cs b/Govor.Application/Exceptions/VerifyFriendship/FriendshipException.cs index ab56926..160e514 100644 --- a/Govor.Application/Exceptions/VerifyFriendship/FriendshipException.cs +++ b/Govor.Application/Exceptions/VerifyFriendship/FriendshipException.cs @@ -1,4 +1,4 @@ -using Govor.Core; +using Govor.Domain; namespace Govor.Application.Exceptions.VerifyFriendship; diff --git a/Govor.Application/Friends/FriendRequestCommandService.cs b/Govor.Application/Friends/FriendRequestCommandService.cs new file mode 100644 index 0000000..6656510 --- /dev/null +++ b/Govor.Application/Friends/FriendRequestCommandService.cs @@ -0,0 +1,126 @@ +using Govor.Application.Exceptions.FriendsService; +using Govor.Application.Interfaces; +using Govor.Application.PrivateUserChats; +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Friends; + +public class FriendRequestCommandService : IFriendRequestCommandService +{ + private readonly GovorDbContext _context; + private readonly IUserPrivateChatsCreator _privateChatsCreator; + + public FriendRequestCommandService( + GovorDbContext context, + IUserPrivateChatsCreator privateChatsCreator) + { + _context = context; + _privateChatsCreator = privateChatsCreator; + } + + public async Task> SendAsync(Guid fromUserId, Guid toUserId) + { + if (fromUserId == toUserId) + return Result.Failure(new Error( + "Friendship.Send", + "Cannot send a request to self user") + ); + + var friendship = await _context.Friendships + .FirstOrDefaultAsync(f => (f.RequesterId == fromUserId && f.AddresseeId == toUserId) || + (f.RequesterId == toUserId && f.AddresseeId == fromUserId)); + + if (friendship is null) + { + friendship = new Friendship + { + Id = Guid.NewGuid(), + RequesterId = fromUserId, + AddresseeId = toUserId, + Status = FriendshipStatus.Pending + }; + await _context.Friendships.AddAsync(friendship); + } + else + { + if (friendship.Status == FriendshipStatus.Pending || + friendship.Status == FriendshipStatus.Accepted || + friendship.Status == FriendshipStatus.Blocked) + { + return Result.Failure(new Error( + "Friendship.Send", + $"The request is already {friendship.Status}") + ); + } + + friendship.RequesterId = fromUserId; + friendship.AddresseeId = toUserId; + friendship.Status = FriendshipStatus.Pending; + } + + await _context.SaveChangesAsync(); + return friendship; + } + + public async Task> AcceptAsync(Guid requestId, Guid currentUserId) + { + var friendship = await _context.Friendships.FindAsync(requestId); + + if (friendship is null) + return Result.Failure(new Error( + "Friendship.Accept", + "Friendship not found! You cant accept request!") + ); + + if (friendship.AddresseeId != currentUserId) + return Result.Failure(new Error( + "Friendship.Accept", + "You cannot accept this request!") + ); + + if (friendship.Status != FriendshipStatus.Pending) + return Result.Failure(new Error( + "Friendship.Accept", + "Request is already accepted!") + ); + + friendship.Status = FriendshipStatus.Accepted; + + await _context.SaveChangesAsync(); + + await _privateChatsCreator.CreateAsync(friendship.AddresseeId, friendship.RequesterId); + + return friendship; + } + + public async Task> RejectAsync(Guid requestId, Guid currentUserId) + { + var friendship = await _context.Friendships.FindAsync(requestId); + + if (friendship == null) + return Result.Failure(new Error( + "Friendship.Reject", + "Friendship not found! You cant reject request!") + ); + + if (friendship.AddresseeId != currentUserId) + return Result.Failure(new Error( + "Friendship.Reject", + "You cannot reject this request!") + ); + + if (friendship.Status != FriendshipStatus.Pending && friendship.Status != FriendshipStatus.Rejected) + return Result.Failure(new Error( + "Friendship.Reject", + $"Request is already {friendship.Status}") + ); + + friendship.Status = FriendshipStatus.Rejected; + + await _context.SaveChangesAsync(); + return friendship; + } +} \ No newline at end of file diff --git a/Govor.Application/Friends/FriendRequestQueryService.cs b/Govor.Application/Friends/FriendRequestQueryService.cs new file mode 100644 index 0000000..855c3d7 --- /dev/null +++ b/Govor.Application/Friends/FriendRequestQueryService.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using Govor.Domain; +using Govor.Domain.Models; + +namespace Govor.Application.Friends; + +public class FriendRequestQueryService : IFriendRequestQueryService +{ + private readonly GovorDbContext _context; + + + public FriendRequestQueryService(GovorDbContext context) + { + _context = context; + } + + public async Task> GetIncomingAsync(Guid userId) + { + return await _context.Friendships + .AsNoTracking() + .Include(f => f.Requester) + .Include(f => f.Addressee) + .Where(f => f.AddresseeId == userId && f.Status == FriendshipStatus.Pending) + .ToListAsync(); + } + + public async Task> GetResponsesAsync(Guid userId) + { + return await _context.Friendships + .AsNoTracking() + .Include(f => f.Requester) + .Include(f => f.Addressee) + .Where(f => f.RequesterId == userId && f.Status != FriendshipStatus.Accepted) + .ToListAsync(); + } +} \ No newline at end of file diff --git a/Govor.Application/Services/Friends/FriendsBlockService.cs b/Govor.Application/Friends/FriendsBlockService.cs similarity index 79% rename from Govor.Application/Services/Friends/FriendsBlockService.cs rename to Govor.Application/Friends/FriendsBlockService.cs index 991f760..57c265c 100644 --- a/Govor.Application/Services/Friends/FriendsBlockService.cs +++ b/Govor.Application/Friends/FriendsBlockService.cs @@ -1,6 +1,4 @@ -using Govor.Application.Interfaces; - -namespace Govor.Application.Services.Friends; +namespace Govor.Application.Friends; public class FriendsBlockService : IFriendsBlockService { diff --git a/Govor.Application/Friends/FriendshipService.cs b/Govor.Application/Friends/FriendshipService.cs new file mode 100644 index 0000000..778c7a5 --- /dev/null +++ b/Govor.Application/Friends/FriendshipService.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore; +using Govor.Domain; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; + +namespace Govor.Application.Friends; + +public class FriendshipService : IFriendshipService +{ + private readonly GovorDbContext _context; + + public FriendshipService(GovorDbContext context) + { + _context = context; + } + + public async Task> SearchUsersAsync(string query, Guid currentId) + { + if (string.IsNullOrWhiteSpace(query)) + { + return []; + } + + return await _context.Users + .AsNoTracking() + .Where(u => u.Id != currentId && u.Username.Contains(query)) + .Take(5) + .ToListAsync(); + } + + public async Task> GetPotentialFriendsAsync(Guid userId) + { + var pendingFriendships = await _context.Friendships + .AsNoTracking() + .Include(f => f.Requester) + .Include(f => f.Addressee) + .Where(f => (f.RequesterId == userId || f.AddresseeId == userId) + && f.Status == FriendshipStatus.Pending) + .ToListAsync(); + + return pendingFriendships + .Select(f => f.RequesterId == userId ? f.Addressee : f.Requester) + .ToList(); + } + + public async Task> GetFriendsAsync(Guid userId) + { + var acceptedFriendships = await _context.Friendships + .AsNoTracking() + .Include(f => f.Requester) + .Include(f => f.Addressee) + .Where(f => (f.RequesterId == userId || f.AddresseeId == userId) + && f.Status == FriendshipStatus.Accepted) + .ToListAsync(); + + var friends = acceptedFriendships + .Select(f => f.RequesterId == userId ? f.Addressee : f.Requester) + .ToList(); + + return friends; + } +} \ No newline at end of file diff --git a/Govor.Application/Friends/IFriendRequestCommandService.cs b/Govor.Application/Friends/IFriendRequestCommandService.cs new file mode 100644 index 0000000..1ed7d01 --- /dev/null +++ b/Govor.Application/Friends/IFriendRequestCommandService.cs @@ -0,0 +1,11 @@ +using Govor.Domain.Common; +using Govor.Domain.Models; + +namespace Govor.Application.Friends; + +public interface IFriendRequestCommandService +{ + Task> SendAsync(Guid fromUserId, Guid toUserId); + Task> AcceptAsync(Guid requestId, Guid currentUserId); + Task> RejectAsync(Guid requestId, Guid currentUserId); +} diff --git a/Govor.Application/Interfaces/Friends/IFriendRequestQueryService.cs b/Govor.Application/Friends/IFriendRequestQueryService.cs similarity index 69% rename from Govor.Application/Interfaces/Friends/IFriendRequestQueryService.cs rename to Govor.Application/Friends/IFriendRequestQueryService.cs index 93e9525..1c18eb8 100644 --- a/Govor.Application/Interfaces/Friends/IFriendRequestQueryService.cs +++ b/Govor.Application/Friends/IFriendRequestQueryService.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models; +using Govor.Domain.Models; -namespace Govor.Application.Interfaces.Friends; +namespace Govor.Application.Friends; public interface IFriendRequestQueryService diff --git a/Govor.Application/Interfaces/Friends/IFriendsBlockService.cs b/Govor.Application/Friends/IFriendsBlockService.cs similarity index 81% rename from Govor.Application/Interfaces/Friends/IFriendsBlockService.cs rename to Govor.Application/Friends/IFriendsBlockService.cs index 2d69160..2883143 100644 --- a/Govor.Application/Interfaces/Friends/IFriendsBlockService.cs +++ b/Govor.Application/Friends/IFriendsBlockService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Friends; public interface IFriendsBlockService { diff --git a/Govor.Application/Interfaces/Friends/IFriendshipService.cs b/Govor.Application/Friends/IFriendshipService.cs similarity index 73% rename from Govor.Application/Interfaces/Friends/IFriendshipService.cs rename to Govor.Application/Friends/IFriendshipService.cs index 0351278..ff8e262 100644 --- a/Govor.Application/Interfaces/Friends/IFriendshipService.cs +++ b/Govor.Application/Friends/IFriendshipService.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Application.Interfaces.Friends; +namespace Govor.Application.Friends; public interface IFriendshipService { diff --git a/Govor.Application/Interfaces/IVerifyFriendship.cs b/Govor.Application/Friends/IVerifyFriendship.cs similarity index 80% rename from Govor.Application/Interfaces/IVerifyFriendship.cs rename to Govor.Application/Friends/IVerifyFriendship.cs index 27fb6bb..4e9dcf4 100644 --- a/Govor.Application/Interfaces/IVerifyFriendship.cs +++ b/Govor.Application/Friends/IVerifyFriendship.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Friends; public interface IVerifyFriendship { diff --git a/Govor.Application/Friends/VerifierFriendship.cs b/Govor.Application/Friends/VerifierFriendship.cs new file mode 100644 index 0000000..9382fc8 --- /dev/null +++ b/Govor.Application/Friends/VerifierFriendship.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore; +using Govor.Application.Exceptions.VerifyFriendship; +using Govor.Domain; +using Govor.Domain.Models; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Friends; + +public class VerifyFriendship : IVerifyFriendship +{ + private readonly GovorDbContext _dbContext; + private readonly ILogger _logger; + private const string FriendshipNotAcceptedError = "Friendship between user {0} and friend {1} does not exist or is not accepted."; + + public VerifyFriendship(GovorDbContext dbContext, ILogger logger) + { + _dbContext = dbContext; + _logger = logger; + } + + public async Task VerifyAsync(Guid targetUserId, Guid friendUserId) + { + if (targetUserId == Guid.Empty || friendUserId == Guid.Empty) + { + _logger.LogWarning("Invalid user IDs provided: targetUserId={TargetUserId}, friendUserId={FriendUserId}", targetUserId, friendUserId); + throw new ArgumentException("User IDs cannot be empty."); + } + + + var isFriendshipAccepted = await _dbContext.Friendships + .AsNoTracking() + .AnyAsync(f => f.Status == FriendshipStatus.Accepted && + ((f.RequesterId == targetUserId && f.AddresseeId == friendUserId) || + (f.RequesterId == friendUserId && f.AddresseeId == targetUserId))); + + if (!isFriendshipAccepted) + { + var errorMessage = string.Format(FriendshipNotAcceptedError, targetUserId, friendUserId); + _logger.LogError(errorMessage); + throw new FriendshipException(errorMessage); + } + + _logger.LogInformation("Friendship verified successfully for targetUserId={TargetUserId}, friendUserId={FriendUserId}", targetUserId, friendUserId); + } + + public async Task TryVerifyAsync(Guid targetUserId, Guid friendUserId) + { + if (targetUserId == Guid.Empty || friendUserId == Guid.Empty) + { + return false; + } + + return await _dbContext.Friendships + .AsNoTracking() + .AnyAsync(f => f.Status == FriendshipStatus.Accepted && + ((f.RequesterId == targetUserId && f.AddresseeId == friendUserId) || + (f.RequesterId == friendUserId && f.AddresseeId == targetUserId))); + } +} diff --git a/Govor.Application/Govor.Application.csproj b/Govor.Application/Govor.Application.csproj index 7b3731b..3fc6ad7 100644 --- a/Govor.Application/Govor.Application.csproj +++ b/Govor.Application/Govor.Application.csproj @@ -6,19 +6,23 @@ enable - - - - - + + + + + + + + + diff --git a/Govor.Application/Interfaces/IGroupService.cs b/Govor.Application/Groups/IGroupService.cs similarity index 79% rename from Govor.Application/Interfaces/IGroupService.cs rename to Govor.Application/Groups/IGroupService.cs index c3a8a40..830b079 100644 --- a/Govor.Application/Interfaces/IGroupService.cs +++ b/Govor.Application/Groups/IGroupService.cs @@ -1,8 +1,8 @@ -using Govor.Application.Interfaces.Messages.Parameters; -using Govor.Core.Models; -using Govor.Core.Models.Users; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; -namespace Govor.Application.Interfaces; +namespace Govor.Application.Groups; public interface IGroupService { diff --git a/Govor.Application/Interfaces/IUserGroupsGetterService.cs b/Govor.Application/Groups/IUserGroupsGetterService.cs similarity index 61% rename from Govor.Application/Interfaces/IUserGroupsGetterService.cs rename to Govor.Application/Groups/IUserGroupsGetterService.cs index a07ad39..184c924 100644 --- a/Govor.Application/Interfaces/IUserGroupsGetterService.cs +++ b/Govor.Application/Groups/IUserGroupsGetterService.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models; +using Govor.Domain.Models; -namespace Govor.Application.Interfaces; +namespace Govor.Application.Groups; public interface IUserGroupsGetterService { diff --git a/Govor.Application/Groups/UserGroupsGetterService.cs b/Govor.Application/Groups/UserGroupsGetterService.cs new file mode 100644 index 0000000..3f0e283 --- /dev/null +++ b/Govor.Application/Groups/UserGroupsGetterService.cs @@ -0,0 +1,25 @@ +using Govor.Domain; +using Govor.Domain.Models; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Groups; + +public class UserGroupsGetterService : IUserGroupsGetterService +{ + private readonly GovorDbContext _context; + + public UserGroupsGetterService(GovorDbContext context) + { + _context = context; + } + + public async Task> GetUserGroupsAsync(Guid userId) + { + return await _context.GroupMemberships + .AsNoTracking() + .Where(m => m.UserId == userId) + .Select(m => m.ChatGroup) + .ToListAsync(); + } + +} \ No newline at end of file diff --git a/Govor.Application/Infrastructure/AdminsStuff/IInvitationGetter.cs b/Govor.Application/Infrastructure/AdminsStuff/IInvitationGetter.cs new file mode 100644 index 0000000..e34c12d --- /dev/null +++ b/Govor.Application/Infrastructure/AdminsStuff/IInvitationGetter.cs @@ -0,0 +1,10 @@ +using Govor.Domain.Common; +using Govor.Domain.Models; + +namespace Govor.Application.Infrastructure.AdminsStuff; + +public interface IInvitationGetter +{ + Task> GetAllAsync(); + Task> FindByIdAsync(Guid id); +} \ No newline at end of file diff --git a/Govor.Application/Interfaces/IInvitionGenerator.cs b/Govor.Application/Infrastructure/AdminsStuff/IInvitionGenerator.cs similarity index 73% rename from Govor.Application/Interfaces/IInvitionGenerator.cs rename to Govor.Application/Infrastructure/AdminsStuff/IInvitionGenerator.cs index 05d80c2..5009599 100644 --- a/Govor.Application/Interfaces/IInvitionGenerator.cs +++ b/Govor.Application/Infrastructure/AdminsStuff/IInvitionGenerator.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Infrastructure.AdminsStuff; public interface IInvitationGenerator { diff --git a/Govor.Application/Interfaces/IUsersAdministration.cs b/Govor.Application/Infrastructure/AdminsStuff/IUsersAdministration.cs similarity index 66% rename from Govor.Application/Interfaces/IUsersAdministration.cs rename to Govor.Application/Infrastructure/AdminsStuff/IUsersAdministration.cs index da49e27..7168139 100644 --- a/Govor.Application/Interfaces/IUsersAdministration.cs +++ b/Govor.Application/Infrastructure/AdminsStuff/IUsersAdministration.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Application.Interfaces; +namespace Govor.Application.Infrastructure.AdminsStuff; public interface IUsersAdministration { diff --git a/Govor.Application/Infrastructure/AdminsStuff/InvitationGenerator.cs b/Govor.Application/Infrastructure/AdminsStuff/InvitationGenerator.cs index f2000b7..4e83563 100644 --- a/Govor.Application/Infrastructure/AdminsStuff/InvitationGenerator.cs +++ b/Govor.Application/Infrastructure/AdminsStuff/InvitationGenerator.cs @@ -1,10 +1,9 @@ -using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.Invaites; +using Govor.Domain; +using Govor.Domain.Models; namespace Govor.Application.Infrastructure.AdminsStuff; -public class InvitationGenerator(IInvitesRepository repository) : IInvitationGenerator +public class InvitationGenerator(GovorDbContext context) : IInvitationGenerator { public async Task GenerateInvitationCode(DateTime time, int maxUsers, bool isAdmin, string description = "") { @@ -19,7 +18,9 @@ public class InvitationGenerator(IInvitesRepository repository) : IInvitationGen IsAdmin = isAdmin }; - await repository.AddAsync(newInvitation); + await context.Invitations.AddAsync(newInvitation); + + await context.SaveChangesAsync(); return newInvitation.Code; } diff --git a/Govor.Application/Infrastructure/AdminsStuff/InvitationGetter.cs b/Govor.Application/Infrastructure/AdminsStuff/InvitationGetter.cs new file mode 100644 index 0000000..961eaa1 --- /dev/null +++ b/Govor.Application/Infrastructure/AdminsStuff/InvitationGetter.cs @@ -0,0 +1,41 @@ +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Infrastructure.AdminsStuff; + +public class InvitationGetter : IInvitationGetter +{ + private readonly ILogger _logger; + private readonly GovorDbContext _context; + + public InvitationGetter(ILogger logger, GovorDbContext context) + { + _logger = logger; + _context = context; + } + + public async Task> GetAllAsync() + { + return await _context.Invitations + .AsNoTracking() + .Where(iv => iv.IsActive) + .ToListAsync(); + } + + public async Task> FindByIdAsync(Guid id) + { + var res = await _context.Invitations.AsNoTracking() + .FirstOrDefaultAsync(iv => iv.Id == id); + + if (res is null) + return Result.Failure(new Error( + nameof(InvalidOperationException), + "Invitation not found.") + ); + + return res; + } +} \ No newline at end of file diff --git a/Govor.Application/Infrastructure/AdminsStuff/UsersService.cs b/Govor.Application/Infrastructure/AdminsStuff/UsersService.cs index fa8ad21..0f4d982 100644 --- a/Govor.Application/Infrastructure/AdminsStuff/UsersService.cs +++ b/Govor.Application/Infrastructure/AdminsStuff/UsersService.cs @@ -1,54 +1,45 @@ -using Govor.Application.Interfaces; -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; +using Govor.Application.Authentication; +using Govor.Domain; +using Govor.Domain.Models.Users; +using Microsoft.EntityFrameworkCore; namespace Govor.Application.Infrastructure.AdminsStuff; public class UsersService : IUsersAdministration { - private readonly IUsersRepository _usersRepository; + private readonly GovorDbContext _context; private readonly IPasswordHasher _passwordHasher; - public UsersService(IUsersRepository usersRepository, IPasswordHasher passwordHasher) + public UsersService(GovorDbContext context, IPasswordHasher passwordHasher) { - _usersRepository = usersRepository; + _context = context; _passwordHasher = passwordHasher; } public async Task> GetAllUsersAsync() { - try - { - var results = await _usersRepository.GetAllAsync(); - return results; - } - catch (NotFoundException ex) - { - return new List(); - } + var results = await _context.Users + .AsNoTracking() + .Take(50) + .ToListAsync(); + return results; } public async Task SetPasswordAsync(Guid userId, string password) { - try - { - var user = await _usersRepository.FindByIdAsync(userId); - - user.PasswordHash = _passwordHasher.Hash(password); - - await _usersRepository.UpdateAsync(user); - } - catch (NotFoundException ex) - { - throw new NotFoundException(ex.Message); - } + var user = await GetUserById(userId); + + if (user is null) + return; + + user.PasswordHash = _passwordHasher.Hash(password); + + await _context.SaveChangesAsync(); } public async Task GetUserById(Guid userId) { - var result = await _usersRepository.FindByIdAsync(userId); + var result = await _context.Users.FirstOrDefaultAsync(user => user.Id == userId); return result; } diff --git a/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs b/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs index dfe4732..2a57b30 100644 --- a/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs +++ b/Govor.Application/Infrastructure/Extensions/CurrentUserService.cs @@ -1,5 +1,3 @@ -using System.Security.Claims; -using Govor.Application.Interfaces.Infrastructure.Extensions; using Microsoft.AspNetCore.Http; namespace Govor.Application.Infrastructure.Extensions; diff --git a/Govor.Application/Infrastructure/Extensions/CurrentUserSessionService.cs b/Govor.Application/Infrastructure/Extensions/CurrentUserSessionService.cs index f986ab4..8af58b8 100644 --- a/Govor.Application/Infrastructure/Extensions/CurrentUserSessionService.cs +++ b/Govor.Application/Infrastructure/Extensions/CurrentUserSessionService.cs @@ -1,4 +1,3 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; using Microsoft.AspNetCore.Http; namespace Govor.Application.Infrastructure.Extensions; diff --git a/Govor.Application/Interfaces/IConnectionStore.cs b/Govor.Application/Infrastructure/Extensions/IConnectionStore.cs similarity index 78% rename from Govor.Application/Interfaces/IConnectionStore.cs rename to Govor.Application/Infrastructure/Extensions/IConnectionStore.cs index 3548722..2ded8fe 100644 --- a/Govor.Application/Interfaces/IConnectionStore.cs +++ b/Govor.Application/Infrastructure/Extensions/IConnectionStore.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Infrastructure.Extensions; public interface IConnectionStore { diff --git a/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs b/Govor.Application/Infrastructure/Extensions/ICurrentUserService.cs similarity index 50% rename from Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs rename to Govor.Application/Infrastructure/Extensions/ICurrentUserService.cs index 42e1156..b59e0f6 100644 --- a/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserService.cs +++ b/Govor.Application/Infrastructure/Extensions/ICurrentUserService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.Infrastructure.Extensions; +namespace Govor.Application.Infrastructure.Extensions; public interface ICurrentUserService { diff --git a/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserSessionService.cs b/Govor.Application/Infrastructure/Extensions/ICurrentUserSessionService.cs similarity index 53% rename from Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserSessionService.cs rename to Govor.Application/Infrastructure/Extensions/ICurrentUserSessionService.cs index f4000a9..3d313d2 100644 --- a/Govor.Application/Interfaces/Infrastructure/Extensions/ICurrentUserSessionService.cs +++ b/Govor.Application/Infrastructure/Extensions/ICurrentUserSessionService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.Infrastructure.Extensions; +namespace Govor.Application.Infrastructure.Extensions; public interface ICurrentUserSessionService { diff --git a/Govor.Application/Interfaces/IFriendsService.cs b/Govor.Application/Infrastructure/Extensions/IFriendsService.cs similarity index 81% rename from Govor.Application/Interfaces/IFriendsService.cs rename to Govor.Application/Infrastructure/Extensions/IFriendsService.cs index 4933f6f..21fd1c1 100644 --- a/Govor.Application/Interfaces/IFriendsService.cs +++ b/Govor.Application/Infrastructure/Extensions/IFriendsService.cs @@ -1,7 +1,7 @@ -using Govor.Core.Models; -using Govor.Core.Models.Users; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; -namespace Govor.Application.Interfaces; +namespace Govor.Application.Infrastructure.Extensions; public interface IFriendsService { diff --git a/Govor.Application/Infrastructure/Validators/IUsernameValidator.cs b/Govor.Application/Infrastructure/Validators/IUsernameValidator.cs new file mode 100644 index 0000000..46106c0 --- /dev/null +++ b/Govor.Application/Infrastructure/Validators/IUsernameValidator.cs @@ -0,0 +1,9 @@ +using Govor.Domain.Common; + +namespace Govor.Application.Infrastructure.Validators; + +public interface IUsernameValidator +{ + Result Validate(string username); + bool TryValidate(string username); +} \ No newline at end of file diff --git a/Govor.Application/Infrastructure/Validators/UsernameValidator.cs b/Govor.Application/Infrastructure/Validators/UsernameValidator.cs index c9b4953..4e9c531 100644 --- a/Govor.Application/Infrastructure/Validators/UsernameValidator.cs +++ b/Govor.Application/Infrastructure/Validators/UsernameValidator.cs @@ -1,13 +1,15 @@ using System.Text.RegularExpressions; -using Govor.Application.Exceptions.AuthService; -using Govor.Application.Interfaces.Authentication; -using Govor.Core.Infrastructure.Validators; +using Govor.Application.Authentication.Exceptions; +using Govor.Domain.Common.Constants; +using Govor.Domain.Common; using Microsoft.Extensions.Configuration; namespace Govor.Application.Infrastructure.Validators; public class UsernameValidator : IUsernameValidator { + private const string ErrorCode = nameof(InvalidUsernameException); + private readonly Regex _usernameRegex = new(@"^[А-Яа-яЁё]+[А-Яа-яЁё0-9]*$", RegexOptions.Compiled); private readonly HashSet _blockedExact; @@ -37,43 +39,61 @@ public class UsernameValidator : IUsernameValidator ?? throw new InvalidOperationException("Reserved not set"); } - public void Validate(string username) + public Result Validate(string username) { - if(username.Length < UserValidator.MIN_LENGHT_OF_NAME || username.Length > UserValidator.MAX_LENGHT_OF_NAME) - throw new InvalidUsernameException($"Username must be between {UserValidator.MIN_LENGHT_OF_NAME} and {UserValidator.MAX_LENGHT_OF_NAME} characters."); - - if (!_usernameRegex.IsMatch(username)) - throw new InvalidUsernameException("The username must be in Cyrillic and start with a letter."); + if (username.Length < UserConstants.MIN_LENGHT_OF_NAME || username.Length > UserConstants.MAX_LENGHT_OF_NAME) + { + return new Error( + ErrorCode, + $"Username must be between {UserConstants.MIN_LENGHT_OF_NAME} and {UserConstants.MAX_LENGHT_OF_NAME} characters."); + } + if (!_usernameRegex.IsMatch(username)) + { + return new Error( + ErrorCode, + "The username must be in Cyrillic and start with a letter."); + } + if (Regex.IsMatch(username, @"(.)\1{4,}")) - throw new InvalidUsernameException("Too many repeating characters."); + { + return new Error( + ErrorCode, + "Too many repeating characters."); + } var normalized = Normalize(username); - + if (_reserved.Contains(normalized)) - throw new InvalidUsernameException("This username is reserved."); - + { + return new Error( + ErrorCode, + "This username is reserved."); + } + if (_blockedExact.Contains(normalized)) - throw new InvalidUsernameException("This username is not allowed."); - + { + return new Error( + ErrorCode, + "This username is not allowed."); + } + foreach (var banned in _blockedContains) { if (normalized.Contains(banned)) - throw new InvalidUsernameException("Username contains prohibited content."); + { + return new Error( + ErrorCode, + "Username contains prohibited content."); + } } + + return Result.Success(); } public bool TryValidate(string username) { - try - { - Validate(username); - return true; - } - catch - { - return false; - } + return Validate(username).IsSuccess; } private static string Normalize(string username) @@ -87,4 +107,4 @@ public class UsernameValidator : IUsernameValidator .Replace("6", "б") .Replace("8", "в"); } -} \ No newline at end of file +} diff --git a/Govor.Application/Interfaces/Authentication/IAuthService.cs b/Govor.Application/Interfaces/Authentication/IAuthService.cs deleted file mode 100644 index 010e82c..0000000 --- a/Govor.Application/Interfaces/Authentication/IAuthService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; -using Govor.Core.Models.Users; - -namespace Govor.Application.Interfaces.Authentication; - -public interface IAccountService -{ - 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.Application/Interfaces/Authentication/IInvitesService.cs b/Govor.Application/Interfaces/Authentication/IInvitesService.cs deleted file mode 100644 index 86e24f8..0000000 --- a/Govor.Application/Interfaces/Authentication/IInvitesService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; -using Govor.Core.Models.Users; - -namespace Govor.Application.Interfaces.Authentication; - -public interface IInvitesService -{ - public Task GetRoleAsync(User user); - public Task ValidateAsync(string inviteCode); -} \ No newline at end of file diff --git a/Govor.Application/Interfaces/Authentication/IUsernameValidator.cs b/Govor.Application/Interfaces/Authentication/IUsernameValidator.cs deleted file mode 100644 index 74fd6de..0000000 --- a/Govor.Application/Interfaces/Authentication/IUsernameValidator.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Govor.Core.Infrastructure.Validators; - -namespace Govor.Application.Interfaces.Authentication; - -public interface IUsernameValidator : IObjectValidator -{ - -} \ No newline at end of file diff --git a/Govor.Application/Interfaces/Friends/IFriendRequestCommandService.cs b/Govor.Application/Interfaces/Friends/IFriendRequestCommandService.cs deleted file mode 100644 index 3d3c4e4..0000000 --- a/Govor.Application/Interfaces/Friends/IFriendRequestCommandService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Application.Interfaces.Friends; - -public interface IFriendRequestCommandService -{ - Task SendAsync(Guid fromUserId, Guid toUserId); - Task AcceptAsync(Guid requestId, Guid currentUserId); - Task RejectAsync(Guid requestId, Guid currentUserId); -} diff --git a/Govor.Application/Interfaces/IProfileService.cs b/Govor.Application/Interfaces/IProfileService.cs deleted file mode 100644 index 37a717f..0000000 --- a/Govor.Application/Interfaces/IProfileService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Application.Profiles; - -namespace Govor.Application.Interfaces; - -public interface IProfileService -{ - public Task GetUserProfileAsync(Guid userId); - public Task SetDescription(string description, Guid userId); - public Task SetNewIcon(Guid userId, Guid iconId); -} diff --git a/Govor.Application/Interfaces/IUserPrivateChatsGetterService.cs b/Govor.Application/Interfaces/IUserPrivateChatsGetterService.cs deleted file mode 100644 index 53dee37..0000000 --- a/Govor.Application/Interfaces/IUserPrivateChatsGetterService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Application.Interfaces; - -public interface IUserPrivateChatsGetterService -{ - Task> GetUserChatsAsync(Guid userId); -} \ No newline at end of file diff --git a/Govor.Application/Interfaces/Messages/IMessageCommandService.cs b/Govor.Application/Interfaces/Messages/IMessageCommandService.cs deleted file mode 100644 index b927074..0000000 --- a/Govor.Application/Interfaces/Messages/IMessageCommandService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Govor.Application.Interfaces.Messages.Parameters; -using Govor.Core.Models.Messages; - -namespace Govor.Application.Interfaces.Messages; - -// Combining IChatService and IGroupService functionalities relevant to messages -public interface IMessageCommandService -{ - Task SendMessageAsync(SendMessage messageParameters); - Task EditMessageAsync(EditMessage messageParameters); - Task DeleteMessageAsync(DeleteMessage messageParameters); - - // Potentially other message-related methods like: - // Task GetMessagesAsync(Guid userId, Guid chatId, RecipientType chatType, int pageNumber, int pageSize); - // Task MarkMessageAsReadAsync(Guid userId, Guid messageId); -} - - - -public record SendMessageResult(bool IsSuccess, Exception? Exception, Message Message) - : Result(IsSuccess, Exception, Message?.Id ?? Guid.Empty); - -public record EditMessageResult(bool IsSuccess, Exception? Exception, Message? OriginalMessage) - : Result(IsSuccess, Exception, OriginalMessage?.Id ?? Guid.Empty) -{ - -} - -public record DeleteMessageResult(bool IsSuccess, Exception? Exception, Message? OriginalMessage) - : Result(IsSuccess, Exception, OriginalMessage?.Id ?? Guid.Empty); diff --git a/Govor.Application/Interfaces/Messages/Parameters/DeleteMessage.cs b/Govor.Application/Interfaces/Messages/Parameters/DeleteMessage.cs deleted file mode 100644 index ceed39d..0000000 --- a/Govor.Application/Interfaces/Messages/Parameters/DeleteMessage.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Govor.Application.Interfaces.Messages.Parameters; - -public record DeleteMessage( - Guid DeleterId, - Guid MessageId); \ No newline at end of file diff --git a/Govor.Application/Interfaces/Messages/Parameters/Result.cs b/Govor.Application/Interfaces/Messages/Parameters/Result.cs deleted file mode 100644 index 7151e86..0000000 --- a/Govor.Application/Interfaces/Messages/Parameters/Result.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Govor.Application.Interfaces.Messages.Parameters; - -public record Result(bool IsSuccess, Exception Exception, Guid messageId); \ No newline at end of file diff --git a/Govor.Application/Interfaces/Messages/Parameters/SendMedia.cs b/Govor.Application/Interfaces/Messages/Parameters/SendMedia.cs deleted file mode 100644 index e07b452..0000000 --- a/Govor.Application/Interfaces/Messages/Parameters/SendMedia.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Application.Interfaces.Messages.Parameters; - -public record SendMedia(Guid MediaId, string EncryptedKey); \ No newline at end of file diff --git a/Govor.Application/Interfaces/PushNotifications/IPushNotificationService.cs b/Govor.Application/Interfaces/PushNotifications/IPushNotificationService.cs deleted file mode 100644 index e7872fa..0000000 --- a/Govor.Application/Interfaces/PushNotifications/IPushNotificationService.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Govor.Application.Interfaces.PushNotifications; - -public interface IPushNotificationService -{ - Task SendToUserAsync(Guid userId, string title, string body, string channelId, string tag = "", Dictionary? data = null); - - Task SendToUsersAsync(IEnumerable userIds, string title, string body, string channelId, string tag = "", Dictionary? data = null); - - Task SendToSessionAsync(Guid sessionId, string title, string body, string channelId, string tag = "", Dictionary? data = null); -} \ No newline at end of file diff --git a/Govor.Application/Interfaces/UserSession/IUserSessionOpener.cs b/Govor.Application/Interfaces/UserSession/IUserSessionOpener.cs deleted file mode 100644 index 243688c..0000000 --- a/Govor.Application/Interfaces/UserSession/IUserSessionOpener.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Application.Interfaces.UserSession; - - -public interface IUserSessionOpener -{ - Task OpenSessionAsync(User user, string deviceInfo); -} - diff --git a/Govor.Application/Interfaces/UserSession/IUserSessionReader.cs b/Govor.Application/Interfaces/UserSession/IUserSessionReader.cs deleted file mode 100644 index 3800917..0000000 --- a/Govor.Application/Interfaces/UserSession/IUserSessionReader.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Application.Interfaces.UserSession; - -public interface IUserSessionReader -{ - Task> GetAllSessionsAsync(Guid userId); -} diff --git a/Govor.Application/Interfaces/UserSession/IUserSessionRefresher.cs b/Govor.Application/Interfaces/UserSession/IUserSessionRefresher.cs deleted file mode 100644 index 1020f96..0000000 --- a/Govor.Application/Interfaces/UserSession/IUserSessionRefresher.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Govor.Application.Interfaces.UserSession; - -public interface IUserSessionRefresher -{ - Task RefreshTokenAsync(string refreshToken); -} - -public record RefreshResult(string refreshToken, string accessToken); \ No newline at end of file diff --git a/Govor.Application/Interfaces/UserSession/IUserSessionRevoker.cs b/Govor.Application/Interfaces/UserSession/IUserSessionRevoker.cs deleted file mode 100644 index af256fa..0000000 --- a/Govor.Application/Interfaces/UserSession/IUserSessionRevoker.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Govor.Application.Interfaces.UserSession; - - -public interface IUserSessionRevoker -{ - Task CloseSessionByIdAsync(Guid sessionId, Guid userId); - Task CloseAllSessionsAsync(Guid userId); -} diff --git a/Govor.Application/Services/Medias/AccesserToDownloadMediaService.cs b/Govor.Application/Medias/AccesserToDownloadMediaService.cs similarity index 91% rename from Govor.Application/Services/Medias/AccesserToDownloadMediaService.cs rename to Govor.Application/Medias/AccesserToDownloadMediaService.cs index c92c024..6fee042 100644 --- a/Govor.Application/Services/Medias/AccesserToDownloadMediaService.cs +++ b/Govor.Application/Medias/AccesserToDownloadMediaService.cs @@ -1,9 +1,8 @@ -using Govor.Application.Interfaces.Medias; -using Govor.Core.Models; -using Govor.Data; +using Govor.Domain.Models; +using Govor.Domain; using Microsoft.EntityFrameworkCore; -namespace Govor.Application.Services.Medias; +namespace Govor.Application.Medias; public class AccesserToDownloadMediaService : IAccesserToDownloadMedia { diff --git a/Govor.Application/Interfaces/Medias/IAccesserToDownloadMedia.cs b/Govor.Application/Medias/IAccesserToDownloadMedia.cs similarity index 69% rename from Govor.Application/Interfaces/Medias/IAccesserToDownloadMedia.cs rename to Govor.Application/Medias/IAccesserToDownloadMedia.cs index a55669e..600296f 100644 --- a/Govor.Application/Interfaces/Medias/IAccesserToDownloadMedia.cs +++ b/Govor.Application/Medias/IAccesserToDownloadMedia.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.Medias; +namespace Govor.Application.Medias; public interface IAccesserToDownloadMedia { diff --git a/Govor.Application/Interfaces/Medias/IMediaService.cs b/Govor.Application/Medias/IMediaService.cs similarity index 79% rename from Govor.Application/Interfaces/Medias/IMediaService.cs rename to Govor.Application/Medias/IMediaService.cs index 53def6b..8e52df9 100644 --- a/Govor.Application/Interfaces/Medias/IMediaService.cs +++ b/Govor.Application/Medias/IMediaService.cs @@ -1,7 +1,7 @@ -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; -namespace Govor.Application.Interfaces.Medias; +namespace Govor.Application.Medias; public interface IMediaService { diff --git a/Govor.Application/Services/Medias/MediaService.cs b/Govor.Application/Medias/MediaService.cs similarity index 96% rename from Govor.Application/Services/Medias/MediaService.cs rename to Govor.Application/Medias/MediaService.cs index 828e6e8..b0adbd6 100644 --- a/Govor.Application/Services/Medias/MediaService.cs +++ b/Govor.Application/Medias/MediaService.cs @@ -1,11 +1,10 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Medias; -using Govor.Core.Models; -using Govor.Data; +using Govor.Application.Storage; +using Govor.Domain.Models; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.Medias; +namespace Govor.Application.Medias; public class MediaService : IMediaService { diff --git a/Govor.Application/Messages/IMessageEditingService.cs b/Govor.Application/Messages/IMessageEditingService.cs new file mode 100644 index 0000000..f94258d --- /dev/null +++ b/Govor.Application/Messages/IMessageEditingService.cs @@ -0,0 +1,8 @@ +using Govor.Application.Messages.Parameters; + +namespace Govor.Application.Messages; + +public interface IMessageEditingService +{ + Task EditMessageAsync(EditMessage editParams); +} \ No newline at end of file diff --git a/Govor.Application/Messages/IMessageRemovingService.cs b/Govor.Application/Messages/IMessageRemovingService.cs new file mode 100644 index 0000000..041e71f --- /dev/null +++ b/Govor.Application/Messages/IMessageRemovingService.cs @@ -0,0 +1,8 @@ +using Govor.Application.Messages.Parameters; + +namespace Govor.Application.Messages; + +public interface IMessageRemovingService +{ + Task DeleteMessageAsync(DeleteMessage deleteParams); +} \ No newline at end of file diff --git a/Govor.Application/Messages/IMessageSendingService.cs b/Govor.Application/Messages/IMessageSendingService.cs new file mode 100644 index 0000000..13b713f --- /dev/null +++ b/Govor.Application/Messages/IMessageSendingService.cs @@ -0,0 +1,8 @@ +using Govor.Application.Messages.Parameters; + +namespace Govor.Application.Messages; + +public interface IMessageSendingService +{ + Task SendMessageAsync(SendMessage sendParams); +} \ No newline at end of file diff --git a/Govor.Application/Interfaces/IMessagesLoader.cs b/Govor.Application/Messages/IMessagesLoader.cs similarity index 80% rename from Govor.Application/Interfaces/IMessagesLoader.cs rename to Govor.Application/Messages/IMessagesLoader.cs index 67633e1..e6591a5 100644 --- a/Govor.Application/Interfaces/IMessagesLoader.cs +++ b/Govor.Application/Messages/IMessagesLoader.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; -namespace Govor.Application.Interfaces; +namespace Govor.Application.Messages; public interface IMessagesLoader { diff --git a/Govor.Application/Messages/MessageEditingService.cs b/Govor.Application/Messages/MessageEditingService.cs new file mode 100644 index 0000000..fce9b21 --- /dev/null +++ b/Govor.Application/Messages/MessageEditingService.cs @@ -0,0 +1,57 @@ +using Govor.Application.Messages.Parameters; +using Microsoft.EntityFrameworkCore; +using Govor.Domain; +using Govor.Domain.Models.Messages; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Messages; + +public class MessageEditingService : IMessageEditingService +{ + private readonly GovorDbContext _dbContext; + private readonly ILogger _logger; + + public MessageEditingService(GovorDbContext dbContext, ILogger logger) + { + _dbContext = dbContext; + _logger = logger; + } + + public async Task EditMessageAsync(EditMessage editParams) + { + var message = await _dbContext.Messages + .Include(m => m.MediaAttachments) + .FirstOrDefaultAsync(m => m.Id == editParams.MessageId); + + if (message == null) + { + return new EditMessageResult(false, new KeyNotFoundException("Message not found."), null); + } + + if (message.SenderId != editParams.EditorId) + { + _logger.LogWarning("User {EditorId} unauthorized to edit message {MessageId}", editParams.EditorId, editParams.MessageId); + return new EditMessageResult(false, new UnauthorizedAccessException("User is not authorized to edit this message."), null); + } + + var originalMessageSnapshot = new Message + { + Id = message.Id, + SenderId = message.SenderId, + RecipientId = message.RecipientId, + RecipientType = message.RecipientType, + SentAt = message.SentAt, + ReplyToMessageId = message.ReplyToMessageId, + MediaAttachments = message.MediaAttachments?.ToList() ?? [] + }; + + message.EncryptedContent = editParams.NewContent; + message.IsEdited = true; + message.EditedAt = editParams.EditedAt; + + await _dbContext.SaveChangesAsync(); + + _logger.LogInformation("Message {MessageId} edited successfully.", editParams.MessageId); + return new EditMessageResult(true, null, originalMessageSnapshot); + } +} diff --git a/Govor.Application/Messages/MessageRemovingService.cs b/Govor.Application/Messages/MessageRemovingService.cs new file mode 100644 index 0000000..51f6f59 --- /dev/null +++ b/Govor.Application/Messages/MessageRemovingService.cs @@ -0,0 +1,24 @@ +using Govor.Application.Messages.Parameters; +using Govor.Domain; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Messages; + +public class MessageRemovingService : IMessageRemovingService +{ + private readonly GovorDbContext _govorDbContext; + private readonly ILogger _logger; + + public MessageRemovingService + (GovorDbContext govorDbContext, + ILogger logger) + { + _govorDbContext = govorDbContext; + _logger = logger; + } + + public Task DeleteMessageAsync(DeleteMessage deleteParams) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Govor.Application/Messages/MessageSendingService.cs b/Govor.Application/Messages/MessageSendingService.cs new file mode 100644 index 0000000..b6c318b --- /dev/null +++ b/Govor.Application/Messages/MessageSendingService.cs @@ -0,0 +1,77 @@ +using Govor.Application.Messages.Parameters; +using Microsoft.EntityFrameworkCore; +using Govor.Domain; +using Govor.Domain.Models.Messages; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Messages; + +public class MessageSendingService : IMessageSendingService +{ + private readonly GovorDbContext _dbContext; + private readonly ILogger _logger; + + public MessageSendingService(GovorDbContext dbContext, ILogger logger) + { + _dbContext = dbContext; + _logger = logger; + } + + public async Task SendMessageAsync(SendMessage sendParams) + { + var validationResult = sendParams.RecipientType switch + { + RecipientType.User => await ValidateUserRecipientAsync(sendParams.RecipientId), + RecipientType.Group => await ValidateGroupRecipientAsync(sendParams.FromUserId, sendParams.RecipientId), + _ => (Success: false, Error: "Invalid recipient type.") + }; + + if (!validationResult.Success) + { + _logger.LogWarning("Message send failed: {Error}", validationResult.Error); + return new SendMessageResult(false, new InvalidOperationException(validationResult.Error), default); + } + + var messageId = Guid.NewGuid(); + var message = new Message + { + Id = messageId, + SenderId = sendParams.FromUserId, + RecipientId = sendParams.RecipientId, + RecipientType = sendParams.RecipientType, + EncryptedContent = sendParams.EncryptContent, + SentAt = sendParams.SendAt, + IsEdited = false, + ReplyToMessageId = sendParams.ReplyToMessageId, + MediaAttachments = sendParams.Media?.Select(m => new MediaAttachments + { + Id = Guid.NewGuid(), + MessageId = messageId, + MediaFileId = m.MediaId + }).ToList() ?? [] + }; + + await _dbContext.Messages.AddAsync(message); + await _dbContext.SaveChangesAsync(); + + _logger.LogInformation("Message {MessageId} sent successfully.", messageId); + return new SendMessageResult(true, null, message); + } + + private async Task<(bool Success, string Error)> ValidateUserRecipientAsync(Guid chatId) + { + var chatExists = await _dbContext.PrivateChats.AnyAsync(c => c.Id == chatId); + return chatExists ? (true, null) : (false, $"Private chat {chatId} not found."); + } + + private async Task<(bool Success, string Error)> ValidateGroupRecipientAsync(Guid userId, Guid groupId) + { + var groupExists = await _dbContext.ChatGroups.AnyAsync(g => g.Id == groupId); + if (!groupExists) return (false, $"Group {groupId} not found."); + + var isMember = await _dbContext.GroupMemberships.AnyAsync(gm => gm.UserId == userId && gm.GroupId == groupId); + if (!isMember) return (false, "Sender is not a member of the group."); + + return (true, null); + } +} diff --git a/Govor.Application/Messages/MessagesLoader.cs b/Govor.Application/Messages/MessagesLoader.cs new file mode 100644 index 0000000..ba11f1e --- /dev/null +++ b/Govor.Application/Messages/MessagesLoader.cs @@ -0,0 +1,107 @@ +using Govor.Application.Interfaces; +using Govor.Domain.Models.Messages; +using Govor.Domain; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Messages; + +public class MessagesLoader : IMessagesLoader +{ + private readonly GovorDbContext _dbContext; + + public MessagesLoader(GovorDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task> LoadMessagesInUserChat( + Guid privateChatId, + Guid currentUser, + Guid? startMessageId, + int before = 20, + int after = 2) + { + if (privateChatId == Guid.Empty) + throw new ArgumentException("PrivateChatId id cannot be empty", nameof(privateChatId)); + + var chatExists = await _dbContext.PrivateChats.AnyAsync(c => c.Id == privateChatId); + if (!chatExists) + return []; + + var query = _dbContext.Messages + .AsNoTracking() + .Include(m => m.MediaAttachments) + .ThenInclude(m => m.MediaFile) + .Where(m => m.RecipientType == RecipientType.User && m.RecipientId == privateChatId); + + return await FetchPaginatedMessagesAsync(query, startMessageId, before, after); + } + + public async Task> LoadMessagesInChatGroup( + Guid chatId, + Guid currentUser, + Guid? startMessageId, + int before = 20, + int after = 2) + { + if (chatId == Guid.Empty) + throw new ArgumentException("Chat id cannot be empty", nameof(chatId)); + + var isMember = await _dbContext.GroupMemberships + .AnyAsync(gm => gm.UserId == currentUser && gm.GroupId == chatId); + + if (!isMember) + return []; + + var query = _dbContext.Messages + .AsNoTracking() + .Include(m => m.MediaAttachments) + .ThenInclude(m => m.MediaFile) + .AsSplitQuery() + .Where(m => m.RecipientType == RecipientType.Group && m.RecipientId == chatId); + + return await FetchPaginatedMessagesAsync(query, startMessageId, before, after); + } + + private static async Task> FetchPaginatedMessagesAsync( + IQueryable baseQuery, + Guid? startMessageId, + int before, + int after) + { + if (startMessageId is null) + { + return await baseQuery + .OrderByDescending(m => m.SentAt) + .Take(before) + .OrderBy(m => m.SentAt) + .ToListAsync(); + } + + var startMessage = await baseQuery.FirstOrDefaultAsync(m => m.Id == startMessageId.Value); + if (startMessage == null) + return []; + + var beforeMessages = await baseQuery + .Where(m => m.SentAt < startMessage.SentAt) + .OrderByDescending(m => m.SentAt) + .Take(before) + .ToListAsync(); + + var afterMessages = await baseQuery + .Where(m => m.SentAt > startMessage.SentAt) + .OrderBy(m => m.SentAt) + .Take(after) + .ToListAsync(); + + + beforeMessages.Reverse(); + + var result = new List(beforeMessages.Count + 1 + afterMessages.Count); + result.AddRange(beforeMessages); + result.Add(startMessage); + result.AddRange(afterMessages); + + return result; + } +} diff --git a/Govor.Application/Messages/Parameters/DeleteMessage.cs b/Govor.Application/Messages/Parameters/DeleteMessage.cs new file mode 100644 index 0000000..409c848 --- /dev/null +++ b/Govor.Application/Messages/Parameters/DeleteMessage.cs @@ -0,0 +1,5 @@ +namespace Govor.Application.Messages.Parameters; + +public record DeleteMessage( + Guid DeleterId, + Guid MessageId); \ No newline at end of file diff --git a/Govor.Application/Messages/Parameters/DeleteMessageResult.cs b/Govor.Application/Messages/Parameters/DeleteMessageResult.cs new file mode 100644 index 0000000..39e8a89 --- /dev/null +++ b/Govor.Application/Messages/Parameters/DeleteMessageResult.cs @@ -0,0 +1,6 @@ +using Govor.Domain.Models.Messages; + +namespace Govor.Application.Messages.Parameters; + +public record DeleteMessageResult(bool IsSuccess, Exception? Exception, Message? OriginalMessage) + : Result(IsSuccess, Exception, OriginalMessage?.Id ?? Guid.Empty); diff --git a/Govor.Application/Interfaces/Messages/Parameters/EditMessage.cs b/Govor.Application/Messages/Parameters/EditMessage.cs similarity index 52% rename from Govor.Application/Interfaces/Messages/Parameters/EditMessage.cs rename to Govor.Application/Messages/Parameters/EditMessage.cs index 4c0e6af..f167df7 100644 --- a/Govor.Application/Interfaces/Messages/Parameters/EditMessage.cs +++ b/Govor.Application/Messages/Parameters/EditMessage.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.Messages.Parameters; +namespace Govor.Application.Messages.Parameters; public record EditMessage( Guid EditorId, diff --git a/Govor.Application/Messages/Parameters/EditMessageResult.cs b/Govor.Application/Messages/Parameters/EditMessageResult.cs new file mode 100644 index 0000000..759c0c4 --- /dev/null +++ b/Govor.Application/Messages/Parameters/EditMessageResult.cs @@ -0,0 +1,9 @@ +using Govor.Domain.Models.Messages; + +namespace Govor.Application.Messages.Parameters; + +public record EditMessageResult(bool IsSuccess, Exception? Exception, Message? OriginalMessage) + : Result(IsSuccess, Exception, OriginalMessage?.Id ?? Guid.Empty) +{ + +} \ No newline at end of file diff --git a/Govor.Application/Messages/Parameters/Result.cs b/Govor.Application/Messages/Parameters/Result.cs new file mode 100644 index 0000000..b548135 --- /dev/null +++ b/Govor.Application/Messages/Parameters/Result.cs @@ -0,0 +1,3 @@ +namespace Govor.Application.Messages.Parameters; + +public record Result(bool IsSuccess, Exception Exception, Guid messageId); \ No newline at end of file diff --git a/Govor.Application/Messages/Parameters/SendMedia.cs b/Govor.Application/Messages/Parameters/SendMedia.cs new file mode 100644 index 0000000..13333fc --- /dev/null +++ b/Govor.Application/Messages/Parameters/SendMedia.cs @@ -0,0 +1,3 @@ +namespace Govor.Application.Messages.Parameters; + +public record SendMedia(Guid MediaId, string EncryptedKey); \ No newline at end of file diff --git a/Govor.Application/Interfaces/Messages/Parameters/SendMessage.cs b/Govor.Application/Messages/Parameters/SendMessage.cs similarity index 58% rename from Govor.Application/Interfaces/Messages/Parameters/SendMessage.cs rename to Govor.Application/Messages/Parameters/SendMessage.cs index 3f68d10..5bdcf46 100644 --- a/Govor.Application/Interfaces/Messages/Parameters/SendMessage.cs +++ b/Govor.Application/Messages/Parameters/SendMessage.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; -namespace Govor.Application.Interfaces.Messages.Parameters; +namespace Govor.Application.Messages.Parameters; public record SendMessage( string EncryptContent, diff --git a/Govor.Application/Messages/Parameters/SendMessageResult.cs b/Govor.Application/Messages/Parameters/SendMessageResult.cs new file mode 100644 index 0000000..61ae63f --- /dev/null +++ b/Govor.Application/Messages/Parameters/SendMessageResult.cs @@ -0,0 +1,6 @@ +using Govor.Domain.Models.Messages; + +namespace Govor.Application.Messages.Parameters; + +public record SendMessageResult(bool IsSuccess, Exception? Exception, Message Message) + : Result(IsSuccess, Exception, Message?.Id ?? Guid.Empty); \ No newline at end of file diff --git a/Govor.Application/Interfaces/IPingHandlerService.cs b/Govor.Application/PingHandler/IPingHandlerService.cs similarity index 61% rename from Govor.Application/Interfaces/IPingHandlerService.cs rename to Govor.Application/PingHandler/IPingHandlerService.cs index fe3fa0f..366a5d0 100644 --- a/Govor.Application/Interfaces/IPingHandlerService.cs +++ b/Govor.Application/PingHandler/IPingHandlerService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.PingHandler; public interface IPingHandlerService { diff --git a/Govor.Application/Services/PingHandlerService.cs b/Govor.Application/PingHandler/PingHandlerService.cs similarity index 90% rename from Govor.Application/Services/PingHandlerService.cs rename to Govor.Application/PingHandler/PingHandlerService.cs index 1cc0e37..ac50d75 100644 --- a/Govor.Application/Services/PingHandlerService.cs +++ b/Govor.Application/PingHandler/PingHandlerService.cs @@ -1,9 +1,8 @@ -using Govor.Application.Interfaces; -using Govor.Data; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -namespace Govor.Application.Services; +namespace Govor.Application.PingHandler; public class PingHandlerService : IPingHandlerService { diff --git a/Govor.Application/Interfaces/IPrivateChatGroupManager.cs b/Govor.Application/PrivateUserChats/IPrivateChatGroupManager.cs similarity index 71% rename from Govor.Application/Interfaces/IPrivateChatGroupManager.cs rename to Govor.Application/PrivateUserChats/IPrivateChatGroupManager.cs index 5d09ed7..7031008 100644 --- a/Govor.Application/Interfaces/IPrivateChatGroupManager.cs +++ b/Govor.Application/PrivateUserChats/IPrivateChatGroupManager.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models; +using Govor.Domain.Models; -namespace Govor.Application.Interfaces; +namespace Govor.Application.PrivateUserChats; public interface IPrivateChatGroupManager { diff --git a/Govor.Application/Interfaces/IUserPrivateChatsCreator.cs b/Govor.Application/PrivateUserChats/IUserPrivateChatsCreator.cs similarity index 59% rename from Govor.Application/Interfaces/IUserPrivateChatsCreator.cs rename to Govor.Application/PrivateUserChats/IUserPrivateChatsCreator.cs index 674c705..f4846a6 100644 --- a/Govor.Application/Interfaces/IUserPrivateChatsCreator.cs +++ b/Govor.Application/PrivateUserChats/IUserPrivateChatsCreator.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models; +using Govor.Domain.Models; -namespace Govor.Application.Interfaces; +namespace Govor.Application.PrivateUserChats; public interface IUserPrivateChatsCreator { diff --git a/Govor.Application/PrivateUserChats/IUserPrivateChatsGetterService.cs b/Govor.Application/PrivateUserChats/IUserPrivateChatsGetterService.cs new file mode 100644 index 0000000..412427e --- /dev/null +++ b/Govor.Application/PrivateUserChats/IUserPrivateChatsGetterService.cs @@ -0,0 +1,11 @@ +using Govor.Domain.Common; +using Govor.Domain.Models; + +namespace Govor.Application.PrivateUserChats; + +public interface IUserPrivateChatsGetterService +{ + Task> GetUserChatsAsync(Guid userId); + Task> GetPrivateChatAsync(Guid chatId); + Task ExistChatAsync(Guid userIdA, Guid userIdB); +} \ No newline at end of file diff --git a/Govor.Application/Services/UserPrivateChatsCreator.cs b/Govor.Application/PrivateUserChats/UserPrivateChatsCreator.cs similarity index 51% rename from Govor.Application/Services/UserPrivateChatsCreator.cs rename to Govor.Application/PrivateUserChats/UserPrivateChatsCreator.cs index 2e2d8c9..600047d 100644 --- a/Govor.Application/Services/UserPrivateChatsCreator.cs +++ b/Govor.Application/PrivateUserChats/UserPrivateChatsCreator.cs @@ -1,46 +1,52 @@ -using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.PrivateChats; +using Govor.Domain; +using Govor.Domain.Models; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services; +namespace Govor.Application.PrivateUserChats; public class UserPrivateChatsCreator : IUserPrivateChatsCreator { - private readonly IPrivateChatsRepository _privateChats; + private readonly GovorDbContext _context; private readonly IPrivateChatGroupManager _privateChatGroupManager; private readonly ILogger _logger; public UserPrivateChatsCreator( - IPrivateChatsRepository privateChats, + GovorDbContext context, IPrivateChatGroupManager privateChatGroupManager, ILogger logger) { - _privateChats = privateChats; + _context = context; _privateChatGroupManager = privateChatGroupManager; _logger = logger; } public async Task CreateAsync(Guid userIdA, Guid userIdB) { - if (!_privateChats.Exist(userIdA, userIdB)) + var existingChat = await _context.PrivateChats + .FirstOrDefaultAsync(c => (c.UserAId == userIdA && c.UserBId == userIdB) || + (c.UserAId == userIdB && c.UserBId == userIdA)); + + if (existingChat is null) { var recipientId = Guid.NewGuid(); - var privateChat = new PrivateChat() + var privateChat = new PrivateChat { Id = recipientId, UserAId = userIdA, UserBId = userIdB }; - await _privateChats.AddAsync(privateChat); - await _privateChatGroupManager.AddUsersToPrivateChatGroupAsync(privateChat); // Notifying + await _context.PrivateChats.AddAsync(privateChat); + await _context.SaveChangesAsync(); - _logger.LogInformation($"User for {userIdA} and {userIdB} was created private chat with Id: {recipientId}"); + await _privateChatGroupManager.AddUsersToPrivateChatGroupAsync(privateChat); + + _logger.LogInformation($"Private chat created with Id: {recipientId} for users {userIdA} and {userIdB}"); return privateChat; } - _logger.LogInformation($"Private chat already exists for {userIdA} and {userIdB}; Returning already created chat..."); - return await _privateChats.GetByMembersAsync(userIdA, userIdB); + _logger.LogInformation($"Private chat already exists for {userIdA} and {userIdB}; Returning existing chat..."); + return existingChat; } } \ No newline at end of file diff --git a/Govor.Application/PrivateUserChats/UserPrivateChatsGetter.cs b/Govor.Application/PrivateUserChats/UserPrivateChatsGetter.cs new file mode 100644 index 0000000..9773a2e --- /dev/null +++ b/Govor.Application/PrivateUserChats/UserPrivateChatsGetter.cs @@ -0,0 +1,46 @@ +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.PrivateUserChats; + +public class UserPrivateChatsGetter : IUserPrivateChatsGetterService +{ + private readonly GovorDbContext _context; + + public UserPrivateChatsGetter(GovorDbContext context) + { + _context = context; + } + + public async Task> GetUserChatsAsync(Guid userId) + { + return await _context.PrivateChats + .AsNoTracking() + .Where(p => p.UserAId == userId || p.UserBId == userId) + .ToListAsync(); + } + + public async Task> GetPrivateChatAsync(Guid chatId) + { + var res = await _context.PrivateChats.AsNoTracking() + .FirstOrDefaultAsync(p => p.Id == chatId); + + if (res == null) + return Result.Failure(new Error(nameof(InvalidOperationException), + "PrivateChat not found.") + ); + + return res; + } + + public async Task ExistChatAsync(Guid userIdA, Guid userIdB) + { + return await _context.PrivateChats + .AsNoTracking() + .AnyAsync(p => (p.UserAId == userIdA && p.UserBId == userIdB) || + (p.UserBId == userIdA && p.UserAId == userIdB) + ); + } +} \ No newline at end of file diff --git a/Govor.Application/Profiles/IProfileService.cs b/Govor.Application/Profiles/IProfileService.cs new file mode 100644 index 0000000..16f4a45 --- /dev/null +++ b/Govor.Application/Profiles/IProfileService.cs @@ -0,0 +1,10 @@ +using Govor.Domain.Common; + +namespace Govor.Application.Profiles; + +public interface IProfileService +{ + public Task> GetUserProfileAsync(Guid userId); + public Task SetDescription(string description, Guid userId); + public Task SetNewIcon(Guid userId, Guid iconId); +} diff --git a/Govor.Application/Profiles/ProfileService.cs b/Govor.Application/Profiles/ProfileService.cs new file mode 100644 index 0000000..b8f7a02 --- /dev/null +++ b/Govor.Application/Profiles/ProfileService.cs @@ -0,0 +1,78 @@ +using Govor.Domain; +using Govor.Domain.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Profiles; + +public class ProfileService : IProfileService +{ + private readonly ILogger _logger; + private readonly GovorDbContext _context; + + public ProfileService(GovorDbContext context, ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task> GetUserProfileAsync(Guid userId) + { + _logger.LogInformation("Getting user {UserId} profile", userId); + + var profile = await _context.Users + .AsNoTracking() + .Where(u => u.Id == userId) + .Select(user => new UserProfile + { + Id = user.Id, + Username = user.Username, + Description = user.Description, + IconId = user.IconId + }) + .FirstOrDefaultAsync(); + + if (profile is null) + { + return Result.Failure(CreateNotFoundError(userId)); + } + + return profile; + } + + public async Task SetDescription(string description, Guid userId) + { + _logger.LogInformation("Updating description for user {UserId}", userId); + + var updatedRows = await _context.Users + .Where(u => u.Id == userId) + .ExecuteUpdateAsync(setters => setters.SetProperty(u => u.Description, description)); + + if (updatedRows == 0) + { + return Result.Failure(CreateNotFoundError(userId)); + } + + return Result.Success(); + } + + public async Task SetNewIcon(Guid userId, Guid iconId) + { + _logger.LogInformation("Updating icon for user {UserId}", userId); + + + var updatedRows = await _context.Users + .Where(u => u.Id == userId) + .ExecuteUpdateAsync(setters => setters.SetProperty(u => u.IconId, iconId)); + + if (updatedRows == 0) + { + return Result.Failure(CreateNotFoundError(userId)); + } + + return Result.Success(); + } + + private static Error CreateNotFoundError(Guid userId) => + new("Profile.UserNotFound", $"User with ID {userId} was not found."); +} diff --git a/Govor.Application/PushNotifications/IPushNotificationService.cs b/Govor.Application/PushNotifications/IPushNotificationService.cs new file mode 100644 index 0000000..39c1a39 --- /dev/null +++ b/Govor.Application/PushNotifications/IPushNotificationService.cs @@ -0,0 +1,12 @@ +using Govor.Domain.Common; + +namespace Govor.Application.PushNotifications; + +public interface IPushNotificationService +{ + Task SendToUserAsync(Guid userId, string title, string body, string channelId, string tag = "", Dictionary? data = null); + + Task SendToUsersAsync(IEnumerable userIds, string title, string body, string channelId, string tag = "", Dictionary? data = null); + + Task SendToSessionAsync(Guid sessionId, string title, string body, string channelId, string tag = "", Dictionary? data = null); +} \ No newline at end of file diff --git a/Govor.Application/PushNotifications/IPushTokenService.cs b/Govor.Application/PushNotifications/IPushTokenService.cs new file mode 100644 index 0000000..57bdca4 --- /dev/null +++ b/Govor.Application/PushNotifications/IPushTokenService.cs @@ -0,0 +1,14 @@ +using Govor.Domain.Common; + +namespace Govor.Application.PushNotifications; + +public interface IPushTokenService +{ + Task DeactivateTokenBySessionAsync(Guid sessionId); + Task DeactivateAllTokensByUserIdAsync(Guid userId); + Task>> GetStringsActiveTokensAsync(Guid userId); + Task>> GetUsersStringsActiveTokensAsync(IEnumerable userIds); + Task> GetActiveTokenBySessionAsync(Guid sessionId); + Task RemoveTokensAsync(IEnumerable tokens); + Task AddOrUpdateTokenAsync(Guid userId, Guid sessionId, string token, string platform); +} \ No newline at end of file diff --git a/Govor.Application/Interfaces/PushNotifications/Models/PushMessage.cs b/Govor.Application/PushNotifications/Models/PushMessage.cs similarity index 100% rename from Govor.Application/Interfaces/PushNotifications/Models/PushMessage.cs rename to Govor.Application/PushNotifications/Models/PushMessage.cs diff --git a/Govor.Application/Interfaces/PushNotifications/Models/SendPushResult.cs b/Govor.Application/PushNotifications/Models/SendPushResult.cs similarity index 100% rename from Govor.Application/Interfaces/PushNotifications/Models/SendPushResult.cs rename to Govor.Application/PushNotifications/Models/SendPushResult.cs diff --git a/Govor.Application/Services/PushNotifications/Providers/FirebasePushProvider.cs b/Govor.Application/PushNotifications/Providers/FirebasePushProvider.cs similarity index 97% rename from Govor.Application/Services/PushNotifications/Providers/FirebasePushProvider.cs rename to Govor.Application/PushNotifications/Providers/FirebasePushProvider.cs index 1964167..7f3be8d 100644 --- a/Govor.Application/Services/PushNotifications/Providers/FirebasePushProvider.cs +++ b/Govor.Application/PushNotifications/Providers/FirebasePushProvider.cs @@ -3,7 +3,7 @@ using Govor.Application.Interfaces.PushNotifications; using Govor.Application.Interfaces.PushNotifications.Models; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.PushNotifications.Providers; +namespace Govor.Application.PushNotifications.Providers; public class FirebasePushProvider : IPushNotificationProvider { @@ -43,7 +43,7 @@ public class FirebasePushProvider : IPushNotificationProvider var multicastMsg = new MulticastMessage { - Tokens = tokens.ToList(), + Tokens = tokens, Notification = new Notification { Title = message.Title, diff --git a/Govor.Application/Interfaces/PushNotifications/IPushNotificationProvider.cs b/Govor.Application/PushNotifications/Providers/IPushNotificationProvider.cs similarity index 84% rename from Govor.Application/Interfaces/PushNotifications/IPushNotificationProvider.cs rename to Govor.Application/PushNotifications/Providers/IPushNotificationProvider.cs index 96dd7fd..825725c 100644 --- a/Govor.Application/Interfaces/PushNotifications/IPushNotificationProvider.cs +++ b/Govor.Application/PushNotifications/Providers/IPushNotificationProvider.cs @@ -1,6 +1,6 @@ using Govor.Application.Interfaces.PushNotifications.Models; -namespace Govor.Application.Interfaces.PushNotifications; +namespace Govor.Application.PushNotifications.Providers; public interface IPushNotificationProvider { diff --git a/Govor.Application/Services/PushNotifications/Providers/NullPushProvider.cs b/Govor.Application/PushNotifications/Providers/NullPushProvider.cs similarity index 88% rename from Govor.Application/Services/PushNotifications/Providers/NullPushProvider.cs rename to Govor.Application/PushNotifications/Providers/NullPushProvider.cs index a7a059f..41ee252 100644 --- a/Govor.Application/Services/PushNotifications/Providers/NullPushProvider.cs +++ b/Govor.Application/PushNotifications/Providers/NullPushProvider.cs @@ -1,7 +1,7 @@ using Govor.Application.Interfaces.PushNotifications; using Govor.Application.Interfaces.PushNotifications.Models; -namespace Govor.Application.Services.PushNotifications.Providers; +namespace Govor.Application.PushNotifications.Providers; public class NullPushProvider : IPushNotificationProvider { diff --git a/Govor.Application/PushNotifications/PushNotificationService.cs b/Govor.Application/PushNotifications/PushNotificationService.cs new file mode 100644 index 0000000..2d7dd61 --- /dev/null +++ b/Govor.Application/PushNotifications/PushNotificationService.cs @@ -0,0 +1,119 @@ +using Govor.Application.Interfaces.PushNotifications.Models; +using Govor.Application.PushNotifications.Providers; +using Govor.Domain.Common; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.PushNotifications; + +public class PushNotificationService : IPushNotificationService +{ + private readonly IPushNotificationProvider _provider; + private readonly IPushTokenService _tokenService; + private readonly ILogger _logger; + + public PushNotificationService( + IPushNotificationProvider provider, + IPushTokenService tokenService, + ILogger logger) + { + _provider = provider; + _tokenService = tokenService; + _logger = logger; + } + + public async Task SendToUserAsync(Guid userId, string title, string body, string channelId, string tag = "", Dictionary? data = null) + { + var resultTokens = await _tokenService.GetStringsActiveTokensAsync(userId); + if (resultTokens.IsFailure) + return Result.Failure(resultTokens.Error); + + var tokens = resultTokens.Value; + if (tokens.Count == 0) + { + _logger.LogInformation("No active push tokens for user {UserId}", userId); + return Result.Success(); + } + + return await SendMulticastInternalAsync(tokens, title, body, channelId, tag, data, userId.ToString()); + } + + public async Task SendToUsersAsync(IEnumerable userIds, string title, string body, string channelId, string tag = "", Dictionary? data = null) + { + if (userIds == null || !userIds.Any()) + return Result.Failure(new Error("Push.InvalidArgs", "User IDs collection cannot be empty.")); + + var tokensResult = await _tokenService.GetUsersStringsActiveTokensAsync(userIds); + if (tokensResult.IsFailure) + return Result.Failure(tokensResult.Error); + + var tokens = tokensResult.Value; + if (tokens.Count == 0) + return Result.Success(); + + return await SendMulticastInternalAsync(tokens, title, body, channelId, tag, data, "bulk_request"); + } + + public async Task SendToSessionAsync(Guid sessionId, string title, string body, string channelId, string tag = "", Dictionary? data = null) + { + var tokenResult = await _tokenService.GetActiveTokenBySessionAsync(sessionId); + if (tokenResult.IsFailure) + return Result.Failure(tokenResult.Error); + + var token = tokenResult.Value; + if (string.IsNullOrEmpty(token)) + return Result.Success(); + + try + { + var message = CreateMessage(title, body, channelId, tag, data); + var result = await _provider.SendToTokenAsync(token, message); + + if (result.FailureCount > 0) + { + await _tokenService.RemoveTokensAsync(result.FailedTokens); + _logger.LogWarning("Removed {Count} invalid FCM tokens for session {SessionId}", result.FailureCount, sessionId); + } + + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to send single push notification to session {SessionId}", sessionId); + return Result.Failure(ex); + } + } + + private async Task SendMulticastInternalAsync(List tokens, string title, string body, string channelId, string tag, Dictionary? data, string targetInfo) + { + try + { + var message = CreateMessage(title, body, channelId, tag, data); + var result = await _provider.SendMulticastAsync(tokens, message); + + if (result.FailureCount > 0) + { + await _tokenService.RemoveTokensAsync(result.FailedTokens); + _logger.LogWarning("Removed {Count} invalid FCM tokens for target: {Target}", result.FailureCount, targetInfo); + } + + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred during push notification multicast sending to {Target}", targetInfo); + return Result.Failure(ex); + } + } + + private static PushMessage CreateMessage(string title, string body, string channelId, string tag, Dictionary? data) + { + return new PushMessage + { + Title = title, + Body = body, + Data = data ?? new(), + Tag = tag, + ChannelId = channelId + }; + } +} \ No newline at end of file diff --git a/Govor.Application/PushNotifications/PushTokenService.cs b/Govor.Application/PushNotifications/PushTokenService.cs new file mode 100644 index 0000000..76f1ad2 --- /dev/null +++ b/Govor.Application/PushNotifications/PushTokenService.cs @@ -0,0 +1,168 @@ +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models.Users; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.PushNotifications; + +public class PushTokenService : IPushTokenService +{ + private readonly GovorDbContext _context; + private readonly ILogger _logger; + + public PushTokenService(GovorDbContext context, ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task DeactivateTokenBySessionAsync(Guid sessionId) + { + try + { + await _context.UserPushTokens + .Where(t => t.UserSessionId == sessionId && t.IsActive) + .ExecuteUpdateAsync(s => s.SetProperty(t => t.IsActive, false)); + + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to deactivate push token for session {SessionId}", sessionId); + return Result.Failure(ex); + } + } + + public async Task DeactivateAllTokensByUserIdAsync(Guid userId) + { + try + { + await _context.UserPushTokens + .Where(t => t.UserId == userId && t.IsActive) + .ExecuteUpdateAsync(s => s.SetProperty(t => t.IsActive, false)); + + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to deactivate all push tokens for user {UserId}", userId); + return Result.Failure(ex); + } + } + + public async Task>> GetStringsActiveTokensAsync(Guid userId) + { + try + { + var tokens = await _context.UserPushTokens + .AsNoTracking() + .Where(t => t.UserId == userId && t.IsActive) + .Select(t => t.Token) + .ToListAsync(); + + return tokens; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to fetch active push tokens for user {UserId}", userId); + return Result>.Failure(ex); + } + } + + public async Task>> GetUsersStringsActiveTokensAsync(IEnumerable userIds) + { + try + { + var tokens = await _context.UserPushTokens + .AsNoTracking() + .Where(t => userIds.Contains(t.UserId) && t.IsActive) + .Select(t => t.Token) + .ToListAsync(); + + return tokens; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to fetch active push tokens for bulk users"); + return Result>.Failure(ex); + } + } + + public async Task> GetActiveTokenBySessionAsync(Guid sessionId) + { + try + { + var token = await _context.UserPushTokens + .AsNoTracking() + .Where(t => t.UserSessionId == sessionId && t.IsActive) + .Select(t => t.Token) + .FirstOrDefaultAsync(); + + return token; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to fetch active push token for session {SessionId}", sessionId); + return Result.Failure(ex); + } + } + + public async Task RemoveTokensAsync(IEnumerable tokens) + { + if (tokens is null || !tokens.Any()) + return Result.Success(); + + try + { + await _context.UserPushTokens + .Where(t => tokens.Contains(t.Token)) + .ExecuteDeleteAsync(); + + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to bulk remove invalid push tokens"); + return Result.Failure(ex); + } + } + + public async Task AddOrUpdateTokenAsync(Guid userId, Guid sessionId, string token, string platform) + { + if (string.IsNullOrWhiteSpace(token)) + { + return new Error("PushToken.Empty", "Push token cannot be empty."); + } + + var existingToken = await _context.UserPushTokens + .FirstOrDefaultAsync(t => t.Token == token); + + if (existingToken is null) + { + var newToken = new UserPushToken + { + Id = Guid.NewGuid(), + UserId = userId, + UserSessionId = sessionId, + Token = token, + Platform = platform, + CreatedAt = DateTime.UtcNow + }; + + await _context.UserPushTokens.AddAsync(newToken); + } + else + { + + existingToken.UserId = userId; + existingToken.UserSessionId = sessionId; + existingToken.Platform = platform; + existingToken.UpdatedAt = DateTime.UtcNow; + } + + await _context.SaveChangesAsync(); + + return Result.Success(); + } +} diff --git a/Govor.Application/Services/Authentication/AuthService.cs b/Govor.Application/Services/Authentication/AuthService.cs deleted file mode 100644 index 0b46164..0000000 --- a/Govor.Application/Services/Authentication/AuthService.cs +++ /dev/null @@ -1,102 +0,0 @@ -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.Models.Users; -using Govor.Core.Repositories.Admins; - -namespace Govor.Application.Services.Authentication; - -public class AuthService : IAccountService -{ - private readonly IPasswordHasher _passwordHasher; - private readonly IUsersRepository _usersRepository; - private readonly IAdminsRepository _adminsRepository; - private readonly IUsernameValidator _usernameValidator; - - public AuthService(IUsersRepository usersRepository, - IPasswordHasher passwordHasher, - IAdminsRepository adminsRepository, - IUsernameValidator usernameValidator - ) - { - _usersRepository = usersRepository; - _passwordHasher = passwordHasher; - _adminsRepository = adminsRepository; - _usernameValidator = usernameValidator; - } - - public async Task RegistrationAsync(string name, string password, Invitation invitation) - { - _usernameValidator.Validate(name); - - 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.Empty, - WasOnline = DateTime.UtcNow, - InviteId = invitation.Id - }; - - await _usersRepository.AddAsync(user); - - await SetRole(user, invitation); - - return user; - } - - - public async Task 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 user; - } - - /* - public async Task RefreshTokenAsync(string refreshToken) - { - try - { - var principal = _jwtService.GetPrincipalFromExpiredToken(refreshToken); - - var userId = Guid.Parse(principal?.FindFirst("userId")?.Value ?? string.Empty); - - var storedTokens = await _userSessionsRepository.GetUserTokensAsync(userId); - - if (!storedTokens.Contains(refreshToken)) - throw new UnauthorizedAccessException("Invalid refresh token"); - - var user = await _usersRepository.FindByIdAsync(userId); - var newAccessToken = await _jwtService.GenerateAccessTokenAsync(user); - return newAccessToken; - } - catch (SecurityTokenException ex) - { - throw new InvalidOperationException("Invalid refresh token", ex); - } - } - */ - - private async Task SetRole(User user, Invitation invitation) - { - if(invitation.IsAdmin) - await _adminsRepository.AddAsync(new Admin() { UserId = user.Id }); - } -} \ No newline at end of file diff --git a/Govor.Application/Services/Friends/FriendRequestCommandService.cs b/Govor.Application/Services/Friends/FriendRequestCommandService.cs deleted file mode 100644 index a6b16f0..0000000 --- a/Govor.Application/Services/Friends/FriendRequestCommandService.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Govor.Application.Exceptions.FriendsService; -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Friends; -using Govor.Core.Models; -using Govor.Core.Repositories.Friendships; -using Govor.Data.Repositories.Exceptions; - -namespace Govor.Application.Services.Friends; - -public class FriendRequestCommandService : IFriendRequestCommandService -{ - private readonly IFriendshipsRepository _friendshipsRepository; - private readonly IUserPrivateChatsCreator _privateChatsCreator; - public FriendRequestCommandService( - IFriendshipsRepository friendshipsRepository, - IUserPrivateChatsCreator privateChatsCreator) - { - _friendshipsRepository = friendshipsRepository; - _privateChatsCreator = privateChatsCreator; - } - - public async Task SendAsync(Guid fromUserId, Guid toUserId) - { - if (fromUserId == toUserId) - throw new InvalidOperationException("Cannot send a request to self user"); - - var friendship = await _friendshipsRepository.GetFriendshipAsync(fromUserId, toUserId); - - if (friendship is null) - { - friendship = new Friendship - { - Id = Guid.NewGuid(), - RequesterId = fromUserId, - AddresseeId = toUserId, - Status = FriendshipStatus.Pending - }; - await _friendshipsRepository.AddAsync(friendship); - } - else - { - if (friendship.Status == FriendshipStatus.Pending || friendship.Status == FriendshipStatus.Accepted - || friendship.Status == FriendshipStatus.Blocked) - { - throw new RequestAlreadySentException(fromUserId, toUserId); - } - - friendship.RequesterId = fromUserId; - friendship.AddresseeId = toUserId; - friendship.Status = FriendshipStatus.Pending; - - await _friendshipsRepository.UpdateAsync(friendship); - } - - return friendship; - } - - public async Task AcceptAsync(Guid requestId, Guid currentUserId) - { - try - { - var friendship = await _friendshipsRepository.GetByIdAsync(requestId); - - - if (friendship.AddresseeId != currentUserId) - throw new UnauthorizedAccessException("You cannot accept this request"); - - if (friendship.Status != FriendshipStatus.Pending) - throw new InvalidOperationException("Request is already accepted"); - - friendship.Status = FriendshipStatus.Accepted; - await _friendshipsRepository.UpdateAsync(friendship); - - await _privateChatsCreator.CreateAsync(friendship.AddresseeId, friendship.RequesterId); - - return friendship; - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("Friendship not found! You cant accept request!", ex); - } - } - - public async Task RejectAsync(Guid requestId, Guid currentUserId) - { - try - { - var friendship = await _friendshipsRepository.GetByIdAsync(requestId); - - if (friendship.AddresseeId != currentUserId) - throw new UnauthorizedAccessException("You cannot accept this request"); - - if (friendship.Status != FriendshipStatus.Pending && friendship.Status != FriendshipStatus.Rejected) - throw new InvalidOperationException($"Request is already {friendship.Status}"); - - friendship.Status = FriendshipStatus.Rejected; - await _friendshipsRepository.UpdateAsync(friendship); - return friendship; - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("Friendship not found! You cant reject request!", ex); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/Friends/FriendRequestQueryService.cs b/Govor.Application/Services/Friends/FriendRequestQueryService.cs deleted file mode 100644 index de66537..0000000 --- a/Govor.Application/Services/Friends/FriendRequestQueryService.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Govor.Application.Interfaces.Friends; -using Govor.Core.Models; -using Govor.Core.Repositories.Friendships; -using Govor.Data.Repositories.Exceptions; - -namespace Govor.Application.Services.Friends; - -public class FriendRequestQueryService : IFriendRequestQueryService -{ - private readonly IFriendshipsRepository _friendshipsRepository; - - public FriendRequestQueryService(IFriendshipsRepository friendshipsRepository) - { - _friendshipsRepository = friendshipsRepository; - } - - public async Task> GetIncomingAsync(Guid userId) - { - try - { - var friendships = await _friendshipsRepository.FindByUserIdAsync(userId); - return friendships.Where(f => f.AddresseeId == userId && f.Status == FriendshipStatus.Pending).ToList() - ?? new List(); - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("User not exist", ex); - } - } - - public async Task> GetResponsesAsync(Guid userId) - { - try - { - var friendships = await _friendshipsRepository.FindByUserIdAsync(userId); - return friendships.Where(f => f.RequesterId == userId && f.Status != FriendshipStatus.Accepted).ToList() - ?? new List(); - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("User not exist", ex); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/Friends/FriendshipService.cs b/Govor.Application/Services/Friends/FriendshipService.cs deleted file mode 100644 index fce9a29..0000000 --- a/Govor.Application/Services/Friends/FriendshipService.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Govor.Application.Exceptions.FriendsService; -using Govor.Application.Interfaces.Friends; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Friendships; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; - -namespace Govor.Application.Services.Friends; - -public class FriendshipService : IFriendshipService -{ - private readonly IUsersRepository _usersRepository; - private readonly IFriendshipsRepository _friendshipsRepository; - - public FriendshipService(IUsersRepository usersRepository, IFriendshipsRepository friendshipsRepository) - { - _usersRepository = usersRepository; - _friendshipsRepository = friendshipsRepository; - } - - - public async Task> SearchUsersAsync(string query, Guid currentId) - { - List all = new List(); - - try - { - all = await _usersRepository.SearchPotentialFriendsAsync(currentId, query); - - return all; - } - catch (NotFoundByKeyException<(string, Guid)> ex) - { - return []; - } - catch (NotFoundByKeyException ex) - { - return []; - } - catch (Exception ex) - { - throw new UnauthorizedAccessException($"When we try find friends by pattern {query} something wrong", ex); - } - } - - public async Task> GetPotentialFriendsAsync(Guid userId) - { - try - { - var friendships = await _friendshipsRepository.FindByUserIdAsync(userId); - - return friendships - .Where(f => f.Status == FriendshipStatus.Pending) - .Select(f => f.RequesterId == userId ? f.Addressee : f.Requester) - .ToList(); - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("Nothing was found for the specified id.", ex); - } - } - - public async Task> GetFriendsAsync(Guid userId) - { - try - { - var friendships = await _friendshipsRepository.FindByUserIdAsync(userId); - - return friendships - .Where(f => f.Status == FriendshipStatus.Accepted) - .Select(f => f.RequesterId == userId ? f.Addressee : f.Requester) - .ToList(); - } - catch (NotFoundByKeyException ex) - { - throw new InvalidOperationException("Nothing was found for the specified id.", ex); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/InvitesService.cs b/Govor.Application/Services/InvitesService.cs deleted file mode 100644 index f281025..0000000 --- a/Govor.Application/Services/InvitesService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Govor.Application.Exceptions.InvitesService; -using Govor.Application.Interfaces.Authentication; -using Govor.Core.Models; -using Govor.Core.Models.Users; -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 GetRoleAsync(User user) - { - try - { - var invitation = await _invitesRepository.FindByIdAsync(user.InviteId); - return invitation.IsAdmin ? "Admin" : "User"; - } - catch (NotFoundByKeyException) - { - return "User"; - } - } - - public async Task ValidateAsync(string inviteCode) - { - try - { - var invite = await _invitesRepository.FindByCodeAsync(inviteCode); - - if (invite.EndDate < DateTime.Now || invite.MaxParticipants <= invite.Users.Count) - { - invite.IsActive = false; - await _invitesRepository.UpdateAsync(invite); - throw new InviteLinkInvalidException(inviteCode); - } - - return invite; - } - catch (NotFoundByKeyException) - { - throw new InviteLinkInvalidException(inviteCode); - } - } -} - diff --git a/Govor.Application/Services/Messages/MessageCommandService.cs b/Govor.Application/Services/Messages/MessageCommandService.cs deleted file mode 100644 index 884c03e..0000000 --- a/Govor.Application/Services/Messages/MessageCommandService.cs +++ /dev/null @@ -1,229 +0,0 @@ -using Govor.Application.Interfaces; -using Govor.Application.Interfaces.Medias; -using Govor.Application.Interfaces.Messages; -using Govor.Application.Interfaces.Messages.Parameters; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.Groups; -using Govor.Core.Repositories.Messages; -using Govor.Core.Repositories.PrivateChats; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services.Messages; - -public class MessageCommandService : IMessageCommandService -{ - private readonly IMessagesRepository _messagesRepository; - private readonly IPrivateChatsRepository _privateChatsRepository; - private readonly IUsersRepository _usersRepository; - private readonly IGroupsRepository _groupsRepository; - private readonly IUserPrivateChatsCreator _privateChatsCreator; - private readonly IVerifyFriendship _verifyFriendship; - private readonly IMediaService _mediaService; - private readonly ILogger _logger; - - public MessageCommandService( - IMessagesRepository messagesRepository, - IUsersRepository usersRepository, - IGroupsRepository groupsRepository, - IPrivateChatsRepository privateChatsRepository, - IUserPrivateChatsCreator privateChatsCreator, - IVerifyFriendship verifyFriendship, - IMediaService mediaService, - ILogger logger) - { - _messagesRepository = messagesRepository; - _usersRepository = usersRepository; - _groupsRepository = groupsRepository; - _privateChatsRepository = privateChatsRepository; - _privateChatsCreator = privateChatsCreator; - _verifyFriendship = verifyFriendship; - _mediaService = mediaService; - _logger = logger; - } - - public async Task SendMessageAsync(SendMessage sendParams) - { - try - { - var recipientId = sendParams.RecipientType switch - { - RecipientType.User => await HandleUserRecipientAsync(sendParams), - RecipientType.Group => await HandleGroupRecipientAsync(sendParams), - _ => throw new ArgumentException("Invalid recipient type.") - }; - - var messageId = Guid.NewGuid(); - var message = new Message - { - Id = messageId, - SenderId = sendParams.FromUserId, - RecipientId = recipientId, - RecipientType = sendParams.RecipientType, - EncryptedContent = sendParams.EncryptContent, - SentAt = sendParams.SendAt, - IsEdited = false, - ReplyToMessageId = sendParams.ReplyToMessageId, - MediaAttachments = sendParams.Media?.Select(m => new MediaAttachments - { - Id = Guid.NewGuid(), - MessageId = messageId, - MediaFileId = m.MediaId - }).ToList() ?? new List() - }; - - // Attach media - if (sendParams.Media?.Any() == true) - foreach (var media in sendParams.Media) - await _mediaService.AttachToMessageAsync(media.MediaId, messageId); - - await _messagesRepository.AddAsync(message); - _logger.LogInformation( - "Message {MessageId} from {SenderId} to {RecipientId} ({RecipientType}) saved successfully.", - messageId, sendParams.FromUserId, sendParams.RecipientId, sendParams.RecipientType); - - return new SendMessageResult(true, null, message); - } - catch (Exception ex) - { - _logger.LogError( - ex, - "Error sending message from {SenderId} to {RecipientId} ({RecipientType})", - sendParams.FromUserId, sendParams.RecipientId, sendParams.RecipientType); - return new SendMessageResult(false, ex, default); - } - } - - private async Task HandleUserRecipientAsync(SendMessage sendParams) - { - var privateChat = await _privateChatsRepository.GetByIdAsync(sendParams.RecipientId); - - if (privateChat == null) - { - _logger.LogWarning("Private chat {ChatId} not found", sendParams.RecipientId); - throw new KeyNotFoundException($"Private chat {sendParams.RecipientId} not found."); - } - - return privateChat.Id; - } - - private async Task HandleGroupRecipientAsync(SendMessage sendParams) - { - if (!_groupsRepository.Exist(sendParams.RecipientId)) - { - _logger.LogWarning("Attempt to send message to non-existent group {GroupId}", sendParams.RecipientId); - throw new KeyNotFoundException($"Recipient group {sendParams.RecipientId} not found."); - } - - var isMember = await _groupsRepository.IsUserMemberOfGroupAsync(sendParams.FromUserId, sendParams.RecipientId); - if (!isMember) - { - _logger.LogWarning("User {UserId} attempted to send message to group {GroupId} but is not a member", - sendParams.FromUserId, sendParams.RecipientId); - throw new UnauthorizedAccessException("Sender is not a member of the group."); - } - - return sendParams.RecipientId; - } - - //TODO: Full Cleanup all them: - public async Task EditMessageAsync(EditMessage editParams) - { - try - { - var message = await _messagesRepository.FindByIdAsync(editParams.MessageId); - - if (message.SenderId != editParams.EditorId) - { - _logger.LogWarning( - "User {EditorId} attempted to edit message {MessageId} not sent by them (sender was {SenderId})", - editParams.EditorId, editParams.MessageId, message.SenderId); - return new EditMessageResult(false, - new UnauthorizedAccessException("User is not authorized to edit this message."), null); - } - - /*if (message.SentAt < DateTime.UtcNow.AddMinutes(-15)) - throw new Exception("Edit time limit exceeded");*/ - - var originalMessageForNotification = new Message - { - Id = message.Id, - SenderId = message.SenderId, - RecipientId = message.RecipientId, - RecipientType = message.RecipientType, - SentAt = message.SentAt, - ReplyToMessageId = message.ReplyToMessageId, - Reactions = message.Reactions, - MediaAttachments = message.MediaAttachments, - MessageViews = message.MessageViews - }; - - message.EncryptedContent = editParams.NewContent; - message.IsEdited = true; - message.EditedAt = editParams.EditedAt; - - await _messagesRepository.UpdateAsync(message); - _logger.LogInformation("Message {MessageId} edited successfully by user {EditorId}", editParams.MessageId, - editParams.EditorId); - return new EditMessageResult(true, default, originalMessageForNotification); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error editing message {MessageId} by user {EditorId}", editParams.MessageId, - editParams.EditorId); - return new EditMessageResult(false, ex, default); - } - } - - public async Task DeleteMessageAsync(DeleteMessage deleteParams) - { - try - { - var message = await _messagesRepository.FindByIdAsync(deleteParams.MessageId); - - if (message.SenderId != deleteParams.DeleterId) - { - // TODO: Allow group admins to delete messages in their groups? - // if (message.RecipientType == RecipientType.Group) { - // bool isAdmin = await _groupsRepository.IsUserAdminOfGroupAsync(deleteParams.DeleterId, message.RecipientId); - // if (!isAdmin) { - // _logger.LogWarning("User {DeleterId} (not sender or admin) attempted to delete group message {MessageId}", deleteParams.DeleterId, deleteParams.MessageId); - // return new DeleteMessageResult(false, new UnauthorizedAccessException("User is not authorized to delete this message."), null); - // } - // } else { - _logger.LogWarning( - "User {DeleterId} attempted to delete message {MessageId} not sent by them (sender was {SenderId})", - deleteParams.DeleterId, deleteParams.MessageId, message.SenderId); - return new DeleteMessageResult(false, - new UnauthorizedAccessException("User is not authorized to delete this message."), default); - // } - } - - var originalMessageForNotification = new Message - { - Id = message.Id, - SenderId = message.SenderId, - RecipientId = message.RecipientId, - RecipientType = message.RecipientType - }; - - await _messagesRepository.RemoveAsync(deleteParams.MessageId); - - _logger.LogInformation("Message {MessageId} deleted successfully by user {DeleterId}", - deleteParams.MessageId, deleteParams.DeleterId); - return new DeleteMessageResult(true, default, originalMessageForNotification); - } - catch (NotFoundByKeyException ex) - { - return new DeleteMessageResult(false, new KeyNotFoundException("Message not found", ex), default); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error deleting message {MessageId} by user {DeleterId}", deleteParams.MessageId, - deleteParams.DeleterId); - return new DeleteMessageResult(false, ex, default); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/Messages/MessagesLoader.cs b/Govor.Application/Services/Messages/MessagesLoader.cs deleted file mode 100644 index ff27317..0000000 --- a/Govor.Application/Services/Messages/MessagesLoader.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Govor.Application.Interfaces; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.Groups; -using Govor.Core.Repositories.PrivateChats; -using Govor.Data; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Application.Services.Messages; - -public class MessagesLoader : IMessagesLoader -{ - private IGroupsRepository _groupsRepository; - private IPrivateChatsRepository _privateChatsRepository; - private GovorDbContext _dbContext; - - public MessagesLoader( - IGroupsRepository groupsRepository, - IPrivateChatsRepository privateChatsRepository, - GovorDbContext dbContext) - { - _groupsRepository = groupsRepository; - _privateChatsRepository = privateChatsRepository; - _dbContext = dbContext; - } - - public async Task> LoadMessagesInUserChat( - Guid privateChatId, - Guid currentUser, - Guid? startMessageId, - int before = 20, - int after = 2) - { - if (privateChatId == Guid.Empty) - throw new ArgumentException("PrivateChatId id cannot be empty"); - - if (!_privateChatsRepository.Exist(privateChatId)) - throw new InvalidOperationException("Private chat not found"); - - var query = _dbContext.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .Where(m => m.RecipientType == RecipientType.User && - m.RecipientId == privateChatId); - - if (startMessageId is null) - { - return await query - .OrderByDescending(m => m.SentAt) - .Take(before) - .ToListAsync(); - } - - var startMessage = await _dbContext.Messages.FindAsync(startMessageId.Value); - if (startMessage == null) - throw new NotFoundException("Start message not found"); - - var beforeMessages = await query - .Where(m => m.SentAt < startMessage.SentAt) - .OrderByDescending(m => m.SentAt) - .Take(before) - .ToListAsync(); - - var afterMessages = await query - .Where(m => m.SentAt > startMessage.SentAt) - .OrderBy(m => m.SentAt) - .Take(after) - .ToListAsync(); - - // older -> start -> newer - var result = beforeMessages - .OrderBy(m => m.SentAt) - .Concat(new[] { startMessage }) - .Concat(afterMessages) - .ToList(); - - return result; - } - - - public async Task> LoadMessagesInChatGroup( - Guid chatId, - Guid currentUser, - Guid? startMessageId, - int before = 20, - int after = 2) - { - if (chatId == Guid.Empty) - throw new ArgumentException("Chat id cannot be empty"); - - var isMember = await _groupsRepository.IsUserMemberOfGroupAsync(currentUser, chatId); - if (!isMember) - throw new UnauthorizedAccessException("You are not a member of this group."); - - var baseQuery = _dbContext.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .Where(m => m.RecipientType == RecipientType.Group && m.RecipientId == chatId); - - if (startMessageId is null) - { - return await baseQuery - .OrderByDescending(m => m.SentAt) - .Take(before) - .OrderBy(m => m.SentAt) - .ToListAsync(); - } - - var startMessage = await _dbContext.Messages - .AsNoTracking() - .FirstOrDefaultAsync(m => m.Id == startMessageId.Value && - m.RecipientType == RecipientType.Group && - m.RecipientId == chatId); - - if (startMessage == null) - throw new NotFoundException("Start message not found in this group."); - - var beforeMessages = await baseQuery - .Where(m => m.SentAt < startMessage.SentAt) - .OrderByDescending(m => m.SentAt) - .Take(before) - .ToListAsync(); - - var afterMessages = await baseQuery - .Where(m => m.SentAt > startMessage.SentAt) - .OrderBy(m => m.SentAt) - .Take(after) - .ToListAsync(); - - var result = beforeMessages - .OrderBy(m => m.SentAt) - .Concat(new[] { startMessage }) - .Concat(afterMessages) - .ToList(); - - return result; - } - -} \ No newline at end of file diff --git a/Govor.Application/Services/ProfileService.cs b/Govor.Application/Services/ProfileService.cs deleted file mode 100644 index ab07ce8..0000000 --- a/Govor.Application/Services/ProfileService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Govor.Application.Interfaces; -using Govor.Application.Profiles; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services; - -public class ProfileService : IProfileService -{ - private readonly ILogger _logger; - private readonly IUsersRepository _userRepository; - - public ProfileService(IUsersRepository userRepository, ILogger logger) - { - _userRepository = userRepository; - _logger = logger; - } - - public async Task GetUserProfileAsync(Guid userId) - { - _logger.LogInformation("Gettings user {userId} profile", userId); - try - { - var user = await _userRepository.FindByIdAsync(userId); - - return new UserProfile - { - Id = user.Id, - Username = user.Username, - Description = user.Description, - IconId = user.IconId - }; - } - catch (NotFoundByKeyException ex) - { - throw new NotFoundException("User's profile cant be found with given id", ex); - } - } - - public async Task SetDescription(string description, Guid userId) - { - var user = await _userRepository.FindByIdAsync(userId); - - user.Description = description; - await _userRepository.UpdateAsync(user); - } - - public async Task SetNewIcon(Guid userId, Guid iconId) - { - var user = await _userRepository.FindByIdAsync(userId); - - user.IconId = iconId; - await _userRepository.UpdateAsync(user); - } -} diff --git a/Govor.Application/Services/PushNotifications/PushNotificationService.cs b/Govor.Application/Services/PushNotifications/PushNotificationService.cs deleted file mode 100644 index 4fa824f..0000000 --- a/Govor.Application/Services/PushNotifications/PushNotificationService.cs +++ /dev/null @@ -1,98 +0,0 @@ -using FirebaseAdmin.Messaging; -using Govor.Application.Interfaces.PushNotifications; -using Govor.Application.Interfaces.PushNotifications.Models; -using Govor.Core.Repositories.PushTokens; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services.PushNotifications; - -public class PushNotificationService : IPushNotificationService -{ - private readonly IPushNotificationProvider _provider; - private readonly IPushTokenRepository _tokenRepo; - private readonly ILogger _logger; - - public PushNotificationService( - IPushNotificationProvider provider, - IPushTokenRepository tokenRepo, - ILogger logger) - { - _provider = provider; - _tokenRepo = tokenRepo; - _logger = logger; - } - - public async Task SendToUserAsync(Guid userId, string title, string body, string channelId, string tag = "", Dictionary? data = null) - { - var tokens = await _tokenRepo.GetActiveTokensAsync(userId); - if (tokens.Count == 0) - { - _logger.LogInformation("No active push tokens for user {UserId}", userId); - return; - } - - var message = new PushMessage - { - Title = title, - Body = body, - Data = data ?? new(), - Tag = tag, - ChannelId = channelId - }; - - var result = await _provider.SendMulticastAsync(tokens, message); - - if (result.FailureCount > 0) - { - await _tokenRepo.RemoveTokensAsync(result.FailedTokens); - _logger.LogWarning("Removed {Count} invalid FCM tokens for user {UserId}", result.FailureCount, userId); - } - } - - public async Task SendToUsersAsync(IEnumerable userIds, string title, string body, string channelId, string tag = "", Dictionary? data = null) - { - if (userIds is null) - throw new ArgumentNullException(nameof(userIds)); - - var tokens = (await _tokenRepo.GetActiveTokensUsersAsync(userIds)).AsReadOnly(); - if (tokens.Count == 0) - return; - - var result = await _provider.SendMulticastAsync(tokens, new PushMessage() - { - Title = title, - Body = body, - Data = data ?? new(), - Tag = tag, - ChannelId = channelId - }); - - if (result.FailureCount > 0) - { - await _tokenRepo.RemoveTokensAsync(result.FailedTokens); - _logger.LogWarning("Removed {Count} invalid FCM tokens for users {Users}...", result.FailureCount, userIds); - } - } - - public async Task SendToSessionAsync(Guid sessionId, string title, string body, string channelId, string tag = "", Dictionary? data = null) - { - var token = await _tokenRepo.GetActiveTokenBySessionAsync(sessionId); - if(string.IsNullOrEmpty(token)) - return; - - var result = await _provider.SendToTokenAsync(token, new PushMessage() - { - Title = title, - Body = body, - Data = data ?? new(), - Tag = tag, - ChannelId = channelId - }); - - if (result.FailureCount > 0) - { - await _tokenRepo.RemoveTokensAsync(result.FailedTokens); - _logger.LogWarning("Removed {Count} invalid FCM tokens for session {Session}...", result.FailureCount, sessionId); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/UserGroupsGetterService.cs b/Govor.Application/Services/UserGroupsGetterService.cs deleted file mode 100644 index a665667..0000000 --- a/Govor.Application/Services/UserGroupsGetterService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.Groups; -using Govor.Data.Repositories.Exceptions; - -namespace Govor.Application.Services; - -public class UserGroupsGetterService : IUserGroupsGetterService -{ - private readonly IGroupsRepository _groupRep; - - public UserGroupsGetterService(IGroupsRepository groupsRepository) - { - _groupRep = groupsRepository; - } - - public async Task> GetUserGroupsAsync(Guid userId) - { - try - { - return await _groupRep.GetByUserIdAsync(userId); - } - catch (NotFoundByKeyException ex) - { - return new List(); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/UserPrivateChatsGetter.cs b/Govor.Application/Services/UserPrivateChatsGetter.cs deleted file mode 100644 index 96e1644..0000000 --- a/Govor.Application/Services/UserPrivateChatsGetter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.PrivateChats; -using Govor.Data.Repositories.Exceptions; - -namespace Govor.Application.Services; - -public class UserPrivateChatsGetter : IUserPrivateChatsGetterService -{ - private readonly IPrivateChatsRepository _groupRep; - - public UserPrivateChatsGetter(IPrivateChatsRepository groupsRepository) - { - _groupRep = groupsRepository; - } - - public async Task> GetUserChatsAsync(Guid userId) - { - try - { - return await _groupRep.GetAllOfUser(userId); - } - catch (NotFoundByKeyException ex) - { - return []; - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/UserSessions/UserSessionReader.cs b/Govor.Application/Services/UserSessions/UserSessionReader.cs deleted file mode 100644 index f9ba04c..0000000 --- a/Govor.Application/Services/UserSessions/UserSessionReader.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Govor.Application.Interfaces.UserSession; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services.UserSessions; - -public class UserSessionReader : IUserSessionReader -{ - private readonly IUserSessionsRepository _repository; - private readonly ILogger _logger; - - public UserSessionReader(IUserSessionsRepository repository, ILogger logger) - { - _repository = repository; - _logger = logger; - } - - public async Task> GetAllSessionsAsync(Guid userId) - { - try - { - _logger.LogInformation($"Getting all sessions for user {userId}"); - var sessions = await _repository.GetByUserIdAsync(userId); - - return sessions.Where(f => !f.IsRevoked).ToList() ?? []; - } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning("The user has no sessions."); - return []; - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/UserSessions/UserSessionRefresher.cs b/Govor.Application/Services/UserSessions/UserSessionRefresher.cs deleted file mode 100644 index 36823a2..0000000 --- a/Govor.Application/Services/UserSessions/UserSessionRefresher.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Govor.Application.Interfaces.Authentication; -using Govor.Application.Interfaces.UserSession; -using Govor.Application.Services.Authentication; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Govor.Application.Services.UserSessions; - -public class UserSessionRefresher : IUserSessionRefresher -{ - private readonly IUserSessionsRepository _sessionsRepository; - private readonly ILogger _logger; - private readonly IUsersRepository _usersRepository; - private readonly JwtRefreshOption _options; - private readonly IJwtTokenHasher _jwtTokenHasher; - private readonly IJwtService _jwtService; - - public UserSessionRefresher( - IUserSessionsRepository sessionsRepository, - ILogger logger, - IUsersRepository usersRepository, - IOptions options, - IJwtTokenHasher jwtTokenHasher, - IJwtService jwtService) - { - _sessionsRepository = sessionsRepository; - _logger = logger; - _usersRepository = usersRepository; - _options = options.Value; - _jwtTokenHasher = jwtTokenHasher; - _jwtService = jwtService; - } - - public async Task RefreshTokenAsync(string refreshToken) - { - try - { - var session = await _sessionsRepository.GetByHashedRefreshTokenAsync(_jwtTokenHasher.HashToken(refreshToken)); - - if (session.IsRevoked || session.ExpiresAt <= DateTime.UtcNow) - throw new UnauthorizedAccessException("Refresh token is invalid or expired"); - - // Find user - var user = await _usersRepository.FindByIdAsync(session.UserId); - - // New tokens - var newAccessToken = await _jwtService.GenerateAccessTokenAsync(user, session.Id); - var newRefreshToken = await _jwtService.GenerateRefreshTokenAsync(user); - - var newRefreshTokenHash = _jwtTokenHasher.HashToken(newRefreshToken); - - // Opening new session - var newSession = new UserSession - { - Id = session.Id, - UserId = user.Id, - RefreshTokenHash = newRefreshTokenHash, - DeviceInfo = session.DeviceInfo, - CreatedAt = DateTime.UtcNow, - ExpiresAt = DateTime.UtcNow.AddDays(_options.RefreshTokenLifetimeDays) - }; - - await _sessionsRepository.UpdateAsync(newSession); - - return new RefreshResult(newRefreshToken, newAccessToken); - } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning(ex, ex.Message); - throw new UnauthorizedAccessException("Invalid refresh token", ex); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/UserSessions/UserSessionRevoker.cs b/Govor.Application/Services/UserSessions/UserSessionRevoker.cs deleted file mode 100644 index a889379..0000000 --- a/Govor.Application/Services/UserSessions/UserSessionRevoker.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Govor.Application.Interfaces.UserSession; -using Govor.Core.Repositories.PushTokens; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services.UserSessions; - -public class UserSessionRevoker : IUserSessionRevoker -{ - private readonly IUserSessionsRepository _sessionsRepository; - private readonly IPushTokenRepository _pushTokenRepository; - private readonly ILogger _logger; - - public UserSessionRevoker( - IUserSessionsRepository sessionsRepository, - IPushTokenRepository pushTokenRepository, - ILogger logger) - { - _sessionsRepository = sessionsRepository; - _pushTokenRepository = pushTokenRepository; - _logger = logger; - } - - public async Task CloseSessionByIdAsync(Guid sessionId, Guid userId) - { - try - { - var session = await _sessionsRepository.GetByIdAsync(sessionId); - - if (session.UserId != userId) - { - _logger.LogWarning("User {userId} does not belong to this session {sessionId}", userId, sessionId); - throw new UnauthorizedAccessException($"User {userId} does not belong to this session {sessionId}"); - } - - if(session.IsRevoked) return; - - session.IsRevoked = true; - await _sessionsRepository.UpdateAsync(session); - - await _pushTokenRepository.DeactivateTokenBySessionAsync(sessionId); // pushes deactivate - } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning("User {userId} tried close unreal session!", userId); - throw new NotFoundException("Session not found", ex); - } - } - - public async Task CloseAllSessionsAsync(Guid userId) - { - try - { - var sessions = await _sessionsRepository.GetByUserIdAsync(userId); - - foreach (var session in sessions) - { - if(session.IsRevoked) continue; - - session.IsRevoked = true; - await _sessionsRepository.UpdateAsync(session); - - await _pushTokenRepository.DeactivateTokenBySessionAsync(session.Id); // pushes deactivate - } - } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning("User {userId} has not sessions", userId); - throw new NotFoundException("Session not found", ex); - } - } -} \ No newline at end of file diff --git a/Govor.Application/Services/VerifierFriendship.cs b/Govor.Application/Services/VerifierFriendship.cs deleted file mode 100644 index 1a57659..0000000 --- a/Govor.Application/Services/VerifierFriendship.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Govor.Application.Exceptions.VerifyFriendship; -using Govor.Application.Interfaces; -using Govor.Core.Models; -using Govor.Core.Repositories.Friendships; -using Govor.Data.Repositories.Exceptions; -using Microsoft.Extensions.Logging; - -namespace Govor.Application.Services; - -public class VerifyFriendship : IVerifyFriendship -{ - private readonly IFriendshipsRepository _friendshipsRepository; - private readonly ILogger _logger; - private const string FriendshipNotAcceptedError = "Friendship between user {0} and friend {1} does not exist or is not accepted."; - - public VerifyFriendship(IFriendshipsRepository friendshipsRepository, ILogger logger) - { - _friendshipsRepository = friendshipsRepository ?? throw new ArgumentNullException(nameof(friendshipsRepository)); - _logger = logger; - } - - public async Task VerifyAsync(Guid targetUserId, Guid friendUserId) - { - try - { - if (targetUserId == Guid.Empty || friendUserId == Guid.Empty) - { - _logger?.LogWarning( - "Invalid user IDs provided: targetUserId={TargetUserId}, friendUserId={FriendUserId}", targetUserId, - friendUserId); - throw new ArgumentException("User IDs cannot be empty.", nameof(targetUserId)); - } - - var friendships = await _friendshipsRepository.FindByUserIdAsync(targetUserId); - var friendship = friendships.Where(f => f.AddresseeId == friendUserId || f.RequesterId == friendUserId) - ?.FirstOrDefault(); - - if (friendship == null || friendship.Status != FriendshipStatus.Accepted) - { - var errorMessage = string.Format(FriendshipNotAcceptedError, targetUserId, friendUserId); - _logger?.LogError(errorMessage); - throw new FriendshipException(errorMessage); - } - - _logger.LogInformation("hello"); - - _logger.LogInformation( - "Friendship verified successfully for targetUserId={TargetUserId}, friendUserId={FriendUserId}", - targetUserId, friendUserId); - } - catch (NotFoundByKeyException ex) - { - var errorMessage = string.Format(FriendshipNotAcceptedError, targetUserId, friendUserId); - _logger.LogError(errorMessage); - - throw new FriendshipException(errorMessage); - } - } - - public async Task TryVerifyAsync(Guid targetUserId, Guid friendUserId) - { - try - { - await VerifyAsync(targetUserId, friendUserId); - return true; - } - catch (Exception ex) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Application/Interfaces/IStorageService.cs b/Govor.Application/Storage/IStorageService.cs similarity index 80% rename from Govor.Application/Interfaces/IStorageService.cs rename to Govor.Application/Storage/IStorageService.cs index f648964..1558caf 100644 --- a/Govor.Application/Interfaces/IStorageService.cs +++ b/Govor.Application/Storage/IStorageService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Storage; public interface IStorageService { diff --git a/Govor.Application/Services/LocalStorageService.cs b/Govor.Application/Storage/LocalStorageService.cs similarity index 97% rename from Govor.Application/Services/LocalStorageService.cs rename to Govor.Application/Storage/LocalStorageService.cs index 80a2791..9a673d2 100644 --- a/Govor.Application/Services/LocalStorageService.cs +++ b/Govor.Application/Storage/LocalStorageService.cs @@ -1,5 +1,4 @@ -using Govor.Application.Interfaces; -namespace Govor.Application.Services; +namespace Govor.Application.Storage; public class LocalStorageService : IStorageService { diff --git a/Govor.Application/Interfaces/ISynchingService.cs b/Govor.Application/Synching/ISynchingService.cs similarity index 89% rename from Govor.Application/Interfaces/ISynchingService.cs rename to Govor.Application/Synching/ISynchingService.cs index ece6de5..44f25cc 100644 --- a/Govor.Application/Interfaces/ISynchingService.cs +++ b/Govor.Application/Synching/ISynchingService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces; +namespace Govor.Application.Synching; public interface ISynchingService { diff --git a/Govor.Application/Services/SynchingService.cs b/Govor.Application/Synching/SynchingService.cs similarity index 82% rename from Govor.Application/Services/SynchingService.cs rename to Govor.Application/Synching/SynchingService.cs index 63f00da..c07f4a0 100644 --- a/Govor.Application/Services/SynchingService.cs +++ b/Govor.Application/Synching/SynchingService.cs @@ -1,6 +1,4 @@ -using Govor.Application.Interfaces; - -namespace Govor.Application.Services; +namespace Govor.Application.Synching; public class SynchingService : ISynchingService { diff --git a/Govor.Application/Users/IUserNameExistValidator.cs b/Govor.Application/Users/IUserNameExistValidator.cs new file mode 100644 index 0000000..95a4b74 --- /dev/null +++ b/Govor.Application/Users/IUserNameExistValidator.cs @@ -0,0 +1,6 @@ +namespace Govor.Application.Users; + +public interface IUserNameExistValidator +{ + Task IsUsernameExistsAsync(string userName); +} \ No newline at end of file diff --git a/Govor.Application/Users/UserNameExistValidator.cs b/Govor.Application/Users/UserNameExistValidator.cs new file mode 100644 index 0000000..f6e40d3 --- /dev/null +++ b/Govor.Application/Users/UserNameExistValidator.cs @@ -0,0 +1,26 @@ +using Govor.Domain; +using Microsoft.EntityFrameworkCore; + +namespace Govor.Application.Users; + +public class UserNameExistValidator : IUserNameExistValidator +{ + private readonly GovorDbContext _context; + + public UserNameExistValidator(GovorDbContext context) + { + _context = context; + } + + public async Task IsUsernameExistsAsync(string userName) + { + if (string.IsNullOrWhiteSpace(userName)) + { + return false; + } + + return await _context.Users + .AsNoTracking() + .AnyAsync(u => u.Username == userName); + } +} \ No newline at end of file diff --git a/Govor.Application/Interfaces/UserOnlineStatus/IOnlineUserStore.cs b/Govor.Application/Users/UserOnlineStatus/IOnlineUserStore.cs similarity index 83% rename from Govor.Application/Interfaces/UserOnlineStatus/IOnlineUserStore.cs rename to Govor.Application/Users/UserOnlineStatus/IOnlineUserStore.cs index 80512ee..12d9952 100644 --- a/Govor.Application/Interfaces/UserOnlineStatus/IOnlineUserStore.cs +++ b/Govor.Application/Users/UserOnlineStatus/IOnlineUserStore.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public interface IOnlineUserStore { diff --git a/Govor.Application/Interfaces/UserOnlineStatus/IUserNotificationScopeService.cs b/Govor.Application/Users/UserOnlineStatus/IUserNotificationScopeService.cs similarity index 63% rename from Govor.Application/Interfaces/UserOnlineStatus/IUserNotificationScopeService.cs rename to Govor.Application/Users/UserOnlineStatus/IUserNotificationScopeService.cs index 0ac93a0..29685d8 100644 --- a/Govor.Application/Interfaces/UserOnlineStatus/IUserNotificationScopeService.cs +++ b/Govor.Application/Users/UserOnlineStatus/IUserNotificationScopeService.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public interface IUserNotificationScopeService { diff --git a/Govor.Application/Interfaces/UserOnlineStatus/IUserPresenceReader.cs b/Govor.Application/Users/UserOnlineStatus/IUserPresenceReader.cs similarity index 61% rename from Govor.Application/Interfaces/UserOnlineStatus/IUserPresenceReader.cs rename to Govor.Application/Users/UserOnlineStatus/IUserPresenceReader.cs index 5291ccb..fb6a53d 100644 --- a/Govor.Application/Interfaces/UserOnlineStatus/IUserPresenceReader.cs +++ b/Govor.Application/Users/UserOnlineStatus/IUserPresenceReader.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public interface IUserPresenceReader { diff --git a/Govor.Application/Services/UserOnlineStatus/OnlineUserStore.cs b/Govor.Application/Users/UserOnlineStatus/OnlineUserStore.cs similarity index 94% rename from Govor.Application/Services/UserOnlineStatus/OnlineUserStore.cs rename to Govor.Application/Users/UserOnlineStatus/OnlineUserStore.cs index b772486..a859537 100644 --- a/Govor.Application/Services/UserOnlineStatus/OnlineUserStore.cs +++ b/Govor.Application/Users/UserOnlineStatus/OnlineUserStore.cs @@ -1,7 +1,6 @@ using System.Collections.Concurrent; -using Govor.Application.Interfaces.UserOnlineStatus; -namespace Govor.Application.Services.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public class OnlineUserStore : IOnlineUserStore { diff --git a/Govor.Application/Services/UserOnlineStatus/UserNotificationScopeService.cs b/Govor.Application/Users/UserOnlineStatus/UserNotificationScopeService.cs similarity index 67% rename from Govor.Application/Services/UserOnlineStatus/UserNotificationScopeService.cs rename to Govor.Application/Users/UserOnlineStatus/UserNotificationScopeService.cs index 82c5cae..8da99c8 100644 --- a/Govor.Application/Services/UserOnlineStatus/UserNotificationScopeService.cs +++ b/Govor.Application/Users/UserOnlineStatus/UserNotificationScopeService.cs @@ -1,9 +1,7 @@ -using Govor.Application.Interfaces.Friends; -using Govor.Application.Interfaces.UserOnlineStatus; -using Govor.Data.Repositories.Exceptions; +using Govor.Application.Friends; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public class UserNotificationScopeService : IUserNotificationScopeService { @@ -18,17 +16,9 @@ public class UserNotificationScopeService : IUserNotificationScopeService public async Task> GetNotifiedUsers(Guid userId) { - try - { - _logger.LogInformation($"Getting notified users of online/offline action user {userId}"); - var users = await _friendships.GetFriendsAsync(userId); - return users.Select(u => u.Id).ToList(); - } - catch (NotFoundByKeyException ex) - { - _logger.LogWarning(ex, ex.Message); - throw new InvalidOperationException("User not found"); - } + _logger.LogInformation($"Getting notified users of online/offline action user {userId}"); + var users = await _friendships.GetFriendsAsync(userId); + return users.Select(u => u.Id).ToList(); } /*public async Task SetWasOnlineAsync(Guid userId, DateTime when) diff --git a/Govor.Application/Services/UserOnlineStatus/UserPresenceReader.cs b/Govor.Application/Users/UserOnlineStatus/UserPresenceReader.cs similarity index 60% rename from Govor.Application/Services/UserOnlineStatus/UserPresenceReader.cs rename to Govor.Application/Users/UserOnlineStatus/UserPresenceReader.cs index aeab7ab..de7f951 100644 --- a/Govor.Application/Services/UserOnlineStatus/UserPresenceReader.cs +++ b/Govor.Application/Users/UserOnlineStatus/UserPresenceReader.cs @@ -1,6 +1,4 @@ -using Govor.Application.Interfaces.UserOnlineStatus; - -namespace Govor.Application.Services.UserOnlineStatus; +namespace Govor.Application.Users.UserOnlineStatus; public class UserPresenceReader : IUserPresenceReader { diff --git a/Govor.Application/Interfaces/UserSession/Crypto/IOneTimePreKeysRotator.cs b/Govor.Application/Users/UserSessions/Crypto/IOneTimePreKeysRotator.cs similarity index 78% rename from Govor.Application/Interfaces/UserSession/Crypto/IOneTimePreKeysRotator.cs rename to Govor.Application/Users/UserSessions/Crypto/IOneTimePreKeysRotator.cs index 9bf0865..6c3a7dc 100644 --- a/Govor.Application/Interfaces/UserSession/Crypto/IOneTimePreKeysRotator.cs +++ b/Govor.Application/Users/UserSessions/Crypto/IOneTimePreKeysRotator.cs @@ -1,4 +1,4 @@ -namespace Govor.Application.Interfaces.UserSession.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public interface IOneTimePreKeysRotator { diff --git a/Govor.Application/Interfaces/UserSession/Crypto/ISessionKeyAttacher.cs b/Govor.Application/Users/UserSessions/Crypto/ISessionKeyAttacher.cs similarity index 70% rename from Govor.Application/Interfaces/UserSession/Crypto/ISessionKeyAttacher.cs rename to Govor.Application/Users/UserSessions/Crypto/ISessionKeyAttacher.cs index d08db89..214aef6 100644 --- a/Govor.Application/Interfaces/UserSession/Crypto/ISessionKeyAttacher.cs +++ b/Govor.Application/Users/UserSessions/Crypto/ISessionKeyAttacher.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; -namespace Govor.Application.Interfaces.UserSession.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public interface ISessionKeyAttacher { diff --git a/Govor.Application/Interfaces/UserSession/Crypto/ISessionKeysReader.cs b/Govor.Application/Users/UserSessions/Crypto/ISessionKeysReader.cs similarity index 75% rename from Govor.Application/Interfaces/UserSession/Crypto/ISessionKeysReader.cs rename to Govor.Application/Users/UserSessions/Crypto/ISessionKeysReader.cs index 5a0a23f..eb5a1a4 100644 --- a/Govor.Application/Interfaces/UserSession/Crypto/ISessionKeysReader.cs +++ b/Govor.Application/Users/UserSessions/Crypto/ISessionKeysReader.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; -namespace Govor.Application.Interfaces.UserSession.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public interface ISessionKeysReader { diff --git a/Govor.Application/Services/UserSessions/Crypto/OneTimePreKeysRotator.cs b/Govor.Application/Users/UserSessions/Crypto/OneTimePreKeysRotator.cs similarity index 90% rename from Govor.Application/Services/UserSessions/Crypto/OneTimePreKeysRotator.cs rename to Govor.Application/Users/UserSessions/Crypto/OneTimePreKeysRotator.cs index 0e5856c..e652413 100644 --- a/Govor.Application/Services/UserSessions/Crypto/OneTimePreKeysRotator.cs +++ b/Govor.Application/Users/UserSessions/Crypto/OneTimePreKeysRotator.cs @@ -1,11 +1,10 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserSession.Crypto; -using Govor.Core.Models.Users.Crypto; -using Govor.Data; +using Govor.Application.Infrastructure.Extensions; +using Govor.Domain.Models.Users.Crypto; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.UserSessions.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public class OneTimePreKeysRotator : IOneTimePreKeysRotator { diff --git a/Govor.Application/Services/UserSessions/Crypto/SessionKeyAttacher.cs b/Govor.Application/Users/UserSessions/Crypto/SessionKeyAttacher.cs similarity index 90% rename from Govor.Application/Services/UserSessions/Crypto/SessionKeyAttacher.cs rename to Govor.Application/Users/UserSessions/Crypto/SessionKeyAttacher.cs index 1a42da3..c4860fb 100644 --- a/Govor.Application/Services/UserSessions/Crypto/SessionKeyAttacher.cs +++ b/Govor.Application/Users/UserSessions/Crypto/SessionKeyAttacher.cs @@ -1,11 +1,10 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserSession.Crypto; -using Govor.Core.Models.Users.Crypto; -using Govor.Data; +using Govor.Application.Infrastructure.Extensions; +using Govor.Domain.Models.Users.Crypto; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.UserSessions.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public class SessionKeyAttacher : ISessionKeyAttacher { diff --git a/Govor.Application/Services/UserSessions/Crypto/SessionKeysReader.cs b/Govor.Application/Users/UserSessions/Crypto/SessionKeysReader.cs similarity index 89% rename from Govor.Application/Services/UserSessions/Crypto/SessionKeysReader.cs rename to Govor.Application/Users/UserSessions/Crypto/SessionKeysReader.cs index 8a9e81a..f8c474f 100644 --- a/Govor.Application/Services/UserSessions/Crypto/SessionKeysReader.cs +++ b/Govor.Application/Users/UserSessions/Crypto/SessionKeysReader.cs @@ -1,11 +1,9 @@ -using Govor.Application.Interfaces.Infrastructure.Extensions; -using Govor.Application.Interfaces.UserSession.Crypto; -using Govor.Core.Models.Users.Crypto; -using Govor.Data; +using Govor.Domain.Models.Users.Crypto; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace Govor.Application.Services.UserSessions.Crypto; +namespace Govor.Application.Users.UserSessions.Crypto; public class SessionKeysReader : ISessionKeysReader { diff --git a/Govor.Application/Users/UserSessions/IUserSessionOpener.cs b/Govor.Application/Users/UserSessions/IUserSessionOpener.cs new file mode 100644 index 0000000..4f95a7a --- /dev/null +++ b/Govor.Application/Users/UserSessions/IUserSessionOpener.cs @@ -0,0 +1,11 @@ +using Govor.Domain.Common; +using Govor.Domain.Models.Users; + +namespace Govor.Application.Users.UserSessions; + + +public interface IUserSessionOpener +{ + Task> OpenSessionAsync(User user, string deviceInfo); +} + diff --git a/Govor.Application/Users/UserSessions/IUserSessionReader.cs b/Govor.Application/Users/UserSessions/IUserSessionReader.cs new file mode 100644 index 0000000..49432c5 --- /dev/null +++ b/Govor.Application/Users/UserSessions/IUserSessionReader.cs @@ -0,0 +1,8 @@ +using Govor.Domain.Common; + +namespace Govor.Application.Users.UserSessions; + +public interface IUserSessionReader +{ + Task>> GetAllSessionsAsync(Guid userId); +} \ No newline at end of file diff --git a/Govor.Application/Users/UserSessions/IUserSessionRefresher.cs b/Govor.Application/Users/UserSessions/IUserSessionRefresher.cs new file mode 100644 index 0000000..602e79e --- /dev/null +++ b/Govor.Application/Users/UserSessions/IUserSessionRefresher.cs @@ -0,0 +1,8 @@ +using Govor.Domain.Common; + +namespace Govor.Application.Users.UserSessions; + +public interface IUserSessionRefresher +{ + Task> RefreshTokenAsync(string refreshToken); +} \ No newline at end of file diff --git a/Govor.Application/Users/UserSessions/IUserSessionRevoker.cs b/Govor.Application/Users/UserSessions/IUserSessionRevoker.cs new file mode 100644 index 0000000..0369cef --- /dev/null +++ b/Govor.Application/Users/UserSessions/IUserSessionRevoker.cs @@ -0,0 +1,10 @@ +using Govor.Domain.Common; + +namespace Govor.Application.Users.UserSessions; + + +public interface IUserSessionRevoker +{ + Task CloseSessionByIdAsync(Guid sessionId, Guid userId); + Task CloseAllSessionsAsync(Guid userId); +} diff --git a/Govor.Application/Users/UserSessions/RefreshResult.cs b/Govor.Application/Users/UserSessions/RefreshResult.cs new file mode 100644 index 0000000..0e907d7 --- /dev/null +++ b/Govor.Application/Users/UserSessions/RefreshResult.cs @@ -0,0 +1,3 @@ +namespace Govor.Application.Users.UserSessions; + +public record RefreshResult(string refreshToken, string accessToken); \ No newline at end of file diff --git a/Govor.Application/Services/UserSessions/UserSessionOpener.cs b/Govor.Application/Users/UserSessions/UserSessionOpener.cs similarity index 52% rename from Govor.Application/Services/UserSessions/UserSessionOpener.cs rename to Govor.Application/Users/UserSessions/UserSessionOpener.cs index bf4a382..4788505 100644 --- a/Govor.Application/Services/UserSessions/UserSessionOpener.cs +++ b/Govor.Application/Users/UserSessions/UserSessionOpener.cs @@ -1,54 +1,74 @@ -using Govor.Application.Interfaces.Authentication; -using Govor.Application.Interfaces.UserSession; -using Govor.Application.Services.Authentication; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data.Repositories.Exceptions; +using Govor.Application.Authentication.JWT; +using Govor.Domain; +using Govor.Domain.Common; // Путь к вашему Result и Error +using Govor.Domain.Models.Users; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace Govor.Application.Services.UserSessions; +namespace Govor.Application.Users.UserSessions; public class UserSessionOpener : IUserSessionOpener { - private readonly IUserSessionsRepository _repository; private readonly ILogger _logger; + private readonly IUserSessionReader _userSessionReader; + private readonly GovorDbContext _context; private readonly IJwtTokenHasher _jwtTokenHasher; private readonly JwtRefreshOption _options; private readonly IJwtService _jwtService; public UserSessionOpener( - IUserSessionsRepository repository, - IJwtService jwtService, + ILogger logger, + IUserSessionReader userSessionReader, + GovorDbContext context, IJwtTokenHasher jwtTokenHasher, IOptions options, - ILogger logger) + IJwtService jwtService) { - _jwtService = jwtService; - _repository = repository; - _jwtTokenHasher = jwtTokenHasher; _logger = logger; + _userSessionReader = userSessionReader; + _context = context; + _jwtTokenHasher = jwtTokenHasher; _options = options.Value; + _jwtService = jwtService; } - public async Task OpenSessionAsync(User user, string deviceInfo) + public async Task> OpenSessionAsync(User user, string deviceInfo) { - _logger.LogInformation($"Opening session for user {user.Id} on device '{deviceInfo}'"); + _logger.LogInformation("Opening session for user {UserId} on device '{DeviceInfo}'", user.Id, deviceInfo); + + var result = await _userSessionReader.GetAllSessionsAsync(user.Id); + + if (result.IsFailure) + { + _logger.LogError("Failed to fetch sessions for user {UserId}: {Error}", user.Id, result.Error.Message); + return Result.Failure(result.Error); + } + + var sessions = result.Value; + var existingSession = sessions.FirstOrDefault(s => s.DeviceInfo == deviceInfo); try { - var sessions = await _repository.GetByUserIdAsync(user.Id); - var existingSession = sessions.FirstOrDefault(s => s.DeviceInfo == deviceInfo ); + RefreshResult refreshResult; if (existingSession is not null) - return await UpdateExistingSessionAsync(user, deviceInfo, existingSession); + { + refreshResult = await UpdateExistingSessionAsync(user, deviceInfo, existingSession); + } + else + { + refreshResult = await CreateNewSessionAsync(user, deviceInfo); + } + + await _context.SaveChangesAsync(); + + return refreshResult; } - catch (NotFoundByKeyException ex) + catch (Exception ex) { - _logger.LogError(ex, "Could not find session for user {userId}", user.Id); + _logger.LogError(ex, "Database error while opening session for user {UserId}", user.Id); + return Result.Failure(ex); } - - return await CreateNewSessionAsync(user, deviceInfo); } private async Task UpdateExistingSessionAsync(User user, string deviceInfo, UserSession session) @@ -57,14 +77,13 @@ public class UserSessionOpener : IUserSessionOpener var newTokenHash = _jwtTokenHasher.HashToken(refreshToken); var newExpiresAt = DateTime.UtcNow.AddDays(_options.RefreshTokenLifetimeDays); - + session.RefreshTokenHash = newTokenHash; session.ExpiresAt = newExpiresAt; session.CreatedAt = DateTime.UtcNow; session.IsRevoked = false; - - await _repository.UpdateAsync(session); - _logger.LogInformation($"Updated session for user {user.Id} on device '{deviceInfo}'"); + + _logger.LogInformation("Updated session for user {UserId} on device '{DeviceInfo}'", user.Id, deviceInfo); return new RefreshResult(refreshToken, accessToken); } @@ -86,10 +105,10 @@ public class UserSessionOpener : IUserSessionOpener ExpiresAt = DateTime.UtcNow.AddDays(_options.RefreshTokenLifetimeDays), IsRevoked = false }; + + await _context.UserSessions.AddAsync(newSession); - await _repository.AddAsync(newSession); - - _logger.LogInformation($"Created new session {sessionId} for user {user.Id} on device '{deviceInfo}'"); + _logger.LogInformation("Created new session {SessionId} for user {UserId} on device '{DeviceInfo}'", sessionId, user.Id, deviceInfo); return new RefreshResult(refreshToken, accessToken); } diff --git a/Govor.Application/Users/UserSessions/UserSessionReader.cs b/Govor.Application/Users/UserSessions/UserSessionReader.cs new file mode 100644 index 0000000..fdbcb68 --- /dev/null +++ b/Govor.Application/Users/UserSessions/UserSessionReader.cs @@ -0,0 +1,46 @@ +using Govor.Domain; +using Govor.Domain.Common; +using Govor.Domain.Models.Users; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Users.UserSessions; + +public class UserSessionReader : IUserSessionReader +{ + private readonly GovorDbContext _context; + private readonly ILogger _logger; + + public UserSessionReader(GovorDbContext context, ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task>> GetAllSessionsAsync(Guid userId) + { + if (userId == Guid.Empty) + { + return Result>.Failure(new Error( + "UserSession.InvalidUserId", + "Provided User ID cannot be empty.")); + } + + _logger.LogInformation("Getting all active sessions for user {UserId}", userId); + + try + { + var sessions = await _context.UserSessions + .AsNoTracking() + .Where(s => s.UserId == userId && !s.IsRevoked) + .ToListAsync(); + + return sessions; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to fetch user sessions for user {UserId}", userId); + return Result>.Failure(ex); + } + } +} \ No newline at end of file diff --git a/Govor.Application/Users/UserSessions/UserSessionRefresher.cs b/Govor.Application/Users/UserSessions/UserSessionRefresher.cs new file mode 100644 index 0000000..1486d16 --- /dev/null +++ b/Govor.Application/Users/UserSessions/UserSessionRefresher.cs @@ -0,0 +1,80 @@ +using Govor.Application.Authentication.JWT; +using Govor.Domain; +using Govor.Domain.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Govor.Application.Users.UserSessions; + +public class UserSessionRefresher : IUserSessionRefresher +{ + private readonly ILogger _logger; + private readonly JwtRefreshOption _options; + private readonly IJwtTokenHasher _jwtTokenHasher; + private readonly IJwtService _jwtService; + private readonly GovorDbContext _context; + + public UserSessionRefresher( + ILogger logger, + IOptions options, + IJwtTokenHasher jwtTokenHasher, + IJwtService jwtService, + GovorDbContext context) + { + _logger = logger; + _options = options.Value; + _jwtTokenHasher = jwtTokenHasher; + _jwtService = jwtService; + _context = context; + } + + public async Task> RefreshTokenAsync(string refreshToken) + { + if (string.IsNullOrWhiteSpace(refreshToken)) + { + return Result.Failure(new Error("Auth.EmptyToken", "Refresh token cannot be empty.")); + } + + var hashedToken = _jwtTokenHasher.HashToken(refreshToken); + + try + { + var session = await _context.UserSessions + .AsNoTracking() + .Include(userSession => userSession.User) + .FirstOrDefaultAsync(s => s.RefreshTokenHash == hashedToken); + + if (session is null) + { + _logger.LogWarning("Refresh token session not found for hashed token"); + return Result.Failure(new Error("Auth.InvalidToken", "Invalid refresh token.")); + } + + if (session.IsRevoked || session.ExpiresAt <= DateTime.UtcNow) + { + _logger.LogWarning("Attempted to refresh an expired or revoked session: {SessionId}", session.Id); + return Result.Failure(new Error("Auth.InvalidToken", "Refresh token is invalid or expired.")); + } + + var newAccessToken = await _jwtService.GenerateAccessTokenAsync(session.User, session.Id); + var newRefreshToken = await _jwtService.GenerateRefreshTokenAsync(session.User); + var newRefreshTokenHash = _jwtTokenHasher.HashToken(newRefreshToken); + + session.RefreshTokenHash = newRefreshTokenHash; + session.CreatedAt = DateTime.UtcNow; + session.ExpiresAt = DateTime.UtcNow.AddDays(_options.RefreshTokenLifetimeDays); + + await _context.SaveChangesAsync(); + + _logger.LogInformation("Successfully refreshed session {SessionId} for user {UserId}", session.Id, session.UserId); + + return new RefreshResult(newRefreshToken, newAccessToken); + } + catch (Exception ex) + { + _logger.LogError(ex, "Database error occurred during token refresh execution"); + return Result.Failure(ex); + } + } +} diff --git a/Govor.Application/Users/UserSessions/UserSessionRevoker.cs b/Govor.Application/Users/UserSessions/UserSessionRevoker.cs new file mode 100644 index 0000000..4135449 --- /dev/null +++ b/Govor.Application/Users/UserSessions/UserSessionRevoker.cs @@ -0,0 +1,85 @@ +using Govor.Application.PushNotifications; +using Govor.Domain; +using Govor.Domain.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Govor.Application.Users.UserSessions; + +public class UserSessionRevoker : IUserSessionRevoker +{ + private readonly GovorDbContext _context; + private readonly IPushTokenService _tokenService; + private readonly ILogger _logger; + + public UserSessionRevoker( + GovorDbContext context, + IPushTokenService tokenService, + ILogger logger) + { + _tokenService = tokenService; + _context = context; + _logger = logger; + } + + public async Task CloseSessionByIdAsync(Guid sessionId, Guid userId) + { + _logger.LogInformation("Attempting to close session {SessionId} for user {UserId}", sessionId, userId); + + try + { + var session = await _context.UserSessions + .FirstOrDefaultAsync(s => s.Id == sessionId && s.UserId == userId && !s.IsRevoked); + + if (session is null) + { + _logger.LogWarning("Active session {SessionId} not found or doesn't belong to user {UserId}", sessionId, userId); + return Result.Failure(new Error( + "UserSession.NotFoundOrUnauthorized", + $"Active session {sessionId} for user {userId} was not found.")); + } + + session.IsRevoked = true; + + await _context.SaveChangesAsync(); + + await _tokenService.DeactivateTokenBySessionAsync(sessionId); + + _logger.LogInformation("Successfully revoked session {SessionId}", sessionId); + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while closing session {SessionId}", sessionId); + return Result.Failure(ex); + } + } + + public async Task CloseAllSessionsAsync(Guid userId) + { + _logger.LogInformation("Attempting to close all active sessions for user {UserId}", userId); + + try + { + var updatedRowsCount = await _context.UserSessions + .Where(s => s.UserId == userId && !s.IsRevoked) + .ExecuteUpdateAsync(setters => setters.SetProperty(s => s.IsRevoked, true)); + + if (updatedRowsCount == 0) + { + _logger.LogInformation("User {UserId} had no active sessions to close", userId); + return Result.Success(); + } + + await _tokenService.DeactivateAllTokensByUserIdAsync(userId); + + _logger.LogInformation("Successfully revoked all {Count} active sessions for user {UserId}", updatedRowsCount, userId); + return Result.Success(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error occurred while closing all sessions for user {UserId}", userId); + return Result.Failure(ex); + } + } +} \ No newline at end of file diff --git a/Govor.ConsoleClient/Govor.ConsoleClient.csproj b/Govor.ConsoleClient/Govor.ConsoleClient.csproj index e3de400..1686633 100644 --- a/Govor.ConsoleClient/Govor.ConsoleClient.csproj +++ b/Govor.ConsoleClient/Govor.ConsoleClient.csproj @@ -16,7 +16,6 @@ - diff --git a/Govor.Contracts/DTOs/FriendshipDto.cs b/Govor.Contracts/DTOs/FriendshipDto.cs index 85065e1..fa09625 100644 --- a/Govor.Contracts/DTOs/FriendshipDto.cs +++ b/Govor.Contracts/DTOs/FriendshipDto.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models; +using Govor.Domain.Models; namespace Govor.Contracts.DTOs; diff --git a/Govor.Contracts/Govor.Contracts.csproj b/Govor.Contracts/Govor.Contracts.csproj index 6427a81..ed3cb48 100644 --- a/Govor.Contracts/Govor.Contracts.csproj +++ b/Govor.Contracts/Govor.Contracts.csproj @@ -7,7 +7,7 @@ - + diff --git a/Govor.Contracts/Requests/AvatarUploadRequest.cs b/Govor.Contracts/Requests/AvatarUploadRequest.cs index 3ae6553..4458dec 100644 --- a/Govor.Contracts/Requests/AvatarUploadRequest.cs +++ b/Govor.Contracts/Requests/AvatarUploadRequest.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.Http; namespace Govor.Contracts.Requests; diff --git a/Govor.Contracts/Requests/LoginRequest.cs b/Govor.Contracts/Requests/LoginRequest.cs index f7a0b11..25f6d20 100644 --- a/Govor.Contracts/Requests/LoginRequest.cs +++ b/Govor.Contracts/Requests/LoginRequest.cs @@ -1,14 +1,14 @@ using System.ComponentModel.DataAnnotations; -using Govor.Core.Infrastructure.Validators; +using Govor.Domain.Common.Constants; namespace Govor.Contracts.Requests; public class LoginRequest { [Required] - [StringLength(UserValidator.MAX_LENGHT_OF_NAME, - MinimumLength = UserValidator.MIN_LENGHT_OF_NAME, - ErrorMessage = "Username must be between 4 and 50 characters.")] + [StringLength(UserConstants.MAX_LENGHT_OF_NAME, + MinimumLength = UserConstants.MIN_LENGHT_OF_NAME, + ErrorMessage = "Username must be between 4 and 44 characters.")] public string Name { get; init; } [Required] [MinLength(8)] diff --git a/Govor.Contracts/Requests/MediaUploadRequest.cs b/Govor.Contracts/Requests/MediaUploadRequest.cs index ec62161..4baa48f 100644 --- a/Govor.Contracts/Requests/MediaUploadRequest.cs +++ b/Govor.Contracts/Requests/MediaUploadRequest.cs @@ -1,5 +1,5 @@ -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.Http; using System.ComponentModel.DataAnnotations; diff --git a/Govor.Contracts/Requests/RegistrationRequest.cs b/Govor.Contracts/Requests/RegistrationRequest.cs index eb130c8..afe6048 100644 --- a/Govor.Contracts/Requests/RegistrationRequest.cs +++ b/Govor.Contracts/Requests/RegistrationRequest.cs @@ -1,19 +1,19 @@ using System.ComponentModel.DataAnnotations; -using Govor.Core.Infrastructure.Validators; +using Govor.Domain.Common.Constants; namespace Govor.Contracts.Requests; public record RegistrationRequest { [Required] - [StringLength(UserValidator.MAX_LENGHT_OF_NAME, - MinimumLength = UserValidator.MIN_LENGHT_OF_NAME, + [StringLength(UserConstants.MAX_LENGHT_OF_NAME, + MinimumLength = UserConstants.MIN_LENGHT_OF_NAME, ErrorMessage = "Username must be between 4 and 44 characters.")] public string Name { get; init; } [Required] [MinLength(8)] public string Password { get; init; } - [MinLength(InvitationValidator.MIN_INVITATION_LENGTH)] + [MinLength(InvitationConstants.MIN_INVITATION_LENGTH)] public string InviteLink { get; init; } public string DeviceInfo { get; init; } } diff --git a/Govor.Contracts/Requests/SignalR/MediaReference.cs b/Govor.Contracts/Requests/SignalR/MediaReference.cs index d2b9a1b..21f8d3a 100644 --- a/Govor.Contracts/Requests/SignalR/MediaReference.cs +++ b/Govor.Contracts/Requests/SignalR/MediaReference.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models; +using Govor.Domain.Models; namespace Govor.Contracts.Requests.SignalR; diff --git a/Govor.Contracts/Requests/SignalR/MessageRequest.cs b/Govor.Contracts/Requests/SignalR/MessageRequest.cs index d2dabaf..61f5802 100644 --- a/Govor.Contracts/Requests/SignalR/MessageRequest.cs +++ b/Govor.Contracts/Requests/SignalR/MessageRequest.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using System.ComponentModel.DataAnnotations; namespace Govor.Contracts.Requests.SignalR; diff --git a/Govor.Contracts/Responses/MessageResponse.cs b/Govor.Contracts/Responses/MessageResponse.cs index 60ea4ba..6d013f0 100644 --- a/Govor.Contracts/Responses/MessageResponse.cs +++ b/Govor.Contracts/Responses/MessageResponse.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; namespace Govor.Contracts.Responses; diff --git a/Govor.Contracts/Responses/SignalR/MessageEditResponse.cs b/Govor.Contracts/Responses/SignalR/MessageEditResponse.cs index f03c638..dcb51d6 100644 --- a/Govor.Contracts/Responses/SignalR/MessageEditResponse.cs +++ b/Govor.Contracts/Responses/SignalR/MessageEditResponse.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; namespace Govor.Contracts.Responses.SignalR; diff --git a/Govor.Contracts/Responses/SignalR/MessageRemovedResponse.cs b/Govor.Contracts/Responses/SignalR/MessageRemovedResponse.cs index 89471b4..07a72d4 100644 --- a/Govor.Contracts/Responses/SignalR/MessageRemovedResponse.cs +++ b/Govor.Contracts/Responses/SignalR/MessageRemovedResponse.cs @@ -1,4 +1,4 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; namespace Govor.Contracts.Responses.SignalR; diff --git a/Govor.Contracts/Responses/SignalR/UserMessageResponse.cs b/Govor.Contracts/Responses/SignalR/UserMessageResponse.cs index 0106c6e..9d664c9 100644 --- a/Govor.Contracts/Responses/SignalR/UserMessageResponse.cs +++ b/Govor.Contracts/Responses/SignalR/UserMessageResponse.cs @@ -1,5 +1,5 @@ -using Govor.Core.Models; -using Govor.Core.Models.Messages; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; namespace Govor.Contracts.Responses.SignalR; diff --git a/Govor.Core/Govor.Core.csproj b/Govor.Core/Govor.Core.csproj deleted file mode 100644 index eaa57c8..0000000 --- a/Govor.Core/Govor.Core.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - diff --git a/Govor.Core/Infrastructure/Validators/AdminValidator.cs b/Govor.Core/Infrastructure/Validators/AdminValidator.cs deleted file mode 100644 index 2aebfb6..0000000 --- a/Govor.Core/Infrastructure/Validators/AdminValidator.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Infrastructure.Validators; - -public class AdminValidator : IObjectValidator -{ - public void Validate(Admin admin) - { - try - { - if(admin is null) - throw new ArgumentNullException(nameof(admin)); - if(admin.UserId == Guid.Empty) - throw new ArgumentException("User ID cannot be empty", nameof(admin.UserId)); - } - catch (Exception e) - { - throw new InvalidObjectException(e); - } - } - - public bool TryValidate(Admin admin) - { - try - { - Validate(admin); - return true; - } - catch (Exception e) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/ChatGroupValidator.cs b/Govor.Core/Infrastructure/Validators/ChatGroupValidator.cs deleted file mode 100644 index c8e70ff..0000000 --- a/Govor.Core/Infrastructure/Validators/ChatGroupValidator.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Infrastructure.Validators; - -public class ChatGroupValidator : IObjectValidator -{ - public void Validate(ChatGroup chat) - { - try - { - if(chat is null) - throw new ArgumentNullException(nameof(chat)); - if(chat.Id == Guid.Empty) - throw new ArgumentException("Id of chat group can't be empty",nameof(chat.Id)); - if(string.IsNullOrEmpty(chat.Name)) - throw new ArgumentException("Name of chat group can't be empty",nameof(chat.Name)); - if(chat.Description is null) - throw new ArgumentException("Description of chat group can't be null",nameof(chat.Description)); - if(chat.ImageId == Guid.Empty) - throw new ArgumentException("ImageId of chat group can't be empty",nameof(chat.ImageId)); - if(chat.IsPrivate && chat.InviteCodes.Count <= 0) - throw new ArgumentException("Private group must have invitation links",nameof(chat.InviteCodes)); - if(chat.Admins.Count <= 0) - throw new ArgumentException("Chat must have owner",nameof(chat.Admins)); - } - catch (Exception ex) - { - throw new InvalidObjectException(ex); - } - } - - public bool TryValidate(ChatGroup chat) - { - try - { - Validate(chat); - return true; - } - catch (Exception) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/FriendshipValidator.cs b/Govor.Core/Infrastructure/Validators/FriendshipValidator.cs deleted file mode 100644 index 96c0c40..0000000 --- a/Govor.Core/Infrastructure/Validators/FriendshipValidator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Infrastructure.Validators; - -public class FriendshipValidator : IObjectValidator -{ - public void Validate(Friendship friendship) - { - try - { - if(friendship is null) - throw new ArgumentNullException(nameof(friendship)); - if(friendship.Id == Guid.Empty) - throw new ArgumentException("Id cannot be empty", nameof(friendship.Id)); - if(friendship.AddresseeId == Guid.Empty) - throw new ArgumentException("Addresses cannot be empty", nameof(friendship.AddresseeId)); - if(friendship.RequesterId == Guid.Empty) - throw new ArgumentException("Requester cannot be empty", nameof(friendship.RequesterId)); - if(friendship.AddresseeId == friendship.RequesterId) - throw new ArgumentException("Addresses cannot be same", nameof(friendship.AddresseeId)); - } - catch (Exception e) - { - throw new InvalidObjectException(e); - } - } - - public bool TryValidate(Friendship friendship) - { - try - { - Validate(friendship); - return true; - } - catch - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/IObjectValidator.cs b/Govor.Core/Infrastructure/Validators/IObjectValidator.cs deleted file mode 100644 index f33f949..0000000 --- a/Govor.Core/Infrastructure/Validators/IObjectValidator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Govor.Core.Infrastructure.Validators; - -public interface IObjectValidator -{ - void Validate(T objectToValidate); - bool TryValidate(T objectToValidate); -} - -public class InvalidObjectException(Exception ex) : GovorCoreException($"The object {typeof(T).FullName} is invalid.", ex); \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/InvitationValidator.cs b/Govor.Core/Infrastructure/Validators/InvitationValidator.cs deleted file mode 100644 index ec8e36a..0000000 --- a/Govor.Core/Infrastructure/Validators/InvitationValidator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Infrastructure.Validators; - -public class InvitationValidator : IObjectValidator -{ - public const int MIN_INVITATION_LENGTH = 10; - public void Validate(Invitation inv) - { - try - { - if(inv is null) - throw new ArgumentNullException(nameof(inv)); - if(inv.Id == Guid.Empty) - 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 && 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)); - } - catch (Exception ex) - { - throw new InvalidObjectException(ex); - } - } - - public bool TryValidate(Invitation inv) - { - try - { - Validate(inv); - return true; - } - catch (Exception e) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/MediaAttachmentsValidator.cs b/Govor.Core/Infrastructure/Validators/MediaAttachmentsValidator.cs deleted file mode 100644 index 6a2bd1c..0000000 --- a/Govor.Core/Infrastructure/Validators/MediaAttachmentsValidator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Govor.Core.Models.Messages; -using Exception = System.Exception; - -namespace Govor.Core.Infrastructure.Validators; - -public class MediaAttachmentsValidator : IObjectValidator -{ - public void Validate(MediaAttachments attachments) - { - try - { - if (attachments is null) - throw new ArgumentNullException(nameof(attachments)); - if(attachments.Id == Guid.Empty) - throw new ArgumentException("Id cannot be empty", nameof(attachments)); - if(attachments.MessageId == Guid.Empty) - throw new ArgumentException("MessageId cannot be empty", nameof(attachments)); - if(string.IsNullOrWhiteSpace(attachments.MediaFile.Url)) - throw new ArgumentException("File path cannot be empty", nameof(attachments)); - } - catch (Exception ex) - { - throw new InvalidObjectException(ex); - } - - } - - public bool TryValidate(MediaAttachments attachments) - { - try - { - Validate(attachments); - return true; - } - catch (Exception) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/MessageValidator.cs b/Govor.Core/Infrastructure/Validators/MessageValidator.cs deleted file mode 100644 index 149ac1d..0000000 --- a/Govor.Core/Infrastructure/Validators/MessageValidator.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Infrastructure.Validators; - -public class MessageValidator : IObjectValidator -{ - public void Validate(Message message) - { - try - { - if (message is null) - throw new ArgumentNullException(nameof(message)); - if (message.Id == Guid.Empty) - throw new ArgumentException("Message ID cannot be empty", nameof(message.Id)); - if (message.SenderId == Guid.Empty) - throw new ArgumentException("Sender ID cannot be empty", nameof(message.SenderId)); - if (message.RecipientId == Guid.Empty) - throw new ArgumentException("Recipient ID cannot be empty", nameof(message.RecipientId)); - if(string.IsNullOrWhiteSpace(message.EncryptedContent) && (message.MediaAttachments is null || message.MediaAttachments.Count == 0)) - throw new ArgumentException("Encrypted content cannot be empty when media attachments are empty", nameof(message.EncryptedContent)); - if(message.IsEdited && message.EditedAt == DateTime.MinValue) - throw new ArgumentException("Edited at time cannot be empty", nameof(message.EditedAt)); - if (message.SentAt == DateTime.MinValue) - throw new ArgumentException("Sent at time cannot be empty", nameof(message.EditedAt)); - } - catch (Exception ex) - { - throw new InvalidObjectException(ex); - } - } - - public bool TryValidate(Message message) - { - try - { - Validate(message); - return true; - } - catch (Exception ex) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/PrivateChatValidator.cs b/Govor.Core/Infrastructure/Validators/PrivateChatValidator.cs deleted file mode 100644 index 184d442..0000000 --- a/Govor.Core/Infrastructure/Validators/PrivateChatValidator.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Infrastructure.Validators; - -public class PrivateChatValidator : IObjectValidator -{ - public void Validate(PrivateChat chat) - { - try - { - if(chat is null) - throw new ArgumentNullException(nameof(chat)); - if(chat.Id == Guid.Empty) - throw new ArgumentException("Id cannot be empty", nameof(chat)); - if(chat.UserAId == Guid.Empty) - throw new ArgumentException("UserAId cannot be empty", nameof(chat.UserAId)); - if(chat.UserBId == Guid.Empty) - throw new ArgumentException("UserBId cannot be empty", nameof(chat.UserBId)); - } - catch (Exception ex) - { - throw new InvalidObjectException(ex); - } - } - - public bool TryValidate(PrivateChat chat) - { - try - { - Validate(chat); - return true; - } - catch (Exception ex) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Validators/UserValidator.cs b/Govor.Core/Infrastructure/Validators/UserValidator.cs deleted file mode 100644 index b849aca..0000000 --- a/Govor.Core/Infrastructure/Validators/UserValidator.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Govor.Core.Models.Users; -using ArgumentNullException = System.ArgumentNullException; - -namespace Govor.Core.Infrastructure.Validators; - -public class UserValidator : IObjectValidator -{ - public const int MIN_LENGHT_OF_NAME = 4; - public const int MAX_LENGHT_OF_NAME = 44; - - public void Validate(User user) - { - try - { - if (user is null) - throw new ArgumentNullException(nameof(user)); - if(user.Id == Guid.Empty) - throw new ArgumentException("User ID cannot be empty", nameof(user.Id)); - if(user.Username is null - || user.Username.Length < MIN_LENGHT_OF_NAME - || user.Username.Length > MAX_LENGHT_OF_NAME) - throw new ArgumentException($"Username cannot be empty or less then {MIN_LENGHT_OF_NAME} chars or more then {MAX_LENGHT_OF_NAME}", nameof(user.Username)); - if(user.PasswordHash is null || user.PasswordHash == string.Empty) - throw new ArgumentException("Password cannot be empty", nameof(user.PasswordHash)); - if(user.CreatedOn == DateOnly.MinValue) - throw new ArgumentException("Time of creation account cannot be empty", nameof(user.CreatedOn)); - } - catch(Exception ex) - { - throw new InvalidObjectException(ex); - } - } - - public bool TryValidate(User objectToValidate) - { - try - { - Validate(objectToValidate); - return true; - } - catch (InvalidObjectException ex) - { - return false; - } - } -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Admins/IAdminsExist.cs b/Govor.Core/Repositories/Admins/IAdminsExist.cs deleted file mode 100644 index c04e928..0000000 --- a/Govor.Core/Repositories/Admins/IAdminsExist.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Admins; - -public interface IAdminsExist -{ - bool Exist(Guid guid); - bool Exist(Admin admin); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Admins/IAdminsReader.cs b/Govor.Core/Repositories/Admins/IAdminsReader.cs deleted file mode 100644 index ca550a8..0000000 --- a/Govor.Core/Repositories/Admins/IAdminsReader.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Admins; - -public interface IAdminsReader -{ - Task> GetAllAsync(); - Task GetByIdAsync(Guid id); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Admins/IAdminsRepository.cs b/Govor.Core/Repositories/Admins/IAdminsRepository.cs deleted file mode 100644 index 09e9962..0000000 --- a/Govor.Core/Repositories/Admins/IAdminsRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Admins; - -public interface IAdminsRepository : IAdminsReader, IAdminsWriter, IAdminsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Admins/IAdminsWriter.cs b/Govor.Core/Repositories/Admins/IAdminsWriter.cs deleted file mode 100644 index 60cbe2a..0000000 --- a/Govor.Core/Repositories/Admins/IAdminsWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Admins; - -public interface IAdminsWriter -{ - Task AddAsync(Admin admin); - Task UpdateAsync(Admin admin); - Task RemoveAsync(Guid admin); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Friendships/IFriendshipsExist.cs b/Govor.Core/Repositories/Friendships/IFriendshipsExist.cs deleted file mode 100644 index 5475414..0000000 --- a/Govor.Core/Repositories/Friendships/IFriendshipsExist.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Govor.Core.Repositories.Friendships; - -public interface IFriendshipsExist -{ - bool Exist(Guid requesterId, Guid addresseeId); - bool IsPossibilityOfCreatingFriendship(Guid requesterId, Guid addresseeId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Friendships/IFriendshipsReader.cs b/Govor.Core/Repositories/Friendships/IFriendshipsReader.cs deleted file mode 100644 index cee9027..0000000 --- a/Govor.Core/Repositories/Friendships/IFriendshipsReader.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Friendships; - -public interface IFriendshipsReader -{ - Task> GetAllAsync(); - Task GetByIdAsync(Guid id); - Task GetFriendshipAsync(Guid fromUserId, Guid toUserId); - Task> FindByUserIdAsync(Guid userId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Friendships/IFriendshipsRepository.cs b/Govor.Core/Repositories/Friendships/IFriendshipsRepository.cs deleted file mode 100644 index b88e805..0000000 --- a/Govor.Core/Repositories/Friendships/IFriendshipsRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Friendships; - -public interface IFriendshipsRepository : IFriendshipsReader, IFriendshipsWriter, IFriendshipsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Friendships/IFriendshipsWriter.cs b/Govor.Core/Repositories/Friendships/IFriendshipsWriter.cs deleted file mode 100644 index 2b1cfa4..0000000 --- a/Govor.Core/Repositories/Friendships/IFriendshipsWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Friendships; - -public interface IFriendshipsWriter -{ - Task AddAsync(Friendship friendship); - Task UpdateAsync(Friendship friendship); - Task RemoveAsync(Friendship friendship); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Groups/IGroupMessagesReader.cs b/Govor.Core/Repositories/Groups/IGroupMessagesReader.cs deleted file mode 100644 index d53b8ce..0000000 --- a/Govor.Core/Repositories/Groups/IGroupMessagesReader.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.Groups; - -public interface IGroupMessagesReader -{ - public Task> GetMessages(Guid chatId, Guid? startMessageId, int pageSize = 20, RecipientType type = RecipientType.User); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Groups/IGroupsExist.cs b/Govor.Core/Repositories/Groups/IGroupsExist.cs deleted file mode 100644 index f6b763f..0000000 --- a/Govor.Core/Repositories/Groups/IGroupsExist.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Groups; - -public interface IGroupsExist -{ - public bool Exist(Guid groupId); - public bool Exist(ChatGroup chatGroup); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Groups/IGroupsReader.cs b/Govor.Core/Repositories/Groups/IGroupsReader.cs deleted file mode 100644 index 26829d0..0000000 --- a/Govor.Core/Repositories/Groups/IGroupsReader.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Groups; - -public interface IGroupsReader -{ - public Task> GetAllAsync(); - public Task GetByIdAsync(Guid id); - public Task> SearchByNameAsync(string name); - public Task> GetByAdminIdAsync(Guid userId); - public Task> GetByUserIdAsync(Guid userId); - public Task IsUserMemberOfGroupAsync(Guid userId, Guid groupId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Groups/IGroupsRepository.cs b/Govor.Core/Repositories/Groups/IGroupsRepository.cs deleted file mode 100644 index 9b2faa7..0000000 --- a/Govor.Core/Repositories/Groups/IGroupsRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Groups; - -public interface IGroupsRepository : IGroupsReader, IGroupsWriter, IGroupsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Groups/IGroupsWriter.cs b/Govor.Core/Repositories/Groups/IGroupsWriter.cs deleted file mode 100644 index 4cc38f4..0000000 --- a/Govor.Core/Repositories/Groups/IGroupsWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Groups; - -public interface IGroupsWriter -{ - Task AddAsync(ChatGroup group); - Task UpdateAsync(ChatGroup group); - Task RemoveAsync(Guid groupId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Invaites/IInvitesExist.cs b/Govor.Core/Repositories/Invaites/IInvitesExist.cs deleted file mode 100644 index e763d28..0000000 --- a/Govor.Core/Repositories/Invaites/IInvitesExist.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -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/Repositories/Invaites/IInvitesReader.cs b/Govor.Core/Repositories/Invaites/IInvitesReader.cs deleted file mode 100644 index 85cb34d..0000000 --- a/Govor.Core/Repositories/Invaites/IInvitesReader.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Invaites; - -public interface IInvitesReader -{ - Task> GetAllAsync(); - Task FindByIdAsync(Guid id); - Task FindByCodeAsync(string code); - Task> FindAdminsInvitesAsync(); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Invaites/IInvitesRepository.cs b/Govor.Core/Repositories/Invaites/IInvitesRepository.cs deleted file mode 100644 index 832517c..0000000 --- a/Govor.Core/Repositories/Invaites/IInvitesRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Invaites; - -public interface IInvitesRepository : IInvitesReader, IInvitesWriter, IInvitesExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Invaites/IInvitesWriter.cs b/Govor.Core/Repositories/Invaites/IInvitesWriter.cs deleted file mode 100644 index b8f7487..0000000 --- a/Govor.Core/Repositories/Invaites/IInvitesWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.Invaites; - -public interface IInvitesWriter -{ - Task AddAsync(Invitation invitation); - Task UpdateAsync(Invitation invitation); - Task RemoveAsync(Invitation invitation); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsExist.cs b/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsExist.cs deleted file mode 100644 index 89ab2d7..0000000 --- a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsExist.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.MediasAttachments; - -public interface IMediaAttachmentsExist -{ - bool Exist(Guid id); - bool Exist(MediaAttachments attachments); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsReader.cs b/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsReader.cs deleted file mode 100644 index cb54728..0000000 --- a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsReader.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.MediasAttachments; - -public interface IMediaAttachmentsReader -{ - Task> GetAllAsync(); - Task FindByIdAsync(Guid id); - Task> GetAllByMessageId(Guid messageId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsRepository.cs b/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsRepository.cs deleted file mode 100644 index 457e84d..0000000 --- a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.MediasAttachments; - -public interface IMediaAttachmentsRepository : IMediaAttachmentsReader, IMediaAttachmentsWriter, IMediaAttachmentsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsWriter.cs b/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsWriter.cs deleted file mode 100644 index 5754a3f..0000000 --- a/Govor.Core/Repositories/MediasAttachments/IMediaAttachmentsWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.MediasAttachments; - -public interface IMediaAttachmentsWriter -{ - Task AddAsync(MediaAttachments mediaAttachments); - Task UpdateAsync(MediaAttachments attachments); - Task RemoveAsync(Guid Id); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Messages/IMessagesExist.cs b/Govor.Core/Repositories/Messages/IMessagesExist.cs deleted file mode 100644 index 6d6deb6..0000000 --- a/Govor.Core/Repositories/Messages/IMessagesExist.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.Messages; - -public interface IMessagesExist -{ - bool Exist(Guid messageId); - bool Exist(Message message); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Messages/IMessagesReader.cs b/Govor.Core/Repositories/Messages/IMessagesReader.cs deleted file mode 100644 index 5ca6afc..0000000 --- a/Govor.Core/Repositories/Messages/IMessagesReader.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.Messages; - -public interface IMessagesReader -{ - Task> GetAllAsync(); - Task FindByIdAsync(Guid messageId); - Task> FindBySenderIdAsync(Guid senderId); - Task> FindByReceiverIdAsync(Guid receiverId); - Task> FindBySenderAndReceiverIdAsync(Guid senderId, Guid receiverId, RecipientType recipientType = RecipientType.User); - Task> FindBySentAtAsync(DateTime date); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Messages/IMessagesRepository.cs b/Govor.Core/Repositories/Messages/IMessagesRepository.cs deleted file mode 100644 index 86867e9..0000000 --- a/Govor.Core/Repositories/Messages/IMessagesRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Messages; - -public interface IMessagesRepository : IMessagesReader, IMessagesWriter, IMessagesExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Messages/IMessagesWriter.cs b/Govor.Core/Repositories/Messages/IMessagesWriter.cs deleted file mode 100644 index f9f7b81..0000000 --- a/Govor.Core/Repositories/Messages/IMessagesWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Messages; - -namespace Govor.Core.Repositories.Messages; - -public interface IMessagesWriter -{ - Task AddAsync(Message message); - Task UpdateAsync(Message message); - Task RemoveAsync(Guid messageId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PrivateChats/IPrivateChatsExist.cs b/Govor.Core/Repositories/PrivateChats/IPrivateChatsExist.cs deleted file mode 100644 index af72f01..0000000 --- a/Govor.Core/Repositories/PrivateChats/IPrivateChatsExist.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Govor.Core.Repositories.PrivateChats; - -public interface IPrivateChatsExist -{ - bool Exist(Guid chatId); - bool Exist(Guid userAId, Guid userBId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PrivateChats/IPrivateChatsReader.cs b/Govor.Core/Repositories/PrivateChats/IPrivateChatsReader.cs deleted file mode 100644 index 0327dad..0000000 --- a/Govor.Core/Repositories/PrivateChats/IPrivateChatsReader.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.PrivateChats; - -public interface IPrivateChatsReader -{ - Task> GetAllAsync(); - Task GetByIdAsync(Guid id); - Task GetByMembersAsync(Guid memberAId, Guid memberBId); - Task> GetAllOfUser(Guid userId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PrivateChats/IPrivateChatsRepository.cs b/Govor.Core/Repositories/PrivateChats/IPrivateChatsRepository.cs deleted file mode 100644 index 7a9829c..0000000 --- a/Govor.Core/Repositories/PrivateChats/IPrivateChatsRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Govor.Core.Repositories.Groups; - -namespace Govor.Core.Repositories.PrivateChats; - -public interface IPrivateChatsRepository : IPrivateChatsReader, IPrivateChatsWriter, IPrivateChatsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PrivateChats/IPrivateChatsWriter.cs b/Govor.Core/Repositories/PrivateChats/IPrivateChatsWriter.cs deleted file mode 100644 index d2afa33..0000000 --- a/Govor.Core/Repositories/PrivateChats/IPrivateChatsWriter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.PrivateChats; - -public interface IPrivateChatsWriter -{ - Task AddAsync(PrivateChat chat); - Task UpdateAsync(PrivateChat chat); - Task RemoveAsync(Guid chatId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PushTokens/IPushTokenReader.cs b/Govor.Core/Repositories/PushTokens/IPushTokenReader.cs deleted file mode 100644 index 17ee1f2..0000000 --- a/Govor.Core/Repositories/PushTokens/IPushTokenReader.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Govor.Core.Repositories.PushTokens; - -public interface IPushTokenReader -{ - Task> GetActiveTokensAsync(Guid userId); - - Task> GetActiveTokensUsersAsync(IEnumerable userIds); - - Task GetActiveTokenBySessionAsync(Guid sessionId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PushTokens/IPushTokenRepository.cs b/Govor.Core/Repositories/PushTokens/IPushTokenRepository.cs deleted file mode 100644 index 9f2a841..0000000 --- a/Govor.Core/Repositories/PushTokens/IPushTokenRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.PushTokens; - -public interface IPushTokenRepository : IPushTokenReader, IPushTokenWriter -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/PushTokens/IPushTokenWriter.cs b/Govor.Core/Repositories/PushTokens/IPushTokenWriter.cs deleted file mode 100644 index 6847af9..0000000 --- a/Govor.Core/Repositories/PushTokens/IPushTokenWriter.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Govor.Core.Repositories.PushTokens; - -public interface IPushTokenWriter -{ - Task AddOrUpdateTokenAsync(Guid userId, Guid? sessionId, string token, - string platform, string provider = "FCM"); - - Task RemoveTokensAsync(IEnumerable tokens); - - Task DeactivateTokenBySessionAsync(Guid sessionId); // logout -} \ No newline at end of file diff --git a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsExist.cs b/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsExist.cs deleted file mode 100644 index 1655ee5..0000000 --- a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsExist.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.UserSessionsRepository; - -public interface IUserSessionsExist -{ - public bool Exist(Guid sessionId); - public bool Exist(string hashedToken); - public bool Exist(UserSession userSession); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsReader.cs b/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsReader.cs deleted file mode 100644 index 851569c..0000000 --- a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsReader.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.UserSessionsRepository; - -public interface IUserSessionsReader -{ - public Task> GetAllAsync(); - public Task GetByIdAsync(Guid sessionId); - public Task> GetByUserIdAsync(Guid userId); - public Task> GetByCreatedAtAsync(DateTime createdAt); - public Task> GetByExpiresAtAsync(DateTime createdAt); - public Task> GetByRevokedAsync(bool isRevoked); - public Task GetByHashedRefreshTokenAsync(string hash); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsRepository.cs b/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsRepository.cs deleted file mode 100644 index 35061b7..0000000 --- a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Govor.Core.Models; - -namespace Govor.Core.Repositories.UserSessionsRepository; - -public interface IUserSessionsRepository : IUserSessionsReader, IUserSessionsWriter, IUserSessionsExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsWriter.cs b/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsWriter.cs deleted file mode 100644 index 4f7eeac..0000000 --- a/Govor.Core/Repositories/UserSessionsRepository/IUserSessionsWriter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Govor.Core.Models; -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.UserSessionsRepository; - -public interface IUserSessionsWriter -{ - Task AddAsync(UserSession userSession); - Task UpdateAsync(UserSession userSession); - Task RemoveAsync(Guid sessionId); - Task RemoveByUserIdAsync(Guid userId); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Users/IUsersExist.cs b/Govor.Core/Repositories/Users/IUsersExist.cs deleted file mode 100644 index a06a180..0000000 --- a/Govor.Core/Repositories/Users/IUsersExist.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Users; - -public interface IUsersExist -{ - public Task ExistsAsync(User user); - public Task ExistsByIdAsync(Guid id); - public Task ExistsUsernameAsync(string username); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Users/IUsersReader.cs b/Govor.Core/Repositories/Users/IUsersReader.cs deleted file mode 100644 index 53c4a32..0000000 --- a/Govor.Core/Repositories/Users/IUsersReader.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Users; - -public interface IUsersReader -{ - public Task> GetAllAsync(); - public Task FindByIdAsync(Guid id); - public Task> FindByRangeIdAsync(IEnumerable ids); - public Task FindByUsernameAsync(string username); - public Task> FindByRangeUsernamesAsync(IEnumerable usernames); - public Task> SearchPotentialFriendsAsync(Guid currentUserId, string query); - public Task> FindUsersByCreatedDateAsync(DateOnly createdDate); -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Users/IUsersRepository.cs b/Govor.Core/Repositories/Users/IUsersRepository.cs deleted file mode 100644 index 8609807..0000000 --- a/Govor.Core/Repositories/Users/IUsersRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Govor.Core.Repositories.Users; - -public interface IUsersRepository : IUsersReader, IUsersWriter, IUsersExist -{ - -} \ No newline at end of file diff --git a/Govor.Core/Repositories/Users/IUsersWriter.cs b/Govor.Core/Repositories/Users/IUsersWriter.cs deleted file mode 100644 index d05c8cf..0000000 --- a/Govor.Core/Repositories/Users/IUsersWriter.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Govor.Core.Models.Users; - -namespace Govor.Core.Repositories.Users; - -public interface IUsersWriter -{ - public Task AddAsync(User user); - public Task UpdateAsync(User user); - public Task RemoveAsync(User user); - public Task RemoveAsync(Guid userId); -} \ No newline at end of file diff --git a/Govor.Data.Tests/Govor.Data.Tests.csproj b/Govor.Data.Tests/Govor.Data.Tests.csproj index 8ad7ddc..c7e42eb 100644 --- a/Govor.Data.Tests/Govor.Data.Tests.csproj +++ b/Govor.Data.Tests/Govor.Data.Tests.csproj @@ -23,8 +23,4 @@ - - - - diff --git a/Govor.Data.Tests/Repositories/AdminsRepositoryTests.cs b/Govor.Data.Tests/Repositories/AdminsRepositoryTests.cs index 5e95ea6..1730862 100644 --- a/Govor.Data.Tests/Repositories/AdminsRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/AdminsRepositoryTests.cs @@ -1,13 +1,13 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class AdminsRepositoryTests diff --git a/Govor.Data.Tests/Repositories/FriendshipsRepositoryTests.cs b/Govor.Data.Tests/Repositories/FriendshipsRepositoryTests.cs index 8b0a905..d7d00f8 100644 --- a/Govor.Data.Tests/Repositories/FriendshipsRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/FriendshipsRepositoryTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class FriendshipsRepositoryTests diff --git a/Govor.Data.Tests/Repositories/GroupRepositoryTests.cs b/Govor.Data.Tests/Repositories/GroupRepositoryTests.cs index 35fb5d3..46def33 100644 --- a/Govor.Data.Tests/Repositories/GroupRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/GroupRepositoryTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class GroupRepositoryTests diff --git a/Govor.Data.Tests/Repositories/InvitesRepositoryTests.cs b/Govor.Data.Tests/Repositories/InvitesRepositoryTests.cs index 413d23f..9ef01af 100644 --- a/Govor.Data.Tests/Repositories/InvitesRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/InvitesRepositoryTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class InvitesRepositoryTests diff --git a/Govor.Data.Tests/Repositories/MediaAttachmentsTests.cs b/Govor.Data.Tests/Repositories/MediaAttachmentsTests.cs index 232b62c..c99629e 100644 --- a/Govor.Data.Tests/Repositories/MediaAttachmentsTests.cs +++ b/Govor.Data.Tests/Repositories/MediaAttachmentsTests.cs @@ -1,13 +1,13 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class MediaAttachmentsTests diff --git a/Govor.Data.Tests/Repositories/MessagesRepositoryTests.cs b/Govor.Data.Tests/Repositories/MessagesRepositoryTests.cs index 7c4a144..8b0c0fe 100644 --- a/Govor.Data.Tests/Repositories/MessagesRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/MessagesRepositoryTests.cs @@ -1,13 +1,13 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class MessagesRepositoryTests diff --git a/Govor.Data.Tests/Repositories/PrivateChatsRepositoryTests.cs b/Govor.Data.Tests/Repositories/PrivateChatsRepositoryTests.cs index 15d6b07..657232d 100644 --- a/Govor.Data.Tests/Repositories/PrivateChatsRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/PrivateChatsRepositoryTests.cs @@ -1,12 +1,12 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class PrivateChatsRepositoryTests diff --git a/Govor.Data.Tests/Repositories/PushTokenRepository.cs b/Govor.Data.Tests/Repositories/PushTokenRepository.cs index 258f092..e590b7b 100644 --- a/Govor.Data.Tests/Repositories/PushTokenRepository.cs +++ b/Govor.Data.Tests/Repositories/PushTokenRepository.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users; -using Govor.Data.Repositories; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class PushTokenRepositoryTests diff --git a/Govor.Data.Tests/Repositories/UserSessionsRepositoryTests.cs b/Govor.Data.Tests/Repositories/UserSessionsRepositoryTests.cs index 234e21b..4006783 100644 --- a/Govor.Data.Tests/Repositories/UserSessionsRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/UserSessionsRepositoryTests.cs @@ -1,11 +1,11 @@ using AutoFixture; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class UserSessionsRepositoryTests diff --git a/Govor.Data.Tests/Repositories/UsersRepositoryTests.cs b/Govor.Data.Tests/Repositories/UsersRepositoryTests.cs index 8a37d46..65d0910 100644 --- a/Govor.Data.Tests/Repositories/UsersRepositoryTests.cs +++ b/Govor.Data.Tests/Repositories/UsersRepositoryTests.cs @@ -1,13 +1,13 @@ using AutoFixture; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Data; -using Govor.Data.Repositories; -using Govor.Data.Repositories.Exceptions; +using Govor.Domain.Infrastructure.Validators; +using Govor.Domain.Models; +using Govor.Domain.Models.Users; +using Govor.Domain; +using Govor.Domain.Repositories; +using Govor.Domain.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; -namespace Govor.Data.Tests.Repositories; +namespace Govor.Domain.Tests.Repositories; [TestFixture] public class UsersRepositoryTests diff --git a/Govor.Data/Migrations/20260301080331_Init.Designer.cs b/Govor.Data/Migrations/20260301080331_Init.Designer.cs deleted file mode 100644 index ec91fae..0000000 --- a/Govor.Data/Migrations/20260301080331_Init.Designer.cs +++ /dev/null @@ -1,848 +0,0 @@ -// -using System; -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("20260301080331_Init")] - partial class Init - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("ImageId") - .HasColumnType("uuid"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.Friendship", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AddresseeId") - .HasColumnType("uuid"); - - b.Property("RequesterId") - .HasColumnType("uuid"); - - b.Property("Status") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("AddresseeId"); - - b.HasIndex("Id") - .IsUnique(); - - b.HasIndex("RequesterId"); - - b.ToTable("Friendships"); - }); - - 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.HasIndex("GroupId"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("InvitationCode") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("MaxParticipants") - .HasColumnType("integer"); - - b.Property("UserMakerId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("UserMakerId"); - - b.ToTable("GroupInvitations"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("InvitationId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("MemberSince") - .HasColumnType("timestamp with time zone"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("InvitationId"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Property("Id") - .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"); - - b.Property("MaxParticipants") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("Invitations"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaFile", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("MediaType") - .IsRequired() - .HasColumnType("text"); - - b.Property("MineType") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("OwnerId") - .HasColumnType("uuid"); - - b.Property("OwnerType") - .HasColumnType("integer"); - - b.Property("UploaderId") - .HasColumnType("uuid"); - - b.Property("Url") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("MediaFiles"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MediaFileId") - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("MediaFileId"); - - b.HasIndex("MessageId"); - - b.ToTable("MediaAttachments"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ChatGroupId") - .HasColumnType("uuid"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedContent") - .IsRequired() - .HasColumnType("text"); - - b.Property("IsEdited") - .HasColumnType("boolean"); - - b.Property("PrivateChatId") - .HasColumnType("uuid"); - - 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("ChatGroupId"); - - b.HasIndex("Id") - .IsUnique(); - - b.HasIndex("PrivateChatId"); - - b.HasIndex("RecipientId") - .IsUnique(); - - b.ToTable("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.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.Messages.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.PrivateChat", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("UserAId") - .HasColumnType("uuid"); - - b.Property("UserBId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.ToTable("PrivateChats"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => - { - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("UserId"); - - b.ToTable("Admins"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("IsUsed") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false); - - b.Property("PublicKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UserCryptoSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UploadedAt"); - - b.HasIndex("UserCryptoSessionId", "IsUsed"); - - b.ToTable("OneTimePreKeys"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("PublicSignedPreKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("SignedPreKeySignature") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UserCryptoSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserCryptoSessionId") - .IsUnique(); - - b.ToTable("SignedPreKeys"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("PublicIdentityKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UserSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserSessionId") - .IsUnique(); - - b.ToTable("UserCryptoSessions"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("InviteId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatedOn"); - - b.HasIndex("InviteId"); - - b.HasIndex("Username") - .IsUnique(); - - b.HasIndex("WasOnline"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserPushToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("LastUsedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Platform") - .IsRequired() - .HasColumnType("text"); - - b.Property("Provider") - .IsRequired() - .HasColumnType("text"); - - b.Property("Token") - .IsRequired() - .HasColumnType("text"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("UserSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId") - .IsUnique(); - - b.HasIndex("UserSessionId") - .IsUnique(); - - b.HasIndex("UserId", "IsActive"); - - b.ToTable("UserPushTokens"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeviceInfo") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("RefreshTokenHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.HasIndex("RefreshTokenHash") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("UserSessions"); - }); - - modelBuilder.Entity("Govor.Core.Models.Friendship", b => - { - b.HasOne("Govor.Core.Models.Users.User", "Addressee") - .WithMany("ReceivedFriendRequests") - .HasForeignKey("AddresseeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "Requester") - .WithMany("SentFriendRequests") - .HasForeignKey("RequesterId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Addressee"); - - b.Navigation("Requester"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Admins") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("InviteCodes") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "UserMaker") - .WithMany() - .HasForeignKey("UserMakerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("UserMaker"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Members") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.GroupInvitation", null) - .WithMany() - .HasForeignKey("InvitationId") - .OnDelete(DeleteBehavior.SetNull); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => - { - b.HasOne("Govor.Core.Models.MediaFile", "MediaFile") - .WithMany() - .HasForeignKey("MediaFileId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Messages.Message", "Message") - .WithMany("MediaAttachments") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MediaFile"); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Messages") - .HasForeignKey("ChatGroupId"); - - b.HasOne("Govor.Core.Models.PrivateChat", null) - .WithMany("Messages") - .HasForeignKey("PrivateChatId"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => - { - b.HasOne("Govor.Core.Models.Messages.Message", "Message") - .WithMany("Reactions") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => - { - b.HasOne("Govor.Core.Models.Messages.Message", null) - .WithMany("MessageViews") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => - { - b.HasOne("Govor.Core.Models.Users.User", "User") - .WithOne() - .HasForeignKey("Govor.Core.Models.Users.Admin", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => - { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") - .WithMany("OneTimePreKeys") - .HasForeignKey("UserCryptoSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserCryptoSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => - { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") - .WithOne("SignedPreKey") - .HasForeignKey("Govor.Core.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserCryptoSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.HasOne("Govor.Core.Models.Users.UserSession", "UserSession") - .WithOne("CryptoSession") - .HasForeignKey("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.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.Users.UserSession", b => - { - b.HasOne("Govor.Core.Models.Users.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Navigation("Admins"); - - b.Navigation("InviteCodes"); - - b.Navigation("Members"); - - b.Navigation("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Navigation("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.Navigation("MediaAttachments"); - - b.Navigation("MessageViews"); - - b.Navigation("Reactions"); - }); - - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => - { - b.Navigation("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.Navigation("OneTimePreKeys"); - - b.Navigation("SignedPreKey") - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.User", b => - { - b.Navigation("ReceivedFriendRequests"); - - b.Navigation("SentFriendRequests"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => - { - b.Navigation("CryptoSession") - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20260301091506_FixRecipientIndex.Designer.cs b/Govor.Data/Migrations/20260301091506_FixRecipientIndex.Designer.cs deleted file mode 100644 index 9327098..0000000 --- a/Govor.Data/Migrations/20260301091506_FixRecipientIndex.Designer.cs +++ /dev/null @@ -1,838 +0,0 @@ -// -using System; -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("20260301091506_FixRecipientIndex")] - partial class FixRecipientIndex - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.6") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("ImageId") - .HasColumnType("uuid"); - - b.Property("IsChannel") - .HasColumnType("boolean"); - - b.Property("IsPrivate") - .HasColumnType("boolean"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("ChatGroups"); - }); - - modelBuilder.Entity("Govor.Core.Models.Friendship", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AddresseeId") - .HasColumnType("uuid"); - - b.Property("RequesterId") - .HasColumnType("uuid"); - - b.Property("Status") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("AddresseeId"); - - b.HasIndex("RequesterId"); - - b.ToTable("Friendships"); - }); - - 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.HasIndex("GroupId"); - - b.ToTable("GroupAdmins"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("InvitationCode") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("MaxParticipants") - .HasColumnType("integer"); - - b.Property("UserMakerId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("UserMakerId"); - - b.ToTable("GroupInvitations"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("GroupId") - .HasColumnType("uuid"); - - b.Property("InvitationId") - .HasColumnType("uuid"); - - b.Property("IsBanned") - .HasColumnType("boolean"); - - b.Property("MemberSince") - .HasColumnType("timestamp with time zone"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("GroupId"); - - b.HasIndex("InvitationId"); - - b.ToTable("GroupMemberships"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Property("Id") - .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"); - - b.Property("MaxParticipants") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("Invitations"); - }); - - modelBuilder.Entity("Govor.Core.Models.MediaFile", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("MediaType") - .IsRequired() - .HasColumnType("text"); - - b.Property("MineType") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("OwnerId") - .HasColumnType("uuid"); - - b.Property("OwnerType") - .HasColumnType("integer"); - - b.Property("UploaderId") - .HasColumnType("uuid"); - - b.Property("Url") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("MediaFiles"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("MediaFileId") - .HasColumnType("uuid"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("MediaFileId"); - - b.HasIndex("MessageId"); - - b.ToTable("MediaAttachments"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ChatGroupId") - .HasColumnType("uuid"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedContent") - .IsRequired() - .HasColumnType("text"); - - b.Property("IsEdited") - .HasColumnType("boolean"); - - b.Property("PrivateChatId") - .HasColumnType("uuid"); - - 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("ChatGroupId"); - - b.HasIndex("PrivateChatId"); - - b.HasIndex("RecipientId"); - - b.ToTable("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.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.Messages.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.PrivateChat", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("UserAId") - .HasColumnType("uuid"); - - b.Property("UserBId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.ToTable("PrivateChats"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => - { - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("UserId"); - - b.ToTable("Admins"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("IsUsed") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false); - - b.Property("PublicKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UserCryptoSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UploadedAt"); - - b.HasIndex("UserCryptoSessionId", "IsUsed"); - - b.ToTable("OneTimePreKeys"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("PublicSignedPreKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("SignedPreKeySignature") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UserCryptoSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserCryptoSessionId") - .IsUnique(); - - b.ToTable("SignedPreKeys"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("PublicIdentityKey") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("UserSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserSessionId") - .IsUnique(); - - b.ToTable("UserCryptoSessions"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedOn") - .HasColumnType("date"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("IconId") - .HasColumnType("uuid"); - - b.Property("InviteId") - .HasColumnType("uuid"); - - b.Property("PasswordHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Username") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("WasOnline") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatedOn"); - - b.HasIndex("InviteId"); - - b.HasIndex("Username") - .IsUnique(); - - b.HasIndex("WasOnline"); - - b.ToTable("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserPushToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("LastUsedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Platform") - .IsRequired() - .HasColumnType("text"); - - b.Property("Provider") - .IsRequired() - .HasColumnType("text"); - - b.Property("Token") - .IsRequired() - .HasColumnType("text"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("UserSessionId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Token") - .IsUnique(); - - b.HasIndex("UserId") - .IsUnique(); - - b.HasIndex("UserSessionId") - .IsUnique(); - - b.HasIndex("UserId", "IsActive"); - - b.ToTable("UserPushTokens"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeviceInfo") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsRevoked") - .HasColumnType("boolean"); - - b.Property("RefreshTokenHash") - .IsRequired() - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.HasIndex("RefreshTokenHash") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("UserSessions"); - }); - - modelBuilder.Entity("Govor.Core.Models.Friendship", b => - { - b.HasOne("Govor.Core.Models.Users.User", "Addressee") - .WithMany("ReceivedFriendRequests") - .HasForeignKey("AddresseeId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "Requester") - .WithMany("SentFriendRequests") - .HasForeignKey("RequesterId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Addressee"); - - b.Navigation("Requester"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Admins") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("InviteCodes") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "UserMaker") - .WithMany() - .HasForeignKey("UserMakerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("UserMaker"); - }); - - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Members") - .HasForeignKey("GroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.GroupInvitation", null) - .WithMany() - .HasForeignKey("InvitationId") - .OnDelete(DeleteBehavior.SetNull); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => - { - b.HasOne("Govor.Core.Models.MediaFile", "MediaFile") - .WithMany() - .HasForeignKey("MediaFileId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Messages.Message", "Message") - .WithMany("MediaAttachments") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MediaFile"); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.HasOne("Govor.Core.Models.ChatGroup", null) - .WithMany("Messages") - .HasForeignKey("ChatGroupId"); - - b.HasOne("Govor.Core.Models.PrivateChat", null) - .WithMany("Messages") - .HasForeignKey("PrivateChatId"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => - { - b.HasOne("Govor.Core.Models.Messages.Message", "Message") - .WithMany("Reactions") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Govor.Core.Models.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => - { - b.HasOne("Govor.Core.Models.Messages.Message", null) - .WithMany("MessageViews") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => - { - b.HasOne("Govor.Core.Models.Users.User", "User") - .WithOne() - .HasForeignKey("Govor.Core.Models.Users.Admin", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => - { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") - .WithMany("OneTimePreKeys") - .HasForeignKey("UserCryptoSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserCryptoSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => - { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") - .WithOne("SignedPreKey") - .HasForeignKey("Govor.Core.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserCryptoSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.HasOne("Govor.Core.Models.Users.UserSession", "UserSession") - .WithOne("CryptoSession") - .HasForeignKey("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserSessionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("UserSession"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.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.Users.UserSession", b => - { - b.HasOne("Govor.Core.Models.Users.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => - { - b.Navigation("Admins"); - - b.Navigation("InviteCodes"); - - b.Navigation("Members"); - - b.Navigation("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Invitation", b => - { - b.Navigation("Users"); - }); - - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => - { - b.Navigation("MediaAttachments"); - - b.Navigation("MessageViews"); - - b.Navigation("Reactions"); - }); - - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => - { - b.Navigation("Messages"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => - { - b.Navigation("OneTimePreKeys"); - - b.Navigation("SignedPreKey") - .IsRequired(); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.User", b => - { - b.Navigation("ReceivedFriendRequests"); - - b.Navigation("SentFriendRequests"); - }); - - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => - { - b.Navigation("CryptoSession") - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Govor.Data/Migrations/20260301091506_FixRecipientIndex.cs b/Govor.Data/Migrations/20260301091506_FixRecipientIndex.cs deleted file mode 100644 index 5e43c86..0000000 --- a/Govor.Data/Migrations/20260301091506_FixRecipientIndex.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class FixRecipientIndex : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_PrivateChats_Id", - table: "PrivateChats"); - - migrationBuilder.DropIndex( - name: "IX_Messages_Id", - table: "Messages"); - - migrationBuilder.DropIndex( - name: "IX_Messages_RecipientId", - table: "Messages"); - - migrationBuilder.DropIndex( - name: "IX_Friendships_Id", - table: "Friendships"); - - migrationBuilder.CreateIndex( - name: "IX_Messages_RecipientId", - table: "Messages", - column: "RecipientId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_Messages_RecipientId", - table: "Messages"); - - migrationBuilder.CreateIndex( - name: "IX_PrivateChats_Id", - table: "PrivateChats", - column: "Id", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Messages_Id", - table: "Messages", - column: "Id", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Messages_RecipientId", - table: "Messages", - column: "RecipientId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Friendships_Id", - table: "Friendships", - column: "Id", - unique: true); - } - } -} diff --git a/Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.cs b/Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.cs deleted file mode 100644 index d57185e..0000000 --- a/Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Govor.Data.Migrations -{ - /// - public partial class FixPushTokensIndexs : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_UserPushTokens_UserId", - table: "UserPushTokens"); - - migrationBuilder.AlterColumn( - name: "Token", - table: "UserPushTokens", - type: "character varying(512)", - maxLength: 512, - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AlterColumn( - name: "Provider", - table: "UserPushTokens", - type: "character varying(50)", - maxLength: 50, - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AlterColumn( - name: "Platform", - table: "UserPushTokens", - type: "character varying(50)", - maxLength: 50, - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Token", - table: "UserPushTokens", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(512)", - oldMaxLength: 512); - - migrationBuilder.AlterColumn( - name: "Provider", - table: "UserPushTokens", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(50)", - oldMaxLength: 50); - - migrationBuilder.AlterColumn( - name: "Platform", - table: "UserPushTokens", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(50)", - oldMaxLength: 50); - - migrationBuilder.CreateIndex( - name: "IX_UserPushTokens_UserId", - table: "UserPushTokens", - column: "UserId", - unique: true); - } - } -} diff --git a/Govor.Data/Repositories/AdminsRepository.cs b/Govor.Data/Repositories/AdminsRepository.cs deleted file mode 100644 index 8e569bc..0000000 --- a/Govor.Data/Repositories/AdminsRepository.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Admins; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class AdminsRepository(GovorDbContext context, IObjectValidator validator) : IAdminsRepository -{ - private GovorDbContext _context = context; - private IObjectValidator _validator = validator; - public async Task> GetAllAsync() - { - return await _context.Admins - .AsNoTracking() - .Include(a => a.User) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task GetByIdAsync(Guid id) - { - return await _context.Admins - .AsNoTracking() - .Include(a => a.User) - .AsSplitQuery() - .FirstOrDefaultAsync(u => u.UserId == id) - ?? throw new NotFoundByKeyException(id, "User with given id does not exist"); - } - - public async Task AddAsync(Admin admin) - { - try - { - _validator.Validate(admin); - - _context.Admins.Add(admin); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Admin with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add admin", ex); - } - } - - public async Task UpdateAsync(Admin admin) - { - try - { - _validator.Validate(admin); - - var rowsAffected = await _context.Admins - .Where(a => a.UserId == admin.UserId) - .ExecuteUpdateAsync(u => u - .SetProperty(a => a.UserId, admin.UserId) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found admin by given id {admin.UserId}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the admin {admin.UserId}", ex); - } - } - - public async Task RemoveAsync(Guid admin) - { - try - { - var result = await GetByIdAsync(admin); - - _context.Admins.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found admin by given id {admin}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the admin", ex); - } - } - - public bool Exist(Guid id) - { - return _context.Users.Any(u => u.Id == id); - } - - public bool Exist(Admin admin) - { - _validator.Validate(admin); - - return _context.Admins.Any(u => - u.UserId == admin.UserId - ); - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/Exceptions/AdditionException.cs b/Govor.Data/Repositories/Exceptions/AdditionException.cs deleted file mode 100644 index 46fa961..0000000 --- a/Govor.Data/Repositories/Exceptions/AdditionException.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Govor.Data.Repositories.Exceptions; - -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/Exceptions/NotFoundByKeyException.cs b/Govor.Data/Repositories/Exceptions/NotFoundByKeyException.cs deleted file mode 100644 index 08f6c8b..0000000 --- a/Govor.Data/Repositories/Exceptions/NotFoundByKeyException.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Govor.Data.Repositories.Exceptions; - -public class NotFoundByKeyException : NotFoundException -{ - public NotFoundByKeyException(T key) - : base($"Not found object by {key}"){} - - public NotFoundByKeyException(T id, string message) - : base($"Not found object by {id}. Message: " + message) {} - - public NotFoundByKeyException(string message, Exception innerException) : base(message, innerException) - { - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/Exceptions/NotFoundException.cs b/Govor.Data/Repositories/Exceptions/NotFoundException.cs deleted file mode 100644 index dc60ca5..0000000 --- a/Govor.Data/Repositories/Exceptions/NotFoundException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Govor.Core; - -namespace Govor.Data.Repositories.Exceptions; - -public class NotFoundException : GovorCoreException -{ - public NotFoundException(string message) - : base(message) {} - public NotFoundException(string message, Exception innerException) - : base(message, innerException){} -} \ No newline at end of file diff --git a/Govor.Data/Repositories/Exceptions/RemoveException.cs b/Govor.Data/Repositories/Exceptions/RemoveException.cs deleted file mode 100644 index 7fbb765..0000000 --- a/Govor.Data/Repositories/Exceptions/RemoveException.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Govor.Data.Repositories.Exceptions; - -public class RemoveException(string s, Exception exception) - : Exception(s, exception); \ No newline at end of file diff --git a/Govor.Data/Repositories/Exceptions/UpdateException.cs b/Govor.Data/Repositories/Exceptions/UpdateException.cs deleted file mode 100644 index a44e54c..0000000 --- a/Govor.Data/Repositories/Exceptions/UpdateException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Govor.Core; - -namespace Govor.Data.Repositories.Exceptions; - -public class UpdateException : GovorCoreException -{ - public UpdateException(string s) - : base(s) { } - - public UpdateException(string s, Exception ex) - : base(s, ex) { } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/FriendshipsRepository.cs b/Govor.Data/Repositories/FriendshipsRepository.cs deleted file mode 100644 index 128ed14..0000000 --- a/Govor.Data/Repositories/FriendshipsRepository.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Friendships; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class FriendshipsRepository : IFriendshipsRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - - public FriendshipsRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.Friendships - .AsNoTracking() - .Include(x => x.Requester) - .Include(x => x.Addressee) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task GetByIdAsync(Guid id) - { - return await _context.Friendships - .AsNoTracking() - .Include(x => x.Requester) - .Include(x => x.Addressee) - .AsSplitQuery() - .FirstOrDefaultAsync(x => x.Id == id) - ?? throw new NotFoundByKeyException(id, "Friendship with given id was not found"); - } - - public async Task GetFriendshipAsync(Guid fromUserId, Guid toUserId) - { - return await _context.Friendships - .FirstOrDefaultAsync(x => - (x.RequesterId == fromUserId && x.AddresseeId == toUserId) || - (x.RequesterId == toUserId && x.AddresseeId == fromUserId)); - } - - public async Task> FindByUserIdAsync(Guid userId) - { - return await _context.Friendships - .AsNoTracking() - .Include(x => x.Requester) - .Include(x => x.Addressee) - .AsSplitQuery() - .Where(f => - (f.RequesterId == userId || f.AddresseeId == userId)) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(userId, "Friendship with given user id was not found")); - } - - public async Task AddAsync(Friendship friendship) - { - try - { - _validator.Validate(friendship); - - _context.Friendships.Add(friendship); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Admin with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add admin", ex); - } - } - - public async Task UpdateAsync(Friendship friendship) - { - try - { - _validator.Validate(friendship); - - var rowsAffected = await _context.Friendships - .Where(a => a.Id == friendship.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(a => a.RequesterId, friendship.RequesterId) - .SetProperty(a => a.AddresseeId, friendship.AddresseeId) - .SetProperty(a => a.Status, friendship.Status) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found friendship by given id {friendship.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the friendship {friendship.Id}", ex); - } - } - - public async Task RemoveAsync(Friendship friendship) - { - try - { - var result = await GetByIdAsync(friendship.Id); - - _context.Friendships.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found friendship by given id {friendship.Id}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the friendship", ex); - } - } - - public bool Exist(Guid requesterId, Guid addresseeId) - { - return _context.Friendships.AsNoTracking().Any(x => (x.RequesterId == requesterId && x.AddresseeId == addresseeId) || - x.RequesterId == addresseeId && x.AddresseeId == requesterId); - } - - public bool IsPossibilityOfCreatingFriendship(Guid requesterId, Guid addresseeId) - { - // Ищем любую существующую связь между пользователями - var existingFriendship = _context.Friendships - .AsNoTracking() - .FirstOrDefault(x => - (x.RequesterId == requesterId && x.AddresseeId == addresseeId) || - (x.RequesterId == addresseeId && x.AddresseeId == requesterId)); - - // Если записи нет — создавать можно - if (existingFriendship == null) return true; - - // Если запись есть, создавать новую НЕЛЬЗЯ (нужно обновлять старую), - // за исключением случаев, когда статус "Rejected" или "Blocked" (смотря какая логика) - // Но обычно метод "IsPossibility" подразумевает именно "можно ли инициировать процесс" - - return existingFriendship.Status == FriendshipStatus.Rejected; - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/GroupRepository.cs b/Govor.Data/Repositories/GroupRepository.cs deleted file mode 100644 index f3a9b3d..0000000 --- a/Govor.Data/Repositories/GroupRepository.cs +++ /dev/null @@ -1,166 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Groups; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class GroupRepository : IGroupsRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - - public GroupRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Admins) - .Include(g => g.Members) - .Include(g => g.InviteCodes) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task GetByIdAsync(Guid id) - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Admins) - .Include(g => g.Members) - .Include(g => g.InviteCodes) - .AsSplitQuery() - .FirstOrDefaultAsync(g => g.Id == id) - ?? throw new NotFoundByKeyException(id, "Group with given id doesn't exist"); - } - - public async Task> SearchByNameAsync(string name) - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Admins) - .Include(g => g.Members) - .Include(g => g.InviteCodes) - .AsSplitQuery() - .Where(g => g.Name.ToLower().Contains(name.ToLower())) - .Take(20) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(name, "Group with name doesn't exist")); - } - - public async Task> GetByAdminIdAsync(Guid userId) - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Admins) - .Include(g => g.Members) - .Include(g => g.InviteCodes) - .AsSplitQuery() - .Where(g => g.Admins.Any(a => a.UserId == userId)) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(userId, "Admin with given id doesn't exist")); - } - - public async Task> GetByUserIdAsync(Guid userId) - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Admins) - .Include(g => g.Members) - .Include(g => g.InviteCodes) - .AsSplitQuery() - .Where(g => g.Members.Any(a => a.UserId == userId)) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(userId, "Member with given id doesn't exist")); - } - - public async Task AddAsync(ChatGroup group) - { - try - { - _validator.Validate(group); - - _context.ChatGroups.Add(group); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Group with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add group", ex); - } - } - - public async Task UpdateAsync(ChatGroup group) - { - try - { - _validator.Validate(group); - - var rowsAffected = await _context.ChatGroups - .Where(u => u.Id == group.Id) - .ExecuteUpdateAsync(g => g - .SetProperty(g => g.Name, group.Name) - .SetProperty(g => g.Description, group.Description) - .SetProperty(g => g.ImageId, group.ImageId) - .SetProperty(g => g.IsChannel, group.IsChannel) - .SetProperty(g => g.IsPrivate, group.IsPrivate) - .SetProperty(g => g.InviteCodes, group.InviteCodes) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found group by given id {group.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the group {group.Id}", ex); - } - } - - public async Task RemoveAsync(Guid groupId) - { - try - { - var result = await GetByIdAsync(groupId); - - _context.ChatGroups.Remove(result); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new RemoveException("User with given data invalid", ex); - } - } - - public bool Exist(Guid groupId) - { - return _context.ChatGroups.Any(g => g.Id == groupId); - } - - public bool Exist(ChatGroup chatGroup) - { - return _context.ChatGroups.Any(g => g.Id == chatGroup.Id && - g.IsChannel == chatGroup.IsChannel && - g.Description == chatGroup.Description && - g.IsPrivate == chatGroup.IsPrivate && - g.Name == chatGroup.Name && - g.ImageId == chatGroup.ImageId); - } - - public async Task IsUserMemberOfGroupAsync(Guid userId, Guid groupId) - { - return await _context.ChatGroups - .AsNoTracking() - .Include(g => g.Members) - .AnyAsync(g => g.Members.Any(a => a.UserId == userId && a.GroupId == groupId)); - } -} diff --git a/Govor.Data/Repositories/InvitesRepository.cs b/Govor.Data/Repositories/InvitesRepository.cs deleted file mode 100644 index ba9050d..0000000 --- a/Govor.Data/Repositories/InvitesRepository.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Invaites; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class InvitesRepository : IInvitesRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - - public InvitesRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.Invitations - .AsNoTracking() - .Include(i => i.Users) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task FindByIdAsync(Guid id) - { - return await _context.Invitations - .AsNoTracking() - .Include(i => i.Users) - .AsSplitQuery() - .FirstOrDefaultAsync(i => i.Id == id) - ?? throw new NotFoundByKeyException(id, "Invitation with given id does not exist"); - } - - public async Task FindByCodeAsync(string code) - { - return await _context.Invitations - .AsNoTracking() - .Include(i => i.Users) - .AsSplitQuery() - .FirstOrDefaultAsync(i => i.Code == code) - ?? throw new NotFoundByKeyException(code, "Invitation with given code does not exist"); - } - - public async Task> FindAdminsInvitesAsync() - { - return await _context.Invitations - .AsNoTracking() - .Include(i => i.Users) - .AsSplitQuery() - .Where(i => i.IsAdmin) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(true, "Admins invites do not exist")); - } - - public async Task AddAsync(Invitation invitation) - { - try - { - _validator.Validate(invitation); - - if(Exist(invitation.Code)) - throw new AdditionException("Invitation with given code already exists"); - - _context.Invitations.Add(invitation); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Invitation with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add invitation", ex); - }; - } - - public async Task UpdateAsync(Invitation invitation) - { - try - { - _validator.Validate(invitation); - - var rowsAffected = await _context.Invitations - .Where(a => a.Id == invitation.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(i => i.IsAdmin, invitation.IsAdmin) - .SetProperty(i => i.Code, invitation.Code) - .SetProperty(i => i.Description, invitation.Description) - .SetProperty(i => i.DateCreated, invitation.DateCreated) - .SetProperty(i => i.EndDate, invitation.EndDate) - .SetProperty(i => i.MaxParticipants, invitation.MaxParticipants) - .SetProperty(i => i.Users, invitation.Users) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found invitation by given id {invitation.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the invitation {invitation.Id}", ex); - } - } - - public async Task RemoveAsync(Invitation invitation) - { - try - { - var result = await FindByIdAsync(invitation.Id); - - _context.Invitations.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found invitation by given id {invitation.Id}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the invitation", ex); - } - } - - public bool Exist(Invitation invitation) - { - _validator.Validate(invitation); - return _context.Invitations.Any(i => i.Id == invitation.Id && - i.Code == invitation.Code && - i.IsAdmin == invitation.IsAdmin && - i.DateCreated == invitation.DateCreated && - i.EndDate == invitation.EndDate && - i.Description == invitation.Description && - i.MaxParticipants == invitation.MaxParticipants - - ); - } - - 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); - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/MediaAttachmentsRepository.cs b/Govor.Data/Repositories/MediaAttachmentsRepository.cs deleted file mode 100644 index bb7588d..0000000 --- a/Govor.Data/Repositories/MediaAttachmentsRepository.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.MediasAttachments; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class MediaAttachmentsRepository : IMediaAttachmentsRepository -{ - public IObjectValidator _validator; - public GovorDbContext _context; - - public MediaAttachmentsRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.MediaAttachments - .AsNoTracking() - .Include(ma => ma.Message) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("No media attachments found.")); - } - - public async Task> GetAllByMessageId(Guid messageId) - { - return await _context.MediaAttachments - .AsNoTracking() - .Include(ma => ma.Message) - .AsSplitQuery() - .Where(m => m.MessageId == messageId) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(messageId, "No media attachments found by given message Id")); - } - - public async Task FindByIdAsync(Guid id) - { - return await _context.MediaAttachments - .AsNoTracking() - .Include(ma => ma.Message) - .AsSplitQuery() - .FirstOrDefaultAsync(m => m.Id == id) - ?? throw new NotFoundByKeyException(id, "No media attachments found by given Id"); - } - - public async Task AddAsync(MediaAttachments mediaAttachments) - { - try - { - _validator.Validate(mediaAttachments); - - _context.MediaAttachments.Add(mediaAttachments); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Attachments with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add Attachments", ex); - } - } - - public async Task UpdateAsync(MediaAttachments attachments) - { - try - { - _validator.Validate(attachments); - - var rowsAffected = await _context.MediaAttachments - .Where(m => m.Id == attachments.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(m => m.MessageId, attachments.MessageId) - .SetProperty(m => m.Message, attachments.Message) - .SetProperty(m => m.MediaFileId, attachments.MediaFileId) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found attachments by given id {attachments.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the attachments {attachments.Id}", ex); - } - } - - public async Task RemoveAsync(Guid Id) - { - try - { - var result = await FindByIdAsync(Id); - - _context.MediaAttachments.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found attachments by given id {Id}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the attachments", ex); - } - } - - public bool Exist(Guid id) - { - return _context.MediaAttachments.Any(e => e.Id == id); - } - - public bool Exist(MediaAttachments attachments) - { - _validator.Validate(attachments); - - return _context.MediaAttachments.Any( - e => e.Id == attachments.Id && - e.MessageId == attachments.MessageId && - e.MediaFileId == attachments.MediaFileId - ); - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/MessagesRepository.cs b/Govor.Data/Repositories/MessagesRepository.cs deleted file mode 100644 index 4932297..0000000 --- a/Govor.Data/Repositories/MessagesRepository.cs +++ /dev/null @@ -1,179 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.Messages; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class MessagesRepository : IMessagesRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - public MessagesRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("No messages found in the database")); - } - - public async Task FindByIdAsync(Guid messageId) - { - return await _context.Messages - .AsNoTracking() - .AsSplitQuery() - .FirstOrDefaultAsync(m => m.Id == messageId) - ?? throw new NotFoundByKeyException(messageId, "Message with given id does not exist"); - } - - public async Task> FindBySenderIdAsync(Guid senderId) - { - return await _context.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .Where(m => m.SenderId == senderId) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(senderId, "Messages with given sender id do not exist")); - } - - public async Task> FindByReceiverIdAsync(Guid receiverId) - { - return await _context.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .Where(m => m.RecipientId == receiverId) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(receiverId, "Messages with given recipient id do not exist")); - } - - public async Task> FindBySenderAndReceiverIdAsync(Guid senderId, Guid receiverId, RecipientType recipientType = RecipientType.User) - { - return await _context.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .Where(m => m.SenderId == senderId - && m.RecipientId == receiverId - && m.RecipientType == recipientType) - .ToListOrThrowIfEmpty(new NotFoundException("No messages found in the database")); - } - - public async Task> FindBySentAtAsync(DateTime date) - { - return await _context.Messages - .AsNoTracking() - .Include(m => m.MediaAttachments) - .ThenInclude(m => m.MediaFile) - .AsSplitQuery() - .Where(m => m.SentAt == date) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(date, "Messages sent at date do not exist")); - } - - public async Task AddAsync(Message message) - { - try - { - _validator.Validate(message); - - _context.Messages.Add(message); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Message with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add message", ex); - } - } - - // TODO: Test this block - public async Task UpdateAsync(Message message) - { - try - { - _validator.Validate(message); - - var rowsAffected = await _context.Messages - .Where(m => m.Id == message.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(m => m.SenderId, message.SenderId) - .SetProperty(m => m.RecipientId, message.RecipientId) - .SetProperty(m => m.SentAt, message.SentAt) - .SetProperty(m => m.RecipientType, message.RecipientType) - .SetProperty(m => m.EncryptedContent, message.EncryptedContent) - .SetProperty(m => m.EditedAt, message.EditedAt) - .SetProperty(m => m.IsEdited, message.IsEdited) - .SetProperty(m => m.Reactions, message.Reactions) - .SetProperty(m => m.ReplyToMessageId, message.ReplyToMessageId) - .SetProperty(m => m.MessageViews, message.MessageViews) - .SetProperty(m => m.MediaAttachments, message.MediaAttachments) - - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found message by given id {message.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the message {message.Id}", ex); - } - } - - public async Task RemoveAsync(Guid messageId) - { - try - { - var result = await FindByIdAsync(messageId); - - _context.Messages.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found message by given id {messageId}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the message", ex); - } - } - - public bool Exist(Message message) - { - _validator.Validate(message); - - return _context.Messages.Any( - m => m.Id == message.Id && - m.SenderId == message.SenderId && - m.RecipientId == message.RecipientId && - m.EncryptedContent == message.EncryptedContent && - m.EditedAt == message.EditedAt && - m.IsEdited == message.IsEdited && - m.SentAt == message.SentAt && - m.ReplyToMessageId == message.ReplyToMessageId - ); - } - - public bool Exist(Guid messageId) - { - return _context.Messages.Any(m => m.Id == messageId); - } -} diff --git a/Govor.Data/Repositories/PrivateChatsRepository.cs b/Govor.Data/Repositories/PrivateChatsRepository.cs deleted file mode 100644 index e72de8a..0000000 --- a/Govor.Data/Repositories/PrivateChatsRepository.cs +++ /dev/null @@ -1,126 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Repositories.PrivateChats; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class PrivateChatsRepository : IPrivateChatsRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - - public PrivateChatsRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.PrivateChats - .AsNoTracking() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task GetByIdAsync(Guid id) - { - return await _context.PrivateChats - .AsNoTracking() - .FirstOrDefaultAsync(p => p.Id == id) - ?? throw new NotFoundByKeyException(id, "Private Chat with given Id does not exist"); - } - - public async Task GetByMembersAsync(Guid memberAId, Guid memberBId) - { - return await _context.PrivateChats - .AsNoTracking() - .FirstOrDefaultAsync(f => (f.UserAId == memberAId && f.UserBId == memberBId) || (f.UserAId == memberBId && f.UserBId == memberAId)) - ?? throw new NotFoundByKeyException<(Guid, Guid)>((memberAId, memberBId), "Private Chat with given members Id's does not exist"); - } - - public async Task> GetAllOfUser(Guid userId) - { - return await _context.PrivateChats - .AsNoTracking() - .Where(f => f.UserAId == userId || f.UserBId == userId) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(userId, "Private Chat with given member Id's does not exist")); - } - - public async Task AddAsync(PrivateChat chat) - { - try - { - _validator.Validate(chat); - - _context.PrivateChats.Add(chat); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("Private chat with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add private chat", ex); - } - } - - public async Task UpdateAsync(PrivateChat chat) - { - try - { - _validator.Validate(chat); - - var rowsAffected = await _context.PrivateChats - .Where(m => m.Id == chat.Id) - .ExecuteUpdateAsync(c => c - .SetProperty(c => c.UserAId, chat.UserAId) - .SetProperty(c => c.UserBId, chat.UserBId) - .SetProperty(c => c.Messages, chat.Messages) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found private chat by given id {chat.Id}"); - - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the private chat {chat.Id}", ex); - } - } - - public async Task RemoveAsync(Guid chatId) - { - try - { - var result = await GetByIdAsync(chatId); - - _context.PrivateChats.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found private chat by given id {chatId}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the private chat", ex); - } - } - - public bool Exist(Guid chatId) - { - return _context.PrivateChats.Any(c => c.Id == chatId); - } - - public bool Exist(Guid userAId, Guid userBId) - { - return _context.PrivateChats.Any(f => (f.UserAId == userAId && f.UserBId == userBId) - || (f.UserAId == userBId && f.UserBId == userAId)); - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/PushTokenRepository.cs b/Govor.Data/Repositories/PushTokenRepository.cs deleted file mode 100644 index 39eeaf4..0000000 --- a/Govor.Data/Repositories/PushTokenRepository.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System.Security; -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.PushTokens; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class PushTokenRepository : IPushTokenRepository -{ - private GovorDbContext _context; - - public PushTokenRepository(GovorDbContext context) - { - _context = context; - } - - public async Task> GetActiveTokensAsync(Guid userId) - { - return await _context.UserPushTokens - .AsNoTracking() - .Where(t => t.UserId == userId && t.IsActive) - .Select(t => t.Token) - .ToListAsync(); - } - - public async Task> GetActiveTokensUsersAsync(IEnumerable userIds) - { - if (userIds is null || !userIds.Any()) - return []; - - var distinctIds = userIds.Distinct().ToList(); - - return await _context.UserPushTokens - .AsNoTracking() - .Where(t => distinctIds.Contains(t.UserId) && t.IsActive) - .Select(t => t.Token) - .ToListAsync(); - } - - public async Task GetActiveTokenBySessionAsync(Guid sessionId) - { - if (sessionId == Guid.Empty) - return ""; - - return await _context.UserPushTokens - .AsNoTracking() - .Where(t => t.UserSessionId == sessionId && t.IsActive) - .Select(t => t.Token) - .FirstOrDefaultAsync() ?? ""; - } - - public async Task AddOrUpdateTokenAsync(Guid userId, Guid? sessionId, string token, string platform, string provider = "FCM") - { - if (userId == Guid.Empty) - throw new ArgumentException("UserId cannot be empty", nameof(userId)); - - if (string.IsNullOrWhiteSpace(token)) - throw new ArgumentException("Token cannot be empty", nameof(token)); - - if (string.IsNullOrWhiteSpace(platform)) - throw new ArgumentException("Platform cannot be empty", nameof(platform)); - - var existing = await _context.UserPushTokens - .FirstOrDefaultAsync(t => t.UserSessionId == sessionId && t.Platform == platform); - - if (existing != null) - { - if(existing.UserId != userId) - throw new SecurityException("Token already belongs to another user"); - - // Updates - existing.UserId = userId; - existing.UserSessionId = sessionId; - existing.Platform = platform; - existing.Provider = provider; - existing.UpdatedAt = DateTime.UtcNow; - existing.LastUsedAt = DateTime.UtcNow; - existing.Token = token; - existing.IsActive = true; - - _context.UserPushTokens.Update(existing); - } - else - { - // Add new - var newToken = new UserPushToken - { - UserId = userId, - UserSessionId = sessionId, - Token = token, - Platform = platform, - Provider = provider, - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow, - LastUsedAt = DateTime.UtcNow, - IsActive = true, - }; - - _context.UserPushTokens.Add(newToken); - } - - await _context.SaveChangesAsync(); - } - - public async Task RemoveTokensAsync(IEnumerable tokens) - { - if (tokens is null || !tokens.Any()) - return; - - var tokenList = tokens.Distinct().ToList(); - - var toRemove = await _context.UserPushTokens - .Where(t => tokenList.Contains(t.Token)) - .ToListAsync(); - - if (toRemove.Any()) - { - foreach (var token in toRemove) - { - token.IsActive = false; - _context.UserPushTokens.Update(token); - } - - await _context.SaveChangesAsync(); - } - } - - public async Task DeactivateTokenBySessionAsync(Guid sessionId) - { - if (sessionId == Guid.Empty) - return; - - var tokens = await _context.UserPushTokens - .Where(t => t.UserSessionId == sessionId && t.IsActive) - .ToListAsync(); - - if (tokens.Any()) - { - foreach (var token in tokens) - { - token.IsActive = false; - token.UpdatedAt = DateTime.UtcNow; - } - - await _context.SaveChangesAsync(); - } - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/UserSessionsRepository.cs b/Govor.Data/Repositories/UserSessionsRepository.cs deleted file mode 100644 index 92b68a5..0000000 --- a/Govor.Data/Repositories/UserSessionsRepository.cs +++ /dev/null @@ -1,169 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.UserSessionsRepository; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class UserSessionsRepository : IUserSessionsRepository -{ - private GovorDbContext _context; - - public UserSessionsRepository(GovorDbContext context) - { - _context = context; - } - - public async Task> GetAllAsync() - { - return await _context.UserSessions - .AsNoTracking() - .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); - } - - public async Task GetByIdAsync(Guid sessionId) - { - return await _context.UserSessions - .AsNoTracking() - .FirstOrDefaultAsync(session => session.Id == sessionId) - ?? throw new NotFoundByKeyException(sessionId, "Session with given id does not exist"); - } - - public async Task> GetByUserIdAsync(Guid userId) - { - return await _context.UserSessions - .AsNoTracking() - .Where(session => session.UserId == userId) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(userId, "Sessions with given user id does not exist")); - } - - public async Task> GetByCreatedAtAsync(DateTime createdAt) - { - return await _context.UserSessions - .AsNoTracking() - .Where(session => session.CreatedAt == createdAt) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(createdAt, "Sessions with given created at does not exist")); - } - - public async Task> GetByExpiresAtAsync(DateTime expiresAt) - { - return await _context.UserSessions - .AsNoTracking() - .Where(session => session.ExpiresAt == expiresAt) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(expiresAt, "Sessions with given expires at does not exist")); - } - - public async Task> GetByRevokedAsync(bool isRevoked) - { - return await _context.UserSessions - .AsNoTracking() - .Where(session => session.IsRevoked == isRevoked) - .ToListOrThrowIfEmpty(new NotFoundByKeyException(isRevoked, "Sessions is revoked does not exist")); - } - - public async Task GetByHashedRefreshTokenAsync(string hash) - { - return await _context.UserSessions - .AsNoTracking() - .FirstOrDefaultAsync(session => session.RefreshTokenHash == hash) - ?? throw new NotFoundByKeyException(hash, "Session with given refresh token does not exist"); - } - - public async Task AddAsync(UserSession userSession) - { - try - { - _context.UserSessions.Add(userSession); - await _context.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new AdditionException("Failed to add user session", ex); - } - } - - public async Task UpdateAsync(UserSession userSession) - { - try - { - //_validator.Validate(user); - - var rowsAffected = await _context.UserSessions - .Where(u => u.Id == userSession.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(a => a.UserId, userSession.UserId) - .SetProperty(u => u.RefreshTokenHash, userSession.RefreshTokenHash) - .SetProperty(u => u.DeviceInfo, userSession.DeviceInfo) - .SetProperty(u => u.ExpiresAt, userSession.ExpiresAt) - .SetProperty(u => u.IsRevoked, userSession.IsRevoked) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found user session by given id {userSession.Id}"); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the user session {userSession.Id}", ex); - } - } - - public async Task RemoveAsync(Guid sessionId) - { - try - { - var result = await GetByIdAsync(sessionId); - - _context.UserSessions.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found session by given id {sessionId}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the session", ex); - } - } - - public async Task RemoveByUserIdAsync(Guid userId) - { - try - { - var result = await GetByUserIdAsync(userId); - - _context.UserSessions.RemoveRange(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found user sessions by given user id {userId}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the user sessions", ex); - } - } - - public bool Exist(Guid sessionId) - { - return _context.UserSessions.Any(session => session.Id == sessionId); - } - - public bool Exist(string hashedToken) - { - return _context.UserSessions.Any(session => session.RefreshTokenHash == hashedToken); - } - - public bool Exist(UserSession userSession) - { - return _context.UserSessions.Any(session => session.Id == userSession.Id && - session.RefreshTokenHash == userSession.RefreshTokenHash && - session.IsRevoked == userSession.IsRevoked && - session.CreatedAt == userSession.CreatedAt && - session.ExpiresAt == userSession.ExpiresAt && - session.DeviceInfo == userSession.DeviceInfo && - session.UserId == userSession.UserId); - } -} \ No newline at end of file diff --git a/Govor.Data/Repositories/UsersRepository.cs b/Govor.Data/Repositories/UsersRepository.cs deleted file mode 100644 index 6cab480..0000000 --- a/Govor.Data/Repositories/UsersRepository.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Govor.Core.Infrastructure.Extensions; -using Govor.Core.Infrastructure.Validators; -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Repositories.Users; -using Govor.Data.Repositories.Exceptions; -using Microsoft.EntityFrameworkCore; - -namespace Govor.Data.Repositories; - -public class UsersRepository : IUsersRepository -{ - private GovorDbContext _context; - private IObjectValidator _validator; - public UsersRepository(GovorDbContext context, IObjectValidator validator) - { - _context = context; - _validator = validator; - } - - public async Task> GetAllAsync() - { - return await _context.Users - .AsNoTracking() - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundException("Users in Database not exists")); - } - - public async Task FindByIdAsync(Guid id) - { - if(id == Guid.Empty) - throw new ArgumentException("Id must not be empty", nameof(id)); - - return await _context.Users - .AsNoTracking() - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .FirstOrDefaultAsync(x => x.Id == id) - ?? throw new NotFoundByKeyException(id, "User with given id does not exist"); - } - - public async Task> FindByRangeIdAsync(IEnumerable ids) - { - if (ids is null || !ids.Any()) - throw new ArgumentException("Ids must not be empty", nameof(ids)); - - return await _context.Users - .AsNoTracking() - .Where(x => ids.Contains(x.Id)) - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundByKeyException>(ids,"Users with given ids not found")); - } - - public async Task FindByUsernameAsync(string username) - { - if(username is null || username == string.Empty) - throw new ArgumentNullException(username, "Username cannot be empty"); - - return await _context.Users - .AsNoTracking() - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .FirstOrDefaultAsync(x => x.Username == username) - ?? throw new NotFoundByKeyException(username, "User with given username does not exist"); - } - - public async Task> SearchPotentialFriendsAsync(Guid currentUserId, string query) - { - return await _context.Users - .AsNoTracking() - .AsSplitQuery() - .Where(u => u.Id != currentUserId && - u.Username.ToLower().Contains(query.ToLower()) && - !_context.Friendships.Any(f => - ((f.RequesterId == currentUserId && f.AddresseeId == u.Id) || - (f.RequesterId == u.Id && f.AddresseeId == currentUserId)) && f.Status != FriendshipStatus.Rejected)) - .Take(7) - .OrderBy(u => u.Username) - .ToListOrThrowIfEmpty(new NotFoundByKeyException<(string, Guid)>((query, currentUserId), $"Users with given query for user {currentUserId} not found")); - } - - - public async Task> FindByRangeUsernamesAsync(IEnumerable usernames) - { - if (usernames is null || !usernames.Any()) - throw new ArgumentException("Usernames must not be empty", nameof(usernames)); - - return await _context.Users - .AsNoTracking() - .Where(x => usernames.Contains(x.Username)) - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundByKeyException>(usernames, "Users with given usernames not found")); - } - - public async Task> FindUsersByCreatedDateAsync(DateOnly createdDate) - { - if(createdDate == DateOnly.MinValue) - throw new ArgumentException("Created date cannot be earlier than MinValue", nameof(createdDate)); - - return await _context.Users - .AsNoTracking() - .Where(u => createdDate == u.CreatedOn) - .Include(u => u.Invite) - .Include(u => u.ReceivedFriendRequests) - .Include(u => u.SentFriendRequests) - .AsSplitQuery() - .ToListOrThrowIfEmpty(new NotFoundByKeyException(createdDate, "Users with given created date do not exist")); - } - - public async Task AddAsync(User user) - { - try - { - _validator.Validate(user); - - _context.Users.Add(user); - await _context.SaveChangesAsync(); - } - catch (InvalidObjectException ex) - { - throw new AdditionException("User with given data invalid", ex); - } - catch (Exception ex) - { - throw new AdditionException("Cannot add user", ex); - } - } - - // TODO: Test this block - public async Task UpdateAsync(User user) - { - try - { - _validator.Validate(user); - - var rowsAffected = await _context.Users - .Where(u => u.Id == user.Id) - .ExecuteUpdateAsync(u => u - .SetProperty(a => a.Username, user.Username) - .SetProperty(u => u.IconId, user.IconId) - .SetProperty(u => u.Description, user.Description) - .SetProperty(u => u.CreatedOn, user.CreatedOn) - .SetProperty(u => u.PasswordHash, user.PasswordHash) - .SetProperty(u => u.WasOnline, user.WasOnline) - .SetProperty(u => u.InviteId, user.InviteId) - ); - - if (rowsAffected == 0) - throw new UpdateException($"Not found user by given id {user.Id}"); - } - catch (Exception ex) - { - throw new UpdateException($"Error when updating the user {user.Id}", ex); - } - } - - public async Task RemoveAsync(User user) - { - try - { - _validator.Validate(user); - await RemoveAsync(user.Id); - } - catch (InvalidObjectException ex) - { - throw new RemoveException("User with given data invalid", ex); - } - } - - public async Task RemoveAsync(Guid userId) - { - try - { - var result = await FindByIdAsync(userId); - - _context.Users.Remove(result); - await _context.SaveChangesAsync(); - } - catch (NotFoundByKeyException ex) - { - throw new RemoveException($"Not found user by given id {userId}", ex); - } - catch (Exception ex) - { - throw new RemoveException("Error when removing the user", ex); - } - } - - public Task ExistsAsync(User user) - { - _validator.Validate(user); - - return _context.Users.AnyAsync(u => - u.Id == user.Id && - u.Username == user.Username && - u.PasswordHash == user.PasswordHash - ); - } - - public Task ExistsByIdAsync(Guid id) - { - return _context.Users.AnyAsync(u => u.Id == id); - } - - public Task ExistsUsernameAsync(string username) - { - return _context.Users.AnyAsync(u => u.Username == username); - } -} \ No newline at end of file diff --git a/Govor.Domain/Common/Constants/InvitationConstants.cs b/Govor.Domain/Common/Constants/InvitationConstants.cs new file mode 100644 index 0000000..2fe4161 --- /dev/null +++ b/Govor.Domain/Common/Constants/InvitationConstants.cs @@ -0,0 +1,6 @@ +namespace Govor.Domain.Common.Constants; + +public class InvitationConstants +{ + public const int MIN_INVITATION_LENGTH = 5; +} \ No newline at end of file diff --git a/Govor.Domain/Common/Constants/UserConstants.cs b/Govor.Domain/Common/Constants/UserConstants.cs new file mode 100644 index 0000000..cc8ebde --- /dev/null +++ b/Govor.Domain/Common/Constants/UserConstants.cs @@ -0,0 +1,7 @@ +namespace Govor.Domain.Common.Constants; + +public class UserConstants +{ + public const int MAX_LENGHT_OF_NAME = 44; + public const int MIN_LENGHT_OF_NAME = 4; +} \ No newline at end of file diff --git a/Govor.Domain/Common/Error.cs b/Govor.Domain/Common/Error.cs new file mode 100644 index 0000000..e49d9f4 --- /dev/null +++ b/Govor.Domain/Common/Error.cs @@ -0,0 +1,9 @@ +namespace Govor.Domain.Common; + + +public record Error(string Code, string Message) +{ + public static readonly Error None = new(string.Empty, string.Empty); + public static readonly Error Null = new("NULL", "Value cannot be null."); + public override string ToString() => $"{Code}: {Message}"; +} \ No newline at end of file diff --git a/Govor.Core/Infrastructure/Extensions/QueryableExtensions.cs b/Govor.Domain/Common/Extensions/QueryableExtensions.cs similarity index 86% rename from Govor.Core/Infrastructure/Extensions/QueryableExtensions.cs rename to Govor.Domain/Common/Extensions/QueryableExtensions.cs index e380f41..a87e92c 100644 --- a/Govor.Core/Infrastructure/Extensions/QueryableExtensions.cs +++ b/Govor.Domain/Common/Extensions/QueryableExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore; -namespace Govor.Core.Infrastructure.Extensions; +namespace Govor.Domain.Common.Extensions; public static class QueryableExtensions { diff --git a/Govor.Domain/Common/Result.cs b/Govor.Domain/Common/Result.cs new file mode 100644 index 0000000..cfcf3a1 --- /dev/null +++ b/Govor.Domain/Common/Result.cs @@ -0,0 +1,49 @@ +namespace Govor.Domain.Common; + +public class Result +{ + protected Result(bool isSuccess, Error error) + { + if (isSuccess && error != Error.None || !isSuccess && error == Error.None) + { + throw new ArgumentException("Invalid error state", nameof(error)); + } + + IsSuccess = isSuccess; + Error = error; + } + + public bool IsSuccess { get; } + public bool IsFailure => !IsSuccess; + public Error Error { get; } + + public static Result Success() => new(true, Error.None); + public static Result Failure(Error error) => new(false, error); + + public static Result Failure(Exception ex) => new(false, new Error(ex.GetType().Name, ex.Message)); + + public static implicit operator Result(Error error) => Failure(error); +} + +public class Result : Result +{ + private readonly T? _value; + + private Result(T? value, bool isSuccess, Error error) : base(isSuccess, error) + { + _value = value; + } + + public T Value => IsSuccess + ? _value! + : throw new InvalidOperationException("The value of a failure result cannot be accessed."); + + public static Result Success(T value) => new(value, true, Error.None); + public static new Result Failure(Error error) => new(default, false, error); + public static new Result Failure(Exception ex) => new(default, false, new Error(ex.GetType().Name, ex.Message)); + + public static implicit operator Result(T value) => Success(value); + + public static implicit operator Result(Error error) => Failure(error); + public static implicit operator T(Result result) => result.Value; +} \ No newline at end of file diff --git a/Govor.Data/Configurations/AdminConfiguration.cs b/Govor.Domain/Configurations/AdminConfiguration.cs similarity index 83% rename from Govor.Data/Configurations/AdminConfiguration.cs rename to Govor.Domain/Configurations/AdminConfiguration.cs index 7f0dfad..603b401 100644 --- a/Govor.Data/Configurations/AdminConfiguration.cs +++ b/Govor.Domain/Configurations/AdminConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class AdminConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/ChatGroupConfigurator.cs b/Govor.Domain/Configurations/ChatGroupConfigurator.cs similarity index 92% rename from Govor.Data/Configurations/ChatGroupConfigurator.cs rename to Govor.Domain/Configurations/ChatGroupConfigurator.cs index f2f5c90..a628bac 100644 --- a/Govor.Data/Configurations/ChatGroupConfigurator.cs +++ b/Govor.Domain/Configurations/ChatGroupConfigurator.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class ChatGroupConfigurator : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/FriendshipConfiguration.cs b/Govor.Domain/Configurations/FriendshipConfiguration.cs similarity index 91% rename from Govor.Data/Configurations/FriendshipConfiguration.cs rename to Govor.Domain/Configurations/FriendshipConfiguration.cs index bd2c17b..20cfb2e 100644 --- a/Govor.Data/Configurations/FriendshipConfiguration.cs +++ b/Govor.Domain/Configurations/FriendshipConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class FriendshipConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/GroupAdminsConfiguration.cs b/Govor.Domain/Configurations/GroupAdminsConfiguration.cs similarity index 85% rename from Govor.Data/Configurations/GroupAdminsConfiguration.cs rename to Govor.Domain/Configurations/GroupAdminsConfiguration.cs index 92866ff..c5a1760 100644 --- a/Govor.Data/Configurations/GroupAdminsConfiguration.cs +++ b/Govor.Domain/Configurations/GroupAdminsConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class GroupAdminsConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/GroupInvitationConfiguration.cs b/Govor.Domain/Configurations/GroupInvitationConfiguration.cs similarity index 92% rename from Govor.Data/Configurations/GroupInvitationConfiguration.cs rename to Govor.Domain/Configurations/GroupInvitationConfiguration.cs index 4d92246..9fa15fa 100644 --- a/Govor.Data/Configurations/GroupInvitationConfiguration.cs +++ b/Govor.Domain/Configurations/GroupInvitationConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class GroupInvitationConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/GroupMembershipConfiguration.cs b/Govor.Domain/Configurations/GroupMembershipConfiguration.cs similarity index 64% rename from Govor.Data/Configurations/GroupMembershipConfiguration.cs rename to Govor.Domain/Configurations/GroupMembershipConfiguration.cs index fb16926..0edf803 100644 --- a/Govor.Data/Configurations/GroupMembershipConfiguration.cs +++ b/Govor.Domain/Configurations/GroupMembershipConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class GroupMembershipConfiguration : IEntityTypeConfiguration { @@ -14,10 +14,16 @@ public class GroupMembershipConfiguration : IEntityTypeConfiguration e.GroupId).IsRequired(); builder.Property(e => e.InvitationId).IsRequired(false); - // Optional: можно добавить навигацию к GroupInvitation + builder.HasOne(e => e.ChatGroup) + .WithMany() + .HasForeignKey(e => e.GroupId) + .OnDelete(DeleteBehavior.Cascade); + + // Optional: настройка связи с GroupInvitation builder.HasOne() .WithMany() .HasForeignKey(e => e.InvitationId) .OnDelete(DeleteBehavior.SetNull); + } } \ No newline at end of file diff --git a/Govor.Data/Configurations/InvitationConfiguration.cs b/Govor.Domain/Configurations/InvitationConfiguration.cs similarity index 87% rename from Govor.Data/Configurations/InvitationConfiguration.cs rename to Govor.Domain/Configurations/InvitationConfiguration.cs index 540032a..2615523 100644 --- a/Govor.Data/Configurations/InvitationConfiguration.cs +++ b/Govor.Domain/Configurations/InvitationConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class InvitationConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/MediaAttachmentsConfiguration.cs b/Govor.Domain/Configurations/MediaAttachmentsConfiguration.cs similarity index 89% rename from Govor.Data/Configurations/MediaAttachmentsConfiguration.cs rename to Govor.Domain/Configurations/MediaAttachmentsConfiguration.cs index 26fcca3..07c9f68 100644 --- a/Govor.Data/Configurations/MediaAttachmentsConfiguration.cs +++ b/Govor.Domain/Configurations/MediaAttachmentsConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class MediaAttachmentsConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/MediaFileConfiguration.cs b/Govor.Domain/Configurations/MediaFileConfiguration.cs similarity index 91% rename from Govor.Data/Configurations/MediaFileConfiguration.cs rename to Govor.Domain/Configurations/MediaFileConfiguration.cs index 452587f..5ff97aa 100644 --- a/Govor.Data/Configurations/MediaFileConfiguration.cs +++ b/Govor.Domain/Configurations/MediaFileConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class MediaFileConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/MessageReactionConfiguration.cs b/Govor.Domain/Configurations/MessageReactionConfiguration.cs similarity index 90% rename from Govor.Data/Configurations/MessageReactionConfiguration.cs rename to Govor.Domain/Configurations/MessageReactionConfiguration.cs index 77ca4f2..d606070 100644 --- a/Govor.Data/Configurations/MessageReactionConfiguration.cs +++ b/Govor.Domain/Configurations/MessageReactionConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class MessageReactionConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/MessageViewConfiguration.cs b/Govor.Domain/Configurations/MessageViewConfiguration.cs similarity index 85% rename from Govor.Data/Configurations/MessageViewConfiguration.cs rename to Govor.Domain/Configurations/MessageViewConfiguration.cs index 04d5774..530bb7e 100644 --- a/Govor.Data/Configurations/MessageViewConfiguration.cs +++ b/Govor.Domain/Configurations/MessageViewConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class MessageViewConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/MessagesConfiguration.cs b/Govor.Domain/Configurations/MessagesConfiguration.cs similarity index 92% rename from Govor.Data/Configurations/MessagesConfiguration.cs rename to Govor.Domain/Configurations/MessagesConfiguration.cs index 5693296..69d3cf8 100644 --- a/Govor.Data/Configurations/MessagesConfiguration.cs +++ b/Govor.Domain/Configurations/MessagesConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class MessagesConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/OneTimePreKeyConfiguration.cs b/Govor.Domain/Configurations/OneTimePreKeyConfiguration.cs similarity index 92% rename from Govor.Data/Configurations/OneTimePreKeyConfiguration.cs rename to Govor.Domain/Configurations/OneTimePreKeyConfiguration.cs index 0b3c347..a1a91c0 100644 --- a/Govor.Data/Configurations/OneTimePreKeyConfiguration.cs +++ b/Govor.Domain/Configurations/OneTimePreKeyConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class OneTimePreKeyConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/PrivacyRuleEntityConfiguration.cs b/Govor.Domain/Configurations/PrivacyRuleEntityConfiguration.cs similarity index 90% rename from Govor.Data/Configurations/PrivacyRuleEntityConfiguration.cs rename to Govor.Domain/Configurations/PrivacyRuleEntityConfiguration.cs index 226fb6f..443faf3 100644 --- a/Govor.Data/Configurations/PrivacyRuleEntityConfiguration.cs +++ b/Govor.Domain/Configurations/PrivacyRuleEntityConfiguration.cs @@ -1,9 +1,8 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; - +namespace Govor.Domain.Configurations; public class PrivacyRuleEntityConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/PrivacyUserSettingsConfiguration.cs b/Govor.Domain/Configurations/PrivacyUserSettingsConfiguration.cs similarity index 92% rename from Govor.Data/Configurations/PrivacyUserSettingsConfiguration.cs rename to Govor.Domain/Configurations/PrivacyUserSettingsConfiguration.cs index 7582db7..48fecf7 100644 --- a/Govor.Data/Configurations/PrivacyUserSettingsConfiguration.cs +++ b/Govor.Domain/Configurations/PrivacyUserSettingsConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class PrivacyUserSettingsConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/PrivateChatsConfiguration.cs b/Govor.Domain/Configurations/PrivateChatsConfiguration.cs similarity index 81% rename from Govor.Data/Configurations/PrivateChatsConfiguration.cs rename to Govor.Domain/Configurations/PrivateChatsConfiguration.cs index 7c42412..ba48a30 100644 --- a/Govor.Data/Configurations/PrivateChatsConfiguration.cs +++ b/Govor.Domain/Configurations/PrivateChatsConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models; +using Govor.Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class PrivateChatsConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/SignedPreKeyConfiguration.cs b/Govor.Domain/Configurations/SignedPreKeyConfiguration.cs similarity index 90% rename from Govor.Data/Configurations/SignedPreKeyConfiguration.cs rename to Govor.Domain/Configurations/SignedPreKeyConfiguration.cs index f28e1c4..383b86a 100644 --- a/Govor.Data/Configurations/SignedPreKeyConfiguration.cs +++ b/Govor.Domain/Configurations/SignedPreKeyConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class SignedPreKeyConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/UserConfiguration.cs b/Govor.Domain/Configurations/UserConfiguration.cs similarity index 92% rename from Govor.Data/Configurations/UserConfiguration.cs rename to Govor.Domain/Configurations/UserConfiguration.cs index 98e4dd6..1a34014 100644 --- a/Govor.Data/Configurations/UserConfiguration.cs +++ b/Govor.Domain/Configurations/UserConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class UserConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/UserCryptoSessionConfiguration.cs b/Govor.Domain/Configurations/UserCryptoSessionConfiguration.cs similarity index 93% rename from Govor.Data/Configurations/UserCryptoSessionConfiguration.cs rename to Govor.Domain/Configurations/UserCryptoSessionConfiguration.cs index 73a8d73..a326bcd 100644 --- a/Govor.Data/Configurations/UserCryptoSessionConfiguration.cs +++ b/Govor.Domain/Configurations/UserCryptoSessionConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class UserCryptoSessionConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/UserPushTokenConfiguration.cs b/Govor.Domain/Configurations/UserPushTokenConfiguration.cs similarity index 91% rename from Govor.Data/Configurations/UserPushTokenConfiguration.cs rename to Govor.Domain/Configurations/UserPushTokenConfiguration.cs index 203408a..51657ff 100644 --- a/Govor.Data/Configurations/UserPushTokenConfiguration.cs +++ b/Govor.Domain/Configurations/UserPushTokenConfiguration.cs @@ -1,8 +1,8 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class UserPushTokenConfiguration : IEntityTypeConfiguration { diff --git a/Govor.Data/Configurations/UserSessionConfiguration.cs b/Govor.Domain/Configurations/UserSessionConfiguration.cs similarity index 76% rename from Govor.Data/Configurations/UserSessionConfiguration.cs rename to Govor.Domain/Configurations/UserSessionConfiguration.cs index 2dd82d2..67a52c4 100644 --- a/Govor.Data/Configurations/UserSessionConfiguration.cs +++ b/Govor.Domain/Configurations/UserSessionConfiguration.cs @@ -1,19 +1,15 @@ -using Govor.Core.Models; -using Govor.Core.Models.Users; -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users; +using Govor.Domain.Models.Users.Crypto; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Govor.Data.Configurations; +namespace Govor.Domain.Configurations; public class UserSessionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.HasKey(us => us.Id); - - builder.HasIndex(us => us.Id) - .IsUnique(); builder.HasIndex(us => us.UserId); @@ -25,15 +21,17 @@ public class UserSessionConfiguration : IEntityTypeConfiguration builder.Property(us => us.DeviceInfo) .HasMaxLength(256); - - builder.HasOne() + + builder.HasOne(us => us.User) .WithMany() .HasForeignKey(us => us.UserId) - .OnDelete(DeleteBehavior.Cascade); + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); builder.HasOne(e => e.CryptoSession) .WithOne(e => e.UserSession) .HasForeignKey(e => e.UserSessionId) + .IsRequired() .OnDelete(DeleteBehavior.Cascade); } } \ No newline at end of file diff --git a/Govor.Data/Govor.Data.csproj b/Govor.Domain/Govor.Domain.csproj similarity index 83% rename from Govor.Data/Govor.Data.csproj rename to Govor.Domain/Govor.Domain.csproj index 036ffa3..0c11df6 100644 --- a/Govor.Data/Govor.Data.csproj +++ b/Govor.Domain/Govor.Domain.csproj @@ -11,9 +11,4 @@ - - - - - diff --git a/Govor.Core/GovorCoreException.cs b/Govor.Domain/GovorCoreException.cs similarity index 93% rename from Govor.Core/GovorCoreException.cs rename to Govor.Domain/GovorCoreException.cs index e109d3d..a37e157 100644 --- a/Govor.Core/GovorCoreException.cs +++ b/Govor.Domain/GovorCoreException.cs @@ -1,4 +1,4 @@ -namespace Govor.Core; +namespace Govor.Domain; /// /// Base exception class for Govor solutions diff --git a/Govor.Data/GovorDbContext.cs b/Govor.Domain/GovorDbContext.cs similarity index 93% rename from Govor.Data/GovorDbContext.cs rename to Govor.Domain/GovorDbContext.cs index d811a88..ecc436a 100644 --- a/Govor.Data/GovorDbContext.cs +++ b/Govor.Domain/GovorDbContext.cs @@ -1,11 +1,11 @@ -using Govor.Core.Models; -using Govor.Core.Models.Messages; -using Govor.Core.Models.Users; -using Govor.Core.Models.Users.Crypto; -using Govor.Data.Configurations; +using Govor.Domain.Models; +using Govor.Domain.Models.Messages; +using Govor.Domain.Models.Users; +using Govor.Domain.Models.Users.Crypto; +using Govor.Domain.Configurations; using Microsoft.EntityFrameworkCore; -namespace Govor.Data; +namespace Govor.Domain; public class GovorDbContext(DbContextOptions options) : DbContext(options) { diff --git a/Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.Designer.cs b/Govor.Domain/Migrations/20260716110338_InitialCreate.Designer.cs similarity index 81% rename from Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.Designer.cs rename to Govor.Domain/Migrations/20260716110338_InitialCreate.Designer.cs index c7439d1..6cfef7d 100644 --- a/Govor.Data/Migrations/20260301120522_FixPushTokensIndexs.Designer.cs +++ b/Govor.Domain/Migrations/20260716110338_InitialCreate.Designer.cs @@ -1,6 +1,6 @@ // using System; -using Govor.Data; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; @@ -9,11 +9,11 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace Govor.Data.Migrations +namespace Govor.Domain.Migrations { [DbContext(typeof(GovorDbContext))] - [Migration("20260301120522_FixPushTokensIndexs")] - partial class FixPushTokensIndexs + [Migration("20260716110338_InitialCreate")] + partial class InitialCreate { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -25,7 +25,7 @@ namespace Govor.Data.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => + modelBuilder.Entity("Govor.Domain.Models.ChatGroup", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -55,7 +55,7 @@ namespace Govor.Data.Migrations b.ToTable("ChatGroups"); }); - modelBuilder.Entity("Govor.Core.Models.Friendship", b => + modelBuilder.Entity("Govor.Domain.Models.Friendship", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -79,7 +79,7 @@ namespace Govor.Data.Migrations b.ToTable("Friendships"); }); - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => + modelBuilder.Entity("Govor.Domain.Models.GroupAdmins", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -98,7 +98,7 @@ namespace Govor.Data.Migrations b.ToTable("GroupAdmins"); }); - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => + modelBuilder.Entity("Govor.Domain.Models.GroupInvitation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -138,12 +138,15 @@ namespace Govor.Data.Migrations b.ToTable("GroupInvitations"); }); - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => + modelBuilder.Entity("Govor.Domain.Models.GroupMembership", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("ChatGroupId") + .HasColumnType("uuid"); + b.Property("GroupId") .HasColumnType("uuid"); @@ -161,6 +164,8 @@ namespace Govor.Data.Migrations b.HasKey("Id"); + b.HasIndex("ChatGroupId"); + b.HasIndex("GroupId"); b.HasIndex("InvitationId"); @@ -168,7 +173,7 @@ namespace Govor.Data.Migrations b.ToTable("GroupMemberships"); }); - modelBuilder.Entity("Govor.Core.Models.Invitation", b => + modelBuilder.Entity("Govor.Domain.Models.Invitation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -202,7 +207,7 @@ namespace Govor.Data.Migrations b.ToTable("Invitations"); }); - modelBuilder.Entity("Govor.Core.Models.MediaFile", b => + modelBuilder.Entity("Govor.Domain.Models.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -238,7 +243,7 @@ namespace Govor.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MediaAttachments", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -259,7 +264,7 @@ namespace Govor.Data.Migrations b.ToTable("MediaAttachments"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -307,7 +312,7 @@ namespace Govor.Data.Migrations b.ToTable("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageReaction", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -337,7 +342,7 @@ namespace Govor.Data.Migrations b.ToTable("MessageReactions"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageView", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -360,7 +365,7 @@ namespace Govor.Data.Migrations b.ToTable("MessageViews"); }); - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => + modelBuilder.Entity("Govor.Domain.Models.PrivateChat", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -377,7 +382,7 @@ namespace Govor.Data.Migrations b.ToTable("PrivateChats"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Admin", b => { b.Property("UserId") .HasColumnType("uuid"); @@ -387,7 +392,7 @@ namespace Govor.Data.Migrations b.ToTable("Admins"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.OneTimePreKey", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -417,7 +422,7 @@ namespace Govor.Data.Migrations b.ToTable("OneTimePreKeys"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.SignedPreKey", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -442,7 +447,7 @@ namespace Govor.Data.Migrations b.ToTable("SignedPreKeys"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -463,7 +468,7 @@ namespace Govor.Data.Migrations b.ToTable("UserCryptoSessions"); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -509,7 +514,7 @@ namespace Govor.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserPushToken", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserPushToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -561,7 +566,7 @@ namespace Govor.Data.Migrations b.ToTable("UserPushTokens"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -590,9 +595,6 @@ namespace Govor.Data.Migrations b.HasKey("Id"); - b.HasIndex("Id") - .IsUnique(); - b.HasIndex("RefreshTokenHash") .IsUnique(); @@ -601,15 +603,15 @@ namespace Govor.Data.Migrations b.ToTable("UserSessions"); }); - modelBuilder.Entity("Govor.Core.Models.Friendship", b => + modelBuilder.Entity("Govor.Domain.Models.Friendship", b => { - b.HasOne("Govor.Core.Models.Users.User", "Addressee") + b.HasOne("Govor.Domain.Models.Users.User", "Addressee") .WithMany("ReceivedFriendRequests") .HasForeignKey("AddresseeId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "Requester") + b.HasOne("Govor.Domain.Models.Users.User", "Requester") .WithMany("SentFriendRequests") .HasForeignKey("RequesterId") .OnDelete(DeleteBehavior.Restrict) @@ -620,24 +622,24 @@ namespace Govor.Data.Migrations b.Navigation("Requester"); }); - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => + modelBuilder.Entity("Govor.Domain.Models.GroupAdmins", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Admins") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => + modelBuilder.Entity("Govor.Domain.Models.GroupInvitation", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("InviteCodes") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "UserMaker") + b.HasOne("Govor.Domain.Models.Users.User", "UserMaker") .WithMany() .HasForeignKey("UserMakerId") .OnDelete(DeleteBehavior.Restrict) @@ -646,29 +648,35 @@ namespace Govor.Data.Migrations b.Navigation("UserMaker"); }); - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => + modelBuilder.Entity("Govor.Domain.Models.GroupMembership", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Members") + .HasForeignKey("ChatGroupId"); + + b.HasOne("Govor.Domain.Models.ChatGroup", "ChatGroup") + .WithMany() .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.GroupInvitation", null) + b.HasOne("Govor.Domain.Models.GroupInvitation", null) .WithMany() .HasForeignKey("InvitationId") .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ChatGroup"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MediaAttachments", b => { - b.HasOne("Govor.Core.Models.MediaFile", "MediaFile") + b.HasOne("Govor.Domain.Models.MediaFile", "MediaFile") .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("Govor.Core.Models.Messages.Message", "Message") + b.HasOne("Govor.Domain.Models.Messages.Message", "Message") .WithMany("MediaAttachments") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) @@ -679,26 +687,26 @@ namespace Govor.Data.Migrations b.Navigation("Message"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Messages") .HasForeignKey("ChatGroupId"); - b.HasOne("Govor.Core.Models.PrivateChat", null) + b.HasOne("Govor.Domain.Models.PrivateChat", null) .WithMany("Messages") .HasForeignKey("PrivateChatId"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageReaction", b => { - b.HasOne("Govor.Core.Models.Messages.Message", "Message") + b.HasOne("Govor.Domain.Models.Messages.Message", "Message") .WithMany("Reactions") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "User") + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -709,29 +717,29 @@ namespace Govor.Data.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageView", b => { - b.HasOne("Govor.Core.Models.Messages.Message", null) + b.HasOne("Govor.Domain.Models.Messages.Message", null) .WithMany("MessageViews") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Admin", b => { - b.HasOne("Govor.Core.Models.Users.User", "User") + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithOne() - .HasForeignKey("Govor.Core.Models.Users.Admin", "UserId") + .HasForeignKey("Govor.Domain.Models.Users.Admin", "UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.OneTimePreKey", b => { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") + b.HasOne("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") .WithMany("OneTimePreKeys") .HasForeignKey("UserCryptoSessionId") .OnDelete(DeleteBehavior.Cascade) @@ -740,31 +748,31 @@ namespace Govor.Data.Migrations b.Navigation("UserCryptoSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.SignedPreKey", b => { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") + b.HasOne("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") .WithOne("SignedPreKey") - .HasForeignKey("Govor.Core.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") + .HasForeignKey("Govor.Domain.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("UserCryptoSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { - b.HasOne("Govor.Core.Models.Users.UserSession", "UserSession") + b.HasOne("Govor.Domain.Models.Users.UserSession", "UserSession") .WithOne("CryptoSession") - .HasForeignKey("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserSessionId") + .HasForeignKey("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserSessionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("UserSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { - b.HasOne("Govor.Core.Models.Invitation", "Invite") + b.HasOne("Govor.Domain.Models.Invitation", "Invite") .WithMany("Users") .HasForeignKey("InviteId") .OnDelete(DeleteBehavior.Cascade) @@ -773,16 +781,18 @@ namespace Govor.Data.Migrations b.Navigation("Invite"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { - b.HasOne("Govor.Core.Models.Users.User", null) + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => + modelBuilder.Entity("Govor.Domain.Models.ChatGroup", b => { b.Navigation("Admins"); @@ -793,12 +803,12 @@ namespace Govor.Data.Migrations b.Navigation("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Invitation", b => + modelBuilder.Entity("Govor.Domain.Models.Invitation", b => { b.Navigation("Users"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { b.Navigation("MediaAttachments"); @@ -807,12 +817,12 @@ namespace Govor.Data.Migrations b.Navigation("Reactions"); }); - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => + modelBuilder.Entity("Govor.Domain.Models.PrivateChat", b => { b.Navigation("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { b.Navigation("OneTimePreKeys"); @@ -820,14 +830,14 @@ namespace Govor.Data.Migrations .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { b.Navigation("ReceivedFriendRequests"); b.Navigation("SentFriendRequests"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { b.Navigation("CryptoSession") .IsRequired(); diff --git a/Govor.Data/Migrations/20260301080331_Init.cs b/Govor.Domain/Migrations/20260716110338_InitialCreate.cs similarity index 95% rename from Govor.Data/Migrations/20260301080331_Init.cs rename to Govor.Domain/Migrations/20260716110338_InitialCreate.cs index da67b0a..ead7690 100644 --- a/Govor.Data/Migrations/20260301080331_Init.cs +++ b/Govor.Domain/Migrations/20260716110338_InitialCreate.cs @@ -3,10 +3,10 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -namespace Govor.Data.Migrations +namespace Govor.Domain.Migrations { /// - public partial class Init : Migration + public partial class InitialCreate : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -83,9 +83,9 @@ namespace Govor.Data.Migrations Id = table.Column(type: "uuid", nullable: false), UserId = table.Column(type: "uuid", nullable: false), UserSessionId = table.Column(type: "uuid", nullable: true), - Token = table.Column(type: "text", nullable: false), - Provider = table.Column(type: "text", nullable: false), - Platform = table.Column(type: "text", nullable: false), + Token = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), + Provider = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Platform = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), LastUsedAt = table.Column(type: "timestamp with time zone", nullable: true), @@ -347,11 +347,17 @@ namespace Govor.Data.Migrations UserId = table.Column(type: "uuid", nullable: false), InvitationId = table.Column(type: "uuid", nullable: true), IsBanned = table.Column(type: "boolean", nullable: false), - MemberSince = table.Column(type: "timestamp with time zone", nullable: false) + MemberSince = table.Column(type: "timestamp with time zone", nullable: false), + ChatGroupId = table.Column(type: "uuid", nullable: true) }, constraints: table => { table.PrimaryKey("PK_GroupMemberships", x => x.Id); + table.ForeignKey( + name: "FK_GroupMemberships_ChatGroups_ChatGroupId", + column: x => x.ChatGroupId, + principalTable: "ChatGroups", + principalColumn: "Id"); table.ForeignKey( name: "FK_GroupMemberships_ChatGroups_GroupId", column: x => x.GroupId, @@ -431,12 +437,6 @@ namespace Govor.Data.Migrations table: "Friendships", column: "AddresseeId"); - migrationBuilder.CreateIndex( - name: "IX_Friendships_Id", - table: "Friendships", - column: "Id", - unique: true); - migrationBuilder.CreateIndex( name: "IX_Friendships_RequesterId", table: "Friendships", @@ -457,6 +457,11 @@ namespace Govor.Data.Migrations table: "GroupInvitations", column: "UserMakerId"); + migrationBuilder.CreateIndex( + name: "IX_GroupMemberships_ChatGroupId", + table: "GroupMemberships", + column: "ChatGroupId"); + migrationBuilder.CreateIndex( name: "IX_GroupMemberships_GroupId", table: "GroupMemberships", @@ -493,12 +498,6 @@ namespace Govor.Data.Migrations table: "Messages", column: "ChatGroupId"); - migrationBuilder.CreateIndex( - name: "IX_Messages_Id", - table: "Messages", - column: "Id", - unique: true); - migrationBuilder.CreateIndex( name: "IX_Messages_PrivateChatId", table: "Messages", @@ -507,8 +506,7 @@ namespace Govor.Data.Migrations migrationBuilder.CreateIndex( name: "IX_Messages_RecipientId", table: "Messages", - column: "RecipientId", - unique: true); + column: "RecipientId"); migrationBuilder.CreateIndex( name: "IX_MessageViews_MessageId_UserId", @@ -526,12 +524,6 @@ namespace Govor.Data.Migrations table: "OneTimePreKeys", columns: new[] { "UserCryptoSessionId", "IsUsed" }); - migrationBuilder.CreateIndex( - name: "IX_PrivateChats_Id", - table: "PrivateChats", - column: "Id", - unique: true); - migrationBuilder.CreateIndex( name: "IX_SignedPreKeys_UserCryptoSessionId", table: "SignedPreKeys", @@ -550,12 +542,6 @@ namespace Govor.Data.Migrations column: "Token", unique: true); - migrationBuilder.CreateIndex( - name: "IX_UserPushTokens_UserId", - table: "UserPushTokens", - column: "UserId", - unique: true); - migrationBuilder.CreateIndex( name: "IX_UserPushTokens_UserId_IsActive", table: "UserPushTokens", @@ -588,12 +574,6 @@ namespace Govor.Data.Migrations table: "Users", column: "WasOnline"); - migrationBuilder.CreateIndex( - name: "IX_UserSessions_Id", - table: "UserSessions", - column: "Id", - unique: true); - migrationBuilder.CreateIndex( name: "IX_UserSessions_RefreshTokenHash", table: "UserSessions", diff --git a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs b/Govor.Domain/Migrations/GovorDbContextModelSnapshot.cs similarity index 81% rename from Govor.Data/Migrations/GovorDbContextModelSnapshot.cs rename to Govor.Domain/Migrations/GovorDbContextModelSnapshot.cs index 7eee105..713c4e5 100644 --- a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs +++ b/Govor.Domain/Migrations/GovorDbContextModelSnapshot.cs @@ -1,6 +1,6 @@ // using System; -using Govor.Data; +using Govor.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; @@ -8,7 +8,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace Govor.Data.Migrations +namespace Govor.Domain.Migrations { [DbContext(typeof(GovorDbContext))] partial class GovorDbContextModelSnapshot : ModelSnapshot @@ -22,7 +22,7 @@ namespace Govor.Data.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => + modelBuilder.Entity("Govor.Domain.Models.ChatGroup", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -52,7 +52,7 @@ namespace Govor.Data.Migrations b.ToTable("ChatGroups"); }); - modelBuilder.Entity("Govor.Core.Models.Friendship", b => + modelBuilder.Entity("Govor.Domain.Models.Friendship", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -76,7 +76,7 @@ namespace Govor.Data.Migrations b.ToTable("Friendships"); }); - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => + modelBuilder.Entity("Govor.Domain.Models.GroupAdmins", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -95,7 +95,7 @@ namespace Govor.Data.Migrations b.ToTable("GroupAdmins"); }); - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => + modelBuilder.Entity("Govor.Domain.Models.GroupInvitation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -135,12 +135,15 @@ namespace Govor.Data.Migrations b.ToTable("GroupInvitations"); }); - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => + modelBuilder.Entity("Govor.Domain.Models.GroupMembership", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("ChatGroupId") + .HasColumnType("uuid"); + b.Property("GroupId") .HasColumnType("uuid"); @@ -158,6 +161,8 @@ namespace Govor.Data.Migrations b.HasKey("Id"); + b.HasIndex("ChatGroupId"); + b.HasIndex("GroupId"); b.HasIndex("InvitationId"); @@ -165,7 +170,7 @@ namespace Govor.Data.Migrations b.ToTable("GroupMemberships"); }); - modelBuilder.Entity("Govor.Core.Models.Invitation", b => + modelBuilder.Entity("Govor.Domain.Models.Invitation", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -199,7 +204,7 @@ namespace Govor.Data.Migrations b.ToTable("Invitations"); }); - modelBuilder.Entity("Govor.Core.Models.MediaFile", b => + modelBuilder.Entity("Govor.Domain.Models.MediaFile", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -235,7 +240,7 @@ namespace Govor.Data.Migrations b.ToTable("MediaFiles"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MediaAttachments", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -256,7 +261,7 @@ namespace Govor.Data.Migrations b.ToTable("MediaAttachments"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -304,7 +309,7 @@ namespace Govor.Data.Migrations b.ToTable("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageReaction", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -334,7 +339,7 @@ namespace Govor.Data.Migrations b.ToTable("MessageReactions"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageView", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -357,7 +362,7 @@ namespace Govor.Data.Migrations b.ToTable("MessageViews"); }); - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => + modelBuilder.Entity("Govor.Domain.Models.PrivateChat", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -374,7 +379,7 @@ namespace Govor.Data.Migrations b.ToTable("PrivateChats"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Admin", b => { b.Property("UserId") .HasColumnType("uuid"); @@ -384,7 +389,7 @@ namespace Govor.Data.Migrations b.ToTable("Admins"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.OneTimePreKey", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -414,7 +419,7 @@ namespace Govor.Data.Migrations b.ToTable("OneTimePreKeys"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.SignedPreKey", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -439,7 +444,7 @@ namespace Govor.Data.Migrations b.ToTable("SignedPreKeys"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -460,7 +465,7 @@ namespace Govor.Data.Migrations b.ToTable("UserCryptoSessions"); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -506,7 +511,7 @@ namespace Govor.Data.Migrations b.ToTable("Users"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserPushToken", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserPushToken", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -558,7 +563,7 @@ namespace Govor.Data.Migrations b.ToTable("UserPushTokens"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -587,9 +592,6 @@ namespace Govor.Data.Migrations b.HasKey("Id"); - b.HasIndex("Id") - .IsUnique(); - b.HasIndex("RefreshTokenHash") .IsUnique(); @@ -598,15 +600,15 @@ namespace Govor.Data.Migrations b.ToTable("UserSessions"); }); - modelBuilder.Entity("Govor.Core.Models.Friendship", b => + modelBuilder.Entity("Govor.Domain.Models.Friendship", b => { - b.HasOne("Govor.Core.Models.Users.User", "Addressee") + b.HasOne("Govor.Domain.Models.Users.User", "Addressee") .WithMany("ReceivedFriendRequests") .HasForeignKey("AddresseeId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "Requester") + b.HasOne("Govor.Domain.Models.Users.User", "Requester") .WithMany("SentFriendRequests") .HasForeignKey("RequesterId") .OnDelete(DeleteBehavior.Restrict) @@ -617,24 +619,24 @@ namespace Govor.Data.Migrations b.Navigation("Requester"); }); - modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => + modelBuilder.Entity("Govor.Domain.Models.GroupAdmins", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Admins") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.GroupInvitation", b => + modelBuilder.Entity("Govor.Domain.Models.GroupInvitation", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("InviteCodes") .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "UserMaker") + b.HasOne("Govor.Domain.Models.Users.User", "UserMaker") .WithMany() .HasForeignKey("UserMakerId") .OnDelete(DeleteBehavior.Restrict) @@ -643,29 +645,35 @@ namespace Govor.Data.Migrations b.Navigation("UserMaker"); }); - modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => + modelBuilder.Entity("Govor.Domain.Models.GroupMembership", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Members") + .HasForeignKey("ChatGroupId"); + + b.HasOne("Govor.Domain.Models.ChatGroup", "ChatGroup") + .WithMany() .HasForeignKey("GroupId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.GroupInvitation", null) + b.HasOne("Govor.Domain.Models.GroupInvitation", null) .WithMany() .HasForeignKey("InvitationId") .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("ChatGroup"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MediaAttachments", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MediaAttachments", b => { - b.HasOne("Govor.Core.Models.MediaFile", "MediaFile") + b.HasOne("Govor.Domain.Models.MediaFile", "MediaFile") .WithMany() .HasForeignKey("MediaFileId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("Govor.Core.Models.Messages.Message", "Message") + b.HasOne("Govor.Domain.Models.Messages.Message", "Message") .WithMany("MediaAttachments") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) @@ -676,26 +684,26 @@ namespace Govor.Data.Migrations b.Navigation("Message"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { - b.HasOne("Govor.Core.Models.ChatGroup", null) + b.HasOne("Govor.Domain.Models.ChatGroup", null) .WithMany("Messages") .HasForeignKey("ChatGroupId"); - b.HasOne("Govor.Core.Models.PrivateChat", null) + b.HasOne("Govor.Domain.Models.PrivateChat", null) .WithMany("Messages") .HasForeignKey("PrivateChatId"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageReaction", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageReaction", b => { - b.HasOne("Govor.Core.Models.Messages.Message", "Message") + b.HasOne("Govor.Domain.Models.Messages.Message", "Message") .WithMany("Reactions") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Govor.Core.Models.Users.User", "User") + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) @@ -706,29 +714,29 @@ namespace Govor.Data.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.MessageView", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.MessageView", b => { - b.HasOne("Govor.Core.Models.Messages.Message", null) + b.HasOne("Govor.Domain.Models.Messages.Message", null) .WithMany("MessageViews") .HasForeignKey("MessageId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.Users.Admin", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Admin", b => { - b.HasOne("Govor.Core.Models.Users.User", "User") + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithOne() - .HasForeignKey("Govor.Core.Models.Users.Admin", "UserId") + .HasForeignKey("Govor.Domain.Models.Users.Admin", "UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.OneTimePreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.OneTimePreKey", b => { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") + b.HasOne("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") .WithMany("OneTimePreKeys") .HasForeignKey("UserCryptoSessionId") .OnDelete(DeleteBehavior.Cascade) @@ -737,31 +745,31 @@ namespace Govor.Data.Migrations b.Navigation("UserCryptoSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.SignedPreKey", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.SignedPreKey", b => { - b.HasOne("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") + b.HasOne("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserCryptoSession") .WithOne("SignedPreKey") - .HasForeignKey("Govor.Core.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") + .HasForeignKey("Govor.Domain.Models.Users.Crypto.SignedPreKey", "UserCryptoSessionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("UserCryptoSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { - b.HasOne("Govor.Core.Models.Users.UserSession", "UserSession") + b.HasOne("Govor.Domain.Models.Users.UserSession", "UserSession") .WithOne("CryptoSession") - .HasForeignKey("Govor.Core.Models.Users.Crypto.UserCryptoSession", "UserSessionId") + .HasForeignKey("Govor.Domain.Models.Users.Crypto.UserCryptoSession", "UserSessionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("UserSession"); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { - b.HasOne("Govor.Core.Models.Invitation", "Invite") + b.HasOne("Govor.Domain.Models.Invitation", "Invite") .WithMany("Users") .HasForeignKey("InviteId") .OnDelete(DeleteBehavior.Cascade) @@ -770,16 +778,18 @@ namespace Govor.Data.Migrations b.Navigation("Invite"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { - b.HasOne("Govor.Core.Models.Users.User", null) + b.HasOne("Govor.Domain.Models.Users.User", "User") .WithMany() .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("User"); }); - modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => + modelBuilder.Entity("Govor.Domain.Models.ChatGroup", b => { b.Navigation("Admins"); @@ -790,12 +800,12 @@ namespace Govor.Data.Migrations b.Navigation("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Invitation", b => + modelBuilder.Entity("Govor.Domain.Models.Invitation", b => { b.Navigation("Users"); }); - modelBuilder.Entity("Govor.Core.Models.Messages.Message", b => + modelBuilder.Entity("Govor.Domain.Models.Messages.Message", b => { b.Navigation("MediaAttachments"); @@ -804,12 +814,12 @@ namespace Govor.Data.Migrations b.Navigation("Reactions"); }); - modelBuilder.Entity("Govor.Core.Models.PrivateChat", b => + modelBuilder.Entity("Govor.Domain.Models.PrivateChat", b => { b.Navigation("Messages"); }); - modelBuilder.Entity("Govor.Core.Models.Users.Crypto.UserCryptoSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.Crypto.UserCryptoSession", b => { b.Navigation("OneTimePreKeys"); @@ -817,14 +827,14 @@ namespace Govor.Data.Migrations .IsRequired(); }); - modelBuilder.Entity("Govor.Core.Models.Users.User", b => + modelBuilder.Entity("Govor.Domain.Models.Users.User", b => { b.Navigation("ReceivedFriendRequests"); b.Navigation("SentFriendRequests"); }); - modelBuilder.Entity("Govor.Core.Models.Users.UserSession", b => + modelBuilder.Entity("Govor.Domain.Models.Users.UserSession", b => { b.Navigation("CryptoSession") .IsRequired(); diff --git a/Govor.Core/Models/ChatGroup.cs b/Govor.Domain/Models/ChatGroup.cs similarity index 93% rename from Govor.Core/Models/ChatGroup.cs rename to Govor.Domain/Models/ChatGroup.cs index 406854e..d6d8f30 100644 --- a/Govor.Core/Models/ChatGroup.cs +++ b/Govor.Domain/Models/ChatGroup.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class ChatGroup { diff --git a/Govor.Core/Models/Friendship.cs b/Govor.Domain/Models/Friendship.cs similarity index 85% rename from Govor.Core/Models/Friendship.cs rename to Govor.Domain/Models/Friendship.cs index 442bf37..725bab1 100644 --- a/Govor.Core/Models/Friendship.cs +++ b/Govor.Domain/Models/Friendship.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class Friendship { diff --git a/Govor.Core/Models/GroupAdmins.cs b/Govor.Domain/Models/GroupAdmins.cs similarity index 80% rename from Govor.Core/Models/GroupAdmins.cs rename to Govor.Domain/Models/GroupAdmins.cs index be21bfc..0f580d2 100644 --- a/Govor.Core/Models/GroupAdmins.cs +++ b/Govor.Domain/Models/GroupAdmins.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class GroupAdmins { diff --git a/Govor.Core/Models/GroupInvitation.cs b/Govor.Domain/Models/GroupInvitation.cs similarity index 87% rename from Govor.Core/Models/GroupInvitation.cs rename to Govor.Domain/Models/GroupInvitation.cs index 3f135fd..e0d5055 100644 --- a/Govor.Core/Models/GroupInvitation.cs +++ b/Govor.Domain/Models/GroupInvitation.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class GroupInvitation { diff --git a/Govor.Core/Models/GroupMembership.cs b/Govor.Domain/Models/GroupMembership.cs similarity index 77% rename from Govor.Core/Models/GroupMembership.cs rename to Govor.Domain/Models/GroupMembership.cs index 509b19e..c27be6e 100644 --- a/Govor.Core/Models/GroupMembership.cs +++ b/Govor.Domain/Models/GroupMembership.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class GroupMembership { @@ -8,4 +8,5 @@ public class GroupMembership public Guid? InvitationId { get; set; } public bool IsBanned { get; set; } public DateTime MemberSince { get; set; } + public ChatGroup ChatGroup { get; set; } } \ No newline at end of file diff --git a/Govor.Core/Models/Invitation.cs b/Govor.Domain/Models/Invitation.cs similarity index 93% rename from Govor.Core/Models/Invitation.cs rename to Govor.Domain/Models/Invitation.cs index 46e0555..b2ebf48 100644 --- a/Govor.Core/Models/Invitation.cs +++ b/Govor.Domain/Models/Invitation.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class Invitation { diff --git a/Govor.Core/Models/MediaFile.cs b/Govor.Domain/Models/MediaFile.cs similarity index 80% rename from Govor.Core/Models/MediaFile.cs rename to Govor.Domain/Models/MediaFile.cs index 940dbd5..c3ef8be 100644 --- a/Govor.Core/Models/MediaFile.cs +++ b/Govor.Domain/Models/MediaFile.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class MediaFile { @@ -20,5 +20,5 @@ public enum MediaOwnerType Message = 0, Avatar = 1, GroupAvatar = 2, - System = 3 // (Emoge, icons e.t.c) + System = 3 // (Emoge, icons � e.t.c) } \ No newline at end of file diff --git a/Govor.Core/Models/Messages/MediaAttachments.cs b/Govor.Domain/Models/Messages/MediaAttachments.cs similarity index 93% rename from Govor.Core/Models/Messages/MediaAttachments.cs rename to Govor.Domain/Models/Messages/MediaAttachments.cs index 99a5a6b..7e4ea58 100644 --- a/Govor.Core/Models/Messages/MediaAttachments.cs +++ b/Govor.Domain/Models/Messages/MediaAttachments.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Messages; +namespace Govor.Domain.Models.Messages; public class MediaAttachments { diff --git a/Govor.Core/Models/Messages/Message.cs b/Govor.Domain/Models/Messages/Message.cs similarity index 96% rename from Govor.Core/Models/Messages/Message.cs rename to Govor.Domain/Models/Messages/Message.cs index d999f4b..c8e423b 100644 --- a/Govor.Core/Models/Messages/Message.cs +++ b/Govor.Domain/Models/Messages/Message.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Messages; +namespace Govor.Domain.Models.Messages; public class Message { diff --git a/Govor.Core/Models/Messages/MessageReaction.cs b/Govor.Domain/Models/Messages/MessageReaction.cs similarity index 83% rename from Govor.Core/Models/Messages/MessageReaction.cs rename to Govor.Domain/Models/Messages/MessageReaction.cs index 1ce2382..0f0ea71 100644 --- a/Govor.Core/Models/Messages/MessageReaction.cs +++ b/Govor.Domain/Models/Messages/MessageReaction.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Users; +using Govor.Domain.Models.Users; -namespace Govor.Core.Models.Messages; +namespace Govor.Domain.Models.Messages; public class MessageReaction { diff --git a/Govor.Core/Models/Messages/MessageView.cs b/Govor.Domain/Models/Messages/MessageView.cs similarity index 82% rename from Govor.Core/Models/Messages/MessageView.cs rename to Govor.Domain/Models/Messages/MessageView.cs index 0bb266a..13f78b8 100644 --- a/Govor.Core/Models/Messages/MessageView.cs +++ b/Govor.Domain/Models/Messages/MessageView.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Messages; +namespace Govor.Domain.Models.Messages; public class MessageView { diff --git a/Govor.Core/Models/PrivateChat.cs b/Govor.Domain/Models/PrivateChat.cs similarity index 86% rename from Govor.Core/Models/PrivateChat.cs rename to Govor.Domain/Models/PrivateChat.cs index e043a92..53e7fde 100644 --- a/Govor.Core/Models/PrivateChat.cs +++ b/Govor.Domain/Models/PrivateChat.cs @@ -1,6 +1,6 @@ -using Govor.Core.Models.Messages; +using Govor.Domain.Models.Messages; -namespace Govor.Core.Models; +namespace Govor.Domain.Models; public class PrivateChat { diff --git a/Govor.Core/Models/Users/Admin.cs b/Govor.Domain/Models/Users/Admin.cs similarity index 81% rename from Govor.Core/Models/Users/Admin.cs rename to Govor.Domain/Models/Users/Admin.cs index c3e20bf..234535e 100644 --- a/Govor.Core/Models/Users/Admin.cs +++ b/Govor.Domain/Models/Users/Admin.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class Admin { diff --git a/Govor.Core/Models/Users/Crypto/OneTimePreKey.cs b/Govor.Domain/Models/Users/Crypto/OneTimePreKey.cs similarity index 87% rename from Govor.Core/Models/Users/Crypto/OneTimePreKey.cs rename to Govor.Domain/Models/Users/Crypto/OneTimePreKey.cs index b356bb3..f8a7572 100644 --- a/Govor.Core/Models/Users/Crypto/OneTimePreKey.cs +++ b/Govor.Domain/Models/Users/Crypto/OneTimePreKey.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Users.Crypto; +namespace Govor.Domain.Models.Users.Crypto; public class OneTimePreKey { diff --git a/Govor.Core/Models/Users/Crypto/SignedPreKey.cs b/Govor.Domain/Models/Users/Crypto/SignedPreKey.cs similarity index 86% rename from Govor.Core/Models/Users/Crypto/SignedPreKey.cs rename to Govor.Domain/Models/Users/Crypto/SignedPreKey.cs index c1b8b27..50381fa 100644 --- a/Govor.Core/Models/Users/Crypto/SignedPreKey.cs +++ b/Govor.Domain/Models/Users/Crypto/SignedPreKey.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Users.Crypto; +namespace Govor.Domain.Models.Users.Crypto; public class SignedPreKey { diff --git a/Govor.Core/Models/Users/Crypto/UserCryptoSession.cs b/Govor.Domain/Models/Users/Crypto/UserCryptoSession.cs similarity index 88% rename from Govor.Core/Models/Users/Crypto/UserCryptoSession.cs rename to Govor.Domain/Models/Users/Crypto/UserCryptoSession.cs index 41403e6..a6a7c09 100644 --- a/Govor.Core/Models/Users/Crypto/UserCryptoSession.cs +++ b/Govor.Domain/Models/Users/Crypto/UserCryptoSession.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Users.Crypto; +namespace Govor.Domain.Models.Users.Crypto; public class UserCryptoSession { diff --git a/Govor.Core/Models/Users/PrivacyRuleEntity.cs b/Govor.Domain/Models/Users/PrivacyRuleEntity.cs similarity index 91% rename from Govor.Core/Models/Users/PrivacyRuleEntity.cs rename to Govor.Domain/Models/Users/PrivacyRuleEntity.cs index 09f1fe0..f57d179 100644 --- a/Govor.Core/Models/Users/PrivacyRuleEntity.cs +++ b/Govor.Domain/Models/Users/PrivacyRuleEntity.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class PrivacyRuleEntity { diff --git a/Govor.Core/Models/Users/PrivacyUserSettings.cs b/Govor.Domain/Models/Users/PrivacyUserSettings.cs similarity index 94% rename from Govor.Core/Models/Users/PrivacyUserSettings.cs rename to Govor.Domain/Models/Users/PrivacyUserSettings.cs index 001c38d..6d80c1a 100644 --- a/Govor.Core/Models/Users/PrivacyUserSettings.cs +++ b/Govor.Domain/Models/Users/PrivacyUserSettings.cs @@ -1,4 +1,4 @@ -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class PrivacyUserSettings { diff --git a/Govor.Core/Models/Users/User.cs b/Govor.Domain/Models/Users/User.cs similarity index 94% rename from Govor.Core/Models/Users/User.cs rename to Govor.Domain/Models/Users/User.cs index cefaf19..acb595a 100644 --- a/Govor.Core/Models/Users/User.cs +++ b/Govor.Domain/Models/Users/User.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class User { diff --git a/Govor.Core/Models/Users/UserPushToken.cs b/Govor.Domain/Models/Users/UserPushToken.cs similarity index 89% rename from Govor.Core/Models/Users/UserPushToken.cs rename to Govor.Domain/Models/Users/UserPushToken.cs index 1ff716a..7d19263 100644 --- a/Govor.Core/Models/Users/UserPushToken.cs +++ b/Govor.Domain/Models/Users/UserPushToken.cs @@ -1,6 +1,4 @@ -using Microsoft.EntityFrameworkCore; - -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class UserPushToken { public Guid Id { get; set; } = Guid.NewGuid(); diff --git a/Govor.Core/Models/Users/UserSession.cs b/Govor.Domain/Models/Users/UserSession.cs similarity index 61% rename from Govor.Core/Models/Users/UserSession.cs rename to Govor.Domain/Models/Users/UserSession.cs index dcd448b..53205f5 100644 --- a/Govor.Core/Models/Users/UserSession.cs +++ b/Govor.Domain/Models/Users/UserSession.cs @@ -1,23 +1,24 @@ -using Govor.Core.Models.Users.Crypto; +using Govor.Domain.Models.Users.Crypto; -namespace Govor.Core.Models.Users; +namespace Govor.Domain.Models.Users; public class UserSession { public Guid Id { get; set; } = Guid.NewGuid(); public Guid UserId { get; set; } public string RefreshTokenHash { get; set; } = string.Empty; - public string DeviceInfo { get; set; } = string.Empty; // "Chrome on Windows" + public string DeviceInfo { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime ExpiresAt { get; set; } public bool IsRevoked { get; set; } = false; - // public DateTime? RevokedAt { get; set; } TODO: Clear old UserSessions - - public UserCryptoSession CryptoSession { get; set; } + + public User User { get; set; } = null!; + public UserCryptoSession CryptoSession { get; set; } = null!; public override bool Equals(object? obj) { - UserSession? userSession = obj as UserSession; + if (obj is not UserSession userSession) + return false; return Id == userSession.Id && UserId == userSession.UserId && @@ -27,4 +28,9 @@ public class UserSession ExpiresAt == userSession.ExpiresAt && IsRevoked == userSession.IsRevoked; } + + public override int GetHashCode() + { + return HashCode.Combine(Id, UserId, RefreshTokenHash, DeviceInfo, CreatedAt, ExpiresAt, IsRevoked); + } } \ No newline at end of file diff --git a/Govor.sln b/Govor.sln index 271c981..adbac74 100644 --- a/Govor.sln +++ b/Govor.sln @@ -4,10 +4,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.API.Tests", "Govor.AP EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.API", "Govor.API\Govor.API.csproj", "{EA8F272F-4276-438A-9DEA-C58860A440AE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Core", "Govor.Core\Govor.Core.csproj", "{F7BB1EC7-63D6-4525-ADE4-E4AC937E219D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Data", "Govor.Data\Govor.Data.csproj", "{E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.ConsoleClient", "Govor.ConsoleClient\Govor.ConsoleClient.csproj", "{F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4}" @@ -27,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Data.Tests", "Govor.D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.ConsoleClient.Tests", "Govor.ConsoleClient.Tests\Govor.ConsoleClient.Tests.csproj", "{B1E79EB6-DBD3-4E82-AB6D-DCFCE6533965}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Govor.Domain", "Govor.Domain\Govor.Domain.csproj", "{868EAA88-A8E8-4508-B264-1AE3576D47C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,14 +39,6 @@ Global {EA8F272F-4276-438A-9DEA-C58860A440AE}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA8F272F-4276-438A-9DEA-C58860A440AE}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA8F272F-4276-438A-9DEA-C58860A440AE}.Release|Any CPU.Build.0 = Release|Any CPU - {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D}.Release|Any CPU.Build.0 = Release|Any CPU - {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E}.Release|Any CPU.Build.0 = Release|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -73,17 +63,20 @@ Global {B1E79EB6-DBD3-4E82-AB6D-DCFCE6533965}.Debug|Any CPU.Build.0 = Debug|Any CPU {B1E79EB6-DBD3-4E82-AB6D-DCFCE6533965}.Release|Any CPU.ActiveCfg = Release|Any CPU {B1E79EB6-DBD3-4E82-AB6D-DCFCE6533965}.Release|Any CPU.Build.0 = Release|Any CPU + {868EAA88-A8E8-4508-B264-1AE3576D47C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {868EAA88-A8E8-4508-B264-1AE3576D47C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {868EAA88-A8E8-4508-B264-1AE3576D47C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {868EAA88-A8E8-4508-B264-1AE3576D47C1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {15031CBD-F319-4755-BA91-B86F20BD8E37} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4} {EA8F272F-4276-438A-9DEA-C58860A440AE} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {F4535DC3-BDFB-4EB2-B259-F92B6BBB535B} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} - {F7BB1EC7-63D6-4525-ADE4-E4AC937E219D} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} - {E4EDB179-7EB5-468D-9C1F-0CBE2E5E459E} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {4E94907F-BE20-42A6-AB15-637850FEAD11} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {FC5EDCA8-FD58-4078-8FB1-2BDBB2F6CA3E} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} {F56A64DF-2938-4BE0-83F2-B86429F19259} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4} {CF6B23EC-932A-4998-BA95-C94CAB7B092C} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4} {B1E79EB6-DBD3-4E82-AB6D-DCFCE6533965} = {4ED5259A-6FB4-4D89-8E6B-4778DC68F7D4} + {868EAA88-A8E8-4508-B264-1AE3576D47C1} = {114F53C1-B0AB-4BA0-9E36-0E811D1B3776} EndGlobalSection EndGlobal