aboutsummaryrefslogtreecommitdiff
path: root/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/ProfileEndpoint.cs
blob: 22cde1953a7280cf63f3cc9f2462f33da9dfbbc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* Copyright (c) 2023 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 static VNLib.Plugins.Essentials.Statics;


namespace VNLib.Plugins.Essentials.Accounts.Endpoints
{
    /// <summary>
    /// Provides an http endpoint for user account profile access
    /// </summary>
    [ConfigurationName("profile_endpoint")]
    internal sealed class ProfileEndpoint : ProtectedWebEndpoint
    {
        private readonly IUserManager Users;
        
        public ProfileEndpoint(PluginBase pbase, IConfigScope config)
        {
            string? path = config["path"].GetString();
            
            InitPathAndLog(path, pbase.Log);
            //Store user system
            Users = pbase.GetOrCreateSingleton<UserManager>();
        }

        protected override async ValueTask<VfReturnType> 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<VfReturnType> PostAsync(HttpEntity entity)
        {
            ValErrWebMessage webm = new();
            try
            {
                //Recover the update message form the client
                AccountData? updateMessage = await entity.GetJsonFromFileAsync<AccountData>(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);
            }
        }
    }
}