From 0725e4f7cf4c6f723264b6d461b91c660d144cb7 Mon Sep 17 00:00:00 2001 From: ivarlovlie Date: Sun, 30 Oct 2022 22:40:03 +0700 Subject: feat: Apiwork --- .../Internal/Account/CreateAccountPayload.cs | 18 ++-- .../Internal/Account/CreateAccountRoute.cs | 68 ++++++------ .../Internal/Account/CreateInitialAccountRoute.cs | 52 +++++----- .../Internal/Account/DeleteAccountRoute.cs | 77 +++++++------- .../Endpoints/Internal/Account/GetArchiveRoute.cs | 115 ++++++++++----------- .../api/src/Endpoints/Internal/Account/GetRoute.cs | 8 +- .../src/Endpoints/Internal/Account/LoginRoute.cs | 57 +++++----- .../src/Endpoints/Internal/Account/LogoutRoute.cs | 32 +++--- .../Internal/Account/UpdateAccountRoute.cs | 93 +++++++++-------- .../PasswordResetRequests/Create/RequestModel.cs | 6 -- .../Internal/PasswordResetRequests/Create/Route.cs | 57 ---------- .../CreateResetRequestPayload.cs | 6 ++ .../CreateResetRequestRoute.cs | 46 +++++++++ .../FulfillResetRequestRoute.cs | 51 +++++---- .../IsResetRequestValidRoute.cs | 42 ++++---- .../Internal/Root/GetApplicationVersionRoute.cs | 29 +++--- code/api/src/Endpoints/Internal/Root/LogRoute.cs | 20 ++-- .../Internal/Root/ReadConfigurationRoute.cs | 22 ++-- .../Internal/Root/RefreshConfigurationRoute.cs | 18 ++-- 19 files changed, 395 insertions(+), 422 deletions(-) delete mode 100644 code/api/src/Endpoints/Internal/PasswordResetRequests/Create/RequestModel.cs delete mode 100644 code/api/src/Endpoints/Internal/PasswordResetRequests/Create/Route.cs create mode 100644 code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestPayload.cs create mode 100644 code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs (limited to 'code/api/src/Endpoints/Internal') diff --git a/code/api/src/Endpoints/Internal/Account/CreateAccountPayload.cs b/code/api/src/Endpoints/Internal/Account/CreateAccountPayload.cs index dc73e68..1161af3 100644 --- a/code/api/src/Endpoints/Internal/Account/CreateAccountPayload.cs +++ b/code/api/src/Endpoints/Internal/Account/CreateAccountPayload.cs @@ -5,13 +5,13 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; /// public class CreateAccountPayload { - /// - /// Username for the new account. - /// - public string Username { get; set; } + /// + /// Username for the new account. + /// + public string Username { get; set; } - /// - /// Password for the new account. - /// - public string Password { get; set; } -} + /// + /// Password for the new account. + /// + public string Password { get; set; } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/CreateAccountRoute.cs b/code/api/src/Endpoints/Internal/Account/CreateAccountRoute.cs index 0f4a383..f34056d 100644 --- a/code/api/src/Endpoints/Internal/Account/CreateAccountRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/CreateAccountRoute.cs @@ -1,44 +1,42 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; -/// public class CreateAccountRoute : RouteBaseAsync.WithRequest.WithActionResult { - private readonly AppDbContext _context; - private readonly UserService _userService; + private readonly MainAppDatabase _database; + private readonly UserService _userService; - /// - public CreateAccountRoute(UserService userService, AppDbContext context) { - _userService = userService; - _context = context; - } + public CreateAccountRoute(UserService userService, MainAppDatabase database) { + _userService = userService; + _database = database; + } - /// - /// Create a new user account. - /// - /// - /// - /// - [AllowAnonymous] - [HttpPost("~/_/account/create")] - public override async Task HandleAsync(CreateAccountPayload request, CancellationToken cancellationToken = default) { - if (request.Username.IsValidEmailAddress() == false) { - return BadRequest(new KnownProblemModel("Invalid form", request.Username + " does not look like a valid email")); - } + /// + /// Create a new user account. + /// + /// + /// + /// + [AllowAnonymous] + [HttpPost("~/_/account/create")] + public override async Task HandleAsync(CreateAccountPayload request, CancellationToken cancellationToken = default) { + if (request.Username.IsValidEmailAddress() == false) { + return BadRequest(new KnownProblemModel("Invalid form", request.Username + " does not look like a valid email")); + } - if (request.Password.Length < 6) { - return BadRequest(new KnownProblemModel("Invalid form", "The password requires 6 or more characters.")); - } + if (request.Password.Length < 6) { + return BadRequest(new KnownProblemModel("Invalid form", "The password requires 6 or more characters.")); + } - var username = request.Username.Trim(); - if (_context.Users.Any(c => c.Username == username)) { - return BadRequest(new KnownProblemModel("Username is not available", "There is already a user registered with email: " + username)); - } + var username = request.Username.Trim(); + if (_database.Users.Any(c => c.Username == username)) { + return BadRequest(new KnownProblemModel("Username is not available", "There is already a user registered with email: " + username)); + } - var user = new User(username); - user.HashAndSetPassword(request.Password); - _context.Users.Add(user); - await _context.SaveChangesAsync(cancellationToken); - await _userService.LogInUser(HttpContext, user); - return Ok(); - } -} + var user = new User(username); + user.HashAndSetPassword(request.Password); + _database.Users.Add(user); + await _database.SaveChangesAsync(cancellationToken); + await _userService.LogInUser(HttpContext, user); + return Ok(); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs b/code/api/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs index 13fbdf4..56ff9c6 100644 --- a/code/api/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs @@ -1,34 +1,32 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; -/// public class CreateInitialAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult { - private readonly AppDbContext _context; - private readonly UserService _userService; + private readonly MainAppDatabase _database; + private readonly UserService _userService; - /// - public CreateInitialAccountRoute(AppDbContext context, UserService userService) { - _context = context; - _userService = userService; - } + public CreateInitialAccountRoute(MainAppDatabase database, UserService userService) { + _database = database; + _userService = userService; + } - /// - /// Create an initial user account. - /// - /// - /// - [AllowAnonymous] - [HttpGet("~/_/account/create-initial")] - public override async Task HandleAsync(CancellationToken cancellationToken = default) { - if (_context.Users.Any()) { - return NotFound(); - } + /// + /// Create an initial user account. + /// + /// + /// + [AllowAnonymous] + [HttpGet("~/_/account/create-initial")] + public override async Task HandleAsync(CancellationToken cancellationToken = default) { + if (_database.Users.Any()) { + return NotFound(); + } - var user = new User("admin@ivarlovlie.no"); - user.HashAndSetPassword("ivar123"); - _context.Users.Add(user); - await _context.SaveChangesAsync(cancellationToken); - await _userService.LogInUser(HttpContext, user); - return Redirect("/"); - } -} + var user = new User("admin@ivarlovlie.no"); + user.HashAndSetPassword("ivar123"); + _database.Users.Add(user); + await _database.SaveChangesAsync(cancellationToken); + await _userService.LogInUser(HttpContext, user); + return Redirect("/"); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/DeleteAccountRoute.cs b/code/api/src/Endpoints/Internal/Account/DeleteAccountRoute.cs index 2149e15..5df1fb6 100644 --- a/code/api/src/Endpoints/Internal/Account/DeleteAccountRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/DeleteAccountRoute.cs @@ -2,48 +2,47 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; public class DeleteAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult { - private readonly AppDbContext _context; - private readonly UserService _userService; + private readonly MainAppDatabase _database; + private readonly UserService _userService; - /// - public DeleteAccountRoute(AppDbContext context, UserService userService) { - _context = context; - _userService = userService; - } + public DeleteAccountRoute(MainAppDatabase database, UserService userService) { + _database = database; + _userService = userService; + } - /// - /// Delete the logged on user's account. - /// - /// - /// - [HttpDelete("~/_/account/delete")] - public override async Task HandleAsync(CancellationToken cancellationToken = default) { - var user = _context.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); - if (user == default) { - await _userService.LogOutUser(HttpContext); - return Unauthorized(); - } + /// + /// Delete the logged on user's account. + /// + /// + /// + [HttpDelete("~/_/account/delete")] + public override async Task HandleAsync(CancellationToken cancellationToken = default) { + var user = _database.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); + if (user == default) { + await _userService.LogOutUser(HttpContext); + return Unauthorized(); + } - if (user.Username == "demo@demo.demo") { - await _userService.LogOutUser(HttpContext); - return Ok(); - } + if (user.Username == "demo@demo.demo") { + await _userService.LogOutUser(HttpContext); + return Ok(); + } - var githubMappings = _context.TimeCategories.Where(c => c.UserId == user.Id); - var passwordResets = _context.ForgotPasswordRequests.Where(c => c.UserId == user.Id); - var entries = _context.TimeEntries.Where(c => c.UserId == user.Id); - var labels = _context.TimeLabels.Where(c => c.UserId == user.Id); - var categories = _context.TimeCategories.Where(c => c.UserId == user.Id); + var githubMappings = _database.TimeCategories.Where(c => c.UserId == user.Id); + var passwordResets = _database.ForgotPasswordRequests.Where(c => c.UserId == user.Id); + var entries = _database.TimeEntries.Where(c => c.UserId == user.Id); + var labels = _database.TimeLabels.Where(c => c.UserId == user.Id); + var categories = _database.TimeCategories.Where(c => c.UserId == user.Id); - _context.TimeCategories.RemoveRange(githubMappings); - _context.ForgotPasswordRequests.RemoveRange(passwordResets); - _context.TimeEntries.RemoveRange(entries); - _context.TimeLabels.RemoveRange(labels); - _context.TimeCategories.RemoveRange(categories); - _context.Users.Remove(user); + _database.TimeCategories.RemoveRange(githubMappings); + _database.ForgotPasswordRequests.RemoveRange(passwordResets); + _database.TimeEntries.RemoveRange(entries); + _database.TimeLabels.RemoveRange(labels); + _database.TimeCategories.RemoveRange(categories); + _database.Users.Remove(user); - await _context.SaveChangesAsync(cancellationToken); - await _userService.LogOutUser(HttpContext); - return Ok(); - } -} + await _database.SaveChangesAsync(cancellationToken); + await _userService.LogOutUser(HttpContext); + return Ok(); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/GetArchiveRoute.cs b/code/api/src/Endpoints/Internal/Account/GetArchiveRoute.cs index f1b70f3..0d9f817 100644 --- a/code/api/src/Endpoints/Internal/Account/GetArchiveRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/GetArchiveRoute.cs @@ -2,61 +2,60 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; public class GetAccountArchiveRoute : RouteBaseAsync.WithoutRequest.WithActionResult { - private readonly AppDbContext _context; - - /// - public GetAccountArchiveRoute(AppDbContext context) { - _context = context; - } - - /// - /// Get a data archive with the currently logged on user's data. - /// - /// - /// - [HttpGet("~/_/account/archive")] - public override async Task> HandleAsync(CancellationToken cancellationToken = default) { - var user = _context.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); - if (user == default) { - await HttpContext.SignOutAsync(); - return Unauthorized(); - } - - var entries = _context.TimeEntries - .AsNoTracking() - .Include(c => c.Labels) - .Include(c => c.Category) - .Where(c => c.UserId == user.Id) - .ToList(); - - var jsonOptions = new JsonSerializerOptions { - WriteIndented = true - }; - - var dto = new UserArchiveDto(user); - dto.Entries.AddRange(entries.Select(entry => new UserArchiveDto.EntryDto { - CreatedAt = entry.CreatedAt.ToString("yyyy-MM-ddTHH:mm:ssZ"), - StartDateTime = entry.Start, - StopDateTime = entry.Stop, - Description = entry.Description, - Labels = entry.Labels - .Select(c => new UserArchiveDto.LabelDto { - Name = c.Name, - Color = c.Color - }) - .ToList(), - Category = new UserArchiveDto.CategoryDto { - Name = entry.Category.Name, - Color = entry.Category.Color - }, - })); - - dto.CountEntries(); - - var entriesSerialized = JsonSerializer.SerializeToUtf8Bytes(dto, jsonOptions); - - return File(entriesSerialized, - "application/json", - user.Username + "-time-tracker-archive-" + AppDateTime.UtcNow.ToString("yyyyMMddTHHmmss") + ".json"); - } -} + private readonly MainAppDatabase _database; + + public GetAccountArchiveRoute(MainAppDatabase database) { + _database = database; + } + + /// + /// Get a data archive with the currently logged on user's data. + /// + /// + /// + [HttpGet("~/_/account/archive")] + public override async Task> HandleAsync(CancellationToken cancellationToken = default) { + var user = _database.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); + if (user == default) { + await HttpContext.SignOutAsync(); + return Unauthorized(); + } + + var entries = _database.TimeEntries + .AsNoTracking() + .Include(c => c.Labels) + .Include(c => c.Category) + .Where(c => c.UserId == user.Id) + .ToList(); + + var jsonOptions = new JsonSerializerOptions { + WriteIndented = true + }; + + var dto = new UserArchiveDto(user); + dto.Entries.AddRange(entries.Select(entry => new UserArchiveDto.EntryDto { + CreatedAt = entry.CreatedAt.ToString("yyyy-MM-ddTHH:mm:ssZ"), + StartDateTime = entry.Start, + StopDateTime = entry.Stop, + Description = entry.Description, + Labels = entry.Labels + .Select(c => new UserArchiveDto.LabelDto { + Name = c.Name, + Color = c.Color + }) + .ToList(), + Category = new UserArchiveDto.CategoryDto { + Name = entry.Category.Name, + Color = entry.Category.Color + }, + })); + + dto.CountEntries(); + + var entriesSerialized = JsonSerializer.SerializeToUtf8Bytes(dto, jsonOptions); + + return File(entriesSerialized, + "application/json", + user.Username + "-time-tracker-archive-" + AppDateTime.UtcNow.ToString("yyyyMMddTHHmmss") + ".json"); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/GetRoute.cs b/code/api/src/Endpoints/Internal/Account/GetRoute.cs index 1aa7ecb..8d6c50f 100644 --- a/code/api/src/Endpoints/Internal/Account/GetRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/GetRoute.cs @@ -2,10 +2,10 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; public class GetAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult { - private readonly AppDbContext _context; + private readonly MainAppDatabase _database; - public GetAccountRoute(AppDbContext context) { - _context = context; + public GetAccountRoute(MainAppDatabase database) { + _database = database; } /// @@ -15,7 +15,7 @@ public class GetAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult [HttpGet("~/_/account")] public override async Task> HandleAsync(CancellationToken cancellationToken = default) { - var user = _context.Users + var user = _database.Users .Select(x => new {x.Username, x.Id}) .SingleOrDefault(c => c.Id == LoggedInUser.Id); if (user != default) { diff --git a/code/api/src/Endpoints/Internal/Account/LoginRoute.cs b/code/api/src/Endpoints/Internal/Account/LoginRoute.cs index e4ef54c..696c3c2 100644 --- a/code/api/src/Endpoints/Internal/Account/LoginRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/LoginRoute.cs @@ -1,37 +1,34 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; -public class LoginRoute : RouteBaseAsync - .WithRequest - .WithActionResult +public class LoginRoute : RouteBaseAsync.WithRequest.WithActionResult { - private readonly AppDbContext _context; - private readonly UserService _userService; + private readonly MainAppDatabase _database; + private readonly UserService _userService; - /// - public LoginRoute(AppDbContext context, UserService userService) { - _context = context; - _userService = userService; - } + public LoginRoute(MainAppDatabase database, UserService userService) { + _database = database; + _userService = userService; + } - /// - /// Login a user. - /// - /// - /// - /// - [AllowAnonymous] - [HttpPost("~/_/account/login")] - public override async Task HandleAsync(LoginPayload request, CancellationToken cancellationToken = default) { - if (!ModelState.IsValid) { - return BadRequest(ModelState); - } + /// + /// Login a user. + /// + /// + /// + /// + [AllowAnonymous] + [HttpPost("~/_/account/login")] + public override async Task HandleAsync(LoginPayload request, CancellationToken cancellationToken = default) { + if (!ModelState.IsValid) { + return BadRequest(ModelState); + } - var user = _context.Users.SingleOrDefault(u => u.Username == request.Username); - if (user == default || !user.VerifyPassword(request.Password)) { - return BadRequest(new KnownProblemModel("Invalid username or password")); - } + var user = _database.Users.SingleOrDefault(u => u.Username == request.Username); + if (user == default || !user.VerifyPassword(request.Password)) { + return BadRequest(new KnownProblemModel("Invalid username or password")); + } - await _userService.LogInUser(HttpContext, user, request.Persist); - return Ok(); - } -} + await _userService.LogInUser(HttpContext, user, request.Persist); + return Ok(); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/LogoutRoute.cs b/code/api/src/Endpoints/Internal/Account/LogoutRoute.cs index 4a06f4a..042d729 100644 --- a/code/api/src/Endpoints/Internal/Account/LogoutRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/LogoutRoute.cs @@ -2,21 +2,21 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; public class LogoutRoute : RouteBaseAsync.WithoutRequest.WithActionResult { - private readonly UserService _userService; + private readonly UserService _userService; - public LogoutRoute(UserService userService) { - _userService = userService; - } + public LogoutRoute(UserService userService) { + _userService = userService; + } - /// - /// Logout a user. - /// - /// - /// - [AllowAnonymous] - [HttpGet("~/_/account/logout")] - public override async Task HandleAsync(CancellationToken cancellationToken = default) { - await _userService.LogOutUser(HttpContext); - return Ok(); - } -} + /// + /// Logout a user. + /// + /// + /// + [AllowAnonymous] + [HttpGet("~/_/account/logout")] + public override async Task HandleAsync(CancellationToken cancellationToken = default) { + await _userService.LogOutUser(HttpContext); + return Ok(); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs b/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs index 31ff10b..02dc3f1 100644 --- a/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs +++ b/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs @@ -2,50 +2,49 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; public class UpdateAccountRoute : RouteBaseAsync.WithRequest.WithActionResult { - private readonly AppDbContext _context; - - /// - public UpdateAccountRoute(AppDbContext context) { - _context = context; - } - - /// - /// Update the logged on user's data. - /// - /// - /// - /// - [HttpPost("~/_/account/update")] - public override async Task HandleAsync(UpdatePayload request, CancellationToken cancellationToken = default) { - var user = _context.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); - if (user == default) { - await HttpContext.SignOutAsync(); - return Unauthorized(); - } - - if (request.Password.IsNullOrWhiteSpace() && request.Username.IsNullOrWhiteSpace()) { - return BadRequest(new KnownProblemModel("Invalid request", "No data was submitted")); - } - - if (request.Password.HasValue() && request.Password.Length < 6) { - return BadRequest(new KnownProblemModel("Invalid request", - "The new password must contain at least 6 characters")); - } - - if (request.Password.HasValue()) { - user.HashAndSetPassword(request.Password); - } - - if (request.Username.HasValue() && !request.Username.IsValidEmailAddress()) { - return BadRequest(new KnownProblemModel("Invalid request", - "The new username does not look like a valid email address")); - } - - if (request.Username.HasValue()) { - user.Username = request.Username.Trim(); - } - - await _context.SaveChangesAsync(cancellationToken); - return Ok(); - } -} + private readonly MainAppDatabase _database; + + public UpdateAccountRoute(MainAppDatabase database) { + _database = database; + } + + /// + /// Update the logged on user's data. + /// + /// + /// + /// + [HttpPost("~/_/account/update")] + public override async Task HandleAsync(UpdatePayload request, CancellationToken cancellationToken = default) { + var user = _database.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); + if (user == default) { + await HttpContext.SignOutAsync(); + return Unauthorized(); + } + + if (request.Password.IsNullOrWhiteSpace() && request.Username.IsNullOrWhiteSpace()) { + return BadRequest(new KnownProblemModel("Invalid request", "No data was submitted")); + } + + if (request.Password.HasValue() && request.Password.Length < 6) { + return BadRequest(new KnownProblemModel("Invalid request", + "The new password must contain at least 6 characters")); + } + + if (request.Password.HasValue()) { + user.HashAndSetPassword(request.Password); + } + + if (request.Username.HasValue() && !request.Username.IsValidEmailAddress()) { + return BadRequest(new KnownProblemModel("Invalid request", + "The new username does not look like a valid email address")); + } + + if (request.Username.HasValue()) { + user.Username = request.Username.Trim(); + } + + await _database.SaveChangesAsync(cancellationToken); + return Ok(); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/RequestModel.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/RequestModel.cs deleted file mode 100644 index 236c650..0000000 --- a/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/RequestModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests.Create; - -public class RequestModel -{ - public string Username { get; set; } -} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/Route.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/Route.cs deleted file mode 100644 index f837fc0..0000000 --- a/code/api/src/Endpoints/Internal/PasswordResetRequests/Create/Route.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests.Create; - -public class Route : RouteBaseAsync.WithRequest.WithActionResult -{ - private readonly ILogger _logger; - private readonly PasswordResetService _passwordResetService; - private readonly AppDbContext _context; - - public Route(ILogger logger, PasswordResetService passwordResetService, AppDbContext context) { - _logger = logger; - _passwordResetService = passwordResetService; - _context = context; - } - - /// - /// Create a new password reset request. - /// - /// - /// - /// - [AllowAnonymous] - [HttpPost("~/_/password-reset-request/create")] - public override async Task HandleAsync(RequestModel request, CancellationToken cancellationToken = default) { - if (!request.Username.IsValidEmailAddress()) { - _logger.LogInformation("Username is invalid, not doing request for password change"); - return KnownProblem("Invalid email address", request.Username + " looks like an invalid email address"); - } - - Request.Headers.TryGetValue(AppHeaders.BROWSER_TIME_ZONE, out var timeZoneHeader); - var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneHeader.ToString().HasValue() ? timeZoneHeader.ToString() : "UTC"); - var offset = tz.BaseUtcOffset.Hours; - - // this is fine as long as the client is not connecting from Australia: Lord Howe Island - // according to https://en.wikipedia.org/wiki/Daylight_saving_time_by_country - if (tz.IsDaylightSavingTime(AppDateTime.UtcNow)) { - offset++; - } - - _logger.LogInformation("Request time zone (" + tz.Id + ") offset is: " + offset + " hours"); - var requestDateTime = TimeZoneInfo.ConvertTimeFromUtc(AppDateTime.UtcNow, tz); - _logger.LogInformation("Creating forgot password request with date time: " + requestDateTime.ToString("u")); - - try { - var user = _context.Users.SingleOrDefault(c => c.Username.Equals(request.Username)); - if (user != default) { - await _passwordResetService.AddRequestAsync(user, tz, cancellationToken); - return Ok(); - } - - _logger.LogInformation("User was not found, not doing request for password change"); - return Ok(); - } catch (Exception e) { - _logger.LogError(e, "_/password-reset-request/create threw an exception"); - return Ok(); - } - } -} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestPayload.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestPayload.cs new file mode 100644 index 0000000..1adb344 --- /dev/null +++ b/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestPayload.cs @@ -0,0 +1,6 @@ +namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; + +public class CreateResetRequestPayload +{ + public string Username { get; set; } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs new file mode 100644 index 0000000..bb72d38 --- /dev/null +++ b/code/api/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs @@ -0,0 +1,46 @@ +namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; + +public class Route : RouteBaseAsync.WithRequest.WithActionResult +{ + private readonly ILogger _logger; + private readonly PasswordResetService _passwordResetService; + private readonly MainAppDatabase _database; + + public Route(ILogger logger, PasswordResetService passwordResetService, MainAppDatabase database) { + _logger = logger; + _passwordResetService = passwordResetService; + _database = database; + } + + /// + /// Create a new password reset request. + /// + /// + /// + /// + [AllowAnonymous] + [HttpPost("~/_/password-reset-request/create")] + public override async Task HandleAsync(CreateResetRequestPayload request, CancellationToken cancellationToken = default) { + if (!request.Username.IsValidEmailAddress()) { + _logger.LogInformation("Username is invalid, not doing request for password change"); + return KnownProblem("Invalid email address", request.Username + " looks like an invalid email address"); + } + + var tz = GetRequestTimeZone(_logger); + _logger.LogInformation("Creating forgot password request with local date time: " + tz.LocalDateTime.ToString("u")); + + try { + var user = _database.Users.SingleOrDefault(c => c.Username.Equals(request.Username)); + if (user != default) { + await _passwordResetService.AddRequestAsync(user, tz.TimeZoneInfo, cancellationToken); + return Ok(); + } + + _logger.LogInformation("User was not found, not doing request for password change"); + return Ok(); + } catch (Exception e) { + _logger.LogError(e, "_/password-reset-request/create threw an exception"); + return Ok(); + } + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs index a0ad4d0..6f71b2f 100644 --- a/code/api/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs +++ b/code/api/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs @@ -1,34 +1,31 @@ - namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; -/// public class FulfillResetRequestRoute : RouteBaseAsync.WithRequest.WithActionResult { - private readonly PasswordResetService _passwordResetService; + private readonly PasswordResetService _passwordResetService; - /// - public FulfillResetRequestRoute(PasswordResetService passwordResetService) { - _passwordResetService = passwordResetService; - } + public FulfillResetRequestRoute(PasswordResetService passwordResetService) { + _passwordResetService = passwordResetService; + } - /// - /// Fulfill a password reset request. - /// - /// - /// - /// - [AllowAnonymous] - [HttpPost("~/_/password-reset-request/fulfill")] - public override async Task HandleAsync(FulfillResetRequestPayload request, CancellationToken cancellationToken = default) { - try { - var fulfilled = await _passwordResetService.FullFillRequestAsync(request.Id, request.NewPassword, cancellationToken); - return Ok(fulfilled); - } catch (Exception e) { - if (e is ForgotPasswordRequestNotFoundException or UserNotFoundException) { - return NotFound(); - } + /// + /// Fulfill a password reset request. + /// + /// + /// + /// + [AllowAnonymous] + [HttpPost("~/_/password-reset-request/fulfill")] + public override async Task HandleAsync(FulfillResetRequestPayload request, CancellationToken cancellationToken = default) { + try { + var fulfilled = await _passwordResetService.FullFillRequestAsync(request.Id, request.NewPassword, cancellationToken); + return Ok(fulfilled); + } catch (Exception e) { + if (e is ForgotPasswordRequestNotFoundException or UserNotFoundException) { + return NotFound(); + } - throw; - } - } -} + throw; + } + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs b/code/api/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs index 917c4f0..687cef6 100644 --- a/code/api/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs +++ b/code/api/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs @@ -1,29 +1,27 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; -/// public class IsResetRequestValidRoute : RouteBaseAsync.WithRequest.WithActionResult { - private readonly PasswordResetService _passwordResetService; + private readonly PasswordResetService _passwordResetService; - /// - public IsResetRequestValidRoute(PasswordResetService passwordResetService) { - _passwordResetService = passwordResetService; - } + public IsResetRequestValidRoute(PasswordResetService passwordResetService) { + _passwordResetService = passwordResetService; + } - /// - /// Check if a given password reset request is still valid. - /// - /// - /// - /// - [AllowAnonymous] - [HttpGet("~/_/password-reset-request/is-valid")] - public override async Task HandleAsync(Guid id, CancellationToken cancellationToken = default) { - var request = await _passwordResetService.GetRequestAsync(id, cancellationToken); - if (request == default) { - return NotFound(); - } + /// + /// Check if a given password reset request is still valid. + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("~/_/password-reset-request/is-valid")] + public override async Task HandleAsync(Guid id, CancellationToken cancellationToken = default) { + var request = await _passwordResetService.GetRequestAsync(id, cancellationToken); + if (request == default) { + return NotFound(); + } - return Ok(request.IsExpired == false); - } -} + return Ok(request.IsExpired == false); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs b/code/api/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs index 5fb8213..34180d1 100644 --- a/code/api/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs +++ b/code/api/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs @@ -2,20 +2,19 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; public class GetApplicationVersionRoute : RouteBaseSync.WithoutRequest.WithActionResult { - private readonly IWebHostEnvironment _environment; + private readonly IWebHostEnvironment _environment; - /// - public GetApplicationVersionRoute(IWebHostEnvironment environment) { - _environment = environment; - } + public GetApplicationVersionRoute(IWebHostEnvironment environment) { + _environment = environment; + } - /// - /// Get the running api version number. - /// - /// - [HttpGet("~/_/version")] - public override ActionResult Handle() { - var versionFilePath = Path.Combine(_environment.WebRootPath, "version.txt"); - return Ok(System.IO.File.ReadAllText(versionFilePath)); - } -} + /// + /// Get the running api version number. + /// + /// + [HttpGet("~/_/version")] + public override ActionResult Handle() { + var versionFilePath = Path.Combine(_environment.WebRootPath, "version.txt"); + return Ok(System.IO.File.ReadAllText(versionFilePath)); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Root/LogRoute.cs b/code/api/src/Endpoints/Internal/Root/LogRoute.cs index 48b497a..2c69e94 100644 --- a/code/api/src/Endpoints/Internal/Root/LogRoute.cs +++ b/code/api/src/Endpoints/Internal/Root/LogRoute.cs @@ -2,15 +2,15 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; public class LogRoute : RouteBaseSync.WithRequest.WithoutResult { - private readonly ILogger _logger; + private readonly ILogger _logger; - public LogRoute(ILogger logger) { - _logger = logger; - } + public LogRoute(ILogger logger) { + _logger = logger; + } - [AllowAnonymous] - [HttpPost("~/_/log")] - public override void Handle([FromBody] string request) { - _logger.LogInformation(request); - } -} + [AllowAnonymous] + [HttpPost("~/_/log")] + public override void Handle([FromBody] string request) { + _logger.LogInformation(request); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs b/code/api/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs index e0dcca3..7270fd8 100644 --- a/code/api/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs +++ b/code/api/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs @@ -2,16 +2,16 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; public class ReadConfigurationRoute : RouteBaseSync.WithoutRequest.WithActionResult { - private readonly VaultService _vaultService; + private readonly VaultService _vaultService; - public ReadConfigurationRoute(VaultService vaultService) { - _vaultService = vaultService; - } + public ReadConfigurationRoute(VaultService vaultService) { + _vaultService = vaultService; + } - [AllowAnonymous] - [HttpGet("~/_/configuration")] - public override ActionResult Handle() { - var config = _vaultService.GetCurrentAppConfiguration(); - return Content(JsonSerializer.Serialize(config.GetPublicVersion()), "application/json"); - } -} + [AllowAnonymous] + [HttpGet("~/_/configuration")] + public override ActionResult Handle() { + var config = _vaultService.GetCurrentAppConfiguration(); + return Content(JsonSerializer.Serialize(config.GetPublicVersion()), "application/json"); + } +} \ No newline at end of file diff --git a/code/api/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs b/code/api/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs index 4b1beec..a616c00 100644 --- a/code/api/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs +++ b/code/api/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs @@ -2,14 +2,14 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; public class RefreshConfigurationRoute : RouteBaseSync.WithoutRequest.WithoutResult { - private readonly VaultService _vaultService; + private readonly VaultService _vaultService; - public RefreshConfigurationRoute(VaultService vaultService) { - _vaultService = vaultService; - } + public RefreshConfigurationRoute(VaultService vaultService) { + _vaultService = vaultService; + } - [HttpGet("~/_/refresh-configuration")] - public override void Handle() { - _vaultService.RefreshCurrentAppConfiguration(); - } -} + [HttpGet("~/_/refresh-configuration")] + public override void Handle() { + _vaultService.RefreshCurrentAppConfiguration(); + } +} \ No newline at end of file -- cgit v1.3