/* * Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials.Accounts * File: ProfileEndpoint.cs * * ProfileEndpoint.cs is part of VNLib.Plugins.Essentials.Accounts which is part of the larger * VNLib collection of libraries and utilities. * * VNLib.Plugins.Essentials.Accounts is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * VNLib.Plugins.Essentials.Accounts is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ using System; using System.Net; using System.Threading.Tasks; using VNLib.Utils.Logging; using VNLib.Plugins.Essentials.Users; using VNLib.Plugins.Essentials.Endpoints; using VNLib.Plugins.Essentials.Extensions; using VNLib.Plugins.Extensions.Validation; using VNLib.Plugins.Extensions.Loading; using VNLib.Plugins.Extensions.Loading.Users; using VNLib.Plugins.Extensions.Loading.Routing; using static VNLib.Plugins.Essentials.Statics; namespace VNLib.Plugins.Essentials.Accounts.Endpoints { /// /// Provides an http endpoint for user account profile access /// [EndpointPath("{{path}}")] [ConfigurationName("profile_endpoint")] internal sealed class ProfileEndpoint(PluginBase pbase) : ProtectedWebEndpoint { private readonly UserManager Users = pbase.GetOrCreateSingleton(); protected override async ValueTask GetAsync(HttpEntity entity) { //get user data from database using IUser? user = await Users.GetUserFromIDAsync(entity.Session.UserID); //Make sure the account exists if (user == null || user.Status != UserStatus.Active) { //Account was not found return VirtualClose(entity, HttpStatusCode.NotFound); } //Get the stored profile AccountData? profile = user.GetProfile(); //No profile found, so return an empty "profile" profile ??= new() { //set email address EmailAddress = user.EmailAddress, //created time in rfc1123 gmt time Created = user.Created.ToString("R") }; //Serialize the profile and return to user return VirtualOkJson(entity, profile); } protected override async ValueTask PostAsync(HttpEntity entity) { ValErrWebMessage webm = new(); try { //Recover the update message form the client AccountData? updateMessage = await entity.GetJsonFromFileAsync(SR_OPTIONS); if (webm.Assert(updateMessage != null, "Malformatted payload")) { return VirtualClose(entity, HttpStatusCode.BadRequest); } //Validate the new account data if (!AccountValidations.AccountDataValidator.Validate(updateMessage, webm)) { return VirtualClose(entity, webm, HttpStatusCode.UnprocessableEntity); } //Get the user from database using IUser? user = await Users.GetUserFromIDAsync(entity.Session.UserID); //Make sure the user exists if (webm.Assert(user != null, "Account does not exist")) { //Should probably log the user out here return VirtualClose(entity, webm, HttpStatusCode.NotFound); } //Overwite the current profile data (will also sanitize inputs) user.SetProfile(updateMessage); //Update the user only if successful await user.ReleaseAsync(); webm.Result = "Successfully updated account"; webm.Success = true; return VirtualOk(entity, webm); } //Catch an account update exception catch (UserUpdateException uue) { Log.Error(uue, "An error occured while the user account is being updated"); //Return message to client webm.Result = "An error occured while updating your account, try again later"; return VirtualClose(entity, webm, HttpStatusCode.InternalServerError); } } } }