mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
new app server and database + added hub and controller of user profile
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.RegularExpressions;
|
||||
using Govor.Application.Exceptions.AuthService;
|
||||
using Govor.Application.Interfaces.Authentication;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using Govor.Application.Profiles;
|
||||
|
||||
namespace Govor.Application.Interfaces;
|
||||
|
||||
public interface IProfileService
|
||||
{
|
||||
public Task<UserProfile> GetUserProfileAsync(Guid userId);
|
||||
public Task SetDescription(string description, Guid userId);
|
||||
public Task SetNewIcon(Guid userId, Guid iconId);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Govor.Core.Models;
|
||||
using Govor.Core.Models.Messages;
|
||||
|
||||
namespace Govor.Application.Interfaces.Medias;
|
||||
@@ -8,6 +9,7 @@ public interface IMediaService
|
||||
public Task DeleteMediaAsync(Guid fileId);
|
||||
public Task<Media> GetMediaByUrlAsync(string url);
|
||||
public Task<Media> GetMediaByIdAsync(Guid mediaId);
|
||||
Task AttachToMessageAsync(Guid mediaId, Guid messageId);
|
||||
}
|
||||
|
||||
public record Media(Guid UploaderId,
|
||||
@@ -16,6 +18,8 @@ public record Media(Guid UploaderId,
|
||||
byte[] Data,
|
||||
MediaType Type,
|
||||
string MimeType,
|
||||
string EncryptedKey);
|
||||
string EncryptedKey,
|
||||
MediaOwnerType OwnerType,
|
||||
Guid? OwnerId);
|
||||
|
||||
public record MediaUploadResult(Guid? MediaId, string Url);
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Govor.Application.Profiles;
|
||||
|
||||
public class UserProfile
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public Guid? IconId { get; set; }
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class AuthService : IAccountService
|
||||
PasswordHash = passwordHash,
|
||||
Description = string.Empty,
|
||||
CreatedOn = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||
IconId = Guid.NewGuid(),
|
||||
IconId = Guid.Empty,
|
||||
WasOnline = DateTime.UtcNow,
|
||||
InviteId = invitation.Id
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ public class LocalStorageService : IStorageService
|
||||
var fullPath = Path.Combine(folder, uniqueFileName);
|
||||
|
||||
await using var stream = new FileStream(fullPath, FileMode.Create);
|
||||
stream.WriteAsync(data, 0, data.Length);
|
||||
await stream.WriteAsync(data, 0, data.Length);
|
||||
|
||||
return Path.Combine(date, uniqueFileName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Govor.Application.Interfaces.Medias;
|
||||
using Govor.Core.Models.Messages;
|
||||
using Govor.Core.Models;
|
||||
using Govor.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -14,20 +14,35 @@ public class AccesserToDownloadMediaService : IAccesserToDownloadMedia
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<bool> HasAccessAsync(Guid mediaFileId, Guid userId)
|
||||
public async Task<bool> HasAccessAsync(Guid mediaId, Guid userId)
|
||||
{
|
||||
return await _dbContext.MediaAttachments
|
||||
.Include(ma => ma.Message)
|
||||
.AnyAsync(ma =>
|
||||
ma.MediaFileId == mediaFileId &&
|
||||
(
|
||||
(ma.Message.RecipientType == RecipientType.User &&
|
||||
(ma.Message.SenderId == userId || ma.Message.RecipientId == userId))
|
||||
||
|
||||
(ma.Message.RecipientType == RecipientType.Group &&
|
||||
_dbContext.GroupMemberships.Any(gm =>
|
||||
gm.GroupId == ma.Message.RecipientId &&
|
||||
gm.UserId == userId))
|
||||
));
|
||||
var media = await _dbContext.MediaFiles
|
||||
.AsNoTracking()
|
||||
.Where(m => m.Id == mediaId)
|
||||
.Select(m => new { m.OwnerType, m.OwnerId, m.UploaderId })
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (media is null)
|
||||
return false;
|
||||
|
||||
return media.OwnerType switch
|
||||
{
|
||||
MediaOwnerType.Avatar => true, // media.OwnerId == userId
|
||||
MediaOwnerType.GroupAvatar => await _dbContext.GroupMemberships
|
||||
.AnyAsync(gm => gm.GroupId == media.OwnerId && gm.UserId == userId),
|
||||
|
||||
MediaOwnerType.Message => await _dbContext.MediaAttachments
|
||||
.AnyAsync(ma =>
|
||||
ma.MediaFileId == mediaId &&
|
||||
(
|
||||
ma.Message.SenderId == userId ||
|
||||
ma.Message.RecipientId == userId ||
|
||||
_dbContext.GroupMemberships.Any(gm =>
|
||||
gm.GroupId == ma.Message.RecipientId && gm.UserId == userId)
|
||||
)),
|
||||
|
||||
MediaOwnerType.System => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,9 @@ public class MediaService : IMediaService
|
||||
DateCreated = file.UploadedOn,
|
||||
MediaType = file.Type,
|
||||
MineType = file.MimeType,
|
||||
Url = url
|
||||
Url = url,
|
||||
OwnerType = file.OwnerType,
|
||||
OwnerId = file.OwnerId,
|
||||
});
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
@@ -87,7 +89,9 @@ public class MediaService : IMediaService
|
||||
contentBytes,
|
||||
mediaFile.MediaType,
|
||||
mediaFile.MineType,
|
||||
string.Empty
|
||||
string.Empty,
|
||||
mediaFile.OwnerType,
|
||||
mediaFile.OwnerId
|
||||
);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
@@ -96,4 +100,24 @@ public class MediaService : IMediaService
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public async Task AttachToMessageAsync(Guid mediaId, Guid messageId)
|
||||
{
|
||||
var mediaFile = await _dbContext.MediaFiles
|
||||
.FirstOrDefaultAsync(x => x.Id == mediaId)
|
||||
?? throw new KeyNotFoundException($"No media found by given id {mediaId}");
|
||||
|
||||
if (mediaFile.OwnerType != MediaOwnerType.Message)
|
||||
{
|
||||
_logger.LogWarning("Attempt to attach already owned media {MediaId}", mediaId);
|
||||
throw new InvalidOperationException($"Media {mediaId} is already attached to {mediaFile.OwnerType}");
|
||||
}
|
||||
|
||||
mediaFile.OwnerType = MediaOwnerType.Message;
|
||||
mediaFile.OwnerId = messageId;
|
||||
|
||||
_dbContext.MediaFiles.Update(mediaFile);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("Media {MediaId} successfully attached to message {MessageId}", mediaId, messageId);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Interfaces.Medias;
|
||||
using Govor.Application.Interfaces.Messages;
|
||||
using Govor.Application.Interfaces.Messages.Parameters;
|
||||
using Govor.Core.Models;
|
||||
@@ -18,7 +19,8 @@ public class MessageCommandService : IMessageCommandService
|
||||
private readonly IUsersRepository _usersRepository;
|
||||
private readonly IGroupsRepository _groupsRepository;
|
||||
private readonly IPrivateChatsRepository _privateChats;
|
||||
private readonly IVerifyFriendship _verifyFriendship;
|
||||
private readonly IVerifyFriendship _verifyFriendship;
|
||||
private readonly IMediaService _mediaService;
|
||||
private readonly ILogger<MessageCommandService> _logger;
|
||||
|
||||
public MessageCommandService(
|
||||
@@ -27,6 +29,7 @@ public class MessageCommandService : IMessageCommandService
|
||||
IGroupsRepository groupsRepository,
|
||||
IVerifyFriendship verifyFriendship,
|
||||
IPrivateChatsRepository privateChats,
|
||||
IMediaService mediaService,
|
||||
ILogger<MessageCommandService> logger)
|
||||
{
|
||||
_messagesRepository = messagesRepository;
|
||||
@@ -34,6 +37,7 @@ public class MessageCommandService : IMessageCommandService
|
||||
_groupsRepository = groupsRepository;
|
||||
_verifyFriendship = verifyFriendship;
|
||||
_privateChats = privateChats;
|
||||
_mediaService = mediaService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -97,6 +101,15 @@ public class MessageCommandService : IMessageCommandService
|
||||
}).ToList() ?? new List<MediaAttachments>()
|
||||
};
|
||||
|
||||
// If there is media, we link them.
|
||||
if (sendParams.Media != null && sendParams.Media.Any())
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using Govor.Application.Interfaces;
|
||||
using Govor.Application.Profiles;
|
||||
using Govor.Core.Repositories.Users;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Govor.Application.Services;
|
||||
|
||||
public class ProfileService : IProfileService
|
||||
{
|
||||
private readonly ILogger<ProfileService> _logger;
|
||||
private readonly IUsersRepository _userRepository;
|
||||
|
||||
public ProfileService(IUsersRepository userRepository, ILogger<ProfileService> logger)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<UserProfile> GetUserProfileAsync(Guid userId)
|
||||
{
|
||||
_logger.LogInformation("Gettings user {userId} profile", userId);
|
||||
var user = await _userRepository.FindByIdAsync(userId);
|
||||
|
||||
return new UserProfile
|
||||
{
|
||||
Id = user.Id,
|
||||
Username = user.Username,
|
||||
Description = user.Description,
|
||||
IconId = user.IconId
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class VerifyFriendship : IVerifyFriendship
|
||||
private readonly ILogger<VerifyFriendship> _logger;
|
||||
private const string FriendshipNotAcceptedError = "Friendship between user {0} and friend {1} does not exist or is not accepted.";
|
||||
|
||||
public VerifyFriendship(IFriendshipsRepository friendshipsRepository, ILogger<VerifyFriendship> logger = null)
|
||||
public VerifyFriendship(IFriendshipsRepository friendshipsRepository, ILogger<VerifyFriendship> logger)
|
||||
{
|
||||
_friendshipsRepository = friendshipsRepository ?? throw new ArgumentNullException(nameof(friendshipsRepository));
|
||||
_logger = logger;
|
||||
@@ -42,14 +42,16 @@ public class VerifyFriendship : IVerifyFriendship
|
||||
throw new FriendshipException(errorMessage);
|
||||
}
|
||||
|
||||
_logger?.LogInformation(
|
||||
_logger.LogInformation("hello");
|
||||
|
||||
_logger.LogInformation(
|
||||
"Friendship verified successfully for targetUserId={TargetUserId}, friendUserId={FriendUserId}",
|
||||
targetUserId, friendUserId);
|
||||
}
|
||||
catch (NotFoundByKeyException<Guid> ex)
|
||||
{
|
||||
var errorMessage = string.Format(FriendshipNotAcceptedError, targetUserId, friendUserId);
|
||||
_logger?.LogError(errorMessage);
|
||||
_logger.LogError(errorMessage);
|
||||
|
||||
throw new FriendshipException(errorMessage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user