diff options
Diffstat (limited to 'BackEnd/Timeline/Services/UserService.cs')
-rw-r--r-- | BackEnd/Timeline/Services/UserService.cs | 230 |
1 files changed, 64 insertions, 166 deletions
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
{
+ /// <summary>
+ /// Null means not change.
+ /// </summary>
+ public record ModifyUserParams(string? Username, string? Password, string? Nickname);
+
public interface IUserService
{
/// <summary>
@@ -33,17 +39,7 @@ namespace Timeline.Services /// <param name="id">The id of the user.</param>
/// <returns>The user info.</returns>
/// <exception cref="UserNotExistException">Thrown when the user with given id does not exist.</exception>
- Task<User> GetUserById(long id);
-
- /// <summary>
- /// Get the user info of given username.
- /// </summary>
- /// <param name="username">Username of the user.</param>
- /// <returns>The info of the user.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> is null.</exception>
- /// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
- Task<User> GetUserByUsername(string username);
+ Task<User> GetUser(long id);
/// <summary>
/// Get the user id of given username.
@@ -59,71 +55,31 @@ namespace Timeline.Services /// List all users.
/// </summary>
/// <returns>The user info of users.</returns>
- Task<User[]> GetUsers();
+ Task<List<User>> GetUsers();
/// <summary>
/// Create a user with given info.
/// </summary>
- /// <param name="info">The info of new user.</param>
+ /// <param name="username">The username of new user.</param>
+ /// <param name="password">The password of new user.</param>
/// <returns>The the new user.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="info"/>is null.</exception>
- /// <exception cref="ArgumentException">Thrown when some fields in <paramref name="info"/> is bad.</exception>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="username"/> or <paramref name="password"/> is of bad format.</exception>
/// <exception cref="EntityAlreadyExistException">Thrown when a user with given username already exists.</exception>
- /// <remarks>
- /// <see cref="User.Username"/> must not be null and must be a valid username.
- /// <see cref="User.Password"/> must not be null or empty.
- /// <see cref="User.Administrator"/> is false by default (null).
- /// <see cref="User.Nickname"/> must be a valid nickname if set. It is empty by default.
- /// Other fields are ignored.
- /// </remarks>
- Task<User> CreateUser(User info);
+ Task<User> CreateUser(string username, string password);
/// <summary>
- /// Modify a user's info.
+ /// Modify a user.
/// </summary>
/// <param name="id">The id of the user.</param>
- /// <param name="info">The new info. May be null.</param>
+ /// <param name="param">The new information.</param>
/// <returns>The new user info.</returns>
/// <exception cref="ArgumentException">Thrown when some fields in <paramref name="info"/> is bad.</exception>
/// <exception cref="UserNotExistException">Thrown when user with given id does not exist.</exception>
/// <remarks>
- /// Only <see cref="User.Username"/>, <see cref="User.Administrator"/>, <see cref="User.Password"/> and <see cref="User.Nickname"/> will be used.
- /// If null, then not change.
- /// Other fields are ignored.
/// Version will increase if password is changed.
- ///
- /// <see cref="User.Username"/> must be a valid username if set.
- /// <see cref="User.Password"/> can't be empty if set.
- /// <see cref="User.Nickname"/> must be a valid nickname if set.
- ///
- /// </remarks>
- /// <seealso cref="ModifyUser(string, User)"/>
- Task<User> ModifyUser(long id, User? info);
-
- /// <summary>
- /// Modify a user's info.
- /// </summary>
- /// <param name="username">The username of the user.</param>
- /// <param name="info">The new info. May be null.</param>
- /// <returns>The new user info.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> is null.</exception>
- /// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format or some fields in <paramref name="info"/> is bad.</exception>
- /// <exception cref="UserNotExistException">Thrown when user with given id does not exist.</exception>
- /// <exception cref="EntityAlreadyExistException">Thrown when user with the newusername already exist.</exception>
- /// <remarks>
- /// Only <see cref="User.Administrator"/>, <see cref="User.Password"/> and <see cref="User.Nickname"/> will be used.
- /// If null, then not change.
- /// Other fields are ignored.
- /// After modified, even if nothing is changed, version will increase.
- ///
- /// <see cref="User.Username"/> must be a valid username if set.
- /// <see cref="User.Password"/> can't be empty if set.
- /// <see cref="User.Nickname"/> must be a valid nickname if set.
- ///
- /// Note: Whether <see cref="User.Version"/> is set or not, version will increase and not set to the specified value if there is one.
/// </remarks>
- /// <seealso cref="ModifyUser(long, User)"/>
- Task<User> ModifyUser(string username, User? info);
+ Task<User> ModifyUser(long id, ModifyUserParams? param);
/// <summary>
/// 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<UserService> logger, DatabaseContext databaseContext, IPasswordService passwordService, IClock clock)
+
+ public UserService(ILogger<UserService> 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<User> 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<User> GetUserById(long id)
+ public async Task<User> 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<User> 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<long> GetUserIdByUsername(string username)
@@ -263,78 +209,69 @@ namespace Timeline.Services return entity.Id;
}
- public async Task<User[]> GetUsers()
+ public async Task<List<User>> GetUsers()
{
- var entities = await _databaseContext.Users.ToArrayAsync();
- return entities.Select(user => CreateUserFromEntity(user)).ToArray();
+ List<User> result = new();
+ foreach (var entity in await _databaseContext.Users.ToArrayAsync())
+ {
+ result.Add(await CreateUserFromEntity(entity));
+ }
+ return result;
}
- public async Task<User> CreateUser(User info)
+ public async Task<User> 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<User> 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<User> 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<User> 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)
|