From 36a5a7c81569bbc4fa76b77e9823767d951944b4 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 18 Aug 2019 18:07:50 +0800 Subject: Add avatar service. --- Timeline/Services/UserAvatarService.cs | 181 +++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 Timeline/Services/UserAvatarService.cs (limited to 'Timeline/Services/UserAvatarService.cs') diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs new file mode 100644 index 00000000..21153575 --- /dev/null +++ b/Timeline/Services/UserAvatarService.cs @@ -0,0 +1,181 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Entities; + +namespace Timeline.Services +{ + public class Avatar + { + public string Type { get; set; } + public byte[] Data { get; set; } + } + + /// + /// Thrown when avatar is of bad format. + /// + [Serializable] + public class AvatarDataException : Exception + { + public AvatarDataException(Avatar avatar, string message) : base(message) { Avatar = avatar; } + public AvatarDataException(Avatar avatar, string message, Exception inner) : base(message, inner) { Avatar = avatar; } + protected AvatarDataException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + + public Avatar Avatar { get; set; } + } + + /// + /// Provider for default user avatar. + /// + /// + /// Mainly for unit tests. + /// + public interface IDefaultUserAvatarProvider + { + /// + /// Get the default avatar. + /// + Task GetDefaultAvatar(); + } + + public interface IUserAvatarService + { + /// + /// Get avatar of a user. If the user has no avatar, a default one is returned. + /// + /// The username of the user to get avatar of. + /// The avatar. + /// Thrown if is null or empty. + /// Thrown if the user does not exist. + Task GetAvatar(string username); + + /// + /// Set avatar for a user. + /// + /// The username of the user to set avatar for. + /// The avatar. Can be null to delete the saved avatar. + /// Throw if is null or empty. + /// Or thrown if is not null but is null or empty or is null. + /// Thrown if the user does not exist. + /// Thrown if avatar is of bad format. + Task SetAvatar(string username, Avatar avatar); + } + + public class DefaultUserAvatarProvider : IDefaultUserAvatarProvider + { + private readonly IHostingEnvironment _environment; + + public DefaultUserAvatarProvider(IHostingEnvironment environment) + { + _environment = environment; + } + + public async Task GetDefaultAvatar() + { + return new Avatar + { + Type = "image/png", + Data = await File.ReadAllBytesAsync(Path.Combine(_environment.ContentRootPath, "default-avatar.png")) + }; + } + } + + public class UserAvatarService : IUserAvatarService + { + + private readonly ILogger _logger; + + private readonly DatabaseContext _database; + + private readonly IDefaultUserAvatarProvider _defaultUserAvatarProvider; + + public UserAvatarService(ILogger logger, DatabaseContext database, IDefaultUserAvatarProvider defaultUserAvatarProvider) + { + _logger = logger; + _database = database; + _defaultUserAvatarProvider = defaultUserAvatarProvider; + } + + public async Task GetAvatar(string username) + { + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("Username is null or empty.", nameof(username)); + + var user = await _database.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + if (user == null) + throw new UserNotExistException(username); + + await _database.Entry(user).Reference(u => u.Avatar).LoadAsync(); + var avatar = user.Avatar; + + if (avatar == null) + { + return await _defaultUserAvatarProvider.GetDefaultAvatar(); + } + else + { + return new Avatar + { + Type = avatar.Type, + Data = avatar.Data + }; + } + } + + public async Task SetAvatar(string username, Avatar avatar) + { + if (string.IsNullOrEmpty(username)) + throw new ArgumentException("Username is null or empty.", nameof(username)); + + if (avatar != null) + { + if (string.IsNullOrEmpty(avatar.Type)) + throw new ArgumentException("Type of avatar is null or empty.", nameof(avatar)); + if (avatar.Data == null) + throw new ArgumentException("Data of avatar is null.", nameof(avatar)); + } + + var user = await _database.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + if (user == null) + throw new UserNotExistException(username); + + await _database.Entry(user).Reference(u => u.Avatar).LoadAsync(); + var avatarEntity = user.Avatar; + + if (avatar == null) + { + if (avatarEntity == null) + return; + else + { + _database.UserAvatars.Remove(avatarEntity); + await _database.SaveChangesAsync(); + } + } + else + { + // TODO: Use image library to check the format to prohibit bad data. + if (avatarEntity == null) + { + user.Avatar = new UserAvatar + { + Type = avatar.Type, + Data = avatar.Data + }; + } + else + { + avatarEntity.Type = avatar.Type; + avatarEntity.Data = avatar.Data; + } + await _database.SaveChangesAsync(); + } + } + } +} -- cgit v1.2.3