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.cs275
1 files changed, 255 insertions, 20 deletions
diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs
index ad36c37b..8ab3bc54 100644
--- a/Timeline/Services/UserService.cs
+++ b/Timeline/Services/UserService.cs
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
+using System;
using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
@@ -13,10 +14,68 @@ namespace Timeline.Services
public UserInfo UserInfo { get; set; }
}
- public enum CreateUserResult
+ public enum PutUserResult
{
+ /// <summary>
+ /// A new user is created.
+ /// </summary>
+ Created,
+ /// <summary>
+ /// A existing user is modified.
+ /// </summary>
+ Modified
+ }
+
+ public enum PatchUserResult
+ {
+ /// <summary>
+ /// Succeed to modify user.
+ /// </summary>
Success,
- AlreadyExists
+ /// <summary>
+ /// A user of given username does not exist.
+ /// </summary>
+ NotExists
+ }
+
+ public enum DeleteUserResult
+ {
+ /// <summary>
+ /// A existing user is deleted.
+ /// </summary>
+ Deleted,
+ /// <summary>
+ /// A user of given username does not exist.
+ /// </summary>
+ NotExists
+ }
+
+ public enum ChangePasswordResult
+ {
+ /// <summary>
+ /// Success to change password.
+ /// </summary>
+ Success,
+ /// <summary>
+ /// The user does not exists.
+ /// </summary>
+ NotExists,
+ /// <summary>
+ /// Old password is wrong.
+ /// </summary>
+ BadOldPassword
+ }
+
+ public enum PutAvatarResult
+ {
+ /// <summary>
+ /// Success to upload avatar.
+ /// </summary>
+ Success,
+ /// <summary>
+ /// The user does not exists.
+ /// </summary>
+ UserNotExists
}
public interface IUserService
@@ -38,7 +97,79 @@ namespace Timeline.Services
/// <returns>Return null if verification failed. The user info if verification succeeded.</returns>
Task<UserInfo> VerifyToken(string token);
- Task<CreateUserResult> CreateUser(string username, string password, string[] roles);
+ /// <summary>
+ /// Get the user info of given username.
+ /// </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>
+ Task<UserInfo> GetUser(string username);
+
+ /// <summary>
+ /// List all users.
+ /// </summary>
+ /// <returns>The user info of users.</returns>
+ Task<UserInfo[]> ListUsers();
+
+ /// <summary>
+ /// Create or modify a user with given username.
+ /// Return <see cref="PutUserResult.Created"/> if a new user is created.
+ /// Return <see cref="PutUserResult.Modified"/> if a existing user is modified.
+ /// </summary>
+ /// <param name="username">Username of user.</param>
+ /// <param name="password">Password of user.</param>
+ /// <param name="roles">Array of roles of user.</param>
+ /// <returns>Return <see cref="PutUserResult.Created"/> if a new user is created.
+ /// Return <see cref="PutUserResult.Modified"/> if a existing user is modified.</returns>
+ Task<PutUserResult> PutUser(string username, string password, string[] roles);
+
+ /// <summary>
+ /// Partially modify a use of given username.
+ /// </summary>
+ /// <param name="username">Username of the user to modify.</param>
+ /// <param name="password">New password. If not modify, then null.</param>
+ /// <param name="roles">New roles. If not modify, then null.</param>
+ /// <returns>Return <see cref="PatchUserResult.Success"/> if modification succeeds.
+ /// Return <see cref="PatchUserResult.NotExists"/> if the user of given username doesn't exist.</returns>
+ Task<PatchUserResult> PatchUser(string username, string password, string[] roles);
+
+ /// <summary>
+ /// Delete a user of given username.
+ /// Return <see cref="DeleteUserResult.Deleted"/> if the user is deleted.
+ /// Return <see cref="DeleteUserResult.NotExists"/> if the user of given username
+ /// does not exist.
+ /// </summary>
+ /// <param name="username">Username of thet user to delete.</param>
+ /// <returns><see cref="DeleteUserResult.Deleted"/> if the user is deleted.
+ /// <see cref="DeleteUserResult.NotExists"/> if the user doesn't exist.</returns>
+ Task<DeleteUserResult> DeleteUser(string username);
+
+ /// <summary>
+ /// Try to change a user's password with old password.
+ /// </summary>
+ /// <param name="username">The name of user to change password of.</param>
+ /// <param name="oldPassword">The user's old password.</param>
+ /// <param name="newPassword">The user's new password.</param>
+ /// <returns><see cref="ChangePasswordResult.Success"/> if success.
+ /// <see cref="ChangePasswordResult.NotExists"/> if user does not exist.
+ /// <see cref="ChangePasswordResult.BadOldPassword"/> if old password is wrong.</returns>
+ Task<ChangePasswordResult> ChangePassword(string username, string oldPassword, string newPassword);
+
+ /// <summary>
+ /// Get the true avatar url of a user.
+ /// </summary>
+ /// <param name="username">The name of user.</param>
+ /// <returns>The url if user exists. Null if user does not exist.</returns>
+ Task<string> GetAvatarUrl(string username);
+
+ /// <summary>
+ /// Put a avatar of a user.
+ /// </summary>
+ /// <param name="username">The name of user.</param>
+ /// <param name="data">The data of avatar image.</param>
+ /// <param name="mimeType">The mime type of the image.</param>
+ /// <returns>Return <see cref="PutAvatarResult.Success"/> if success.
+ /// Return <see cref="PutAvatarResult.UserNotExists"/> if user does not exist.</returns>
+ Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType);
}
public class UserService : IUserService
@@ -47,19 +178,19 @@ namespace Timeline.Services
private readonly DatabaseContext _databaseContext;
private readonly IJwtService _jwtService;
private readonly IPasswordService _passwordService;
+ private readonly IQCloudCosService _cosService;
- public UserService(ILogger<UserService> logger, DatabaseContext databaseContext, IJwtService jwtService, IPasswordService passwordService)
+ public UserService(ILogger<UserService> logger, DatabaseContext databaseContext, IJwtService jwtService, IPasswordService passwordService, IQCloudCosService cosService)
{
_logger = logger;
_databaseContext = databaseContext;
_jwtService = jwtService;
_passwordService = passwordService;
+ _cosService = cosService;
}
public async Task<CreateTokenResult> CreateToken(string username, string password)
{
- var users = _databaseContext.Users.ToList();
-
var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
if (user == null)
@@ -72,11 +203,11 @@ namespace Timeline.Services
if (verifyResult)
{
- var userInfo = new UserInfo(user);
+ var userInfo = UserInfo.Create(user);
return new CreateTokenResult
{
- Token = _jwtService.GenerateJwtToken(user.Id, userInfo.Roles),
+ Token = _jwtService.GenerateJwtToken(user.Id, userInfo.Username, userInfo.Roles),
UserInfo = userInfo
};
}
@@ -89,38 +220,142 @@ namespace Timeline.Services
public async Task<UserInfo> VerifyToken(string token)
{
- var userId = _jwtService.VerifyJwtToken(token);
+ var userInfo = _jwtService.VerifyJwtToken(token);
- if (userId == null)
+ if (userInfo == null)
{
_logger.LogInformation($"Verify token falied. Reason: invalid token. Token: {token} .");
return null;
}
- var user = await _databaseContext.Users.Where(u => u.Id == userId.Value).SingleOrDefaultAsync();
+ return await Task.FromResult(userInfo);
+ }
+
+ public async Task<UserInfo> GetUser(string username)
+ {
+ return await _databaseContext.Users
+ .Where(user => user.Name == username)
+ .Select(user => UserInfo.Create(user.Name, user.RoleString))
+ .SingleOrDefaultAsync();
+ }
+
+ public async Task<UserInfo[]> ListUsers()
+ {
+ return await _databaseContext.Users
+ .Select(user => UserInfo.Create(user.Name, user.RoleString))
+ .ToArrayAsync();
+ }
+
+ public async Task<PutUserResult> PutUser(string username, string password, string[] roles)
+ {
+ var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
if (user == null)
{
- _logger.LogInformation($"Verify token falied. Reason: invalid user id. UserId: {userId} Token: {token} .");
- return null;
+ await _databaseContext.AddAsync(new User
+ {
+ Name = username,
+ EncryptedPassword = _passwordService.HashPassword(password),
+ RoleString = string.Join(',', roles)
+ });
+ await _databaseContext.SaveChangesAsync();
+ return PutUserResult.Created;
}
- return new UserInfo(user);
+ user.EncryptedPassword = _passwordService.HashPassword(password);
+ user.RoleString = string.Join(',', roles);
+ await _databaseContext.SaveChangesAsync();
+
+ return PutUserResult.Modified;
}
- public async Task<CreateUserResult> CreateUser(string username, string password, string[] roles)
+ public async Task<PatchUserResult> PatchUser(string username, string password, string[] roles)
{
- var exists = (await _databaseContext.Users.Where(u => u.Name == username).ToListAsync()).Count != 0;
+ var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
- if (exists)
+ if (user == null)
+ return PatchUserResult.NotExists;
+
+ bool modified = false;
+
+ if (password != null)
{
- return CreateUserResult.AlreadyExists;
+ modified = true;
+ user.EncryptedPassword = _passwordService.HashPassword(password);
}
- await _databaseContext.Users.AddAsync(new User { Name = username, EncryptedPassword = _passwordService.HashPassword(password), RoleString = string.Join(',', roles) });
+ if (roles != null)
+ {
+ modified = true;
+ user.RoleString = string.Join(',', roles);
+ }
+
+ if (modified)
+ {
+ await _databaseContext.SaveChangesAsync();
+ }
+
+ return PatchUserResult.Success;
+ }
+
+ public async Task<DeleteUserResult> DeleteUser(string username)
+ {
+ var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
+
+ if (user == null)
+ {
+ return DeleteUserResult.NotExists;
+ }
+
+ _databaseContext.Users.Remove(user);
+ await _databaseContext.SaveChangesAsync();
+ return DeleteUserResult.Deleted;
+ }
+
+ public async Task<ChangePasswordResult> ChangePassword(string username, string oldPassword, string newPassword)
+ {
+ var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync();
+ if (user == null)
+ return ChangePasswordResult.NotExists;
+
+ var verifyResult = _passwordService.VerifyPassword(user.EncryptedPassword, oldPassword);
+ if (!verifyResult)
+ return ChangePasswordResult.BadOldPassword;
+
+ user.EncryptedPassword = _passwordService.HashPassword(newPassword);
await _databaseContext.SaveChangesAsync();
+ return ChangePasswordResult.Success;
+ }
+
+ public async Task<string> GetAvatarUrl(string username)
+ {
+ if (username == null)
+ throw new ArgumentNullException(nameof(username));
+
+ if ((await GetUser(username)) == null)
+ return null;
+
+ var exists = await _cosService.IsObjectExists("avatar", username);
+ if (exists)
+ return _cosService.GenerateObjectGetUrl("avatar", username);
+ else
+ return _cosService.GenerateObjectGetUrl("avatar", "__default");
+ }
+
+ public async Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType)
+ {
+ if (username == null)
+ throw new ArgumentNullException(nameof(username));
+ if (data == null)
+ throw new ArgumentNullException(nameof(data));
+ if (mimeType == null)
+ throw new ArgumentNullException(nameof(mimeType));
+
+ if ((await GetUser(username)) == null)
+ return PutAvatarResult.UserNotExists;
- return CreateUserResult.Success;
+ await _cosService.PutObject("avatar", username, data, mimeType);
+ return PutAvatarResult.Success;
}
}
}