aboutsummaryrefslogtreecommitdiff
path: root/Timeline/Services/UserService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Timeline/Services/UserService.cs')
-rw-r--r--Timeline/Services/UserService.cs95
1 files changed, 57 insertions, 38 deletions
diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs
index 45ef8a5c..d706d05e 100644
--- a/Timeline/Services/UserService.cs
+++ b/Timeline/Services/UserService.cs
@@ -1,15 +1,13 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
+using Timeline.Helpers;
using Timeline.Models;
using Timeline.Models.Validation;
-using static Timeline.Helpers.MyLogHelper;
-using static Timeline.Models.UserUtility;
namespace Timeline.Services
{
@@ -30,6 +28,7 @@ namespace Timeline.Services
/// <param name="expires">The expired time point. Null then use default. See <see cref="JwtService.GenerateJwtToken(TokenInfo, DateTime?)"/> for what is default.</param>
/// <returns>An <see cref="CreateTokenResult"/> containing the created token and user info.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown when username is of bad format.</exception>
/// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown when password is wrong.</exception>
Task<CreateTokenResult> CreateToken(string username, string password, DateTime? expires = null);
@@ -50,6 +49,8 @@ namespace Timeline.Services
/// </summary>
/// <param name="username">Username of the user.</param>
/// <returns>The info of the user. Null if the user of given username does not exists.</returns>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> is null.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown when <paramref name="username"/> is of bad format.</exception>
Task<UserInfo> GetUser(string username);
/// <summary>
@@ -82,6 +83,7 @@ namespace Timeline.Services
/// <param name="password">New password. Null if not modify.</param>
/// <param name="administrator">Whether the user is administrator. Null if not modify.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown when <paramref name="username"/> is of bad format.</exception>
/// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception>
Task PatchUser(string username, string? password, bool? administrator);
@@ -90,6 +92,7 @@ namespace Timeline.Services
/// </summary>
/// <param name="username">Username of thet user to delete. Can't be null.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown when <paramref name="username"/> is of bad format.</exception>
/// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception>
Task DeleteUser(string username);
@@ -100,6 +103,7 @@ namespace Timeline.Services
/// <param name="oldPassword">The user's old password.</param>
/// <param name="newPassword">The user's new password.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> or <paramref name="oldPassword"/> or <paramref name="newPassword"/> is null.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown when <paramref name="username"/> is of bad format.</exception>
/// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown if the old password is wrong.</exception>
Task ChangePassword(string username, string oldPassword, string newPassword);
@@ -109,9 +113,9 @@ namespace Timeline.Services
/// </summary>
/// <param name="oldUsername">The user's old username.</param>
/// <param name="newUsername">The new username.</param>
- /// <exception cref="ArgumentException">Thrown if <paramref name="oldUsername"/> or <paramref name="newUsername"/> is null or empty.</exception>
+ /// <exception cref="ArgumentNullException">Thrown if <paramref name="oldUsername"/> or <paramref name="newUsername"/> is null.</exception>
/// <exception cref="UserNotExistException">Thrown if the user with old username does not exist.</exception>
- /// <exception cref="UsernameBadFormatException">Thrown if the new username is not accepted because of bad format.</exception>
+ /// <exception cref="UsernameBadFormatException">Thrown if the <paramref name="oldUsername"/> or <paramref name="newUsername"/> is of bad format.</exception>
/// <exception cref="UsernameConfictException">Thrown if user with the new username already exists.</exception>
Task ChangeUsername(string oldUsername, string newUsername);
}
@@ -157,7 +161,19 @@ namespace Timeline.Services
{
var key = GenerateCacheKeyByUserId(id);
_memoryCache.Remove(key);
- _logger.LogInformation(FormatLogMessage("A cache entry is removed.", Pair("Key", key)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogCacheRemove, ("Key", key)));
+ }
+
+ private void CheckUsernameFormat(string username, string? message = null)
+ {
+ var (result, messageGenerator) = _usernameValidator.Validate(username);
+ if (!result)
+ {
+ if (message == null)
+ throw new UsernameBadFormatException(username, messageGenerator(null));
+ else
+ throw new UsernameBadFormatException(username, message + messageGenerator(null));
+ }
}
public async Task<CreateTokenResult> CreateToken(string username, string password, DateTime? expires)
@@ -166,6 +182,7 @@ namespace Timeline.Services
throw new ArgumentNullException(nameof(username));
if (password == null)
throw new ArgumentNullException(nameof(password));
+ CheckUsernameFormat(username);
// We need password info, so always check the database.
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
@@ -185,7 +202,7 @@ namespace Timeline.Services
return new CreateTokenResult
{
Token = token,
- User = CreateUserInfo(user)
+ User = UserConvert.CreateUserInfo(user)
};
}
@@ -208,9 +225,9 @@ namespace Timeline.Services
throw new UserNotExistException(id);
// create cache
- cache = CreateUserCache(user);
+ cache = UserConvert.CreateUserCache(user);
_memoryCache.CreateEntry(key).SetValue(cache);
- _logger.LogInformation(FormatLogMessage("A cache entry is created.", Pair("Key", key)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogCacheCreate, ("Key", key)));
}
if (tokenInfo.Version != cache.Version)
@@ -221,16 +238,20 @@ namespace Timeline.Services
public async Task<UserInfo> GetUser(string username)
{
+ if (username == null)
+ throw new ArgumentNullException(nameof(username));
+ CheckUsernameFormat(username);
+
return await _databaseContext.Users
.Where(user => user.Name == username)
- .Select(user => CreateUserInfo(user))
+ .Select(user => UserConvert.CreateUserInfo(user))
.SingleOrDefaultAsync();
}
public async Task<UserInfo[]> ListUsers()
{
return await _databaseContext.Users
- .Select(user => CreateUserInfo(user))
+ .Select(user => UserConvert.CreateUserInfo(user))
.ToArrayAsync();
}
@@ -240,12 +261,7 @@ namespace Timeline.Services
throw new ArgumentNullException(nameof(username));
if (password == null)
throw new ArgumentNullException(nameof(password));
-
- var (result, messageGenerator) = _usernameValidator.Validate(username);
- if (!result)
- {
- throw new UsernameBadFormatException(username, messageGenerator(null));
- }
+ CheckUsernameFormat(username);
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
@@ -255,20 +271,22 @@ namespace Timeline.Services
{
Name = username,
EncryptedPassword = _passwordService.HashPassword(password),
- RoleString = IsAdminToRoleString(administrator),
+ RoleString = UserRoleConvert.ToString(administrator),
Avatar = UserAvatar.Create(DateTime.Now)
};
await _databaseContext.AddAsync(newUser);
await _databaseContext.SaveChangesAsync();
- _logger.LogInformation(FormatLogMessage("A new user entry is added to the database.", Pair("Id", newUser.Id)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseCreate,
+ ("Id", newUser.Id), ("Username", username), ("Administrator", administrator)));
return PutResult.Create;
}
user.EncryptedPassword = _passwordService.HashPassword(password);
- user.RoleString = IsAdminToRoleString(administrator);
+ user.RoleString = UserRoleConvert.ToString(administrator);
user.Version += 1;
await _databaseContext.SaveChangesAsync();
- _logger.LogInformation(FormatLogMessage("A user entry is updated to the database.", Pair("Id", user.Id)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseUpdate,
+ ("Id", user.Id), ("Username", username), ("Administrator", administrator)));
//clear cache
RemoveCache(user.Id);
@@ -276,10 +294,11 @@ namespace Timeline.Services
return PutResult.Modify;
}
- public async Task PatchUser(string username, string password, bool? administrator)
+ public async Task PatchUser(string username, string? password, bool? administrator)
{
if (username == null)
throw new ArgumentNullException(nameof(username));
+ CheckUsernameFormat(username);
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
if (user == null)
@@ -292,12 +311,12 @@ namespace Timeline.Services
if (administrator != null)
{
- user.RoleString = IsAdminToRoleString(administrator.Value);
+ user.RoleString = UserRoleConvert.ToString(administrator.Value);
}
user.Version += 1;
await _databaseContext.SaveChangesAsync();
- _logger.LogInformation(FormatLogMessage("A user entry is updated to the database.", Pair("Id", user.Id)));
+ _logger.LogInformation(Resources.Services.UserService.LogDatabaseUpdate, ("Id", user.Id));
//clear cache
RemoveCache(user.Id);
@@ -307,6 +326,7 @@ namespace Timeline.Services
{
if (username == null)
throw new ArgumentNullException(nameof(username));
+ CheckUsernameFormat(username);
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
if (user == null)
@@ -314,7 +334,8 @@ namespace Timeline.Services
_databaseContext.Users.Remove(user);
await _databaseContext.SaveChangesAsync();
- _logger.LogInformation(FormatLogMessage("A user entry is removed from the database.", Pair("Id", user.Id)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseRemove,
+ ("Id", user.Id)));
//clear cache
RemoveCache(user.Id);
@@ -328,6 +349,7 @@ namespace Timeline.Services
throw new ArgumentNullException(nameof(oldPassword));
if (newPassword == null)
throw new ArgumentNullException(nameof(newPassword));
+ CheckUsernameFormat(username);
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
if (user == null)
@@ -340,23 +362,20 @@ namespace Timeline.Services
user.EncryptedPassword = _passwordService.HashPassword(newPassword);
user.Version += 1;
await _databaseContext.SaveChangesAsync();
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseUpdate,
+ ("Id", user.Id), ("Operation", "Change password")));
//clear cache
RemoveCache(user.Id);
}
public async Task ChangeUsername(string oldUsername, string newUsername)
{
- if (string.IsNullOrEmpty(oldUsername))
- throw new ArgumentException("Old username is null or empty", nameof(oldUsername));
- if (string.IsNullOrEmpty(newUsername))
- throw new ArgumentException("New username is null or empty", nameof(newUsername));
-
-
- var (result, messageGenerator) = _usernameValidator.Validate(newUsername);
- if (!result)
- {
- throw new UsernameBadFormatException(newUsername, $"New username is of bad format. {messageGenerator(null)}");
- }
+ if (oldUsername == null)
+ throw new ArgumentNullException(nameof(oldUsername));
+ if (newUsername == null)
+ throw new ArgumentNullException(nameof(newUsername));
+ CheckUsernameFormat(oldUsername, Resources.Services.UserService.ExceptionOldUsernameBadFormat);
+ CheckUsernameFormat(newUsername, Resources.Services.UserService.ExceptionNewUsernameBadFormat);
var user = await _databaseContext.Users.Where(u => u.Name == oldUsername).SingleOrDefaultAsync();
if (user == null)
@@ -369,8 +388,8 @@ namespace Timeline.Services
user.Name = newUsername;
user.Version += 1;
await _databaseContext.SaveChangesAsync();
- _logger.LogInformation(FormatLogMessage("A user entry changed name field.",
- Pair("Id", user.Id), Pair("Old Username", oldUsername), Pair("New Username", newUsername)));
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseUpdate,
+ ("Id", user.Id), ("Old Username", oldUsername), ("New Username", newUsername)));
RemoveCache(user.Id);
}
}