mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 19:54:55 +00:00
FriendsController
This commit is contained in:
@@ -28,6 +28,7 @@ public class FriendshipValidatorTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void Given_ValidFriendship_When_Validate_Then_Returns_True()
|
public void Given_ValidFriendship_When_Validate_Then_Returns_True()
|
||||||
{
|
{
|
||||||
|
// Arrange
|
||||||
var friendship = _fixture.Create<Friendship>();
|
var friendship = _fixture.Create<Friendship>();
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
@@ -38,6 +39,7 @@ public class FriendshipValidatorTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void Given_EmptyFriendshipId_When_Validate_Then_Returns_False()
|
public void Given_EmptyFriendshipId_When_Validate_Then_Returns_False()
|
||||||
{
|
{
|
||||||
|
// Arrange
|
||||||
var friendship = _fixture.Create<Friendship>();
|
var friendship = _fixture.Create<Friendship>();
|
||||||
friendship.Id = Guid.Empty;
|
friendship.Id = Guid.Empty;
|
||||||
|
|
||||||
@@ -49,6 +51,7 @@ public class FriendshipValidatorTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void Given_EmptyRequesterId_When_Validate_Then_Returns_False()
|
public void Given_EmptyRequesterId_When_Validate_Then_Returns_False()
|
||||||
{
|
{
|
||||||
|
// Arrange
|
||||||
var friendship = _fixture.Create<Friendship>();
|
var friendship = _fixture.Create<Friendship>();
|
||||||
friendship.RequesterId = Guid.Empty;
|
friendship.RequesterId = Guid.Empty;
|
||||||
|
|
||||||
@@ -57,9 +60,22 @@ public class FriendshipValidatorTests
|
|||||||
Assert.That(_friendshipValidator.TryValidate(friendship), Is.False);
|
Assert.That(_friendshipValidator.TryValidate(friendship), Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GivenSameRequesterId_When_Validate_Then_Returns_False()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var friendship = _fixture.Create<Friendship>();
|
||||||
|
friendship.RequesterId = friendship.AddresseeId;
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<InvalidObjectException<Friendship>>( () => _friendshipValidator.Validate(friendship));
|
||||||
|
Assert.That(_friendshipValidator.TryValidate(friendship), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Given_AddresseeId_When_Validate_Then_Returns_False()
|
public void Given_AddresseeId_When_Validate_Then_Returns_False()
|
||||||
{
|
{
|
||||||
|
// Arrange
|
||||||
var friendship = _fixture.Create<Friendship>();
|
var friendship = _fixture.Create<Friendship>();
|
||||||
friendship.AddresseeId = Guid.Empty;
|
friendship.AddresseeId = Guid.Empty;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
using Govor.Application.Exceptions.FriendsService;
|
||||||
|
using Govor.Application.Interfaces;
|
||||||
|
using Govor.Contracts.DTOs;
|
||||||
|
using Govor.Core.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@@ -9,48 +13,151 @@ namespace Govor.API.Controllers;
|
|||||||
public class FriendsController : Controller
|
public class FriendsController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<FriendsController> _logger;
|
private readonly ILogger<FriendsController> _logger;
|
||||||
|
private readonly IFriendsService _friendsService;
|
||||||
|
|
||||||
|
public FriendsController(ILogger<FriendsController> logger, IFriendsService friendsService)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_friendsService = friendsService;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("search")]
|
[HttpGet("search")]
|
||||||
public async Task<IActionResult> Search([FromBody] string query)
|
public async Task<IActionResult> Search(string query)
|
||||||
{
|
{
|
||||||
return BadRequest("Not a valid request");
|
try
|
||||||
|
{
|
||||||
|
var result = await _friendsService.SearchUsersAsync(query, GetCurrentUserId());
|
||||||
|
|
||||||
|
return Ok(BuildUserDtos(result));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, ex.Message);
|
||||||
|
return BadRequest("Something happened during the search... try again");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("request")]
|
[HttpPost("request")]
|
||||||
public async Task<IActionResult> SendRequest([FromBody] Guid targetUserId)
|
public async Task<IActionResult> SendRequest(Guid targetUserId)
|
||||||
{
|
{
|
||||||
return BadRequest("Not a valid request");
|
try
|
||||||
|
{
|
||||||
|
await _friendsService.SendFriendRequestAsync(targetUserId, GetCurrentUserId());
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("The user tried to send a friend request to themselves");
|
||||||
|
return BadRequest("You can't send a friend request to themselves");
|
||||||
|
}
|
||||||
|
catch (RequestAlreadySentException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("The user tried to send a friend request but the request is already sent");
|
||||||
|
return BadRequest("You already sent a friend request");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, ex.Message);
|
||||||
|
return BadRequest("Something happened during the request... try again");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("requests")]
|
[HttpGet("requests")]
|
||||||
public async Task<IActionResult> GetIncomingRequests()
|
public async Task<IActionResult> GetIncomingRequests()
|
||||||
{
|
{
|
||||||
return BadRequest("Not a valid request");
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Getting incoming requests for user {GetCurrentUserId()}...");
|
||||||
|
var result = await _friendsService.GetIncomingRequestsAsync(GetCurrentUserId());
|
||||||
|
return Ok(BuildFriendshipDtos(result));
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, ex.Message);
|
||||||
|
return BadRequest("You can't get real friend requests because we can't find your user data! Try again");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("accept")]
|
[HttpPost("accept")]
|
||||||
public async Task<IActionResult> AcceptFriend([FromBody] Guid requesterId)
|
public async Task<IActionResult> AcceptFriend(Guid requesterId)
|
||||||
{
|
{
|
||||||
return BadRequest("Not a valid request");
|
try
|
||||||
|
{
|
||||||
|
await _friendsService.AcceptFriendRequestAsync(requesterId, GetCurrentUserId());
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("The user tried to accept a friend request but the request not exists");
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("User tried to accept a friend request but addresseeId not equal userId");
|
||||||
|
return BadRequest("You can't accept a friend request");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetFriends()
|
public async Task<IActionResult> GetFriends()
|
||||||
{
|
{
|
||||||
return BadRequest("Not a valid request");
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Getting friends by user {GetCurrentUserId()}...");
|
||||||
|
var result = await _friendsService.GetFriendsAsync(GetCurrentUserId());
|
||||||
|
|
||||||
|
return Ok(BuildUserDtos(result));
|
||||||
|
}
|
||||||
|
catch(UnauthorizedAccessException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, ex.Message);
|
||||||
|
return BadRequest("Something happened during the request... try again");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Guid GetCurrentUserId()
|
private Guid GetCurrentUserId()
|
||||||
{
|
{
|
||||||
var userIdClaim = HttpContext.User?.FindFirst("userID")?.Value;
|
var userIdClaim = HttpContext.User?.FindFirst("userID")?.Value;
|
||||||
_logger.LogInformation("Claims: {Claims}", string.Join(", ", HttpContext.User?.Claims.Select(c => $"{c.Type}: {c.Value}") ?? new string[0]));
|
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(userIdClaim))
|
|
||||||
{
|
{
|
||||||
_logger.LogError("No userID claim found");
|
throw new UnauthorizedAccessException("userID claim is missing or invalid");
|
||||||
return Guid.Empty;
|
}
|
||||||
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Guid.TryParse(userIdClaim, out var userId) ? userId : Guid.Empty;
|
private List<UserDto> BuildUserDtos(IEnumerable<User> users)
|
||||||
|
{
|
||||||
|
List<UserDto> userDtos = new List<UserDto>();
|
||||||
|
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
userDtos.Add(new UserDto()
|
||||||
|
{
|
||||||
|
Id = user.Id,
|
||||||
|
Description = user.Description,
|
||||||
|
Username = user.Username,
|
||||||
|
WasOnline = user.WasOnline,
|
||||||
|
IconId = user.IconId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return userDtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FriendshipDto> BuildFriendshipDtos(List<Friendship> result)
|
||||||
|
{
|
||||||
|
List<FriendshipDto> dtos = new List<FriendshipDto>();
|
||||||
|
|
||||||
|
foreach (var friendship in result)
|
||||||
|
{
|
||||||
|
dtos.Add(new FriendshipDto()
|
||||||
|
{
|
||||||
|
Id = friendship.Id,
|
||||||
|
Status = friendship.Status,
|
||||||
|
AddresseeId = friendship.AddresseeId,
|
||||||
|
RequesterId = friendship.RequesterId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ using Govor.Core.Infrastructure.Extensions;
|
|||||||
using Govor.Core.Infrastructure.Validators;
|
using Govor.Core.Infrastructure.Validators;
|
||||||
using Govor.Core.Models;
|
using Govor.Core.Models;
|
||||||
using Govor.Core.Repositories.Admins;
|
using Govor.Core.Repositories.Admins;
|
||||||
|
using Govor.Core.Repositories.Friendships;
|
||||||
using Govor.Core.Repositories.Invaites;
|
using Govor.Core.Repositories.Invaites;
|
||||||
using Govor.Core.Repositories.MediasAttachments;
|
using Govor.Core.Repositories.MediasAttachments;
|
||||||
using Govor.Core.Repositories.Messages;
|
using Govor.Core.Repositories.Messages;
|
||||||
@@ -30,6 +31,7 @@ public static class ConfigurationProgramExtensions
|
|||||||
services.AddScoped<IInvitesService, InvitesService>();
|
services.AddScoped<IInvitesService, InvitesService>();
|
||||||
services.AddScoped<IInvitationGenerator, InvitationGenerator>();
|
services.AddScoped<IInvitationGenerator, InvitationGenerator>();
|
||||||
services.AddScoped<IUsernameValidator, UsernameValidator>();
|
services.AddScoped<IUsernameValidator, UsernameValidator>();
|
||||||
|
services.AddScoped<IFriendsService, FriendsService>();
|
||||||
|
|
||||||
services.AddScoped<IStorageService>(sp =>
|
services.AddScoped<IStorageService>(sp =>
|
||||||
{
|
{
|
||||||
@@ -45,6 +47,7 @@ public static class ConfigurationProgramExtensions
|
|||||||
services.AddScoped<IInvitesRepository, InvitesRepository>();
|
services.AddScoped<IInvitesRepository, InvitesRepository>();
|
||||||
services.AddScoped<IAdminsRepository, AdminsRepository>();
|
services.AddScoped<IAdminsRepository, AdminsRepository>();
|
||||||
services.AddScoped<IMediaAttachmentsRepository, MediaAttachmentsRepository>();
|
services.AddScoped<IMediaAttachmentsRepository, MediaAttachmentsRepository>();
|
||||||
|
services.AddScoped<IFriendshipsRepository, FriendshipsRepository>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddValidators(this IServiceCollection services)
|
public static void AddValidators(this IServiceCollection services)
|
||||||
@@ -54,6 +57,7 @@ public static class ConfigurationProgramExtensions
|
|||||||
services.AddScoped<IObjectValidator<MediaAttachments>, MediaAttachmentsValidator>();
|
services.AddScoped<IObjectValidator<MediaAttachments>, MediaAttachmentsValidator>();
|
||||||
services.AddScoped<IObjectValidator<Admin>, AdminValidator>();
|
services.AddScoped<IObjectValidator<Admin>, AdminValidator>();
|
||||||
services.AddScoped<IObjectValidator<Invitation>, InvitationValidator>();
|
services.AddScoped<IObjectValidator<Invitation>, InvitationValidator>();
|
||||||
|
services.AddScoped<IObjectValidator<Friendship>, FriendshipValidator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddGovorDbContext(this IServiceCollection services, IConfiguration configuration)
|
public static void AddGovorDbContext(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
|||||||
@@ -98,14 +98,10 @@ public class ChatsHub : Hub
|
|||||||
private Guid GetUserId()
|
private Guid GetUserId()
|
||||||
{
|
{
|
||||||
var userIdClaim = Context.User?.FindFirst("userID")?.Value;
|
var userIdClaim = Context.User?.FindFirst("userID")?.Value;
|
||||||
_logger.LogInformation("Claims: {Claims}", string.Join(", ", Context.User?.Claims.Select(c => $"{c.Type}: {c.Value}") ?? new string[0]));
|
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(userIdClaim))
|
|
||||||
{
|
{
|
||||||
_logger.LogError("No userID claim found");
|
throw new UnauthorizedAccessException("userID claim is missing or invalid");
|
||||||
return Guid.Empty;
|
|
||||||
}
|
}
|
||||||
|
return userId;
|
||||||
return Guid.TryParse(userIdClaim, out var userId) ? userId : Guid.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using Govor.Core;
|
||||||
|
|
||||||
|
namespace Govor.Application.Exceptions.FriendsService;
|
||||||
|
|
||||||
|
public class RequestAlreadySentException(Guid fromId, Guid userId)
|
||||||
|
: GovorCoreException($"Request was already sent from {fromId} to {userId}") {}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Govor.Core;
|
||||||
|
|
||||||
|
namespace Govor.Application.Exceptions.FriendsService;
|
||||||
|
|
||||||
|
public class SearchUsersException : GovorCoreException
|
||||||
|
{
|
||||||
|
public SearchUsersException(string message, Exception innerException)
|
||||||
|
: base(message, innerException){}
|
||||||
|
|
||||||
|
public SearchUsersException(string message)
|
||||||
|
: base(message){}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using Govor.Core;
|
||||||
|
|
||||||
|
namespace Govor.Application.Exceptions.FriendsService;
|
||||||
|
|
||||||
|
public class SendFriendRequestException(Guid fromUserId, Guid toUserId, Exception exception)
|
||||||
|
: GovorCoreException($"Something happened when we try to send request from {fromUserId} to {toUserId}", exception);
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Govor.Core.Models;
|
||||||
|
|
||||||
|
namespace Govor.Application.Interfaces;
|
||||||
|
|
||||||
|
public interface IFriendsService
|
||||||
|
{
|
||||||
|
Task<List<User>> SearchUsersAsync(string searchTerm, Guid currentId);
|
||||||
|
Task SendFriendRequestAsync(Guid fromUserId, Guid toUserId);
|
||||||
|
Task AcceptFriendRequestAsync(Guid requestId, Guid currentUserId);
|
||||||
|
Task<List<User>> GetFriendsAsync(Guid userId);
|
||||||
|
Task<List<Friendship>> GetIncomingRequestsAsync(Guid userId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
using Govor.Application.Exceptions;
|
||||||
|
using Govor.Application.Exceptions.FriendsService;
|
||||||
|
using Govor.Application.Interfaces;
|
||||||
|
using Govor.Core.Models;
|
||||||
|
using Govor.Core.Repositories.Friendships;
|
||||||
|
using Govor.Core.Repositories.Users;
|
||||||
|
using Govor.Data.Repositories.Exceptions;
|
||||||
|
|
||||||
|
namespace Govor.Application.Services;
|
||||||
|
|
||||||
|
public class FriendsService : IFriendsService
|
||||||
|
{
|
||||||
|
private IUsersRepository _usersRepository;
|
||||||
|
private IFriendshipsRepository _friendshipsRepository;
|
||||||
|
|
||||||
|
public FriendsService(IUsersRepository usersRepository, IFriendshipsRepository relationshipsRepository)
|
||||||
|
{
|
||||||
|
_usersRepository = usersRepository;
|
||||||
|
_friendshipsRepository = relationshipsRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<User>> SearchUsersAsync(string searchTerm, Guid currentId)
|
||||||
|
{
|
||||||
|
var all = await _usersRepository.SearchPotentialFriendsAsync(currentId, searchTerm);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var friends = await _friendshipsRepository.FindByUserIdAsync(currentId);
|
||||||
|
|
||||||
|
friends = friends.Where(f => f.Status == FriendshipStatus.Accepted).ToList();
|
||||||
|
|
||||||
|
return all
|
||||||
|
.Where(u => u.Id != currentId && !friends.Select(f => f.RequesterId).Contains(u.Id))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
catch (NotFoundByKeyException<Guid> ex)
|
||||||
|
{
|
||||||
|
return all.Where(u => u.Id != currentId).ToList();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new SearchUsersException($"When we try find friends by pattern {searchTerm} something wrong", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendFriendRequestAsync(Guid fromUserId, Guid toUserId)
|
||||||
|
{
|
||||||
|
if (fromUserId == toUserId)
|
||||||
|
throw new InvalidOperationException("Cannot send a request to self user");
|
||||||
|
|
||||||
|
if (_friendshipsRepository.Exist(fromUserId, toUserId))
|
||||||
|
throw new RequestAlreadySentException(fromUserId, toUserId);
|
||||||
|
|
||||||
|
await _friendshipsRepository.AddAsync(new Friendship()
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
RequesterId = fromUserId,
|
||||||
|
AddresseeId = toUserId,
|
||||||
|
Status = FriendshipStatus.Pending
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AcceptFriendRequestAsync(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);
|
||||||
|
}
|
||||||
|
catch (NotFoundByKeyException<Guid> e)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Friendship not found! You cant accept request!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<User>> GetFriendsAsync(Guid userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _usersRepository.FindByIdAsync(userId);
|
||||||
|
|
||||||
|
var sent = user.SentFriendRequests
|
||||||
|
.Where(f => f.Status == FriendshipStatus.Accepted)
|
||||||
|
.Select(f => f.Addressee);
|
||||||
|
|
||||||
|
var received = user.ReceivedFriendRequests
|
||||||
|
.Where(f => f.Status == FriendshipStatus.Accepted)
|
||||||
|
.Select(f => f.Requester);
|
||||||
|
|
||||||
|
return sent.Concat(received).ToList();
|
||||||
|
}
|
||||||
|
catch (NotFoundByKeyException<Guid> ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("User not exist", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Friendship>> GetIncomingRequestsAsync(Guid userId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _usersRepository.FindByIdAsync(userId);
|
||||||
|
return user.ReceivedFriendRequests;
|
||||||
|
}
|
||||||
|
catch (NotFoundByKeyException<Guid> ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("User not exist", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Govor.Core.Models;
|
||||||
|
|
||||||
|
namespace Govor.Contracts.DTOs;
|
||||||
|
|
||||||
|
public class FriendshipDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid RequesterId { get; set; }
|
||||||
|
public Guid AddresseeId { get; set; }
|
||||||
|
public FriendshipStatus Status { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Govor.Contracts.DTOs;
|
||||||
|
|
||||||
|
public class UserDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public DateTime WasOnline { get; set; }
|
||||||
|
public Guid IconId {get; set;}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@ public class FriendshipValidator : IObjectValidator<Friendship>
|
|||||||
throw new ArgumentException("Addresses cannot be empty", nameof(friendship.AddresseeId));
|
throw new ArgumentException("Addresses cannot be empty", nameof(friendship.AddresseeId));
|
||||||
if(friendship.RequesterId == Guid.Empty)
|
if(friendship.RequesterId == Guid.Empty)
|
||||||
throw new ArgumentException("Requester cannot be empty", nameof(friendship.RequesterId));
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ public interface IUsersReader
|
|||||||
public Task<List<User>> FindByRangeIdAsync(IEnumerable<Guid> ids);
|
public Task<List<User>> FindByRangeIdAsync(IEnumerable<Guid> ids);
|
||||||
public Task<User> FindByUsernameAsync(string username);
|
public Task<User> FindByUsernameAsync(string username);
|
||||||
public Task<List<User>> FindByRangeUsernamesAsync(IEnumerable<string> usernames);
|
public Task<List<User>> FindByRangeUsernamesAsync(IEnumerable<string> usernames);
|
||||||
|
public Task<List<User>> SearchPotentialFriendsAsync(Guid currentUserId, string query);
|
||||||
public Task<List<User>> FindUsersByCreatedDateAsync(DateOnly createdDate);
|
public Task<List<User>> FindUsersByCreatedDateAsync(DateOnly createdDate);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,467 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Govor.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Govor.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(GovorDbContext))]
|
||||||
|
[Migration("20250627101322_friendships")]
|
||||||
|
partial class friendships
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.6")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Admins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.ChatGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<List<Guid>>("Admins")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("uuid[]");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<List<string>>("InviteCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text[]");
|
||||||
|
|
||||||
|
b.Property<bool>("IsChannel")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPrivate")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChatGroups");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Friendship", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("AddresseeId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("RequesterId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AddresseeId");
|
||||||
|
|
||||||
|
b.HasIndex("RequesterId");
|
||||||
|
|
||||||
|
b.ToTable("Friendships");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("GroupId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GroupAdmins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.GroupMembership", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("GroupId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("IsBanned")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GroupMemberships");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Invitation", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateCreated")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("EndDate")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAdmin")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<int>("MaxParticipants")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Invitations");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedKey")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)");
|
||||||
|
|
||||||
|
b.Property<string>("FilePath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("MessageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("MimeType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MessageId");
|
||||||
|
|
||||||
|
b.ToTable("MediaAttachments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Message", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("EditedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedContent")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEdited")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<Guid?>("PrivateChatId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("RecipientId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("RecipientType")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid?>("ReplyToMessageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("SenderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("SentAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PrivateChatId");
|
||||||
|
|
||||||
|
b.HasIndex("ReplyToMessageId");
|
||||||
|
|
||||||
|
b.ToTable("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MessageReaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("MessageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReactedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("ReactionCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("MessageId", "UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("MessageReactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MessageView", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("MessageId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("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<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserAId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserBId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PrivateChats");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateOnly>("CreatedOn")
|
||||||
|
.HasColumnType("date");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("IconId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("InviteId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("WasOnline")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("InviteId");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.User", "User")
|
||||||
|
.WithOne()
|
||||||
|
.HasForeignKey("Govor.Core.Models.Admin", "UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Friendship", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.User", "Addressee")
|
||||||
|
.WithMany("ReceivedFriendRequests")
|
||||||
|
.HasForeignKey("AddresseeId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Govor.Core.Models.User", "Requester")
|
||||||
|
.WithMany("SentFriendRequests")
|
||||||
|
.HasForeignKey("RequesterId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Addressee");
|
||||||
|
|
||||||
|
b.Navigation("Requester");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.Message", "Message")
|
||||||
|
.WithMany("MediaAttachments")
|
||||||
|
.HasForeignKey("MessageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Message");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Message", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.PrivateChat", null)
|
||||||
|
.WithMany("Messages")
|
||||||
|
.HasForeignKey("PrivateChatId");
|
||||||
|
|
||||||
|
b.HasOne("Govor.Core.Models.Message", "ReplyToMessage")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ReplyToMessageId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("ReplyToMessage");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MessageReaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.Message", "Message")
|
||||||
|
.WithMany("Reactions")
|
||||||
|
.HasForeignKey("MessageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Govor.Core.Models.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Message");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.MessageView", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.Message", null)
|
||||||
|
.WithMany("MessageViews")
|
||||||
|
.HasForeignKey("MessageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.Invitation", "Invite")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("InviteId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Invite");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Invitation", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Message", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("MediaAttachments");
|
||||||
|
|
||||||
|
b.Navigation("MessageViews");
|
||||||
|
|
||||||
|
b.Navigation("Reactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.PrivateChat", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ReceivedFriendRequests");
|
||||||
|
|
||||||
|
b.Navigation("SentFriendRequests");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Govor.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class friendships : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "PrivateChatId",
|
||||||
|
table: "Messages",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Friendships",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
RequesterId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
AddresseeId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Friendships", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Friendships_Users_AddresseeId",
|
||||||
|
column: x => x.AddresseeId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Friendships_Users_RequesterId",
|
||||||
|
column: x => x.RequesterId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PrivateChats",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
UserAId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
UserBId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PrivateChats", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Messages_PrivateChatId",
|
||||||
|
table: "Messages",
|
||||||
|
column: "PrivateChatId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Friendships_AddresseeId",
|
||||||
|
table: "Friendships",
|
||||||
|
column: "AddresseeId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Friendships_RequesterId",
|
||||||
|
table: "Friendships",
|
||||||
|
column: "RequesterId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Messages_PrivateChats_PrivateChatId",
|
||||||
|
table: "Messages",
|
||||||
|
column: "PrivateChatId",
|
||||||
|
principalTable: "PrivateChats",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Messages_PrivateChats_PrivateChatId",
|
||||||
|
table: "Messages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Friendships");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PrivateChats");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Messages_PrivateChatId",
|
||||||
|
table: "Messages");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PrivateChatId",
|
||||||
|
table: "Messages");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,6 +62,30 @@ namespace Govor.Data.Migrations
|
|||||||
b.ToTable("ChatGroups");
|
b.ToTable("ChatGroups");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Friendship", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("AddresseeId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("RequesterId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AddresseeId");
|
||||||
|
|
||||||
|
b.HasIndex("RequesterId");
|
||||||
|
|
||||||
|
b.ToTable("Friendships");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b =>
|
modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@@ -181,6 +205,9 @@ namespace Govor.Data.Migrations
|
|||||||
b.Property<bool>("IsEdited")
|
b.Property<bool>("IsEdited")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<Guid?>("PrivateChatId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
b.Property<Guid>("RecipientId")
|
b.Property<Guid>("RecipientId")
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
@@ -198,6 +225,8 @@ namespace Govor.Data.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PrivateChatId");
|
||||||
|
|
||||||
b.HasIndex("ReplyToMessageId");
|
b.HasIndex("ReplyToMessageId");
|
||||||
|
|
||||||
b.ToTable("Messages");
|
b.ToTable("Messages");
|
||||||
@@ -256,6 +285,23 @@ namespace Govor.Data.Migrations
|
|||||||
b.ToTable("MessageViews");
|
b.ToTable("MessageViews");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.PrivateChat", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserAId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserBId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PrivateChats");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@@ -304,6 +350,25 @@ namespace Govor.Data.Migrations
|
|||||||
b.Navigation("User");
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.Friendship", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.User", "Addressee")
|
||||||
|
.WithMany("ReceivedFriendRequests")
|
||||||
|
.HasForeignKey("AddresseeId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Govor.Core.Models.User", "Requester")
|
||||||
|
.WithMany("SentFriendRequests")
|
||||||
|
.HasForeignKey("RequesterId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Addressee");
|
||||||
|
|
||||||
|
b.Navigation("Requester");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b =>
|
modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Govor.Core.Models.Message", "Message")
|
b.HasOne("Govor.Core.Models.Message", "Message")
|
||||||
@@ -317,6 +382,10 @@ namespace Govor.Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Govor.Core.Models.Message", b =>
|
modelBuilder.Entity("Govor.Core.Models.Message", b =>
|
||||||
{
|
{
|
||||||
|
b.HasOne("Govor.Core.Models.PrivateChat", null)
|
||||||
|
.WithMany("Messages")
|
||||||
|
.HasForeignKey("PrivateChatId");
|
||||||
|
|
||||||
b.HasOne("Govor.Core.Models.Message", "ReplyToMessage")
|
b.HasOne("Govor.Core.Models.Message", "ReplyToMessage")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ReplyToMessageId")
|
.HasForeignKey("ReplyToMessageId")
|
||||||
@@ -377,6 +446,18 @@ namespace Govor.Data.Migrations
|
|||||||
|
|
||||||
b.Navigation("Reactions");
|
b.Navigation("Reactions");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.PrivateChat", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Govor.Core.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ReceivedFriendRequests");
|
||||||
|
|
||||||
|
b.Navigation("SentFriendRequests");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public class UsersRepository : IUsersRepository
|
|||||||
{
|
{
|
||||||
return await _context.Users
|
return await _context.Users
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.ToListOrThrowIfEmpty(new NotFoundException("Users in Database not exists"));
|
.ToListOrThrowIfEmpty(new NotFoundException("Users in Database not exists"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +36,8 @@ public class UsersRepository : IUsersRepository
|
|||||||
return await _context.Users
|
return await _context.Users
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(u => u.Invite)
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.FirstOrDefaultAsync(x => x.Id == id)
|
.FirstOrDefaultAsync(x => x.Id == id)
|
||||||
?? throw new NotFoundByKeyException<Guid>(id, "User with given id does not exist");
|
?? throw new NotFoundByKeyException<Guid>(id, "User with given id does not exist");
|
||||||
}
|
}
|
||||||
@@ -46,6 +51,8 @@ public class UsersRepository : IUsersRepository
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(x => ids.Contains(x.Id))
|
.Where(x => ids.Contains(x.Id))
|
||||||
.Include(u => u.Invite)
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.ToListOrThrowIfEmpty(new NotFoundByKeyException<IEnumerable<Guid>>(ids,"Users with given ids not found"));
|
.ToListOrThrowIfEmpty(new NotFoundByKeyException<IEnumerable<Guid>>(ids,"Users with given ids not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +64,30 @@ public class UsersRepository : IUsersRepository
|
|||||||
return await _context.Users
|
return await _context.Users
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(u => u.Invite)
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.FirstOrDefaultAsync(x => x.Username == username)
|
.FirstOrDefaultAsync(x => x.Username == username)
|
||||||
?? throw new NotFoundByKeyException<string>(username, "User with given username does not exist");
|
?? throw new NotFoundByKeyException<string>(username, "User with given username does not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<User>> SearchPotentialFriendsAsync(Guid currentUserId, string query)
|
||||||
|
{
|
||||||
|
return await _context.Users
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
|
.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)))
|
||||||
|
.Take(20)
|
||||||
|
.OrderBy(u => u.Username)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<List<User>> FindByRangeUsernamesAsync(IEnumerable<string> usernames)
|
public async Task<List<User>> FindByRangeUsernamesAsync(IEnumerable<string> usernames)
|
||||||
{
|
{
|
||||||
if (usernames is null || !usernames.Any())
|
if (usernames is null || !usernames.Any())
|
||||||
@@ -70,6 +97,8 @@ public class UsersRepository : IUsersRepository
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(x => usernames.Contains(x.Username))
|
.Where(x => usernames.Contains(x.Username))
|
||||||
.Include(u => u.Invite)
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.ToListOrThrowIfEmpty(new NotFoundByKeyException<IEnumerable<string>>(usernames, "Users with given usernames not found"));
|
.ToListOrThrowIfEmpty(new NotFoundByKeyException<IEnumerable<string>>(usernames, "Users with given usernames not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +111,8 @@ public class UsersRepository : IUsersRepository
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(u => createdDate == u.CreatedOn)
|
.Where(u => createdDate == u.CreatedOn)
|
||||||
.Include(u => u.Invite)
|
.Include(u => u.Invite)
|
||||||
|
.Include(u => u.ReceivedFriendRequests)
|
||||||
|
.Include(u => u.SentFriendRequests)
|
||||||
.ToListOrThrowIfEmpty(new NotFoundByKeyException<DateOnly>(createdDate, "Users with given created date do not exist"));
|
.ToListOrThrowIfEmpty(new NotFoundByKeyException<DateOnly>(createdDate, "Users with given created date do not exist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user