using Microsoft.AspNetCore.Mvc; using VoidCat.Model; using VoidCat.Services.Abstractions; namespace VoidCat.Controllers; [Route("user/{id}")] public class UserController : Controller { private readonly IUserStore _store; private readonly IUserUploadsStore _userUploads; private readonly IEmailVerification _emailVerification; private readonly IFileInfoManager _fileInfoManager; public UserController(IUserStore store, IUserUploadsStore userUploads, IEmailVerification emailVerification, IFileInfoManager fileInfoManager) { _store = store; _userUploads = userUploads; _emailVerification = emailVerification; _fileInfoManager = fileInfoManager; } /// /// Return user profile /// /// /// 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. /// /// User id to load /// [HttpGet] public async Task GetUser([FromRoute] string id) { var loggedUser = HttpContext.GetUserId(); var isMe = id.Equals("me", StringComparison.InvariantCultureIgnoreCase); if (isMe && !loggedUser.HasValue) return Unauthorized(); var requestedId = isMe ? loggedUser!.Value : id.FromBase58Guid(); if (loggedUser == requestedId) { var pUser = await _store.Get(requestedId); if (pUser == default) return NotFound(); return Json(pUser); } var user = await _store.Get(requestedId); if (!(user?.Flags.HasFlag(VoidUserFlags.PublicProfile) ?? false)) return NotFound(); return Json(user); } /// /// Update profile settings /// /// /// User id /// /// [HttpPost] public async Task UpdateUser([FromRoute] string id, [FromBody] PublicVoidUser user) { var loggedUser = await GetAuthorizedUser(id); if (loggedUser == default) return Unauthorized(); if (!loggedUser.Flags.HasFlag(VoidUserFlags.EmailVerified)) return Forbid(); await _store.UpdateProfile(user); return Ok(); } /// /// Return a list of files which the user has uploaded /// /// /// 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. /// /// User id /// Page request /// [HttpPost] [Route("files")] public async Task ListUserFiles([FromRoute] string id, [FromBody] PagedRequest request) { var loggedUser = HttpContext.GetUserId(); 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 && !user.Flags.HasFlag(VoidUserFlags.PublicUploads)) return Forbid(); var results = await _userUploads.ListFiles(id.FromBase58Guid(), request); var files = await results.Results.ToListAsync(); var fileInfo = await Task.WhenAll(files.Select(a => _fileInfoManager.Get(a).AsTask())); return Json(new RenderedResults() { PageSize = results.PageSize, Page = results.Page, TotalResults = results.TotalResults, Results = fileInfo.Where(a => a != null).ToList()! }); } /// /// Send a verification code for a specific user /// /// User id to send code for /// [HttpGet] [Route("verify")] public async Task SendVerificationCode([FromRoute] string id) { var user = await GetAuthorizedUser(id); if (user == default) return Unauthorized(); var isEmailVerified = (user?.Flags.HasFlag(VoidUserFlags.EmailVerified) ?? false); if (isEmailVerified) return UnprocessableEntity(); await _emailVerification.SendNewCode(user!); return Accepted(); } /// /// Confirm email verification code /// /// User id to verify /// Verification code to check /// [HttpPost] [Route("verify")] public async Task VerifyCode([FromRoute] string id, [FromBody] string code) { var user = await GetAuthorizedUser(id); if (user == default) return Unauthorized(); var token = code.FromBase58Guid(); if (!await _emailVerification.VerifyCode(user, token)) return BadRequest(); user.Flags |= VoidUserFlags.EmailVerified; await _store.UpdateProfile(user.ToPublic()); return Accepted(); } private async Task GetAuthorizedUser(string id) { var loggedUser = HttpContext.GetUserId(); var gid = id.FromBase58Guid(); var user = await _store.Get(gid); return user?.Id != loggedUser ? default : user; } private async Task GetRequestedUser(string id) { var gid = id.FromBase58Guid(); return await _store.Get(gid); } }