• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Scripta-Qumranica-Electronica / SQE_API / 29775976052

20 Jul 2026 08:24PM UTC coverage: 82.822% (-0.004%) from 82.826%
29775976052

push

github

web-flow
Merge pull request #72 from Scripta-Qumranica-Electronica/fix-compiler-warnings

Fix all compiler code warnings (CS/SYSLIB/RS)

1533 of 2335 branches covered (65.65%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

12382 of 14466 relevant lines covered (85.59%)

25537.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.04
/sqe-database-access/UserRepository.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Data;
4
using System.Linq;
5
using System.Threading.Tasks;
6
using SQE.DatabaseAccess.Helpers;
7
using SQE.DatabaseAccess.Models;
8
using SQE.DatabaseAccess.Queries;
9

10
namespace SQE.DatabaseAccess;
11

12
public interface IUserRepository
13
{
14
        // Get user data
15
        Task<DetailedUserWithToken> GetUserByPasswordAsync(string email, string password);
16

17
        Task<DetailedUserWithToken> GetDetailedUserByIdAsync(uint?     userId);
18
        Task<DetailedUser>          GetDetailedUserByTokenAsync(string token);
19

20
        Task<DetailedUserWithToken> GetUnactivatedUserByEmailAsync(string email);
21

22
        Task<UserEditionPermissions> GetUserEditionPermissionsAsync(UserInfo editionUser);
23

24
        Task<List<UserSystemRoles>> GetUserSystemRolesAsync(UserInfo editionUser);
25

26
        Task<List<EditorInfo>> GetEditionEditorsAsync(uint editionId);
27

28
        // Create/update account data
29
        Task<DetailedUserWithToken> CreateNewUserAsync(
30
                        string          email
31
                        , string        password
32
                        , string        forename     = null
33
                        , string        surname      = null
34
                        , string        organization = null
35
                        , IDbConnection connection   = null);
36

37
        Task ResolveExistingUserConflictAsync(string email);
38

39
        Task UpdateUserAsync(
40
                        uint            userId
41
                        , string        password
42
                        , string        email
43
                        , bool          resetActivation
44
                        , string        forename     = null
45
                        , string        surname      = null
46
                        , string        organization = null
47
                        , IDbConnection connection   = null);
48

49
        Task<DetailedUserWithToken> CreateUserActivateTokenAsync(string    email);
50
        Task                        ConfirmAccountCreationAsync(string     token);
51
        Task                        UpdateUnactivatedUserEmailAsync(string oldEmail, string newEmail);
52

53
        Task ChangePasswordAsync(uint userId, string oldPassword, string newPassword);
54

55
        Task<DetailedUserWithToken> RequestResetForgottenPasswordAsync(string email);
56

57
        Task<DetailedUser> ResetForgottenPasswordAsync(string token, string password);
58

59
        Task<string>          GetUserDataStoreAsync(uint       userId);
60
        Task                  SetUserDataStoreAsync(uint       userId, string data);
61
        Task<DatabaseVersion> GetDatabaseVersion(IDbConnection connection = null);
62
}
63

64
public class UserRepository(IDatabaseAccessor dba) : IUserRepository
10,379✔
65
{
66
        /// <summary>
67
        ///  Returns user information based on the submitted credentials.
68
        /// </summary>
69
        /// <param name="email"></param>
70
        /// <param name="password">The user's password</param>
71
        /// <returns></returns>
72
        public async Task<DetailedUserWithToken> GetUserByPasswordAsync(string email, string password)
73
        {
992✔
74
                var columns = new List<string>
992✔
75
                {
992✔
76
                                "user_id"
992✔
77
                                , "email"
992✔
78
                                , "activated"
992✔
79
                                , "forename"
992✔
80
                                , "surname"
992✔
81
                                , "organization"
992✔
82
                                ,
992✔
83
                };
992✔
84

85
                var where = new List<string> { "email", "pw" };
992✔
86

87
                try
88
                {
992✔
89
                        return await dba.QuerySingleAsync<DetailedUserWithToken>(
992✔
90
                                        UserDetails.GetQuery(columns, where)
992✔
91
                                        , new { Email = email, Pw = password });
992✔
92
                }
93
                catch (InvalidOperationException)
3✔
94
                {
3✔
95
                        throw new StandardExceptions.BadLoginException(email);
3✔
96
                }
97
        }
989✔
98

99
        public async Task<DetailedUserWithToken> GetDetailedUserByIdAsync(uint? userId)
100
        {
21✔
101
                var columns = new List<string>
21✔
102
                {
21✔
103
                                "user_id"
21✔
104
                                , "email"
21✔
105
                                , "forename"
21✔
106
                                , "surname"
21✔
107
                                , "organization"
21✔
108
                                , "activated"
21✔
109
                                ,
21✔
110
                };
21✔
111

112
                var where = new List<string> { "user_id" };
21✔
113

114
                return await dba.QuerySingleAsync<DetailedUserWithToken>(
21✔
115
                                UserDetails.GetQuery(columns, where)
21✔
116
                                , new { UserId = userId });
21✔
117
        }
21✔
118

119
        public async Task<DetailedUser> GetDetailedUserByTokenAsync(string token)
120
        {
16✔
121
                try
122
                {
16✔
123
                        return await dba.QuerySingleAsync<DetailedUser>(
16✔
124
                                        UserByTokenQuery.GetQuery
16✔
125
                                        , new { Token = Guid.Parse(token) });
16✔
126
                }
127
                catch (InvalidOperationException)
×
128
                {
×
129
                        throw new StandardExceptions.DataNotFoundException("user", token, "token");
×
130
                }
131
        }
16✔
132

133
        /// <summary>
134
        ///  Gets user details for the unactivated account with the provided email address.  Do not use this unless you
135
        ///  know what you are doing!
136
        /// </summary>
137
        /// <param name="email">Email address for the account details you want to retrieve</param>
138
        /// <returns></returns>
139
        public async Task<DetailedUserWithToken> GetUnactivatedUserByEmailAsync(string email)
140
        {
6✔
141
                // Generate our new secret token
142
                var token = Guid.NewGuid().ToString();
6✔
143

144
                await dba.ExecuteAsync(
6✔
145
                                CreateUserEmailTokenQuery.GetQuery(true)
6✔
146
                                , new
6✔
147
                                {
6✔
148
                                                Email = email
6✔
149
                                                , Token = Guid.Parse(token)
6✔
150
                                                , Type = CreateUserEmailTokenQuery.Activate
6✔
151
                                                ,
6✔
152
                                });
6✔
153

154
                // Prepare account details request
155
                var columns = new List<string>
6✔
156
                {
6✔
157
                                "email"
6✔
158
                                , "user_id"
6✔
159
                                , "forename"
6✔
160
                                , "surname"
6✔
161
                                , "token"
6✔
162
                                ,
6✔
163
                };
6✔
164

165
                var where = new List<string>
6✔
166
                {
6✔
167
                                "email"
6✔
168
                                , "activated"
6✔
169
                                , "token"
6✔
170
                                ,
6✔
171
                };
6✔
172

173
                try
174
                {
6✔
175
                        return await dba.QuerySingleAsync<DetailedUserWithToken>(
6✔
176
                                        UserDetails.GetQuery(columns, where)
6✔
177
                                        , new
6✔
178
                                        {
6✔
179
                                                        Email = email
6✔
180
                                                        , Activated = 0
6✔
181
                                                        , Token = Guid.Parse(token)
6✔
182
                                                        ,
6✔
183
                                        });
6✔
184
                }
185
                catch (InvalidOperationException)
×
186
                {
×
187
                        throw new StandardExceptions.DataNotFoundException("user", email, email);
×
188
                }
189
        }
6✔
190

191
        /// <summary>
192
        ///  Retrieves the current users permissions for a specific edition.
193
        /// </summary>
194
        /// <param name="editionUser"></param>
195
        /// <returns>Returns the user's rights to read, write, and admin the edition and the users editor id for the edition</returns>
196
        public async Task<UserEditionPermissions> GetUserEditionPermissionsAsync(UserInfo editionUser)
197
        {
1,497✔
198
                try
199
                {
1,497✔
200
                        var results = await dba.QuerySingleAsync<UserEditionPermissions>(
1,497✔
201
                                        UserPermissionQuery.GetQuery
1,497✔
202
                                        , new
1,497✔
203
                                        {
1,497✔
204
                                                        editionUser.EditionId
1,497✔
205
                                                        , UserId = editionUser.userId
1,497✔
206
                                                        ,
1,497✔
207
                                        });
1,497✔
208

209
                        return results;
1,497✔
210
                }
NEW
211
                catch (InvalidOperationException)
×
212
                {
×
213
                        throw new StandardExceptions.NoPermissionsException(editionUser);
×
214
                }
215
        }
1,497✔
216

217
        /// <summary>
218
        ///  Retrieves the current users permissions for a specific edition.
219
        /// </summary>
220
        /// <param name="editionUser"></param>
221
        /// <returns>Returns the user's rights to read, write, and admin the edition and the users editor id for the edition</returns>
222
        public async Task<List<UserSystemRoles>> GetUserSystemRolesAsync(UserInfo editionUser)
223
        {
1,370✔
224
                try
225
                {
1,370✔
226
                        var results = await dba.QueryAsync<string>(
1,370✔
227
                                        UserSystemRolesQuery.GetQuery
1,370✔
228
                                        , new { UserId = editionUser.userId });
1,370✔
229

230
                        // Note, I could use Dapper to map the UserSystemRoles by internal database id.
231
                        // To do this make the enum `UserSystemRoles : uint`, but I like the string matching,
232
                        // since that decouples the systems. The system here will break down if the database is
233
                        // altered without matching changes made to the API (or the reverse).
234
                        return results.Select(x => x switch
5,284!
235
                                                                           {
5,284✔
236
                                                                                           "REGISTERED_USER" => UserSystemRoles.REGISTERED_USER
992✔
237
                                                                                           , "CATALOGUE_CURATOR" => UserSystemRoles
974✔
238
                                                                                                           .CATALOGUE_CURATOR
974✔
239
                                                                                           , "IMAGE_DATA_CURATOR" => UserSystemRoles
974✔
240
                                                                                                           .IMAGE_DATA_CURATOR
974✔
241
                                                                                           , "USER_ADMIN" => UserSystemRoles.USER_ADMIN
974✔
242
                                                                                           , _            => UserSystemRoles.REGISTERED_USER
×
243
                                                                                           ,
5,284✔
244
                                                                           })
5,284✔
245
                                                  .ToList();
1,370✔
246
                }
247
                catch (InvalidOperationException)
×
248
                {
×
249
                        throw new StandardExceptions.NoPermissionsException(editionUser);
×
250
                }
251
        }
1,370✔
252

253
        /// <summary>
254
        ///  Create a new user in the database and create the email token record.  This method checks
255
        ///  for any conflicts with existing emails, and it will respond accordingly.
256
        /// </summary>
257
        /// <param name="email">Email address for the new account (it will be verified)</param>
258
        /// <param name="password">Password for the new account (it is hashed in the database)</param>
259
        /// <param name="forename">Optional given name</param>
260
        /// <param name="surname">Optional family name</param>
261
        /// <param name="organization">Optional organizational affiliation</param>
262
        /// <returns>
263
        ///  Returns a User object with the details of the newly created user. This object contains
264
        ///  the secret confirmation token that should be emailed to the user and then likely stripped
265
        ///  from the User object, which can be returned as a DTO to the HTTP request.
266
        /// </returns>
267
        public async Task<DetailedUserWithToken> CreateNewUserAsync(
268
                        string          email
269
                        , string        password
270
                        , string        forename     = null
271
                        , string        surname      = null
272
                        , string        organization = null
273
                        , IDbConnection connection   = null)
274
        {
19✔
275
                await dba.BeginTransactionAsync();
19✔
276

277
                // Find any users with either the same  email address.
278
                await ResolveExistingUserConflictAsync(email);
19✔
279

280
                // Ok, the input email is unique so create the record
281
                var newUser = await dba.ExecuteAsync(
18✔
282
                                CreateNewUserQuery.GetQuery
18✔
283
                                , new
18✔
284
                                {
18✔
285
                                                Email = email
18✔
286
                                                , Password = password
18✔
287
                                                , Forename = forename
18✔
288
                                                , Surname = surname
18✔
289
                                                , Organization = organization
18✔
290
                                                ,
18✔
291
                                });
18✔
292

293
                if (newUser != 1) // Something strange must have gone wrong
18!
294
                        throw new StandardExceptions.DataNotWrittenException("create user");
×
295

296
                // Everything went well, so create the email token so the
297
                // calling function can email the new user.
298
                var newUserObject = await CreateUserActivateTokenAsync(email);
18✔
299

300
                dba.CommitTransaction();
18✔
301

302
                return newUserObject;
18✔
303
        }
18✔
304

305
        /// <summary>
306
        ///  Note that this method may be destructive!  This method resolves any uniqueness constraints
307
        ///  on an email. It will throw if an activated user account already exists with the
308
        ///  email.  If an unactivated user account exists with the email, it will be overwritten.
309
        /// </summary>
310
        /// <param name="email">Email to check for uniqueness</param>
311
        /// <returns></returns>
312
        public async Task ResolveExistingUserConflictAsync(string email)
313
        {
26✔
314
                await dba.BeginTransactionAsync();
26✔
315

316
                // Find any users with either the same email address.
317
                var columns = new List<string>
26✔
318
                {
26✔
319
                                "user_id"
26✔
320
                                , "activated"
26✔
321
                                , "email"
26✔
322
                                ,
26✔
323
                };
26✔
324

325
                var where = new List<string> { "email" };
26✔
326

327
                var existingUser = (await dba.QueryAsync<DetailedUserWithToken>(
26✔
328
                                UserDetails.GetQuery(columns, where)
26✔
329
                                , new { Email = email })).ToList();
26✔
330

331
                // Check if we need to send error because email already exist.
332
                if (existingUser.Any())
26✔
333
                {
2✔
334
                        foreach (var record in existingUser)
9✔
335
                        {
2✔
336
                                if (record.Activated) // If this user record has been authenticated throw a conflict error
2✔
337
                                        throw new StandardExceptions.ConflictingDataException("email");
1✔
338

339
                                await dba.ExecuteAsync(
1✔
340
                                                DeleteUserEmailTokenQuery.GetUserIdQuery
1✔
341
                                                , new { record.UserId });
1✔
342

343
                                // Remove the child rows an unactivated account may hold (system role, profile data)
344
                                // before deleting the user row itself, otherwise the delete violates a foreign key.
345
                                await dba.ExecuteAsync(
1✔
346
                                                DeleteUnactivatedUserChildrenQuery.SystemRoles
1✔
347
                                                , new { record.UserId });
1✔
348

349
                                await dba.ExecuteAsync(
1✔
350
                                                DeleteUnactivatedUserChildrenQuery.DataStore
1✔
351
                                                , new { record.UserId });
1✔
352

353
                                await dba.ExecuteAsync(DeleteUserQuery.GetQuery, new { record.UserId });
1✔
354
                        }
1✔
355
                }
1✔
356

357
                dba.CommitTransaction();
25✔
358
        }
25✔
359

360
        /// <summary>
361
        ///  Updates the info for an existing user.  This cannot be used to reset a password, use ChangePasswordAsync
362
        ///  instead. You should probably have run ResolveExistingUserConflict before attempting this.
363
        /// </summary>
364
        /// <param name="userId"></param>
365
        /// <param name="password"></param>
366
        /// <param name="email">Email address for the new account (it will be verified)</param>
367
        /// <param name="resetActivation"></param>
368
        /// <param name="forename">Optional given name</param>
369
        /// <param name="surname">Optional family name</param>
370
        /// <param name="organization">Optional organizational affiliation</param>
371
        /// <returns>
372
        ///  Returns a User object with the details of the newly created user. This object contains
373
        ///  the secret confirmation token that should be emailed to the user and then likely stripped
374
        ///  from the User object, which can be returned as a DTO to the HTTP request.
375
        /// </returns>
376
        public async Task UpdateUserAsync(
377
                        uint            userId
378
                        , string        password
379
                        , string        email
380
                        , bool          resetActivation
381
                        , string        forename     = null
382
                        , string        surname      = null
383
                        , string        organization = null
384
                        , IDbConnection connection   = null)
385
        {
5✔
386
                await dba.BeginTransactionAsync();
5✔
387

388
                if (resetActivation) // If email is new, make sure it is unique
5✔
389
                        await ResolveExistingUserConflictAsync(email);
3✔
390

391
                var userUpdate = await dba.ExecuteAsync(
5✔
392
                                UpdateUserInfo.GetQuery(resetActivation)
5✔
393
                                , new
5✔
394
                                {
5✔
395
                                                Pw = password
5✔
396
                                                , Email = email
5✔
397
                                                , Forename = forename
5✔
398
                                                , Surname = surname
5✔
399
                                                , Organization = organization
5✔
400
                                                , UserId = userId
5✔
401
                                                ,
5✔
402
                                });
5✔
403

404
                if (userUpdate != 1) // The password was wrong
5✔
405
                        throw new StandardExceptions.WrongPasswordException();
1✔
406

407
                dba.CommitTransaction();
4✔
408
        }
4✔
409

410
        /// <summary>
411
        ///  Generates an activation token for the user account in the database.  This only works
412
        ///  if the account is not yet activated.
413
        /// </summary>
414
        /// <param name="email">Email address of the unactivated account</param>
415
        /// <returns>User details for the account with the activation token</returns>
416
        public async Task<DetailedUserWithToken> CreateUserActivateTokenAsync(string email)
417
        {
20✔
418
                // Confirm creation by getting the User object for the new user
419
                var columns = new List<string>
20✔
420
                {
20✔
421
                                "user_id"
20✔
422
                                , "email"
20✔
423
                                , "forename"
20✔
424
                                , "surname"
20✔
425
                                , "organization"
20✔
426
                                ,
20✔
427
                };
20✔
428

429
                var where = new List<string> { "email" };
20✔
430

431
                await dba.BeginTransactionAsync();
20✔
432

433
                var userObject = await dba.QuerySingleAsync<DetailedUserWithToken>(
20✔
434
                                UserDetails.GetQuery(columns, where)
20✔
435
                                , new { Email = email });
20✔
436

437
                // Generate our secret token
438
                var token = Guid.NewGuid();
20✔
439

440
                // Add the secret token to the database
441
                var userEmailConfirmation = await dba.ExecuteAsync(
20✔
442
                                CreateUserEmailTokenQuery.GetQuery()
20✔
443
                                , new
20✔
444
                                {
20✔
445
                                                userObject.UserId
20✔
446
                                                , Token = token
20✔
447
                                                , Type = CreateUserEmailTokenQuery.Activate
20✔
448
                                                ,
20✔
449
                                });
20✔
450

451
                if (userEmailConfirmation != 1) // Something strange must have gone wrong
20!
452
                        throw new StandardExceptions.DataNotWrittenException("create confirmation token");
×
453

454
                dba.CommitTransaction();
20✔
455

456
                // Everything went well, so add the token to the User object so the calling function
457
                // can email the new user.
458
                userObject.Token = token;
20✔
459

460
                return userObject;
20✔
461
        }
20✔
462

463
        /// <summary>
464
        ///  Activates user account based on the secret token sent to the new user's email address.
465
        /// </summary>
466
        /// <param name="token">Secret token for user authentication</param>
467
        /// <returns></returns>
468
        public async Task ConfirmAccountCreationAsync(string token)
469
        {
14✔
470
                await dba.BeginTransactionAsync();
14✔
471

472
                var confirmRegistration = await dba.ExecuteAsync(
14✔
473
                                ConfirmNewUserAccount.GetQuery
14✔
474
                                , new { Token = Guid.Parse(token) });
14✔
475

476
                if (confirmRegistration != 1)
14!
477
                {
×
478
                        throw new StandardExceptions.ImproperInputDataException(
×
479
                                        "user account activation token");
×
480
                }
481

482
                // Set the user's system role
483
                await SetNewUserRole(token);
14✔
484

485
                // Create the user's data store
486
                await dba.ExecuteAsync(
14✔
487
                                CreateUserDataStoreEntry.GetQuery
14✔
488
                                , new
14✔
489
                                {
14✔
490
                                                Token = Guid.Parse(token)
14✔
491
                                                , Data = "{}"
14✔
492
                                                ,
14✔
493
                                });
14✔
494

495
                // Get all Activate tokens for this user
496
                var tokens = await dba.QueryAsync<Guid>(
14✔
497
                                GetTokensQuery.GetQuery
14✔
498
                                , new
14✔
499
                                {
14✔
500
                                                Token = Guid.Parse(token)
14✔
501
                                                , Type = CreateUserEmailTokenQuery.Activate
14✔
502
                                                ,
14✔
503
                                });
14✔
504

505
                // Delete them all
506
                await dba.ExecuteAsync(
14✔
507
                                DeleteUserEmailTokenQuery.GetTokenQuery
14✔
508
                                , new
14✔
509
                                {
14✔
510
                                                Tokens = tokens
14✔
511
                                                , Type = CreateUserEmailTokenQuery.Activate
14✔
512
                                                ,
14✔
513
                                });
14✔
514

515
                dba.CommitTransaction();
14✔
516
        }
14✔
517

518
        /// <summary>
519
        ///  Updates the email address for an account that has not yet been activated.
520
        /// </summary>
521
        /// <param name="oldEmail">Email address that was originally entered when creating the account</param>
522
        /// <param name="newEmail">New email address to use for the account</param>
523
        /// <returns></returns>
524
        public async Task UpdateUnactivatedUserEmailAsync(string oldEmail, string newEmail)
525
        {
2✔
526
                await dba.BeginTransactionAsync();
2✔
527
                await ResolveExistingUserConflictAsync(newEmail);
2✔
528

529
                var newEmailEntry = await dba.ExecuteAsync(
2✔
530
                                ChangeUnactivatedUserEmail.GetQuery
2✔
531
                                , new
2✔
532
                                {
2✔
533
                                                OldEmail = oldEmail
2✔
534
                                                , NewEmail = newEmail
2✔
535
                                                ,
2✔
536
                                });
2✔
537

538
                if (newEmailEntry != 1)
2!
539
                        throw new StandardExceptions.DataNotWrittenException("update email");
×
540

541
                dba.CommitTransaction();
2✔
542
        }
2✔
543

544
        /// <summary>
545
        ///  Change password from old password to new password for the user's account.
546
        /// </summary>
547
        /// <param name="userId"></param>
548
        /// <param name="oldPassword">The old password for the user's account</param>
549
        /// <param name="newPassword">The new password for the user's account</param>
550
        /// <returns></returns>
551
        public async Task ChangePasswordAsync(uint userId, string oldPassword, string newPassword)
552
        {
3✔
553
                var changePassword = await dba.ExecuteAsync(
3✔
554
                                ChangePasswordQuery.GetQuery
3✔
555
                                , new
3✔
556
                                {
3✔
557
                                                UserId = userId
3✔
558
                                                , OldPassword = oldPassword
3✔
559
                                                , NewPassword = newPassword
3✔
560
                                                ,
3✔
561
                                });
3✔
562

563
                if (changePassword != 1)
3✔
564
                        throw new StandardExceptions.WrongPasswordException();
1✔
565
        }
2✔
566

567
        /// <summary>
568
        ///  Creates a request in the database for a reset password token.
569
        /// </summary>
570
        /// <param name="email">Email address of the user who has forgotten the password</param>
571
        /// <returns>Returns user information and secret token that are used to format the reset password email</returns>
572
        public async Task<DetailedUserWithToken> RequestResetForgottenPasswordAsync(string email)
573
        {
2✔
574
                await dba.BeginTransactionAsync();
2✔
575

576
                try
577
                {
2✔
578
                        // Get the user's details via the submitted email address
579
                        var columns = new List<string>
2✔
580
                        {
2✔
581
                                        "email"
2✔
582
                                        , "user_id"
2✔
583
                                        , "forename"
2✔
584
                                        , "surname"
2✔
585
                                        , "organization"
2✔
586
                                        ,
2✔
587
                        };
2✔
588

589
                        var where = new List<string> { "email" };
2✔
590

591
                        var userInfo = await dba.QuerySingleAsync<DetailedUserWithToken>(
2✔
592
                                        UserDetails.GetQuery(columns, where)
2✔
593
                                        , new { Email = email });
2✔
594

595
                        // Generate our secret token
596
                        var token = Guid.NewGuid();
2✔
597

598
                        // Write the token to the database
599
                        var tokenEntry = await dba.ExecuteAsync(
2✔
600
                                        CreateUserEmailTokenQuery.GetQuery()
2✔
601
                                        , new
2✔
602
                                        {
2✔
603
                                                        Token = token
2✔
604
                                                        , userInfo.UserId
2✔
605
                                                        , Type = CreateUserEmailTokenQuery.ResetPassword
2✔
606
                                                        ,
2✔
607
                                        });
2✔
608

609
                        if (tokenEntry != 1)
2!
610
                                return null;
×
611

612
                        // Cleanup
613
                        dba.CommitTransaction();
2✔
614

615
                        // Pass the token back in the user info object
616
                        userInfo.Token = token;
2✔
617

618
                        return userInfo;
2✔
619
                }
620
                catch { } // Suppress errors here. We don't want to risk people fishing for valid email addresses,
×
621

622
                // though any errors are suppressed in the controller too.
623

624
                return null;
×
625
        }
2✔
626

627
        /// <summary>
628
        ///  Resets a user's password based on the secret reset password token sent to the user's email address
629
        /// </summary>
630
        /// <param name="token">Secret token for resetting password</param>
631
        /// <param name="password">New password for the user's account</param>
632
        /// <returns></returns>
633
        public async Task<DetailedUser> ResetForgottenPasswordAsync(string token, string password)
634
        {
2✔
635
                await dba.BeginTransactionAsync();
2✔
636
                var detailedUserInfo = await GetDetailedUserByTokenAsync(token);
2✔
637

638
                var resetPassword = await dba.ExecuteAsync(
2✔
639
                                UpdatePasswordByToken.GetQuery
2✔
640
                                , new
2✔
641
                                {
2✔
642
                                                Token = Guid.Parse(token)
2✔
643
                                                , Password = password
2✔
644
                                                ,
2✔
645
                                });
2✔
646

647
                if (resetPassword != 1)
2!
648
                        throw new StandardExceptions.DataNotWrittenException("reset password");
×
649

650
                // Get all unused ResetPassword tokens
651
                var tokens = await dba.QueryAsync<Guid>(
2✔
652
                                GetTokensQuery.GetQuery
2✔
653
                                , new
2✔
654
                                {
2✔
655
                                                Token = Guid.Parse(token)
2✔
656
                                                , Type = CreateUserEmailTokenQuery.ResetPassword
2✔
657
                                                ,
2✔
658
                                });
2✔
659

660
                // Delete them all
661
                await dba.ExecuteAsync(
2✔
662
                                DeleteUserEmailTokenQuery.GetTokenQuery
2✔
663
                                , new
2✔
664
                                {
2✔
665
                                                Tokens = tokens
2✔
666
                                                , Type = CreateUserEmailTokenQuery.ResetPassword
2✔
667
                                                ,
2✔
668
                                });
2✔
669

670
                dba.CommitTransaction(); // Close the transaction
2✔
671

672
                return detailedUserInfo;
2✔
673
        }
2✔
674

675
        public async Task<string> GetUserDataStoreAsync(uint userId)
676
                => await dba.QuerySingleAsync<string>(
14✔
677
                                GetInformationFromUserDataStore.GetQuery
14✔
678
                                , new { UserId = userId });
14✔
679

680
        public async Task SetUserDataStoreAsync(uint userId, string data)
681
        {
4✔
682
                var insertData = await dba.ExecuteAsync(
4✔
683
                                SetInformationInUserDataStore.GetQuery
4✔
684
                                , new
4✔
685
                                {
4✔
686
                                                UserId = userId
4✔
687
                                                , Data = data
4✔
688
                                                ,
4✔
689
                                });
4✔
690

691
                if (insertData != 1)
4!
692
                        throw new StandardExceptions.DataNotWrittenException("INSERT INTO user data store");
×
693
        }
4✔
694

695
        public async Task<List<EditorInfo>> GetEditionEditorsAsync(uint editionId)
696
                => (await dba.QueryAsync<EditorInfo>(GetEditorInfo.GetQuery, new { EditionId = editionId }))
21✔
697
                                .ToList();
21✔
698

699
        public async Task<DatabaseVersion> GetDatabaseVersion(IDbConnection connection = null)
700
        {
3✔
701
                const string databaseVersionQuery = @"
702
SELECT Version, completed AS Date
703
FROM db_version
704
ORDER BY completed DESC
705
LIMIT 1";
706

707
                return await dba.QuerySingleAsync<DatabaseVersion>(databaseVersionQuery);
3✔
708
        }
3✔
709

710
        /// <summary>
711
        ///  When a new user confirms registration, they must be assigned the default user role
712
        ///  for a registered user.  This function receives the registration token and sets
713
        ///  the necessary system role for the new user.
714
        /// </summary>
715
        /// <param name="token">Registration token from the new user who is confirming registration</param>
716
        /// <returns></returns>
717
        /// <exception cref="StandardExceptions.DataNotWrittenException">The role could not be added for the new user</exception>
718
        private async Task SetNewUserRole(string token)
719
        {
14✔
720
                var setUserRole = await dba.ExecuteAsync(
14✔
721
                                SetUserSystemRole.GetQuery
14✔
722
                                , new
14✔
723
                                {
14✔
724
                                                Token = Guid.Parse(token)
14✔
725
                                                , SystemRole = "REGISTERED_USER"
14✔
726
                                                ,
14✔
727
                                });
14✔
728

729
                // Confirm the entry was written
730
                if (setUserRole != 1)
14!
731
                        throw new StandardExceptions.DataNotWrittenException("set user role");
×
732
        }
14✔
733
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc