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);
}
}
}
}