using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Threading.Tasks; using Timeline.Auth; using Timeline.Filters; using Timeline.Models.Http; using Timeline.Models.Validation; using Timeline.Services; using Timeline.Services.Mapper; using Timeline.Services.User; namespace Timeline.Controllers { /// /// Operations about users. /// [ApiController] [ProducesErrorResponseType(typeof(CommonResponse))] public class UserController : MyControllerBase { private readonly IUserService _userService; private readonly IUserPermissionService _userPermissionService; private readonly IUserDeleteService _userDeleteService; private readonly IGenericMapper _mapper; /// public UserController(IUserService userService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService, IGenericMapper mapper) { _userService = userService; _userPermissionService = userPermissionService; _userDeleteService = userDeleteService; _mapper = mapper; } private bool UserHasUserManagementPermission => UserHasPermission(UserPermission.UserManagement); /// /// Get all users. /// /// All user list. [HttpGet("users")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> List() { var users = await _userService.GetUsersAsync(); var result = await _mapper.MapListAsync(users, Url, User); return result; } /// /// Create a new user. You have to be administrator. /// /// The new user's info. [HttpPost("users")] [PermissionAuthorize(UserPermission.UserManagement)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> Post([FromBody] HttpUserPostRequest body) { var user = await _userService.CreateUserAsync( new CreateUserParams(body.Username, body.Password) { Nickname = body.Nickname }); return await _mapper.MapAsync(user, Url, User); } /// /// 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) { var id = await _userService.GetUserIdByUsernameAsync(username); var user = await _userService.GetUserAsync(id); return await _mapper.MapAsync(user, Url, User); } /// /// 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] HttpUserPatchRequest body, [FromRoute][Username] string username) { if (UserHasUserManagementPermission) { var id = await _userService.GetUserIdByUsernameAsync(username); var user = await _userService.ModifyUserAsync(id, _mapper.AutoMapperMap(body)); return await _mapper.MapAsync(user, Url, User); } else { if (!await CheckIsSelf(username)) return ForbidWithCommonResponse(Resource.MessageForbidNotAdministratorOrOwner); if (body.Username is not null) return ForbidWithCommonResponse(Resource.MessageForbidNotAdministrator); if (body.Password is not null) return ForbidWithCommonResponse(Resource.MessageForbidNotAdministrator); var user = await _userService.ModifyUserAsync(GetAuthUserId(), _mapper.AutoMapperMap(body)); return await _mapper.MapAsync(user, Url, 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}")] [PermissionAuthorize(UserPermission.UserManagement)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> Delete([FromRoute][Username] string username) { try { await _userDeleteService.DeleteUserAsync(username); return DeleteWithCommonDeleteResponse(); } catch (InvalidOperationOnRootUserException) { return BadRequestWithCommonResponse(ErrorCodes.UserController.InvalidOperationOnRootUser, Resource.MessageInvalidOperationOnRootUser); } } /// /// Change password with old password. /// [HttpPost("userop/changepassword"), Authorize] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> ChangePassword([FromBody] HttpChangePasswordRequest request) { try { await _userService.ChangePassword(GetAuthUserId(), request.OldPassword, request.NewPassword); return OkWithCommonResponse(); } catch (BadPasswordException) { return BadRequestWithCommonResponse(ErrorCodes.UserController.ChangePasswordBadOldPassword, Resource.MessageOldPasswordWrong); } // User can't be non-existent or the token is bad. } [HttpPut("users/{username}/permissions/{permission}"), PermissionAuthorize(UserPermission.UserManagement)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> PutUserPermission([FromRoute][Username] string username, [FromRoute] UserPermission permission) { try { var id = await _userService.GetUserIdByUsernameAsync(username); await _userPermissionService.AddPermissionToUserAsync(id, permission); return OkWithCommonResponse(); } catch (InvalidOperationOnRootUserException) { return BadRequestWithCommonResponse(ErrorCodes.UserController.InvalidOperationOnRootUser, Resource.MessageInvalidOperationOnRootUser); } } [HttpDelete("users/{username}/permissions/{permission}"), PermissionAuthorize(UserPermission.UserManagement)] [NotEntityDelete] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> DeleteUserPermission([FromRoute][Username] string username, [FromRoute] UserPermission permission) { try { var id = await _userService.GetUserIdByUsernameAsync(username); await _userPermissionService.RemovePermissionFromUserAsync(id, permission); return OkWithCommonResponse(); } catch (InvalidOperationOnRootUserException) { return BadRequestWithCommonResponse(ErrorCodes.UserController.InvalidOperationOnRootUser, Resource.MessageInvalidOperationOnRootUser); } } } }