2022-02-27 13:54:25 +00:00
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2023-06-09 00:20:54 +00:00
|
|
|
using Newtonsoft.Json;
|
2023-05-09 13:56:57 +00:00
|
|
|
using VoidCat.Database;
|
2022-02-27 13:54:25 +00:00
|
|
|
using VoidCat.Model;
|
|
|
|
using VoidCat.Services.Abstractions;
|
2022-09-06 21:32:22 +00:00
|
|
|
using VoidCat.Services.Files;
|
2023-05-09 13:56:57 +00:00
|
|
|
using UserFlags = VoidCat.Database.UserFlags;
|
2022-02-27 13:54:25 +00:00
|
|
|
|
|
|
|
namespace VoidCat.Controllers;
|
|
|
|
|
2022-03-02 11:37:15 +00:00
|
|
|
[Route("user/{id}")]
|
2022-02-27 13:54:25 +00:00
|
|
|
public class UserController : Controller
|
|
|
|
{
|
|
|
|
private readonly IUserStore _store;
|
2022-02-27 23:01:57 +00:00
|
|
|
private readonly IUserUploadsStore _userUploads;
|
2022-03-02 11:37:15 +00:00
|
|
|
private readonly IEmailVerification _emailVerification;
|
2022-09-06 21:32:22 +00:00
|
|
|
private readonly FileInfoManager _fileInfoManager;
|
2022-02-27 13:54:25 +00:00
|
|
|
|
2022-07-25 17:59:32 +00:00
|
|
|
public UserController(IUserStore store, IUserUploadsStore userUploads, IEmailVerification emailVerification,
|
2022-09-06 21:32:22 +00:00
|
|
|
FileInfoManager fileInfoManager)
|
2022-02-27 13:54:25 +00:00
|
|
|
{
|
|
|
|
_store = store;
|
2022-02-27 23:01:57 +00:00
|
|
|
_userUploads = userUploads;
|
2022-03-02 11:37:15 +00:00
|
|
|
_emailVerification = emailVerification;
|
2022-06-10 20:42:36 +00:00
|
|
|
_fileInfoManager = fileInfoManager;
|
2022-02-27 13:54:25 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Return user profile
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// You do not need to be logged in to return a user profile if their profile is set to public.
|
|
|
|
///
|
|
|
|
/// You may also use `me` as the `id` to get the logged in users profile.
|
|
|
|
/// </remarks>
|
|
|
|
/// <param name="id">User id to load</param>
|
|
|
|
/// <returns></returns>
|
2022-02-27 13:54:25 +00:00
|
|
|
[HttpGet]
|
2022-03-02 11:37:15 +00:00
|
|
|
public async Task<IActionResult> GetUser([FromRoute] string id)
|
2022-02-27 13:54:25 +00:00
|
|
|
{
|
|
|
|
var loggedUser = HttpContext.GetUserId();
|
2022-03-04 21:12:01 +00:00
|
|
|
var isMe = id.Equals("me", StringComparison.InvariantCultureIgnoreCase);
|
|
|
|
if (isMe && !loggedUser.HasValue) return Unauthorized();
|
2022-03-08 13:47:42 +00:00
|
|
|
|
2022-03-04 21:12:01 +00:00
|
|
|
var requestedId = isMe ? loggedUser!.Value : id.FromBase58Guid();
|
2023-05-09 13:56:57 +00:00
|
|
|
var user = await _store.Get(requestedId);
|
2023-06-09 00:14:32 +00:00
|
|
|
if (user == default) return NotFound();
|
2023-10-13 21:04:45 +00:00
|
|
|
if (loggedUser != requestedId && !user.Flags.HasFlag(UserFlags.PublicProfile) && !HttpContext.IsRole(Roles.Admin))
|
2023-05-09 13:56:57 +00:00
|
|
|
return NotFound();
|
2022-02-27 18:15:37 +00:00
|
|
|
|
2023-06-09 00:14:32 +00:00
|
|
|
var isMyProfile = requestedId == user.Id;
|
|
|
|
return Json(user!.ToApiUser(isMyProfile));
|
2022-02-27 18:15:37 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Update profile settings
|
|
|
|
/// </summary>
|
|
|
|
///
|
|
|
|
/// <param name="id">User id</param>
|
|
|
|
/// <param name="user"></param>
|
|
|
|
/// <returns></returns>
|
2022-02-27 18:15:37 +00:00
|
|
|
[HttpPost]
|
2023-05-09 13:56:57 +00:00
|
|
|
public async Task<IActionResult> UpdateUser([FromRoute] string id, [FromBody] ApiUser user)
|
2022-02-27 18:15:37 +00:00
|
|
|
{
|
2022-03-02 11:37:15 +00:00
|
|
|
var loggedUser = await GetAuthorizedUser(id);
|
|
|
|
if (loggedUser == default) return Unauthorized();
|
2022-02-27 18:15:37 +00:00
|
|
|
|
2022-09-08 09:41:31 +00:00
|
|
|
if (!loggedUser.Flags.HasFlag(UserFlags.EmailVerified)) return Forbid();
|
2022-03-04 21:12:01 +00:00
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
loggedUser.Avatar = user.Avatar;
|
|
|
|
loggedUser.DisplayName = user.Name ?? "void user";
|
|
|
|
loggedUser.Flags = UserFlags.EmailVerified | (user.PublicProfile ? UserFlags.PublicProfile : 0) |
|
|
|
|
(user.PublicUploads ? UserFlags.PublicUploads : 0);
|
|
|
|
|
|
|
|
await _store.UpdateProfile(loggedUser);
|
|
|
|
|
2022-02-27 18:15:37 +00:00
|
|
|
return Ok();
|
2022-02-27 13:54:25 +00:00
|
|
|
}
|
2022-02-27 23:01:57 +00:00
|
|
|
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Return a list of files which the user has uploaded
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// This will return files if the profile has public uploads set on their profile.
|
|
|
|
/// Otherwise you can return your own uploaded files if you are logged in.
|
|
|
|
/// </remarks>
|
|
|
|
/// <param name="id">User id</param>
|
|
|
|
/// <param name="request">Page request</param>
|
|
|
|
/// <returns></returns>
|
2022-02-27 23:01:57 +00:00
|
|
|
[HttpPost]
|
2022-03-02 11:37:15 +00:00
|
|
|
[Route("files")]
|
|
|
|
public async Task<IActionResult> ListUserFiles([FromRoute] string id,
|
|
|
|
[FromBody] PagedRequest request)
|
2022-02-27 23:01:57 +00:00
|
|
|
{
|
|
|
|
var loggedUser = HttpContext.GetUserId();
|
2022-03-02 11:37:15 +00:00
|
|
|
var isAdmin = HttpContext.IsRole(Roles.Admin);
|
|
|
|
|
|
|
|
var user = await GetRequestedUser(id);
|
|
|
|
if (user == default) return NotFound();
|
|
|
|
|
|
|
|
// not logged in user files, check public flag
|
|
|
|
var canViewUploads = loggedUser == user.Id || isAdmin;
|
|
|
|
if (!canViewUploads &&
|
2022-09-08 09:41:31 +00:00
|
|
|
!user.Flags.HasFlag(UserFlags.PublicUploads)) return Forbid();
|
2022-03-02 11:37:15 +00:00
|
|
|
|
2022-02-27 23:01:57 +00:00
|
|
|
var results = await _userUploads.ListFiles(id.FromBase58Guid(), request);
|
2023-08-24 10:53:12 +00:00
|
|
|
var files = await results.Data.ToListAsync();
|
2023-05-09 13:56:57 +00:00
|
|
|
var fileInfo = await _fileInfoManager.Get(files.ToArray(), false);
|
|
|
|
return Json(new RenderedResults<VoidFileResponse>()
|
2022-06-10 20:42:36 +00:00
|
|
|
{
|
|
|
|
PageSize = results.PageSize,
|
|
|
|
Page = results.Page,
|
|
|
|
TotalResults = results.TotalResults,
|
2023-05-09 13:56:57 +00:00
|
|
|
Results = fileInfo.ToList()
|
2022-06-10 20:42:36 +00:00
|
|
|
});
|
2022-03-02 11:37:15 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Send a verification code for a specific user
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">User id to send code for</param>
|
|
|
|
/// <returns></returns>
|
2022-03-02 11:37:15 +00:00
|
|
|
[HttpGet]
|
|
|
|
[Route("verify")]
|
|
|
|
public async Task<IActionResult> SendVerificationCode([FromRoute] string id)
|
|
|
|
{
|
|
|
|
var user = await GetAuthorizedUser(id);
|
|
|
|
if (user == default) return Unauthorized();
|
|
|
|
|
2022-09-08 09:41:31 +00:00
|
|
|
var isEmailVerified = (user?.Flags.HasFlag(UserFlags.EmailVerified) ?? false);
|
2022-03-02 11:37:15 +00:00
|
|
|
if (isEmailVerified) return UnprocessableEntity();
|
|
|
|
|
|
|
|
await _emailVerification.SendNewCode(user!);
|
|
|
|
return Accepted();
|
|
|
|
}
|
|
|
|
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Confirm email verification code
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">User id to verify</param>
|
2023-06-09 00:20:54 +00:00
|
|
|
/// <param name="req">Verification code to check</param>
|
2022-03-08 13:47:42 +00:00
|
|
|
/// <returns></returns>
|
2022-03-02 11:37:15 +00:00
|
|
|
[HttpPost]
|
|
|
|
[Route("verify")]
|
2023-06-09 00:20:54 +00:00
|
|
|
public async Task<IActionResult> VerifyCode([FromRoute] string id, [FromBody] VerifyCodeRequest req)
|
2022-03-02 11:37:15 +00:00
|
|
|
{
|
|
|
|
var user = await GetAuthorizedUser(id);
|
|
|
|
if (user == default) return Unauthorized();
|
|
|
|
|
2023-06-09 00:20:54 +00:00
|
|
|
if (!await _emailVerification.VerifyCode(user, req.Code)) return BadRequest();
|
2022-03-02 11:37:15 +00:00
|
|
|
|
2022-09-08 09:41:31 +00:00
|
|
|
user.Flags |= UserFlags.EmailVerified;
|
2023-05-09 13:56:57 +00:00
|
|
|
await _store.UpdateProfile(user);
|
2022-03-02 11:37:15 +00:00
|
|
|
return Accepted();
|
|
|
|
}
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
private async Task<User?> GetAuthorizedUser(string id)
|
2022-03-02 11:37:15 +00:00
|
|
|
{
|
|
|
|
var loggedUser = HttpContext.GetUserId();
|
|
|
|
var gid = id.FromBase58Guid();
|
2023-05-09 13:56:57 +00:00
|
|
|
var user = await _store.Get(gid);
|
2022-03-02 11:37:15 +00:00
|
|
|
return user?.Id != loggedUser ? default : user;
|
|
|
|
}
|
|
|
|
|
2023-05-09 13:56:57 +00:00
|
|
|
private async Task<User?> GetRequestedUser(string id)
|
2022-03-02 11:37:15 +00:00
|
|
|
{
|
|
|
|
var gid = id.FromBase58Guid();
|
2023-05-09 13:56:57 +00:00
|
|
|
return await _store.Get(gid);
|
2022-02-27 23:01:57 +00:00
|
|
|
}
|
2023-06-09 00:20:54 +00:00
|
|
|
|
|
|
|
public class VerifyCodeRequest
|
|
|
|
{
|
|
|
|
[JsonProperty("code")]
|
|
|
|
[JsonConverter(typeof(Base58GuidConverter))]
|
|
|
|
public Guid Code { get; init; }
|
|
|
|
}
|
2022-07-25 17:59:32 +00:00
|
|
|
}
|