469 lines
15 KiB
C#
469 lines
15 KiB
C#
using MediatR;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Modules.User.Application;
|
|
using Modules.User.Application.Commands;
|
|
using Modules.User.Application.Queries;
|
|
using Modules.User.WebApi.Models;
|
|
using System.Net;
|
|
using Modules.User.Api.Models;
|
|
using Modules.User.Application.Commands.User;
|
|
using Modules.User.Application.Commands.User.Access;
|
|
using Modules.User.Application.Commands.User.Ban;
|
|
using Modules.User.Application.Commands.User.PersonalData;
|
|
using Modules.User.Application.Commands.User.Session;
|
|
using Modules.User.Application.Queries.User;
|
|
using Modules.User.WebApi.Models.User.Access;
|
|
|
|
namespace Modules.User.WebApi.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("[controller]")]
|
|
[ProducesResponseType(400, StatusCode = 400, Type = typeof(ProblemDetails))]
|
|
[ProducesResponseType(401, StatusCode = 401, Type = typeof(UnauthorizedResult))]
|
|
[Authorize]
|
|
public class UserController : ControllerBase
|
|
{
|
|
private readonly IMediator _mediator;
|
|
private readonly ILogger<UserController> _logger;
|
|
|
|
|
|
public UserController(IMediator mediator, ILogger<UserController> logger)
|
|
{
|
|
_mediator = mediator;
|
|
_logger = logger;
|
|
}
|
|
|
|
[HttpPost("Login")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(AuthenticationResultModel))]
|
|
[AllowAnonymous]
|
|
public async Task<IActionResult> Login(LoginModel model)
|
|
{
|
|
var loginResult = await _mediator.Send(new LoginCommand
|
|
{
|
|
Email = model.Login,
|
|
Password = model.Password,
|
|
IsAdmin = false,
|
|
|
|
Ip = model.Ip,
|
|
|
|
Response = Response,
|
|
//CookiePath = "Account/Refresh",
|
|
CookiePath = "/",
|
|
});
|
|
return Ok(new AuthenticationResultModel
|
|
{
|
|
AccessToken = loginResult.AccessToken,
|
|
SessionExpireDate = loginResult.SessionExpireDate.ToString("O"),
|
|
});
|
|
}
|
|
|
|
[HttpPost("Refresh")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(AuthenticationResultModel))]
|
|
[AllowAnonymous]
|
|
public async Task<IActionResult> Refresh(RefreshModel model)
|
|
{
|
|
var refreshResult = await _mediator.Send(new RefreshTokensCommand
|
|
{
|
|
Ip = model.Ip,
|
|
|
|
Response = Response,
|
|
//CookiePath = "Account/Refresh",
|
|
CookiePath = "/",
|
|
});
|
|
//if (tokens != null)
|
|
//{
|
|
// return Ok(tokens.Value.AccessToken);
|
|
//}
|
|
//else
|
|
//{
|
|
// return Unauthorized();
|
|
//}
|
|
return refreshResult == null ? Unauthorized() : Ok(new AuthenticationResultModel
|
|
{
|
|
AccessToken = refreshResult.AccessToken,
|
|
SessionExpireDate = refreshResult.SessionExpireDate.ToString("O"),
|
|
});
|
|
|
|
//return tokens == null ? Unauthorized() : Ok(new TokensModel
|
|
//{
|
|
// AccessToken = tokens.Value.AccessToken,
|
|
// RefreshToken = tokens.Value.RefreshToken,
|
|
//});
|
|
}
|
|
|
|
|
|
[HttpPost("Register")]
|
|
[AllowAnonymous]
|
|
public async Task Register(RegisterModel model)
|
|
{
|
|
var token = await _mediator.Send(new CreateUserCommand
|
|
{
|
|
Nickname = model.Nickname,
|
|
Email = model.Login,
|
|
Password = model.Password,
|
|
//IsAdmin = false,
|
|
});
|
|
}
|
|
|
|
#region Sessions
|
|
|
|
[HttpGet("sessions")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(List<Session>))]
|
|
public async Task<IActionResult> GetSessions()
|
|
{
|
|
var sessions = await _mediator.Send(new GetAccountSessionsQuery());
|
|
return Ok(sessions.Select(q => new Session
|
|
{
|
|
Id = q.Id,
|
|
IsCurrentSession = q.IsCurrentSession,
|
|
Country = q.ClientInfo.Location.Country,
|
|
Region = q.ClientInfo.Location.Region,
|
|
OnlineStatus = q.OnlineStatus switch
|
|
{
|
|
Application.Models.UserOnlineStatus.Online => UserOnlineStatus.Online,
|
|
Application.Models.UserOnlineStatus.Away => UserOnlineStatus.Away,
|
|
Application.Models.UserOnlineStatus.Offline => UserOnlineStatus.Offline,
|
|
_ => UserOnlineStatus.Unknown,
|
|
},
|
|
LastOnline = q.LastOnline,
|
|
//Latitude = q.ClientInfo.Location.Latitude,
|
|
//Longitude = q.ClientInfo.Location.Longutude,
|
|
UserAgent = q.ClientInfo.UserAgent,
|
|
ExpiredDate = q.ExpiredDate,
|
|
}));
|
|
}
|
|
|
|
[HttpDelete("sessions/{id:guid}")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
|
|
public async Task<IActionResult> DeleteSession(Guid id)
|
|
{
|
|
try
|
|
{
|
|
await _mediator.Send(new DeleteSessionCommand
|
|
{
|
|
SessionId = id,
|
|
});
|
|
return Ok();
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
//TODO: log
|
|
return Unauthorized();
|
|
}
|
|
}
|
|
|
|
[HttpDelete("sessions/current")]
|
|
public async Task<IActionResult> DeleteCurrentSession()
|
|
{
|
|
try
|
|
{
|
|
await _mediator.Send(new DeleteCurrentSessionCommand());
|
|
return Ok();
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
//TODO: log
|
|
return Unauthorized();
|
|
}
|
|
}
|
|
|
|
[HttpDelete("sessions/all")]
|
|
public async Task<IActionResult> DeleteAllSessions()
|
|
{
|
|
try
|
|
{
|
|
await _mediator.Send(new DeleteAllSessionsCommand());
|
|
return Ok();
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
//TODO: log
|
|
return Unauthorized();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Access
|
|
|
|
[HttpPost("ban")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> BanUser(AccountBanModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new BanAccountCommand
|
|
{
|
|
AccountId = model.AccountId,
|
|
Reason = model.Reason,
|
|
ExpiresAtUtc = model.ExpiresAtUtc,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("unban")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> UnbanUser(AccountUnbanModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new UnbanAccountCommand()
|
|
{
|
|
AccountId = model.AccountId,
|
|
Reason = model.Reason,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
|
|
[HttpPost("{id:guid}/role/assign")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> AssignRoleToUser(Guid id, RoleAssignModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new RoleAssignToUserCommand
|
|
{
|
|
AccountId = id,
|
|
RoleId = model.RoleId,
|
|
AssignReason = model.AssignReason,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("{id:guid}/role/revoke")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> RevokeRoleFromUser(Guid id, RoleRevokeModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new RoleRevokeFromUserCommand()
|
|
{
|
|
AccountId = id,
|
|
RoleId = model.RoleId,
|
|
RevokeReason = model.RevokeReason,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
|
|
[HttpPost("{id:guid}/permission/assign")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> GrantPermissionToUser(Guid id, PermissionGrantModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new PermissionGrantToUserCommand()
|
|
{
|
|
AccountId = id,
|
|
PermissionId = model.PermissionId,
|
|
GrantReason = model.GrantReason,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("{id:guid}/permission/revoke")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
|
|
public async Task<IActionResult> RevokePermissionFromUser(Guid id, PermissionRevokeModel model, CancellationToken cancellationToken)
|
|
{
|
|
await _mediator.Send(new PermissionRevokeFromUserCommand()
|
|
{
|
|
AccountId = id,
|
|
PermissionId = model.PermissionId,
|
|
RevokeReason = model.RevokeReason,
|
|
}, cancellationToken);
|
|
return Ok();
|
|
}
|
|
|
|
#endregion
|
|
|
|
[HttpGet("list")]
|
|
public async Task<PagedData<UserInfoShort>> GetUsers(bool? hasAvatar, string? nickName,
|
|
DateTimeOffset? lastOnlineFrom = null, DateTimeOffset? lastOnlineTo = null,
|
|
bool? isBanned = null, int page = 1, int itemsOnPage = 10)
|
|
{
|
|
var usersPaged = await _mediator.Send(new GetUserListQuery()
|
|
{
|
|
HasAvatar = hasAvatar,
|
|
NickName = nickName,
|
|
LastOnlineFrom = lastOnlineFrom,
|
|
LastOnlineTo = lastOnlineTo,
|
|
IsBanned = isBanned,
|
|
|
|
ItemsOnPage = itemsOnPage,
|
|
Page = page,
|
|
});
|
|
|
|
return new PagedData<UserInfoShort>
|
|
{
|
|
PagesCount = usersPaged.PagesCount,
|
|
Page = usersPaged.Page,
|
|
ItemsOnPage = usersPaged.ItemsOnPage,
|
|
ItemsCount = usersPaged.ItemsCount,
|
|
Items = usersPaged.Items.Select(q => new UserInfoShort
|
|
{
|
|
Id = q.Id,
|
|
NickName = q.NickName,
|
|
FirstName = q.FirstName,
|
|
Patronymic = q.Patronymic,
|
|
LastName = q.LastName,
|
|
Email = q.Email,
|
|
HasAvatar = q.HasAvatar,
|
|
BirthDate = q.BirthDate,
|
|
LanguageId = q.LanguageId,
|
|
|
|
OnlineStatus = q.OnlineStatus switch
|
|
{
|
|
Application.Models.UserOnlineStatus.Online => UserOnlineStatus.Online,
|
|
Application.Models.UserOnlineStatus.Away => UserOnlineStatus.Away,
|
|
Application.Models.UserOnlineStatus.Offline => UserOnlineStatus.Offline,
|
|
_ => UserOnlineStatus.Unknown,
|
|
},
|
|
LastOnline = q.LastOnline,
|
|
|
|
BanStatus = new BanStatus(q.BanStatus.IsBanned, q.BanStatus.BannedUntil),
|
|
|
|
// Roles = q.roles
|
|
})
|
|
};
|
|
}
|
|
|
|
// [HttpGet("UserAvatar")]
|
|
// [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))]
|
|
// [AllowAnonymous]
|
|
// public async Task<IActionResult> GetUserAvatar(string userId)
|
|
// {
|
|
// if (!string.IsNullOrEmpty(objectId))
|
|
// {
|
|
// var media = await _mediator.Send(new GetUserAvatarQuery
|
|
// {
|
|
// ObjectId = objectId,
|
|
// });
|
|
// if (media == null)
|
|
// {
|
|
// return NotFound();
|
|
// }
|
|
// else
|
|
// {
|
|
// return new FileStreamResult(media.Data, media.ContentType);
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// return NotFound();
|
|
// }
|
|
// }
|
|
|
|
// [HttpGet]
|
|
// [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserInfo))]
|
|
// public async Task<IActionResult> GetUser()
|
|
// {
|
|
// var user = await _userContext.GetUserInfo();
|
|
// if (user?.Id == null) return NotFound();
|
|
// return Ok(new UserInfo
|
|
// {
|
|
// Id = user.Id,
|
|
// AccountId = user.AccountId,
|
|
// SessionId = user.SessionId,
|
|
// NickName = user.NickName,
|
|
// FirstName = user.FirstName,
|
|
// Patronymic = user.Patronymic,
|
|
// LastName = user.LastName,
|
|
// BirthDate = user.BirthDate,
|
|
// LanguageId = user.LanguageId,
|
|
// Email = user.Email,
|
|
// IsAuthenticated = user.IsAuthenticated,
|
|
// OnlineStatus = UserOnlineStatus.Online,
|
|
// });
|
|
// }
|
|
|
|
[HttpGet("Id")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserInfo))]
|
|
public async Task<IActionResult> GetUserId(CancellationToken cancellationToken)
|
|
{
|
|
return Ok(await _mediator.Send(new GetUserIdQuery(), cancellationToken));
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpGet("Avatar")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))]
|
|
public async Task<IActionResult> GetAvatar([FromQuery]Guid userId)
|
|
{
|
|
var avatar = await _mediator.Send(new GetUserAvatarQuery { UserId = userId });
|
|
if (avatar == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
else
|
|
{
|
|
return new FileStreamResult(avatar.Data, avatar.ContentType);
|
|
}
|
|
}
|
|
|
|
[HttpPost("SetAvatar")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
public async Task<IActionResult> SetAvatar(IFormFile file)
|
|
{
|
|
if (file.Length == 0) return BadRequest("File is empty.");
|
|
await using var stream = file.OpenReadStream();
|
|
await _mediator.Send(new SetUserAvatarCommand
|
|
{
|
|
ContentType = file.ContentType,
|
|
Extension = Path.GetExtension(file.FileName),
|
|
Data = stream,
|
|
});
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("DeleteAvatar")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
public async Task<IActionResult> DeleteAvatar()
|
|
{
|
|
await _mediator.Send(new DeleteUserAvatarCommand());
|
|
return Ok();
|
|
}
|
|
|
|
/*
|
|
public string? NickName { get; set; } = default!;
|
|
public string? FirstName { get; set; }
|
|
public string? Patronymic { get; set; }
|
|
public string? LastName { get; set; }
|
|
public Guid? LanguageId { get; set; }
|
|
*/
|
|
|
|
|
|
[HttpPost("SetUserInformation")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
public async Task<IActionResult> SetUserInformation(UserInformationEditModel model)
|
|
{
|
|
await _mediator.Send(new SetUserNameCommand
|
|
{
|
|
FirstName = model.FirstName,
|
|
Patronymic = model.Patronymic,
|
|
LastName = model.LastName,
|
|
});
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("SetBirthDate")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
public async Task<IActionResult> SetBirthDate(BirthDateEditModel model)
|
|
{
|
|
await _mediator.Send(new SetUserBirthDateCommand
|
|
{
|
|
BirthDate = model.BirthDate,
|
|
});
|
|
return Ok();
|
|
}
|
|
|
|
|
|
[HttpPost("SetLanguage")]
|
|
[ProducesResponseType((int)HttpStatusCode.OK)]
|
|
public async Task<IActionResult> SetLanguage(LanguageEditModel model)
|
|
{
|
|
await _mediator.Send(new SetUserLanguageCommand
|
|
{
|
|
LanguageId = model.LanguageId,
|
|
});
|
|
return Ok();
|
|
}
|
|
}
|