aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Timeline/Controllers/AdminUserController.cs83
-rw-r--r--Timeline/Controllers/UserController.cs17
-rw-r--r--Timeline/Entities/AdminUser.cs30
-rw-r--r--Timeline/Entities/User.cs15
-rw-r--r--Timeline/Services/UserService.cs155
5 files changed, 259 insertions, 41 deletions
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<ActionResult<UserInfo[]>> List()
+ {
+ return Ok(await _userService.ListUsers());
+ }
+
+ [HttpGet("user/{username}")]
+ public async Task<IActionResult> Get([FromRoute] string username)
+ {
+ var user = await _userService.GetUser(username);
+ if (user == null)
+ {
+ return NotFound();
+ }
+ return Ok(user);
+ }
+
+ [HttpPut("user/{username}")]
+ public async Task<IActionResult> 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<IActionResult> 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<ActionResult<AdminUserDeleteResponse>> 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<ActionResult<CreateUserResponse>> 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
{
+ /// <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>
+ /// Succeed to delete user.
+ /// </summary>
+ Success,
+ /// <summary>
+ /// A user of given username does not exist.
+ /// </summary>
+ NotExists
}
public interface IUserService
@@ -38,7 +68,51 @@ 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.Success"/> if success to delete.
+ /// 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.Success"/> if success to delete.
+ /// <see cref="DeleteUserResult.NotExists"/> if the user doesn't exist.</returns>
+ Task<DeleteUserResult> DeleteUser(string username);
}
public class UserService : IUserService
@@ -108,19 +182,82 @@ namespace Timeline.Services
return new UserInfo(user);
}
- public async Task<CreateUserResult> CreateUser(string username, string password, string[] roles)
+ public async Task<UserInfo> 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<UserInfo[]> ListUsers()
+ {
+ return await _databaseContext.Users.Select(user => new UserInfo(user)).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)
{
- 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<PatchUserResult> 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<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.Success;
}
}
}