From ac309245d21f16c06abe2d1d9bb260e094d0805e Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Apr 2021 19:37:11 +0800 Subject: refactor: ... --- .../Services/User/Avatar/UserAvatarService.cs | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs (limited to 'BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs') diff --git a/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs b/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs new file mode 100644 index 00000000..4f943e3a --- /dev/null +++ b/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs @@ -0,0 +1,154 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Entities; +using Timeline.Helpers.Cache; +using Timeline.Models; +using Timeline.Services.Data; +using Timeline.Services.Imaging; + +namespace Timeline.Services.User.Avatar +{ + public class UserAvatarService : IUserAvatarService + { + private readonly ILogger _logger; + private readonly DatabaseContext _database; + private readonly IBasicUserService _basicUserService; + private readonly IDefaultUserAvatarProvider _defaultUserAvatarProvider; + private readonly IImageService _imageService; + private readonly IDataManager _dataManager; + private readonly IClock _clock; + + public UserAvatarService( + ILogger logger, + DatabaseContext database, + IBasicUserService basicUserService, + IDefaultUserAvatarProvider defaultUserAvatarProvider, + IImageService imageValidator, + IDataManager dataManager, + IClock clock) + { + _logger = logger; + _database = database; + _basicUserService = basicUserService; + _defaultUserAvatarProvider = defaultUserAvatarProvider; + _imageService = imageValidator; + _dataManager = dataManager; + _clock = clock; + } + + public async Task GetAvatarDigest(long userId) + { + var usernameChangeTime = await _basicUserService.GetUsernameLastModifiedTimeAsync(userId); + + var entity = await _database.UserAvatars.Where(a => a.UserId == userId).Select(a => new { a.DataTag, a.LastModified }).SingleOrDefaultAsync(); + + if (entity is null) + { + var defaultAvatarDigest = await _defaultUserAvatarProvider.GetDefaultAvatarDigest(); + return new CacheableDataDigest(defaultAvatarDigest.ETag, new DateTime[] { usernameChangeTime, defaultAvatarDigest.LastModified }.Max()); + } + else if (entity.DataTag is null) + { + var defaultAvatarDigest = await _defaultUserAvatarProvider.GetDefaultAvatarDigest(); + return new CacheableDataDigest(defaultAvatarDigest.ETag, new DateTime[] { usernameChangeTime, defaultAvatarDigest.LastModified, entity.LastModified }.Max()); + } + else + { + return new CacheableDataDigest(entity.DataTag, new DateTime[] { usernameChangeTime, entity.LastModified }.Max()); + } + } + + public async Task GetAvatar(long userId) + { + await _basicUserService.ThrowIfUserNotExist(userId); + + var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); + + if (entity is null || entity.DataTag is null) + { + return await _defaultUserAvatarProvider.GetDefaultAvatar(); + } + + var data = await _dataManager.GetEntryAndCheck(entity.DataTag, $"This is required by avatar of {userId}."); + + if (entity.Type is null) + { + var format = await _imageService.DetectFormatAsync(data); + entity.Type = format.DefaultMimeType; + await _database.SaveChangesAsync(); + } + + return new ByteData(data, entity.Type); + } + + public async Task SetAvatar(long userId, ByteData avatar) + { + if (avatar is null) + throw new ArgumentNullException(nameof(avatar)); + + await _imageService.ValidateAsync(avatar.Data, avatar.ContentType, true); + + await _basicUserService.ThrowIfUserNotExist(userId); + + var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); + + await using var transaction = await _database.Database.BeginTransactionAsync(); + + var tag = await _dataManager.RetainEntryAsync(avatar.Data); + + var now = _clock.GetCurrentTime(); + + if (entity is null) + { + var newEntity = new UserAvatarEntity + { + DataTag = tag, + Type = avatar.ContentType, + LastModified = now, + UserId = userId + }; + _database.Add(newEntity); + } + else + { + if (entity.DataTag is not null) + await _dataManager.FreeEntryAsync(entity.DataTag); + + entity.DataTag = tag; + entity.Type = avatar.ContentType; + entity.LastModified = now; + } + + await _database.SaveChangesAsync(); + + await transaction.CommitAsync(); + + return new CacheableDataDigest(tag, now); + } + + public async Task DeleteAvatar(long userId) + { + await _basicUserService.ThrowIfUserNotExist(userId); + + var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); + + if (entity is null || entity.DataTag is null) + return; + + await using var transaction = await _database.Database.BeginTransactionAsync(); + + await _dataManager.FreeEntryAsync(entity.DataTag); + + entity.DataTag = null; + entity.Type = null; + entity.LastModified = _clock.GetCurrentTime(); + + await _database.SaveChangesAsync(); + + await transaction.CommitAsync(); + } + } +} -- cgit v1.2.3