From ee1b2b5b100268aa510257a1a2cd4cd03f9fc72b Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 12 Nov 2020 21:38:43 +0800 Subject: ... --- BackEnd/Timeline/Services/UserService.cs | 230 +++++++++---------------------- 1 file changed, 64 insertions(+), 166 deletions(-) (limited to 'BackEnd/Timeline/Services/UserService.cs') diff --git a/BackEnd/Timeline/Services/UserService.cs b/BackEnd/Timeline/Services/UserService.cs index 821bc33d..ed637ba3 100644 --- a/BackEnd/Timeline/Services/UserService.cs +++ b/BackEnd/Timeline/Services/UserService.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; @@ -13,6 +14,11 @@ using static Timeline.Resources.Services.UserService; namespace Timeline.Services { + /// + /// Null means not change. + /// + public record ModifyUserParams(string? Username, string? Password, string? Nickname); + public interface IUserService { /// @@ -33,17 +39,7 @@ namespace Timeline.Services /// The id of the user. /// The user info. /// Thrown when the user with given id does not exist. - Task GetUserById(long id); - - /// - /// Get the user info of given username. - /// - /// Username of the user. - /// The info of the user. - /// Thrown when is null. - /// Thrown when is of bad format. - /// Thrown when the user with given username does not exist. - Task GetUserByUsername(string username); + Task GetUser(long id); /// /// Get the user id of given username. @@ -59,71 +55,31 @@ namespace Timeline.Services /// List all users. /// /// The user info of users. - Task GetUsers(); + Task> GetUsers(); /// /// Create a user with given info. /// - /// The info of new user. + /// The username of new user. + /// The password of new user. /// The the new user. - /// Thrown when is null. - /// Thrown when some fields in is bad. + /// Thrown when or is null. + /// Thrown when or is of bad format. /// Thrown when a user with given username already exists. - /// - /// must not be null and must be a valid username. - /// must not be null or empty. - /// is false by default (null). - /// must be a valid nickname if set. It is empty by default. - /// Other fields are ignored. - /// - Task CreateUser(User info); + Task CreateUser(string username, string password); /// - /// Modify a user's info. + /// Modify a user. /// /// The id of the user. - /// The new info. May be null. + /// The new information. /// The new user info. /// Thrown when some fields in is bad. /// Thrown when user with given id does not exist. /// - /// Only , , and will be used. - /// If null, then not change. - /// Other fields are ignored. /// Version will increase if password is changed. - /// - /// must be a valid username if set. - /// can't be empty if set. - /// must be a valid nickname if set. - /// - /// - /// - Task ModifyUser(long id, User? info); - - /// - /// Modify a user's info. - /// - /// The username of the user. - /// The new info. May be null. - /// The new user info. - /// Thrown when is null. - /// Thrown when is of bad format or some fields in is bad. - /// Thrown when user with given id does not exist. - /// Thrown when user with the newusername already exist. - /// - /// Only , and will be used. - /// If null, then not change. - /// Other fields are ignored. - /// After modified, even if nothing is changed, version will increase. - /// - /// must be a valid username if set. - /// can't be empty if set. - /// must be a valid nickname if set. - /// - /// Note: Whether is set or not, version will increase and not set to the specified value if there is one. /// - /// - Task ModifyUser(string username, User? info); + Task ModifyUser(long id, ModifyUserParams? param); /// /// Try to change a user's password with old password. @@ -146,15 +102,18 @@ namespace Timeline.Services private readonly DatabaseContext _databaseContext; private readonly IPasswordService _passwordService; + private readonly IUserPermissionService _userPermissionService; private readonly UsernameValidator _usernameValidator = new UsernameValidator(); private readonly NicknameValidator _nicknameValidator = new NicknameValidator(); - public UserService(ILogger logger, DatabaseContext databaseContext, IPasswordService passwordService, IClock clock) + + public UserService(ILogger logger, DatabaseContext databaseContext, IPasswordService passwordService, IClock clock, IUserPermissionService userPermissionService) { _logger = logger; _clock = clock; _databaseContext = databaseContext; _passwordService = passwordService; + _userPermissionService = userPermissionService; } private void CheckUsernameFormat(string username, string? paramName) @@ -186,13 +145,15 @@ namespace Timeline.Services throw new EntityAlreadyExistException(EntityNames.User, ExceptionUsernameConflict); } - private static User CreateUserFromEntity(UserEntity entity) + private async Task CreateUserFromEntity(UserEntity entity) { + var permission = await _userPermissionService.GetPermissionsOfUserAsync(entity.Id); return new User { UniqueId = entity.UniqueId, Username = entity.Username, - Administrator = UserRoleConvert.ToBool(entity.Roles), + Administrator = permission.Contains(UserPermission.UserManagement), + Permissions = permission, Nickname = string.IsNullOrEmpty(entity.Nickname) ? entity.Username : entity.Nickname, Id = entity.Id, Version = entity.Version, @@ -220,32 +181,17 @@ namespace Timeline.Services if (!_passwordService.VerifyPassword(entity.Password, password)) throw new BadPasswordException(password); - return CreateUserFromEntity(entity); + return await CreateUserFromEntity(entity); } - public async Task GetUserById(long id) + public async Task GetUser(long id) { var user = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); if (user == null) throw new UserNotExistException(id); - return CreateUserFromEntity(user); - } - - public async Task GetUserByUsername(string username) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - - CheckUsernameFormat(username, nameof(username)); - - var entity = await _databaseContext.Users.Where(user => user.Username == username).SingleOrDefaultAsync(); - - if (entity == null) - throw new UserNotExistException(username); - - return CreateUserFromEntity(entity); + return await CreateUserFromEntity(user); } public async Task GetUserIdByUsername(string username) @@ -263,78 +209,69 @@ namespace Timeline.Services return entity.Id; } - public async Task GetUsers() + public async Task> GetUsers() { - var entities = await _databaseContext.Users.ToArrayAsync(); - return entities.Select(user => CreateUserFromEntity(user)).ToArray(); + List result = new(); + foreach (var entity in await _databaseContext.Users.ToArrayAsync()) + { + result.Add(await CreateUserFromEntity(entity)); + } + return result; } - public async Task CreateUser(User info) + public async Task CreateUser(string username, string password) { - if (info == null) - throw new ArgumentNullException(nameof(info)); - - if (info.Username == null) - throw new ArgumentException(ExceptionUsernameNull, nameof(info)); - CheckUsernameFormat(info.Username, nameof(info)); - - if (info.Password == null) - throw new ArgumentException(ExceptionPasswordNull, nameof(info)); - CheckPasswordFormat(info.Password, nameof(info)); - - if (info.Nickname != null) - CheckNicknameFormat(info.Nickname, nameof(info)); + if (username == null) + throw new ArgumentNullException(nameof(username)); + if (password == null) + throw new ArgumentNullException(nameof(password)); - var username = info.Username; + CheckUsernameFormat(username, nameof(username)); + CheckPasswordFormat(password, nameof(password)); var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == username); if (conflict) ThrowUsernameConflict(); - var administrator = info.Administrator ?? false; - var password = info.Password; - var nickname = info.Nickname; - var newEntity = new UserEntity { Username = username, Password = _passwordService.HashPassword(password), - Roles = UserRoleConvert.ToString(administrator), - Nickname = nickname, + Roles = "", Version = 1 }; _databaseContext.Users.Add(newEntity); await _databaseContext.SaveChangesAsync(); - _logger.LogInformation(Log.Format(LogDatabaseCreate, - ("Id", newEntity.Id), ("Username", username), ("Administrator", administrator))); + _logger.LogInformation(Log.Format(LogDatabaseCreate, ("Id", newEntity.Id), ("Username", username))); - return CreateUserFromEntity(newEntity); + return await CreateUserFromEntity(newEntity); } - private void ValidateModifyUserInfo(User? info) + public async Task ModifyUser(long id, ModifyUserParams? param) { - if (info != null) + if (param != null) { - if (info.Username != null) - CheckUsernameFormat(info.Username, nameof(info)); + if (param.Username != null) + CheckUsernameFormat(param.Username, nameof(param)); - if (info.Password != null) - CheckPasswordFormat(info.Password, nameof(info)); + if (param.Password != null) + CheckPasswordFormat(param.Password, nameof(param)); - if (info.Nickname != null) - CheckNicknameFormat(info.Nickname, nameof(info)); + if (param.Nickname != null) + CheckNicknameFormat(param.Nickname, nameof(param)); } - } - private async Task UpdateUserEntity(UserEntity entity, User? info) - { - if (info != null) + var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); + if (entity == null) + throw new UserNotExistException(id); + + if (param != null) { var now = _clock.GetCurrentTime(); bool updateLastModified = false; - var username = info.Username; + var username = param.Username; if (username != null && username != entity.Username) { var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == username); @@ -346,21 +283,14 @@ namespace Timeline.Services updateLastModified = true; } - var password = info.Password; + var password = param.Password; if (password != null) { entity.Password = _passwordService.HashPassword(password); entity.Version += 1; } - var administrator = info.Administrator; - if (administrator.HasValue && UserRoleConvert.ToBool(entity.Roles) != administrator) - { - entity.Roles = UserRoleConvert.ToString(administrator.Value); - updateLastModified = true; - } - - var nickname = info.Nickname; + var nickname = param.Nickname; if (nickname != null && nickname != entity.Nickname) { entity.Nickname = nickname; @@ -371,44 +301,12 @@ namespace Timeline.Services { entity.LastModified = now; } - } - } + await _databaseContext.SaveChangesAsync(); + _logger.LogInformation(LogDatabaseUpdate, ("Id", id)); + } - public async Task ModifyUser(long id, User? info) - { - ValidateModifyUserInfo(info); - - var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); - if (entity == null) - throw new UserNotExistException(id); - - await UpdateUserEntity(entity, info); - - await _databaseContext.SaveChangesAsync(); - _logger.LogInformation(LogDatabaseUpdate, ("Id", id)); - - return CreateUserFromEntity(entity); - } - - public async Task ModifyUser(string username, User? info) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - CheckUsernameFormat(username, nameof(username)); - - ValidateModifyUserInfo(info); - - var entity = await _databaseContext.Users.Where(u => u.Username == username).SingleOrDefaultAsync(); - if (entity == null) - throw new UserNotExistException(username); - - await UpdateUserEntity(entity, info); - - await _databaseContext.SaveChangesAsync(); - _logger.LogInformation(LogDatabaseUpdate, ("Username", username)); - - return CreateUserFromEntity(entity); + return await CreateUserFromEntity(entity); } public async Task ChangePassword(long id, string oldPassword, string newPassword) -- cgit v1.2.3