using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Timeline.Auth;
using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Models.Validation;
using Timeline.Services;
using Timeline.Services.User;
namespace Timeline.Controllers.V2
{
///
/// Operations about users.
///
[ApiController]
[Route("v2/users")]
public class UserV2Controller : V2ControllerBase
{
private readonly IUserService _userService;
private readonly IUserPermissionService _userPermissionService;
private readonly IUserDeleteService _userDeleteService;
public UserV2Controller(IUserService userService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService)
{
_userService = userService;
_userPermissionService = userPermissionService;
_userDeleteService = userDeleteService;
}
///
/// Get all users.
///
/// All user list.
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task>> ListAsync([FromQuery][PositiveInteger] int? page, [FromQuery][PositiveInteger] int? pageSize)
{
var p = await _userService.GetUsersV2Async(page ?? 1, pageSize ?? 20);
var items = await MapListAsync(p.Items);
return p.WithItems(items);
}
///
/// Create a new user. You have to be administrator.
///
/// The new user's info.
[HttpPost]
[PermissionAuthorize(UserPermission.UserManagement)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task> PostAsync([FromBody] HttpUserPostRequest body)
{
var user = await _userService.CreateUserAsync(
new CreateUserParams(body.Username, body.Password) { Nickname = body.Nickname });
return CreatedAtAction("Get", new { username = body.Username }, await MapAsync(user));
}
///
/// Get a user's info.
///
/// Username of the user.
/// User info.
[HttpGet("{username}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task> GetAsync([FromRoute][Username] string username)
{
var id = await _userService.GetUserIdByUsernameAsync(username);
var user = await _userService.GetUserAsync(id);
return await MapAsync(user);
}
///
/// Change a user's property.
///
///
/// Username of the user to change.
/// The new user info.
[HttpPatch("{username}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task> PatchAsync([FromBody] HttpUserPatchRequest body, [FromRoute][Username] string username)
{
var userId = await _userService.GetUserIdByUsernameAsync(username);
if (UserHasPermission(UserPermission.UserManagement))
{
var user = await _userService.ModifyUserAsync(userId, AutoMapperMap(body));
return await MapAsync(user);
}
else
{
if (userId != GetAuthUserId())
return Forbid();
if (body.Username is not null)
return Forbid();
if (body.Password is not null)
return Forbid();
var user = await _userService.ModifyUserAsync(GetAuthUserId(), AutoMapperMap(body));
return await MapAsync(user);
}
}
private const string RootUserInvalidOperationMessage = "Can't do this operation on root user.";
///
/// Delete a user and all his related data. You have to be administrator.
///
/// Username of the user to delete.
/// Info of deletion.
[HttpDelete("{username}")]
[PermissionAuthorize(UserPermission.UserManagement)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task DeleteAsync([FromRoute][Username] string username)
{
try
{
await _userDeleteService.DeleteUserAsync(username);
return NoContent();
}
catch (EntityNotExistException)
{
return NoContent();
}
catch (InvalidOperationOnRootUserException)
{
return UnprocessableEntity(new ErrorResponse(ErrorResponse.InvalidOperation, RootUserInvalidOperationMessage));
}
}
[HttpPut("{username}/permissions/{permission}"), PermissionAuthorize(UserPermission.UserManagement)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task PutUserPermissionAsync([FromRoute][Username] string username, [FromRoute] UserPermission permission)
{
try
{
var id = await _userService.GetUserIdByUsernameAsync(username);
await _userPermissionService.AddPermissionToUserAsync(id, permission);
return NoContent();
}
catch (InvalidOperationOnRootUserException)
{
return UnprocessableEntity(new ErrorResponse(ErrorResponse.InvalidOperation, RootUserInvalidOperationMessage));
}
}
[HttpDelete("{username}/permissions/{permission}"), PermissionAuthorize(UserPermission.UserManagement)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task DeleteUserPermissionAsync([FromRoute][Username] string username, [FromRoute] UserPermission permission)
{
try
{
var id = await _userService.GetUserIdByUsernameAsync(username);
await _userPermissionService.RemovePermissionFromUserAsync(id, permission);
return NoContent();
}
catch (InvalidOperationOnRootUserException)
{
return UnprocessableEntity(new ErrorResponse(ErrorResponse.InvalidOperation, RootUserInvalidOperationMessage));
}
}
}
}