From 05ccb4d8f1bbe3fb64e117136b4a89bcfb0b0b33 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Oct 2020 19:21:35 +0800 Subject: Split front and back end. --- BackEnd/Timeline/Controllers/UserController.cs | 195 +++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 BackEnd/Timeline/Controllers/UserController.cs (limited to 'BackEnd/Timeline/Controllers/UserController.cs') diff --git a/BackEnd/Timeline/Controllers/UserController.cs b/BackEnd/Timeline/Controllers/UserController.cs new file mode 100644 index 00000000..02c09aab --- /dev/null +++ b/BackEnd/Timeline/Controllers/UserController.cs @@ -0,0 +1,195 @@ +using AutoMapper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Auth; +using Timeline.Helpers; +using Timeline.Models; +using Timeline.Models.Http; +using Timeline.Models.Validation; +using Timeline.Services; +using Timeline.Services.Exceptions; +using static Timeline.Resources.Controllers.UserController; +using static Timeline.Resources.Messages; + +namespace Timeline.Controllers +{ + /// + /// Operations about users. + /// + [ApiController] + [ProducesErrorResponseType(typeof(CommonResponse))] + public class UserController : Controller + { + private readonly ILogger _logger; + private readonly IUserService _userService; + private readonly IUserDeleteService _userDeleteService; + private readonly IMapper _mapper; + + /// + public UserController(ILogger logger, IUserService userService, IUserDeleteService userDeleteService, IMapper mapper) + { + _logger = logger; + _userService = userService; + _userDeleteService = userDeleteService; + _mapper = mapper; + } + + private UserInfo ConvertToUserInfo(User user) => _mapper.Map(user); + + /// + /// Get all users. + /// + /// All user list. + [HttpGet("users")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task> List() + { + var users = await _userService.GetUsers(); + var result = users.Select(u => ConvertToUserInfo(u)).ToArray(); + return Ok(result); + } + + /// + /// Get a user's info. + /// + /// Username of the user. + /// User info. + [HttpGet("users/{username}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> Get([FromRoute][Username] string username) + { + try + { + var user = await _userService.GetUserByUsername(username); + return Ok(ConvertToUserInfo(user)); + } + catch (UserNotExistException e) + { + _logger.LogInformation(e, Log.Format(LogGetUserNotExist, ("Username", username))); + return NotFound(ErrorResponse.UserCommon.NotExist()); + } + } + + /// + /// Change a user's property. + /// + /// + /// Username of the user to change. + /// The new user info. + [HttpPatch("users/{username}"), Authorize] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> Patch([FromBody] UserPatchRequest body, [FromRoute][Username] string username) + { + if (this.IsAdministrator()) + { + try + { + var user = await _userService.ModifyUser(username, _mapper.Map(body)); + return Ok(ConvertToUserInfo(user)); + } + catch (UserNotExistException e) + { + _logger.LogInformation(e, Log.Format(LogPatchUserNotExist, ("Username", username))); + return NotFound(ErrorResponse.UserCommon.NotExist()); + } + catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.User) + { + return BadRequest(ErrorResponse.UserController.UsernameConflict()); + } + } + else + { + if (User.Identity.Name != username) + return StatusCode(StatusCodes.Status403Forbidden, + ErrorResponse.Common.CustomMessage_Forbid(Common_Forbid_NotSelf)); + + if (body.Username != null) + return StatusCode(StatusCodes.Status403Forbidden, + ErrorResponse.Common.CustomMessage_Forbid(UserController_Patch_Forbid_Username)); + + if (body.Password != null) + return StatusCode(StatusCodes.Status403Forbidden, + ErrorResponse.Common.CustomMessage_Forbid(UserController_Patch_Forbid_Password)); + + if (body.Administrator != null) + return StatusCode(StatusCodes.Status403Forbidden, + ErrorResponse.Common.CustomMessage_Forbid(UserController_Patch_Forbid_Administrator)); + + var user = await _userService.ModifyUser(this.GetUserId(), _mapper.Map(body)); + return Ok(ConvertToUserInfo(user)); + } + } + + /// + /// Delete a user and all his related data. You have to be administrator. + /// + /// Username of the user to delete. + /// Info of deletion. + [HttpDelete("users/{username}"), AdminAuthorize] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task> Delete([FromRoute][Username] string username) + { + var delete = await _userDeleteService.DeleteUser(username); + if (delete) + return Ok(CommonDeleteResponse.Delete()); + else + return Ok(CommonDeleteResponse.NotExist()); + } + + /// + /// Create a new user. You have to be administrator. + /// + /// The new user's info. + [HttpPost("userop/createuser"), AdminAuthorize] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task> CreateUser([FromBody] CreateUserRequest body) + { + try + { + var user = await _userService.CreateUser(_mapper.Map(body)); + return Ok(ConvertToUserInfo(user)); + } + catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.User) + { + return BadRequest(ErrorResponse.UserController.UsernameConflict()); + } + } + + /// + /// Change password with old password. + /// + [HttpPost("userop/changepassword"), Authorize] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task ChangePassword([FromBody] ChangePasswordRequest request) + { + try + { + await _userService.ChangePassword(this.GetUserId(), request.OldPassword, request.NewPassword); + return Ok(); + } + catch (BadPasswordException e) + { + _logger.LogInformation(e, Log.Format(LogChangePasswordBadPassword, + ("Username", User.Identity.Name), ("Old Password", request.OldPassword))); + return BadRequest(ErrorResponse.UserController.ChangePassword_BadOldPassword()); + } + // User can't be non-existent or the token is bad. + } + } +} -- cgit v1.2.3