Add friendship feature with models, repository, and tests

Introduces Friendship and PrivateChat models, repository interfaces, and implementations for managing friendships. Adds validators and comprehensive unit and integration tests for friendship logic. Updates InviteUserController with new endpoints and restricts access to admin role. Removes unnecessary project references from Govor.API.csproj and registers new DbSets in GovorDbContext.
This commit is contained in:
Artemy
2025-06-27 15:09:28 +07:00
parent 4f3f4ec066
commit 9b9cd73a96
15 changed files with 565 additions and 20 deletions
+2
View File
@@ -8,6 +8,8 @@ namespace Govor.Data;
public class GovorDbContext(DbContextOptions<GovorDbContext> options) : DbContext(options)
{
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Friendship> Friendships { get; set; }
public virtual DbSet<PrivateChat> PrivateChats { get; set; }
public virtual DbSet<Admin> Admins { get; set; }
public virtual DbSet<Invitation> Invitations { get; set; }
@@ -0,0 +1,119 @@
using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models;
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<Friendship> _validator;
public FriendshipsRepository(GovorDbContext context, IObjectValidator<Friendship> validator)
{
_context = context;
_validator = validator;
}
public async Task<List<Friendship>> GetAllAsync()
{
return await _context.Friendships
.AsNoTracking()
.Include(x => x.Requester)
.Include(x => x.Addressee)
.ToListOrThrowIfEmpty(new NotFoundException("Database is empty"));
}
public async Task<Friendship> GetByIdAsync(Guid id)
{
return await _context.Friendships
.AsNoTracking()
.Include(x => x.Requester)
.Include(x => x.Addressee)
.FirstOrDefaultAsync(x => x.Id == id)
?? throw new NotFoundByKeyException<Guid>(id, "Friendship with given id was not found");
}
public async Task<List<Friendship>> FindByUserIdAsync(Guid userId)
{
return await _context.Friendships
.AsNoTracking()
.Include(x => x.Requester)
.Include(x => x.Addressee)
.Where(x => x.RequesterId == userId)
.ToListOrThrowIfEmpty(new NotFoundByKeyException<Guid>(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<Admin> 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 NotFoundByKeyException<Guid>(friendship.Id);
}
catch (NotFoundByKeyException<Guid> ex)
{
throw new UpdateException($"Not found friendship by given id {friendship.Id}", ex);
}
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<Guid> 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));
}
}