From 325d4c7dbfba45e9c5a7518279831f54c4690d20 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 18 Apr 2019 21:23:21 +0800 Subject: Add user management REST api. --- Timeline/Controllers/AdminUserController.cs | 83 +++++++++++++++ Timeline/Controllers/UserController.cs | 17 --- Timeline/Entities/AdminUser.cs | 30 ++++++ Timeline/Entities/User.cs | 15 --- Timeline/Services/UserService.cs | 155 ++++++++++++++++++++++++++-- 5 files changed, 259 insertions(+), 41 deletions(-) create mode 100644 Timeline/Controllers/AdminUserController.cs create mode 100644 Timeline/Entities/AdminUser.cs (limited to 'Timeline') diff --git a/Timeline/Controllers/AdminUserController.cs b/Timeline/Controllers/AdminUserController.cs new file mode 100644 index 00000000..7cc8c150 --- /dev/null +++ b/Timeline/Controllers/AdminUserController.cs @@ -0,0 +1,83 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Timeline.Entities; +using Timeline.Services; + +namespace Timeline.Controllers +{ + [Route("admin")] + [Authorize(Roles = "admin")] + public class AdminUserController : Controller + { + private readonly IUserService _userService; + + public AdminUserController(IUserService userService) + { + _userService = userService; + } + + [HttpGet("users")] + public async Task> List() + { + return Ok(await _userService.ListUsers()); + } + + [HttpGet("user/{username}")] + public async Task Get([FromRoute] string username) + { + var user = await _userService.GetUser(username); + if (user == null) + { + return NotFound(); + } + return Ok(user); + } + + [HttpPut("user/{username}")] + public async Task Put([FromBody] AdminUserEntityRequest request, [FromRoute] string username) + { + var result = await _userService.PutUser(username, request.Password, request.Roles); + switch (result) + { + case PutUserResult.Created: + return CreatedAtAction("Get", new { username }, AdminUserPutResponse.Created); + case PutUserResult.Modified: + return Ok(AdminUserPutResponse.Modified); + default: + throw new Exception("Unreachable code."); + } + } + + [HttpPatch("user/{username}")] + public async Task Patch([FromBody] AdminUserEntityRequest request, [FromRoute] string username) + { + var result = await _userService.PatchUser(username, request.Password, request.Roles); + switch (result) + { + case PatchUserResult.Success: + return Ok(); + case PatchUserResult.NotExists: + return NotFound(); + default: + throw new Exception("Unreachable code."); + } + } + + [HttpDelete("user/{username}")] + public async Task> Delete([FromRoute] string username) + { + var result = await _userService.DeleteUser(username); + switch (result) + { + case DeleteUserResult.Success: + return Ok(AdminUserDeleteResponse.Success); + case DeleteUserResult.NotExists: + return Ok(AdminUserDeleteResponse.NotExists); + default: + throw new Exception("Uncreachable code."); + } + } + } +} diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 147724c1..285e0146 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -using System; using System.Threading.Tasks; using Timeline.Entities; using Timeline.Services; @@ -71,21 +70,5 @@ namespace Timeline.Controllers UserInfo = result }); } - - [HttpPost("[action]")] - [Authorize(Roles = "admin")] - public async Task> CreateUser([FromBody] CreateUserRequest request) - { - var result = await _userService.CreateUser(request.Username, request.Password, request.Roles); - switch (result) - { - case CreateUserResult.Success: - return Ok(new CreateUserResponse { ReturnCode = CreateUserResponse.SuccessCode }); - case CreateUserResult.AlreadyExists: - return Ok(new CreateUserResponse { ReturnCode = CreateUserResponse.AlreadyExistsCode }); - default: - throw new Exception("Unreachable code."); - } - } } } diff --git a/Timeline/Entities/AdminUser.cs b/Timeline/Entities/AdminUser.cs new file mode 100644 index 00000000..7b8b7fb7 --- /dev/null +++ b/Timeline/Entities/AdminUser.cs @@ -0,0 +1,30 @@ +namespace Timeline.Entities +{ + public class AdminUserEntityRequest + { + public string Password { get; set; } + public string[] Roles { get; set; } + } + + public class AdminUserPutResponse + { + public const int CreatedCode = 0; + public const int ModifiedCode = 1; + + public static AdminUserPutResponse Created { get; } = new AdminUserPutResponse { ReturnCode = CreatedCode }; + public static AdminUserPutResponse Modified { get; } = new AdminUserPutResponse { ReturnCode = ModifiedCode }; + + public int ReturnCode { get; set; } + } + + public class AdminUserDeleteResponse + { + public const int SuccessCode = 0; + public const int NotExistsCode = 1; + + public static AdminUserDeleteResponse Success { get; } = new AdminUserDeleteResponse { ReturnCode = SuccessCode }; + public static AdminUserDeleteResponse NotExists { get; } = new AdminUserDeleteResponse { ReturnCode = NotExistsCode }; + + public int ReturnCode { get; set; } + } +} diff --git a/Timeline/Entities/User.cs b/Timeline/Entities/User.cs index b5664bb0..1b5a469d 100644 --- a/Timeline/Entities/User.cs +++ b/Timeline/Entities/User.cs @@ -23,19 +23,4 @@ public bool IsValid { get; set; } public UserInfo UserInfo { get; set; } } - - public class CreateUserRequest - { - public string Username { get; set; } - public string Password { get; set; } - public string[] Roles { get; set; } - } - - public class CreateUserResponse - { - public const int SuccessCode = 0; - public const int AlreadyExistsCode = 1; - - public int ReturnCode { get; set; } - } } diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index ad36c37b..caeb4efe 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -13,10 +13,40 @@ namespace Timeline.Services public UserInfo UserInfo { get; set; } } - public enum CreateUserResult + public enum PutUserResult { + /// + /// A new user is created. + /// + Created, + /// + /// A existing user is modified. + /// + Modified + } + + public enum PatchUserResult + { + /// + /// Succeed to modify user. + /// Success, - AlreadyExists + /// + /// A user of given username does not exist. + /// + NotExists + } + + public enum DeleteUserResult + { + /// + /// Succeed to delete user. + /// + Success, + /// + /// A user of given username does not exist. + /// + NotExists } public interface IUserService @@ -38,7 +68,51 @@ namespace Timeline.Services /// Return null if verification failed. The user info if verification succeeded. Task VerifyToken(string token); - Task CreateUser(string username, string password, string[] roles); + /// + /// Get the user info of given username. + /// + /// Username of the user. + /// The info of the user. Null if the user of given username does not exists. + Task GetUser(string username); + + /// + /// List all users. + /// + /// The user info of users. + Task ListUsers(); + + /// + /// Create or modify a user with given username. + /// Return if a new user is created. + /// Return if a existing user is modified. + /// + /// Username of user. + /// Password of user. + /// Array of roles of user. + /// Return if a new user is created. + /// Return if a existing user is modified. + Task PutUser(string username, string password, string[] roles); + + /// + /// Partially modify a use of given username. + /// + /// Username of the user to modify. + /// New password. If not modify, then null. + /// New roles. If not modify, then null. + /// Return if modification succeeds. + /// Return if the user of given username doesn't exist. + Task PatchUser(string username, string password, string[] roles); + + /// + /// Delete a user of given username. + /// Return if success to delete. + /// Return if the user of given username + /// does not exist. + /// + /// Username of thet user to delete. + /// if success to delete. + /// if the user doesn't exist. + Task DeleteUser(string username); } public class UserService : IUserService @@ -108,19 +182,82 @@ namespace Timeline.Services return new UserInfo(user); } - public async Task CreateUser(string username, string password, string[] roles) + public async Task GetUser(string username) { - var exists = (await _databaseContext.Users.Where(u => u.Name == username).ToListAsync()).Count != 0; + return await _databaseContext.Users + .Where(user => user.Name == username) + .Select(user => new UserInfo(user)).SingleOrDefaultAsync(); + } - if (exists) + public async Task ListUsers() + { + return await _databaseContext.Users.Select(user => new UserInfo(user)).ToArrayAsync(); + } + + public async Task PutUser(string username, string password, string[] roles) + { + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + + if (user == null) { - return CreateUserResult.AlreadyExists; + await _databaseContext.AddAsync(new User + { + Name = username, + EncryptedPassword = _passwordService.HashPassword(password), + RoleString = string.Join(',', roles) + }); + await _databaseContext.SaveChangesAsync(); + return PutUserResult.Created; } - await _databaseContext.Users.AddAsync(new User { Name = username, EncryptedPassword = _passwordService.HashPassword(password), RoleString = string.Join(',', roles) }); + user.EncryptedPassword = _passwordService.HashPassword(password); + user.RoleString = string.Join(',', roles); await _databaseContext.SaveChangesAsync(); - return CreateUserResult.Success; + return PutUserResult.Modified; + } + + public async Task PatchUser(string username, string password, string[] roles) + { + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + + if (user == null) + return PatchUserResult.NotExists; + + bool modified = false; + + if (password != null) + { + modified = true; + user.EncryptedPassword = _passwordService.HashPassword(password); + } + + if (roles != null) + { + modified = true; + user.RoleString = string.Join(',', roles); + } + + if (modified) + { + await _databaseContext.SaveChangesAsync(); + } + + return PatchUserResult.Success; + } + + public async Task 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.Success; } } } -- cgit v1.2.3