From 34305283aca89b8b2ebacd26ad3faf859a6a78b0 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 25 Mar 2022 20:20:47 +0800 Subject: … MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BackEnd/Timeline.Tests/Services/ServiceTestBase.cs | 2 +- .../Services/Api/BookmarkTimelineService.cs | 6 +- .../Services/Api/HighlightTimelineService.cs | 6 +- BackEnd/Timeline/Services/EntityType.cs | 25 +++- .../Services/Timeline/BasicTimelineService.cs | 131 --------------------- .../Timeline/BasicTimelineServiceExtensions.cs | 17 --- .../Services/Timeline/IBasicTimelineService.cs | 30 ----- .../Timeline/Services/Timeline/ITimelineService.cs | 23 +++- .../Services/Timeline/TimelinePostService.cs | 6 +- .../Timeline/Services/Timeline/TimelineService.cs | 109 ++++++++++++++++- .../Services/Timeline/TimelineServiceExtensions.cs | 11 +- .../TimelineServicesServiceCollectionExtensions.cs | 1 - .../Services/User/Avatar/UserAvatarService.cs | 14 +-- BackEnd/Timeline/Services/User/BasicUserService.cs | 65 ---------- .../Services/User/BasicUserServiceExtensions.cs | 17 --- .../Timeline/Services/User/CreateTokenResult.cs | 12 -- .../Timeline/Services/User/IBasicUserService.cs | 36 ------ BackEnd/Timeline/Services/User/IUserService.cs | 29 ++++- .../Services/User/UserPermissionService.cs | 8 +- BackEnd/Timeline/Services/User/UserService.cs | 71 ++++++++--- .../Services/User/UserServiceExtensions.cs | 17 +++ .../UserServicesServiceCollectionExtensions.cs | 1 - 22 files changed, 278 insertions(+), 359 deletions(-) delete mode 100644 BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs delete mode 100644 BackEnd/Timeline/Services/User/BasicUserService.cs delete mode 100644 BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs delete mode 100644 BackEnd/Timeline/Services/User/CreateTokenResult.cs delete mode 100644 BackEnd/Timeline/Services/User/IBasicUserService.cs create mode 100644 BackEnd/Timeline/Services/User/UserServiceExtensions.cs diff --git a/BackEnd/Timeline.Tests/Services/ServiceTestBase.cs b/BackEnd/Timeline.Tests/Services/ServiceTestBase.cs index fea31d0a..039d3f59 100644 --- a/BackEnd/Timeline.Tests/Services/ServiceTestBase.cs +++ b/BackEnd/Timeline.Tests/Services/ServiceTestBase.cs @@ -43,7 +43,7 @@ namespace Timeline.Tests.Services UserTokenService = UserTokenServiceMock.Object; UserService = new UserService(NullLogger.Instance, Database, new PasswordService(), UserTokenService, Clock); - TimelineService = new TimelineService(NullLoggerFactory.Instance, Database, UserService, Clock); + TimelineService = new TimelineService(NullLogger.Instance, Database, UserService, Clock); UserId = await UserService.GetUserIdByUsernameAsync("user"); AdminId = await UserService.GetUserIdByUsernameAsync("admin"); diff --git a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs index 9d6ec93f..b48f99c9 100644 --- a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs @@ -12,10 +12,10 @@ namespace Timeline.Services.Api public class BookmarkTimelineService : IBookmarkTimelineService { private readonly DatabaseContext _database; - private readonly IBasicUserService _userService; - private readonly IBasicTimelineService _timelineService; + private readonly IUserService _userService; + private readonly ITimelineService _timelineService; - public BookmarkTimelineService(DatabaseContext database, IBasicUserService userService, IBasicTimelineService timelineService) + public BookmarkTimelineService(DatabaseContext database, IUserService userService, ITimelineService timelineService) { _database = database; _userService = userService; diff --git a/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs b/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs index eb606ae6..837f3091 100644 --- a/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs @@ -11,11 +11,11 @@ namespace Timeline.Services.Api public class HighlightTimelineService : IHighlightTimelineService { private readonly DatabaseContext _database; - private readonly IBasicUserService _userService; - private readonly IBasicTimelineService _timelineService; + private readonly IUserService _userService; + private readonly ITimelineService _timelineService; private readonly IClock _clock; - public HighlightTimelineService(DatabaseContext database, IBasicUserService userService, IBasicTimelineService timelineService, IClock clock) + public HighlightTimelineService(DatabaseContext database, IUserService userService, ITimelineService timelineService, IClock clock) { _database = database; _userService = userService; diff --git a/BackEnd/Timeline/Services/EntityType.cs b/BackEnd/Timeline/Services/EntityType.cs index c379d211..5111904f 100644 --- a/BackEnd/Timeline/Services/EntityType.cs +++ b/BackEnd/Timeline/Services/EntityType.cs @@ -1,8 +1,9 @@ -using System.Reflection; +using System; +using System.Reflection; namespace Timeline.Services { - public class EntityType + public class EntityType : IEquatable { public EntityType(string name) { @@ -29,6 +30,24 @@ namespace Timeline.Services if (field is not null) return (int)field.GetRawConstantValue()!; return ErrorCodes.Conflict.Default; } - } + } + + public bool Equals(EntityType? other) + { + if (other is null) + return false; + + return other.Name.Equals(other.Name); + } + + public override bool Equals(object? obj) + { + return Equals(obj as EntityType); + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } } } diff --git a/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs b/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs deleted file mode 100644 index 360f6c63..00000000 --- a/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs +++ /dev/null @@ -1,131 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Models; -using Timeline.Models.Validation; -using Timeline.Services.User; - -namespace Timeline.Services.Timeline -{ - public class BasicTimelineService : IBasicTimelineService - { - private readonly ILogger _logger; - - private readonly DatabaseContext _database; - - private readonly IBasicUserService _basicUserService; - private readonly IClock _clock; - - private readonly GeneralTimelineNameValidator _generalTimelineNameValidator = new GeneralTimelineNameValidator(); - - public BasicTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IBasicUserService basicUserService, IClock clock) - { - _logger = loggerFactory.CreateLogger(); - _database = database; - _basicUserService = basicUserService; - _clock = clock; - } - - protected TimelineEntity CreateNewTimelineEntity(string? name, long ownerId) - { - var currentTime = _clock.GetCurrentTime(); - - return new TimelineEntity - { - Name = name, - NameLastModified = currentTime, - OwnerId = ownerId, - Visibility = TimelineVisibility.Register, - CreateTime = currentTime, - LastModified = currentTime, - CurrentPostLocalId = 0, - Members = new List() - }; - } - - protected static EntityNotExistException CreateTimelineNotExistException(string name, Exception? inner = null) - { - return new EntityNotExistException(EntityTypes.Timeline, new Dictionary - { - ["name"] = name - }, null, inner); - } - - protected static EntityNotExistException CreateTimelineNotExistException(long id) - { - return new EntityNotExistException(EntityTypes.Timeline, new Dictionary - { - ["id"] = id - }); - } - - protected void CheckGeneralTimelineName(string timelineName, string? paramName) - { - if (!_generalTimelineNameValidator.Validate(timelineName, out var message)) - throw new ArgumentException(string.Format(Resource.ExceptionGeneralTimelineNameBadFormat, message), paramName); - } - - public async Task CheckTimelineExistenceAsync(long id) - { - return await _database.Timelines.AnyAsync(t => t.Id == id); - } - - public async Task GetTimelineIdByNameAsync(string timelineName) - { - if (timelineName == null) - throw new ArgumentNullException(nameof(timelineName)); - - CheckGeneralTimelineName(timelineName, nameof(timelineName)); - - var name = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - - if (isPersonal) - { - var username = name; - long userId; - try - { - userId = await _basicUserService.GetUserIdByUsernameAsync(username); - } - catch (EntityNotExistException e) - { - throw CreateTimelineNotExistException(timelineName, e); - } - - var timelineEntity = await _database.Timelines.Where(t => t.OwnerId == userId && t.Name == null).Select(t => new { t.Id }).SingleOrDefaultAsync(); - - if (timelineEntity != null) - { - return timelineEntity.Id; - } - else - { - var newTimelineEntity = CreateNewTimelineEntity(null, userId); - _database.Timelines.Add(newTimelineEntity); - await _database.SaveChangesAsync(); - - _logger.LogInformation(Resource.LogPersonalTimelineAutoCreate, username); - - return newTimelineEntity.Id; - } - } - else - { - var timelineEntity = await _database.Timelines.Where(t => t.Name == timelineName).Select(t => new { t.Id }).SingleOrDefaultAsync(); - - if (timelineEntity == null) - { - throw CreateTimelineNotExistException(timelineName); - } - else - { - return timelineEntity.Id; - } - } - } - } -} diff --git a/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs b/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs deleted file mode 100644 index 4075c9c0..00000000 --- a/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Timeline.Services.Timeline -{ - public static class BasicTimelineServiceExtensions - { - public static async Task ThrowIfTimelineNotExist(this IBasicTimelineService service, long timelineId) - { - if (!await service.CheckTimelineExistenceAsync(timelineId)) - { - throw new EntityNotExistException(EntityTypes.Timeline, - new Dictionary { ["id"] = timelineId }); - } - } - } -} diff --git a/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs b/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs deleted file mode 100644 index b6f1e6de..00000000 --- a/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Timeline.Services.Timeline -{ - /// - /// This service provide some basic timeline functions, which should be used internally for other services. - /// - public interface IBasicTimelineService - { - /// - /// Check whether a timeline with given id exists without getting full info. - /// - /// The timeline id. - /// True if exist. Otherwise false. - Task CheckTimelineExistenceAsync(long id); - - /// - /// Get the timeline id by name. - /// - /// Timeline name. - /// Id of the timeline. - /// Thrown when is null. - /// Throw when is of bad format. - /// - /// Thrown when timeline with name does not exist. - /// - Task GetTimelineIdByNameAsync(string timelineName); - } -} diff --git a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs index c5bd5abf..62117903 100644 --- a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs +++ b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs @@ -9,8 +9,27 @@ namespace Timeline.Services.Timeline /// /// This define the interface of both personal timeline and ordinary timeline. /// - public interface ITimelineService : IBasicTimelineService - { + public interface ITimelineService + { + /// + /// Check whether a timeline with given id exists without getting full info. + /// + /// The timeline id. + /// True if exist. Otherwise false. + Task CheckTimelineExistenceAsync(long id); + + /// + /// Get the timeline id by name. + /// + /// Timeline name. + /// Id of the timeline. + /// Thrown when is null. + /// Throw when is of bad format. + /// + /// Thrown when timeline with name does not exist. + /// + Task GetTimelineIdByNameAsync(string timelineName); + /// /// Get the timeline info. /// diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs index ae034767..e6297d2c 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs @@ -20,15 +20,15 @@ namespace Timeline.Services.Timeline { private readonly ILogger _logger; private readonly DatabaseContext _database; - private readonly IBasicTimelineService _basicTimelineService; - private readonly IBasicUserService _basicUserService; + private readonly ITimelineService _basicTimelineService; + private readonly IUserService _basicUserService; private readonly IDataManager _dataManager; private readonly IImageService _imageValidator; private readonly IClock _clock; private readonly ColorValidator _colorValidator = new ColorValidator(); private readonly ColorValidator _colorValidatorAllowEmptyAndDefault = new ColorValidator() { PermitEmpty = true, PermitDefault = true }; - public TimelinePostService(ILogger logger, DatabaseContext database, IBasicTimelineService basicTimelineService, IBasicUserService basicUserService, IDataManager dataManager, IImageService imageValidator, IClock clock) + public TimelinePostService(ILogger logger, DatabaseContext database, ITimelineService basicTimelineService, IUserService basicUserService, IDataManager dataManager, IImageService imageValidator, IClock clock) { _logger = logger; _database = database; diff --git a/BackEnd/Timeline/Services/Timeline/TimelineService.cs b/BackEnd/Timeline/Services/Timeline/TimelineService.cs index 6f22ff05..82713eb1 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineService.cs @@ -12,23 +12,23 @@ using Timeline.Services.User; namespace Timeline.Services.Timeline { - public class TimelineService : BasicTimelineService, ITimelineService + public class TimelineService : ITimelineService { private readonly ILogger _logger; private readonly DatabaseContext _database; - private readonly IBasicUserService _userService; + private readonly IUserService _userService; private readonly IClock _clock; + private readonly GeneralTimelineNameValidator _generalTimelineNameValidator = new GeneralTimelineNameValidator(); private readonly TimelineNameValidator _timelineNameValidator = new TimelineNameValidator(); private readonly ColorValidator _colorValidator = new ColorValidator() { PermitDefault = true, PermitEmpty = true }; - public TimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IBasicUserService userService, IClock clock) - : base(loggerFactory, database, userService, clock) + public TimelineService(ILogger logger, DatabaseContext database, IUserService userService, IClock clock) { - _logger = loggerFactory.CreateLogger(); + _logger = logger; _database = database; _userService = userService; _clock = clock; @@ -48,8 +48,107 @@ namespace Timeline.Services.Timeline { throw new ArgumentException(string.Format(Resource.ExceptionTimelineNameBadFormat, message), paramName); } + } + + protected TimelineEntity CreateNewTimelineEntity(string? name, long ownerId) + { + var currentTime = _clock.GetCurrentTime(); + + return new TimelineEntity + { + Name = name, + NameLastModified = currentTime, + OwnerId = ownerId, + Visibility = TimelineVisibility.Register, + CreateTime = currentTime, + LastModified = currentTime, + CurrentPostLocalId = 0, + Members = new List() + }; + } + + protected static EntityNotExistException CreateTimelineNotExistException(string name, Exception? inner = null) + { + return new EntityNotExistException(EntityTypes.Timeline, new Dictionary + { + ["name"] = name + }, null, inner); + } + + protected static EntityNotExistException CreateTimelineNotExistException(long id) + { + return new EntityNotExistException(EntityTypes.Timeline, new Dictionary + { + ["id"] = id + }); + } + + protected void CheckGeneralTimelineName(string timelineName, string? paramName) + { + if (!_generalTimelineNameValidator.Validate(timelineName, out var message)) + throw new ArgumentException(string.Format(Resource.ExceptionGeneralTimelineNameBadFormat, message), paramName); + } + + public async Task CheckTimelineExistenceAsync(long id) + { + return await _database.Timelines.AnyAsync(t => t.Id == id); + } + + public async Task GetTimelineIdByNameAsync(string timelineName) + { + if (timelineName == null) + throw new ArgumentNullException(nameof(timelineName)); + + CheckGeneralTimelineName(timelineName, nameof(timelineName)); + + var name = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); + + if (isPersonal) + { + var username = name; + long userId; + try + { + userId = await _userService.GetUserIdByUsernameAsync(username); + } + catch (EntityNotExistException e) + { + throw CreateTimelineNotExistException(timelineName, e); + } + + var timelineEntity = await _database.Timelines.Where(t => t.OwnerId == userId && t.Name == null).Select(t => new { t.Id }).SingleOrDefaultAsync(); + + if (timelineEntity != null) + { + return timelineEntity.Id; + } + else + { + var newTimelineEntity = CreateNewTimelineEntity(null, userId); + _database.Timelines.Add(newTimelineEntity); + await _database.SaveChangesAsync(); + + _logger.LogInformation(Resource.LogPersonalTimelineAutoCreate, username); + + return newTimelineEntity.Id; + } + } + else + { + var timelineEntity = await _database.Timelines.Where(t => t.Name == timelineName).Select(t => new { t.Id }).SingleOrDefaultAsync(); + + if (timelineEntity == null) + { + throw CreateTimelineNotExistException(timelineName); + } + else + { + return timelineEntity.Id; + } + } } + public async Task GetTimelineAsync(long id) { var entity = await _database.Timelines.Where(t => t.Id == id).SingleOrDefaultAsync(); diff --git a/BackEnd/Timeline/Services/Timeline/TimelineServiceExtensions.cs b/BackEnd/Timeline/Services/Timeline/TimelineServiceExtensions.cs index 7b745168..48f63a5f 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineServiceExtensions.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineServiceExtensions.cs @@ -5,7 +5,16 @@ using Timeline.Entities; namespace Timeline.Services.Timeline { public static class TimelineServiceExtensions - { + { + public static async Task ThrowIfTimelineNotExist(this ITimelineService service, long timelineId) + { + if (!await service.CheckTimelineExistenceAsync(timelineId)) + { + throw new EntityNotExistException(EntityTypes.Timeline, + new Dictionary { ["id"] = timelineId }); + } + } + public static async Task> GetTimelineList(this ITimelineService service, IEnumerable ids) { var timelines = new List(); diff --git a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs index 97b313cd..41c8e246 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs @@ -7,7 +7,6 @@ namespace Timeline.Services.Timeline { public static IServiceCollection AddTimelineServices(this IServiceCollection services) { - services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); diff --git a/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs b/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs index 92979a68..8b1a69a0 100644 --- a/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs +++ b/BackEnd/Timeline/Services/User/Avatar/UserAvatarService.cs @@ -15,7 +15,7 @@ namespace Timeline.Services.User.Avatar { private readonly ILogger _logger; private readonly DatabaseContext _database; - private readonly IBasicUserService _basicUserService; + private readonly IUserService _userService; private readonly IDefaultUserAvatarProvider _defaultUserAvatarProvider; private readonly IImageService _imageService; private readonly IDataManager _dataManager; @@ -24,7 +24,7 @@ namespace Timeline.Services.User.Avatar public UserAvatarService( ILogger logger, DatabaseContext database, - IBasicUserService basicUserService, + IUserService basicUserService, IDefaultUserAvatarProvider defaultUserAvatarProvider, IImageService imageValidator, IDataManager dataManager, @@ -32,7 +32,7 @@ namespace Timeline.Services.User.Avatar { _logger = logger; _database = database; - _basicUserService = basicUserService; + _userService = basicUserService; _defaultUserAvatarProvider = defaultUserAvatarProvider; _imageService = imageValidator; _dataManager = dataManager; @@ -41,7 +41,7 @@ namespace Timeline.Services.User.Avatar public async Task GetAvatarDigestAsync(long userId) { - var usernameChangeTime = await _basicUserService.GetUsernameLastModifiedTimeAsync(userId); + var usernameChangeTime = await _userService.GetUsernameLastModifiedTimeAsync(userId); var entity = await _database.UserAvatars.Where(a => a.UserId == userId).Select(a => new { a.DataTag, a.LastModified }).SingleOrDefaultAsync(); @@ -63,7 +63,7 @@ namespace Timeline.Services.User.Avatar public async Task GetAvatarAsync(long userId) { - await _basicUserService.ThrowIfUserNotExist(userId); + await _userService.ThrowIfUserNotExist(userId); var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); @@ -91,7 +91,7 @@ namespace Timeline.Services.User.Avatar await _imageService.ValidateAsync(avatar.Data, avatar.ContentType, true); - await _basicUserService.ThrowIfUserNotExist(userId); + await _userService.ThrowIfUserNotExist(userId); var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); @@ -133,7 +133,7 @@ namespace Timeline.Services.User.Avatar public async Task DeleteAvatarAsync(long userId) { - await _basicUserService.ThrowIfUserNotExist(userId); + await _userService.ThrowIfUserNotExist(userId); var entity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync(); diff --git a/BackEnd/Timeline/Services/User/BasicUserService.cs b/BackEnd/Timeline/Services/User/BasicUserService.cs deleted file mode 100644 index 0ee8dabd..00000000 --- a/BackEnd/Timeline/Services/User/BasicUserService.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Models.Validation; - -namespace Timeline.Services.User -{ - public class BasicUserService : IBasicUserService - { - private readonly DatabaseContext _database; - - private readonly UsernameValidator _usernameValidator = new UsernameValidator(); - - public BasicUserService(DatabaseContext database) - { - _database = database; - } - - protected static EntityNotExistException CreateUserNotExistException(string username) - { - return new EntityNotExistException(EntityTypes.User, - new Dictionary { ["username"] = username }); - } - - protected static EntityNotExistException CreateUserNotExistException(long id) - { - return new EntityNotExistException(EntityTypes.User, - new Dictionary { ["id"] = id }); - } - - public async Task CheckUserExistenceAsync(long id) - { - return await _database.Users.AnyAsync(u => u.Id == id); - } - - public async Task GetUserIdByUsernameAsync(string username) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - - if (!_usernameValidator.Validate(username, out var message)) - throw new ArgumentException(message); - - var entity = await _database.Users.Where(user => user.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync(); - - if (entity == null) - throw CreateUserNotExistException(username); - - return entity.Id; - } - - public async Task GetUsernameLastModifiedTimeAsync(long userId) - { - var entity = await _database.Users.Where(u => u.Id == userId).Select(u => new { u.UsernameChangeTime }).SingleOrDefaultAsync(); - - if (entity is null) - throw CreateUserNotExistException(userId); - - return entity.UsernameChangeTime; - } - } -} diff --git a/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs b/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs deleted file mode 100644 index 8a05f452..00000000 --- a/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Timeline.Services.User -{ - public static class BasicUserServiceExtensions - { - public static async Task ThrowIfUserNotExist(this IBasicUserService service, long userId) - { - if (!await service.CheckUserExistenceAsync(userId)) - { - throw new EntityNotExistException(EntityTypes.User, - new Dictionary { ["id"] = userId }); - } - } - } -} diff --git a/BackEnd/Timeline/Services/User/CreateTokenResult.cs b/BackEnd/Timeline/Services/User/CreateTokenResult.cs deleted file mode 100644 index b71a9e9e..00000000 --- a/BackEnd/Timeline/Services/User/CreateTokenResult.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Timeline.Entities; - -namespace Timeline.Services.User -{ - public class CreateTokenResult - { - public string Token { get; set; } = default!; - public UserEntity User { get; set; } = default!; - } -} - diff --git a/BackEnd/Timeline/Services/User/IBasicUserService.cs b/BackEnd/Timeline/Services/User/IBasicUserService.cs deleted file mode 100644 index 0ae3fdff..00000000 --- a/BackEnd/Timeline/Services/User/IBasicUserService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Timeline.Services.User -{ - /// - /// This service provide some basic user features, which should be used internally for other services. - /// - public interface IBasicUserService - { - /// - /// Check if a user exists. - /// - /// The id of the user. - /// True if exists. Otherwise false. - Task CheckUserExistenceAsync(long id); - - /// - /// Get the user id of given username. - /// - /// Username of the user. - /// The id of the user. - /// Thrown when is null. - /// Thrown when is of bad format. - /// Thrown when the user with given username does not exist. - Task GetUserIdByUsernameAsync(string username); - - /// - /// Get the username modified time of a user. - /// - /// User id. - /// The time. - /// Thrown when user does not exist. - Task GetUsernameLastModifiedTimeAsync(long userId); - } -} diff --git a/BackEnd/Timeline/Services/User/IUserService.cs b/BackEnd/Timeline/Services/User/IUserService.cs index 745bd524..6ea9a4d2 100644 --- a/BackEnd/Timeline/Services/User/IUserService.cs +++ b/BackEnd/Timeline/Services/User/IUserService.cs @@ -5,8 +5,33 @@ using Timeline.Entities; namespace Timeline.Services.User { - public interface IUserService : IBasicUserService - { + public interface IUserService + { + /// + /// Check if a user exists. + /// + /// The id of the user. + /// True if exists. Otherwise false. + Task CheckUserExistenceAsync(long id); + + /// + /// Get the user id of given username. + /// + /// Username of the user. + /// The id of the user. + /// Thrown when is null. + /// Thrown when is of bad format. + /// Thrown when the user with given username does not exist. + Task GetUserIdByUsernameAsync(string username); + + /// + /// Get the username modified time of a user. + /// + /// User id. + /// The time. + /// Thrown when user does not exist. + Task GetUsernameLastModifiedTimeAsync(long userId); + /// /// Try to get a user by id. /// diff --git a/BackEnd/Timeline/Services/User/UserPermissionService.cs b/BackEnd/Timeline/Services/User/UserPermissionService.cs index f6f11c61..69c23b84 100644 --- a/BackEnd/Timeline/Services/User/UserPermissionService.cs +++ b/BackEnd/Timeline/Services/User/UserPermissionService.cs @@ -8,19 +8,19 @@ namespace Timeline.Services.User public class UserPermissionService : IUserPermissionService { private readonly DatabaseContext _database; - private readonly IBasicUserService _basicUserService; + private readonly IUserService _userService; - public UserPermissionService(DatabaseContext database, IBasicUserService basicUserService) + public UserPermissionService(DatabaseContext database, IUserService userService) { _database = database; - _basicUserService = basicUserService; + _userService = userService; } private async Task CheckUserExistence(long userId, bool checkUserExistence) { if (checkUserExistence) { - await _basicUserService.ThrowIfUserNotExist(userId); + await _userService.ThrowIfUserNotExist(userId); } } diff --git a/BackEnd/Timeline/Services/User/UserService.cs b/BackEnd/Timeline/Services/User/UserService.cs index 1ad74bec..d5ee9a2f 100644 --- a/BackEnd/Timeline/Services/User/UserService.cs +++ b/BackEnd/Timeline/Services/User/UserService.cs @@ -11,12 +11,12 @@ using Timeline.Services.Token; namespace Timeline.Services.User { - public class UserService : BasicUserService, IUserService + public class UserService : IUserService { private readonly ILogger _logger; private readonly IClock _clock; - private readonly DatabaseContext _databaseContext; + private readonly DatabaseContext _database; private readonly IPasswordService _passwordService; @@ -25,10 +25,10 @@ namespace Timeline.Services.User private readonly UsernameValidator _usernameValidator = new UsernameValidator(); private readonly NicknameValidator _nicknameValidator = new NicknameValidator(); - public UserService(ILogger logger, DatabaseContext databaseContext, IPasswordService passwordService, IUserTokenService userTokenService, IClock clock) : base(databaseContext) + public UserService(ILogger logger, DatabaseContext database, IPasswordService passwordService, IUserTokenService userTokenService, IClock clock) { _logger = logger; - _databaseContext = databaseContext; + _database = database; _passwordService = passwordService; _userTokenService = userTokenService; _clock = clock; @@ -58,15 +58,56 @@ namespace Timeline.Services.User } } + private static EntityNotExistException CreateUserNotExistException(string username) + { + throw new EntityNotExistException(EntityTypes.User, new Dictionary { ["username"] = username }); + } + + private static EntityNotExistException CreateUserNotExistException(long userId) + { + throw new EntityNotExistException(EntityTypes.User, new Dictionary { ["id"] = userId }); + } + private static EntityAlreadyExistException CreateUsernameConflictException(string username) { throw new EntityAlreadyExistException(EntityTypes.User, new Dictionary { ["username"] = username }); + } + + public async Task CheckUserExistenceAsync(long id) + { + return await _database.Users.AnyAsync(u => u.Id == id); + } + + public async Task GetUserIdByUsernameAsync(string username) + { + if (username == null) + throw new ArgumentNullException(nameof(username)); + + if (!_usernameValidator.Validate(username, out var message)) + throw new ArgumentException(message); + + var entity = await _database.Users.Where(user => user.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync(); + + if (entity == null) + throw CreateUserNotExistException(username); + + return entity.Id; + } + + public async Task GetUsernameLastModifiedTimeAsync(long userId) + { + var entity = await _database.Users.Where(u => u.Id == userId).Select(u => new { u.UsernameChangeTime }).SingleOrDefaultAsync(); + + if (entity is null) + throw CreateUserNotExistException(userId); + + return entity.UsernameChangeTime; } public async Task GetUserAsync(long id) { - var user = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); + var user = await _database.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); if (user is null) throw CreateUserNotExistException(id); @@ -76,7 +117,7 @@ namespace Timeline.Services.User public async Task> GetUsersAsync() { - return await _databaseContext.Users.ToListAsync(); + return await _database.Users.ToListAsync(); } public async Task CreateUserAsync(CreateUserParams param) @@ -92,7 +133,7 @@ namespace Timeline.Services.User if (param.Nickname is not null) CheckNicknameFormat(param.Nickname, nameof(param)); - var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == param.Username); + var conflict = await _database.Users.AnyAsync(u => u.Username == param.Username); if (conflict) throw CreateUsernameConflictException(param.Username); @@ -103,8 +144,8 @@ namespace Timeline.Services.User Nickname = param.Nickname, Version = 1 }; - _databaseContext.Users.Add(newEntity); - await _databaseContext.SaveChangesAsync(); + _database.Users.Add(newEntity); + await _database.SaveChangesAsync(); _logger.LogInformation(Resource.LogUserCreated, param.Username, newEntity.Id); return newEntity; @@ -124,7 +165,7 @@ namespace Timeline.Services.User CheckNicknameFormat(param.Nickname, nameof(param)); } - var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); + var entity = await _database.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); if (entity is null) throw CreateUserNotExistException(id); @@ -136,7 +177,7 @@ namespace Timeline.Services.User var username = param.Username; if (username is not null && username != entity.Username) { - var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == username); + var conflict = await _database.Users.AnyAsync(u => u.Username == username); if (conflict) throw CreateUsernameConflictException(username); @@ -164,7 +205,7 @@ namespace Timeline.Services.User entity.LastModified = now; } - await _databaseContext.SaveChangesAsync(); + await _database.SaveChangesAsync(); _logger.LogInformation(Resource.LogUserModified, entity.Username, id); if (password is not null) @@ -185,7 +226,7 @@ namespace Timeline.Services.User CheckUsernameFormat(username, nameof(username)); CheckPasswordFormat(password, nameof(password)); - var entity = await _databaseContext.Users.Where(u => u.Username == username).Select(u => new { u.Id, u.Password }).SingleOrDefaultAsync(); + var entity = await _database.Users.Where(u => u.Username == username).Select(u => new { u.Id, u.Password }).SingleOrDefaultAsync(); if (entity is null) { @@ -211,7 +252,7 @@ namespace Timeline.Services.User CheckPasswordFormat(oldPassword, nameof(oldPassword)); CheckPasswordFormat(newPassword, nameof(newPassword)); - var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); + var entity = await _database.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); if (entity is null) throw CreateUserNotExistException(id); @@ -221,7 +262,7 @@ namespace Timeline.Services.User entity.Password = _passwordService.HashPassword(newPassword); entity.Version += 1; - await _databaseContext.SaveChangesAsync(); + await _database.SaveChangesAsync(); _logger.LogInformation(Resource.LogChangePassowrd, entity.Username, id); await _userTokenService.RevokeAllTokenByUserIdAsync(id); diff --git a/BackEnd/Timeline/Services/User/UserServiceExtensions.cs b/BackEnd/Timeline/Services/User/UserServiceExtensions.cs new file mode 100644 index 00000000..82b55fba --- /dev/null +++ b/BackEnd/Timeline/Services/User/UserServiceExtensions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Timeline.Services.User +{ + public static class UserServiceExtensions + { + public static async Task ThrowIfUserNotExist(this IUserService service, long userId) + { + if (!await service.CheckUserExistenceAsync(userId)) + { + throw new EntityNotExistException(EntityTypes.User, + new Dictionary { ["id"] = userId }); + } + } + } +} diff --git a/BackEnd/Timeline/Services/User/UserServicesServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/User/UserServicesServiceCollectionExtensions.cs index a5a743df..76d101a0 100644 --- a/BackEnd/Timeline/Services/User/UserServicesServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/User/UserServicesServiceCollectionExtensions.cs @@ -9,7 +9,6 @@ namespace Timeline.Services.User public static IServiceCollection AddUserServices(this IServiceCollection services) { services.TryAddTransient(); - services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); -- cgit v1.2.3