From b7e39b59fd0fc7b5610ebff29035bf622079e0d8 Mon Sep 17 00:00:00 2001 From: ivarlovlie Date: Wed, 5 Oct 2022 20:45:21 +0800 Subject: refactor: Change file structure --- .../Internal/Account/CreateAccountPayload.cs | 17 -- .../Internal/Account/CreateAccountRoute.cs | 44 ----- .../Internal/Account/CreateInitialAccountRoute.cs | 34 ---- .../Internal/Account/DeleteAccountRoute.cs | 49 ------ .../Endpoints/Internal/Account/GetArchiveRoute.cs | 62 ------- server/src/Endpoints/Internal/Account/GetRoute.cs | 31 ---- .../src/Endpoints/Internal/Account/LoginPayload.cs | 22 --- .../src/Endpoints/Internal/Account/LoginRoute.cs | 37 ---- .../src/Endpoints/Internal/Account/LogoutRoute.cs | 22 --- .../Internal/Account/UpdateAccountPayload.cs | 17 -- .../Internal/Account/UpdateAccountRoute.cs | 51 ------ server/src/Endpoints/Internal/BaseRoute.cs | 16 -- .../CreateResetRequestRoute.cs | 59 ------- .../FulfillResetRequestPayload.cs | 14 -- .../FulfillResetRequestRoute.cs | 34 ---- .../IsResetRequestValidRoute.cs | 29 ---- .../Internal/Root/GetApplicationVersionRoute.cs | 21 --- server/src/Endpoints/Internal/Root/LogRoute.cs | 16 -- .../Internal/Root/ReadConfigurationRoute.cs | 17 -- .../Internal/Root/RefreshConfigurationRoute.cs | 15 -- .../Endpoints/Internal/Root/ValidSessionRoute.cs | 10 -- server/src/Endpoints/Internal/RouteBaseAsync.cs | 73 -------- server/src/Endpoints/Internal/RouteBaseSync.cs | 53 ------ server/src/Endpoints/V1/ApiSpecV1.cs | 18 -- .../src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs | 57 ------- .../src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs | 33 ---- .../src/Endpoints/V1/ApiTokens/GetTokensRoute.cs | 22 --- server/src/Endpoints/V1/BaseRoute.cs | 39 ----- .../Endpoints/V1/Categories/CreateCategoryRoute.cs | 43 ----- .../Endpoints/V1/Categories/DeleteCategoryRoute.cs | 38 ----- .../Endpoints/V1/Categories/GetCategoriesRoute.cs | 35 ---- .../Endpoints/V1/Categories/UpdateCategoryRoute.cs | 39 ----- .../src/Endpoints/V1/Entries/CreateEntryRoute.cs | 65 ------- .../src/Endpoints/V1/Entries/DeleteEntryRoute.cs | 35 ---- .../src/Endpoints/V1/Entries/EntryQueryPayload.cs | 60 ------- .../src/Endpoints/V1/Entries/EntryQueryResponse.cs | 37 ---- server/src/Endpoints/V1/Entries/EntryQueryRoute.cs | 186 --------------------- server/src/Endpoints/V1/Entries/GetEntryRoute.cs | 34 ---- .../src/Endpoints/V1/Entries/UpdateEntryRoute.cs | 66 -------- server/src/Endpoints/V1/Labels/CreateLabelRoute.cs | 46 ----- server/src/Endpoints/V1/Labels/DeleteLabelRoute.cs | 35 ---- server/src/Endpoints/V1/Labels/GetLabelRoute.cs | 34 ---- server/src/Endpoints/V1/Labels/UpdateLabelRoute.cs | 38 ----- server/src/Endpoints/V1/RouteBaseAsync.cs | 73 -------- server/src/Endpoints/V1/RouteBaseSync.cs | 53 ------ 45 files changed, 1829 deletions(-) delete mode 100644 server/src/Endpoints/Internal/Account/CreateAccountPayload.cs delete mode 100644 server/src/Endpoints/Internal/Account/CreateAccountRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/DeleteAccountRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/GetArchiveRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/GetRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/LoginPayload.cs delete mode 100644 server/src/Endpoints/Internal/Account/LoginRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/LogoutRoute.cs delete mode 100644 server/src/Endpoints/Internal/Account/UpdateAccountPayload.cs delete mode 100644 server/src/Endpoints/Internal/Account/UpdateAccountRoute.cs delete mode 100644 server/src/Endpoints/Internal/BaseRoute.cs delete mode 100644 server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs delete mode 100644 server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestPayload.cs delete mode 100644 server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs delete mode 100644 server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs delete mode 100644 server/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs delete mode 100644 server/src/Endpoints/Internal/Root/LogRoute.cs delete mode 100644 server/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs delete mode 100644 server/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs delete mode 100644 server/src/Endpoints/Internal/Root/ValidSessionRoute.cs delete mode 100644 server/src/Endpoints/Internal/RouteBaseAsync.cs delete mode 100644 server/src/Endpoints/Internal/RouteBaseSync.cs delete mode 100644 server/src/Endpoints/V1/ApiSpecV1.cs delete mode 100644 server/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs delete mode 100644 server/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs delete mode 100644 server/src/Endpoints/V1/ApiTokens/GetTokensRoute.cs delete mode 100644 server/src/Endpoints/V1/BaseRoute.cs delete mode 100644 server/src/Endpoints/V1/Categories/CreateCategoryRoute.cs delete mode 100644 server/src/Endpoints/V1/Categories/DeleteCategoryRoute.cs delete mode 100644 server/src/Endpoints/V1/Categories/GetCategoriesRoute.cs delete mode 100644 server/src/Endpoints/V1/Categories/UpdateCategoryRoute.cs delete mode 100644 server/src/Endpoints/V1/Entries/CreateEntryRoute.cs delete mode 100644 server/src/Endpoints/V1/Entries/DeleteEntryRoute.cs delete mode 100644 server/src/Endpoints/V1/Entries/EntryQueryPayload.cs delete mode 100644 server/src/Endpoints/V1/Entries/EntryQueryResponse.cs delete mode 100644 server/src/Endpoints/V1/Entries/EntryQueryRoute.cs delete mode 100644 server/src/Endpoints/V1/Entries/GetEntryRoute.cs delete mode 100644 server/src/Endpoints/V1/Entries/UpdateEntryRoute.cs delete mode 100644 server/src/Endpoints/V1/Labels/CreateLabelRoute.cs delete mode 100644 server/src/Endpoints/V1/Labels/DeleteLabelRoute.cs delete mode 100644 server/src/Endpoints/V1/Labels/GetLabelRoute.cs delete mode 100644 server/src/Endpoints/V1/Labels/UpdateLabelRoute.cs delete mode 100644 server/src/Endpoints/V1/RouteBaseAsync.cs delete mode 100644 server/src/Endpoints/V1/RouteBaseSync.cs (limited to 'server/src/Endpoints') diff --git a/server/src/Endpoints/Internal/Account/CreateAccountPayload.cs b/server/src/Endpoints/Internal/Account/CreateAccountPayload.cs deleted file mode 100644 index dc73e68..0000000 --- a/server/src/Endpoints/Internal/Account/CreateAccountPayload.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -/// -/// Payload for creating new user accounts. -/// -public class CreateAccountPayload -{ - /// - /// Username for the new account. - /// - public string Username { get; set; } - - /// - /// Password for the new account. - /// - public string Password { get; set; } -} diff --git a/server/src/Endpoints/Internal/Account/CreateAccountRoute.cs b/server/src/Endpoints/Internal/Account/CreateAccountRoute.cs deleted file mode 100644 index 954fbf5..0000000 --- a/server/src/Endpoints/Internal/Account/CreateAccountRoute.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -/// -public class CreateAccountRoute : RouteBaseAsync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - private readonly UserService _userService; - - /// - public CreateAccountRoute(UserService userService, AppDbContext context) { - _userService = userService; - _context = context; - } - - /// - /// 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 ErrorResult("Invalid form", request.Username + " does not look like a valid email")); - } - - if (request.Password.Length < 6) { - return BadRequest(new ErrorResult("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 ErrorResult("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(); - } -} diff --git a/server/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs b/server/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs deleted file mode 100644 index 13fbdf4..0000000 --- a/server/src/Endpoints/Internal/Account/CreateInitialAccountRoute.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -/// -public class CreateInitialAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult -{ - private readonly AppDbContext _context; - private readonly UserService _userService; - - /// - public CreateInitialAccountRoute(AppDbContext context, UserService userService) { - _context = context; - _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(); - } - - 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("/"); - } -} diff --git a/server/src/Endpoints/Internal/Account/DeleteAccountRoute.cs b/server/src/Endpoints/Internal/Account/DeleteAccountRoute.cs deleted file mode 100644 index 2149e15..0000000 --- a/server/src/Endpoints/Internal/Account/DeleteAccountRoute.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -public class DeleteAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult -{ - private readonly AppDbContext _context; - private readonly UserService _userService; - - /// - public DeleteAccountRoute(AppDbContext context, UserService userService) { - _context = context; - _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(); - } - - 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); - - _context.TimeCategories.RemoveRange(githubMappings); - _context.ForgotPasswordRequests.RemoveRange(passwordResets); - _context.TimeEntries.RemoveRange(entries); - _context.TimeLabels.RemoveRange(labels); - _context.TimeCategories.RemoveRange(categories); - _context.Users.Remove(user); - - await _context.SaveChangesAsync(cancellationToken); - await _userService.LogOutUser(HttpContext); - return Ok(); - } -} diff --git a/server/src/Endpoints/Internal/Account/GetArchiveRoute.cs b/server/src/Endpoints/Internal/Account/GetArchiveRoute.cs deleted file mode 100644 index f1b70f3..0000000 --- a/server/src/Endpoints/Internal/Account/GetArchiveRoute.cs +++ /dev/null @@ -1,62 +0,0 @@ -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"); - } -} diff --git a/server/src/Endpoints/Internal/Account/GetRoute.cs b/server/src/Endpoints/Internal/Account/GetRoute.cs deleted file mode 100644 index 1aa7ecb..0000000 --- a/server/src/Endpoints/Internal/Account/GetRoute.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -public class GetAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public GetAccountRoute(AppDbContext context) { - _context = context; - } - - /// - /// Get the logged on user's session data. - /// - /// - /// - [HttpGet("~/_/account")] - public override async Task> HandleAsync(CancellationToken cancellationToken = default) { - var user = _context.Users - .Select(x => new {x.Username, x.Id}) - .SingleOrDefault(c => c.Id == LoggedInUser.Id); - if (user != default) { - return Ok(new LoggedInUserModel { - Id = LoggedInUser.Id, - Username = LoggedInUser.Username - }); - } - - await HttpContext.SignOutAsync(); - return Unauthorized(); - } -} \ No newline at end of file diff --git a/server/src/Endpoints/Internal/Account/LoginPayload.cs b/server/src/Endpoints/Internal/Account/LoginPayload.cs deleted file mode 100644 index 807662c..0000000 --- a/server/src/Endpoints/Internal/Account/LoginPayload.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -/// -/// Payload for logging in a user. -/// -public class LoginPayload -{ - /// - /// Username of the user's account. - /// - public string Username { get; set; } - - /// - /// Password of the user's account. - /// - public string Password { get; set; } - - /// - /// Specify that the created session should be long lived and continually refreshed. - /// - public bool Persist { get; set; } -} diff --git a/server/src/Endpoints/Internal/Account/LoginRoute.cs b/server/src/Endpoints/Internal/Account/LoginRoute.cs deleted file mode 100644 index 5b41c61..0000000 --- a/server/src/Endpoints/Internal/Account/LoginRoute.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -public class LoginRoute : RouteBaseAsync - .WithRequest - .WithActionResult -{ - private readonly AppDbContext _context; - private readonly UserService _userService; - - /// - public LoginRoute(AppDbContext context, UserService userService) { - _context = context; - _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); - } - - var user = _context.Users.SingleOrDefault(u => u.Username == request.Username); - if (user == default || !user.VerifyPassword(request.Password)) { - return BadRequest(new ErrorResult("Invalid username or password")); - } - - await _userService.LogInUser(HttpContext, user, request.Persist); - return Ok(); - } -} diff --git a/server/src/Endpoints/Internal/Account/LogoutRoute.cs b/server/src/Endpoints/Internal/Account/LogoutRoute.cs deleted file mode 100644 index 4a06f4a..0000000 --- a/server/src/Endpoints/Internal/Account/LogoutRoute.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -public class LogoutRoute : RouteBaseAsync.WithoutRequest.WithActionResult -{ - private readonly 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(); - } -} diff --git a/server/src/Endpoints/Internal/Account/UpdateAccountPayload.cs b/server/src/Endpoints/Internal/Account/UpdateAccountPayload.cs deleted file mode 100644 index 88a3237..0000000 --- a/server/src/Endpoints/Internal/Account/UpdateAccountPayload.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Account; - -/// -/// Payload for updating an account. -/// -public class UpdatePayload -{ - /// - /// Username to set on the logged on user's account. - /// - public string Username { get; set; } - - /// - /// Password to set on the logged on user's account. - /// - public string Password { get; set; } -} diff --git a/server/src/Endpoints/Internal/Account/UpdateAccountRoute.cs b/server/src/Endpoints/Internal/Account/UpdateAccountRoute.cs deleted file mode 100644 index a997dcb..0000000 --- a/server/src/Endpoints/Internal/Account/UpdateAccountRoute.cs +++ /dev/null @@ -1,51 +0,0 @@ -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 ErrorResult("Invalid request", "No data was submitted")); - } - - if (request.Password.HasValue() && request.Password.Length < 6) { - return BadRequest(new ErrorResult("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 ErrorResult("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(); - } -} diff --git a/server/src/Endpoints/Internal/BaseRoute.cs b/server/src/Endpoints/Internal/BaseRoute.cs deleted file mode 100644 index 3e2c6af..0000000 --- a/server/src/Endpoints/Internal/BaseRoute.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal; - -[Authorize] -[ApiController] -[ApiExplorerSettings(IgnoreApi = true)] -[ApiVersionNeutral] -public class BaseRoute : ControllerBase -{ - /// - /// User data for the currently logged on user. - /// - protected LoggedInUserModel LoggedInUser => new() { - Username = User.FindFirstValue(AppClaims.NAME), - Id = User.FindFirstValue(AppClaims.USER_ID).AsGuid(), - }; -} diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs deleted file mode 100644 index 8fbc9a0..0000000 --- a/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; - -/// -public class CreateResetRequestRoute : RouteBaseAsync.WithRequest.WithActionResult -{ - private readonly ILogger _logger; - private readonly PasswordResetService _passwordResetService; - private readonly AppDbContext _context; - - /// - public CreateResetRequestRoute(ILogger logger, PasswordResetService passwordResetService, AppDbContext context) { - _logger = logger; - _passwordResetService = passwordResetService; - _context = context; - } - - /// - /// Create a new password reset request. - /// - /// - /// - /// - [AllowAnonymous] - [HttpGet("~/_/forgot-password-requests/create")] - public override async Task HandleAsync(string username, CancellationToken cancellationToken = default) { - if (!username.IsValidEmailAddress()) { - _logger.LogInformation("Username is invalid, not doing request for password change"); - return BadRequest(new ErrorResult("Invalid email address", 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(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, "ForgotAction failed badly"); - return Ok(); - } - } -} diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestPayload.cs b/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestPayload.cs deleted file mode 100644 index f0fb59f..0000000 --- a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestPayload.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; - -public class FulfillResetRequestPayload -{ - /// - /// Id of the password reset request to fulfill - /// - public Guid Id { get; set; } - - /// - /// New password to set on the relevant account - /// - public string NewPassword { get; set; } -} diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs deleted file mode 100644 index 96f344a..0000000 --- a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs +++ /dev/null @@ -1,34 +0,0 @@ - -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; - -/// -public class FulfillResetRequestRoute : RouteBaseAsync.WithRequest.WithActionResult -{ - private readonly PasswordResetService _passwordResetService; - - /// - public FulfillResetRequestRoute(PasswordResetService passwordResetService) { - _passwordResetService = passwordResetService; - } - - /// - /// Fulfill a password reset request. - /// - /// - /// - /// - [AllowAnonymous] - [HttpPost("~/_/forgot-password-requests/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; - } - } -} diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs deleted file mode 100644 index c4dcd22..0000000 --- a/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests; - -/// -public class IsResetRequestValidRoute : RouteBaseAsync.WithRequest.WithActionResult -{ - private readonly PasswordResetService _passwordResetService; - - /// - public IsResetRequestValidRoute(PasswordResetService passwordResetService) { - _passwordResetService = passwordResetService; - } - - /// - /// Check if a given password reset request is still valid. - /// - /// - /// - /// - [AllowAnonymous] - [HttpGet("~/_/forgot-password-requests/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); - } -} diff --git a/server/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs b/server/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs deleted file mode 100644 index 5fb8213..0000000 --- a/server/src/Endpoints/Internal/Root/GetApplicationVersionRoute.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; - -public class GetApplicationVersionRoute : RouteBaseSync.WithoutRequest.WithActionResult -{ - private readonly IWebHostEnvironment _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)); - } -} diff --git a/server/src/Endpoints/Internal/Root/LogRoute.cs b/server/src/Endpoints/Internal/Root/LogRoute.cs deleted file mode 100644 index 48b497a..0000000 --- a/server/src/Endpoints/Internal/Root/LogRoute.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; - -public class LogRoute : RouteBaseSync.WithRequest.WithoutResult -{ - private readonly ILogger _logger; - - public LogRoute(ILogger logger) { - _logger = logger; - } - - [AllowAnonymous] - [HttpPost("~/_/log")] - public override void Handle([FromBody] string request) { - _logger.LogInformation(request); - } -} diff --git a/server/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs b/server/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs deleted file mode 100644 index e0dcca3..0000000 --- a/server/src/Endpoints/Internal/Root/ReadConfigurationRoute.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; - -public class ReadConfigurationRoute : RouteBaseSync.WithoutRequest.WithActionResult -{ - private readonly 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"); - } -} diff --git a/server/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs b/server/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs deleted file mode 100644 index 4b1beec..0000000 --- a/server/src/Endpoints/Internal/Root/RefreshConfigurationRoute.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; - -public class RefreshConfigurationRoute : RouteBaseSync.WithoutRequest.WithoutResult -{ - private readonly VaultService _vaultService; - - public RefreshConfigurationRoute(VaultService vaultService) { - _vaultService = vaultService; - } - - [HttpGet("~/_/refresh-configuration")] - public override void Handle() { - _vaultService.RefreshCurrentAppConfiguration(); - } -} diff --git a/server/src/Endpoints/Internal/Root/ValidSessionRoute.cs b/server/src/Endpoints/Internal/Root/ValidSessionRoute.cs deleted file mode 100644 index f377ff6..0000000 --- a/server/src/Endpoints/Internal/Root/ValidSessionRoute.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal.Root; - -public class ValidSessionRoute : RouteBaseSync.WithoutRequest.WithActionResult -{ - [Authorize] - [HttpGet("~/_/valid-session")] - public override ActionResult Handle() { - return Ok(); - } -} \ No newline at end of file diff --git a/server/src/Endpoints/Internal/RouteBaseAsync.cs b/server/src/Endpoints/Internal/RouteBaseAsync.cs deleted file mode 100644 index 1bb0af0..0000000 --- a/server/src/Endpoints/Internal/RouteBaseAsync.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal; - -/// -/// A base class for an endpoint that accepts parameters. -/// -public static class RouteBaseAsync -{ - public static class WithRequest - { - public abstract class WithResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task> HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - } - - public static class WithoutRequest - { - public abstract class WithResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task> HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - } -} diff --git a/server/src/Endpoints/Internal/RouteBaseSync.cs b/server/src/Endpoints/Internal/RouteBaseSync.cs deleted file mode 100644 index 173999d..0000000 --- a/server/src/Endpoints/Internal/RouteBaseSync.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.Internal; - -/// -/// A base class for an endpoint that accepts parameters. -/// -public static class RouteBaseSync -{ - public static class WithRequest - { - public abstract class WithResult : BaseRoute - { - public abstract TResponse Handle(TRequest request); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract void Handle(TRequest request); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(TRequest request); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(TRequest request); - } - } - - public static class WithoutRequest - { - public abstract class WithResult : BaseRoute - { - public abstract TResponse Handle(); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract void Handle(); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(); - } - } -} diff --git a/server/src/Endpoints/V1/ApiSpecV1.cs b/server/src/Endpoints/V1/ApiSpecV1.cs deleted file mode 100644 index e4f9cc9..0000000 --- a/server/src/Endpoints/V1/ApiSpecV1.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1; - -public static class ApiSpecV1 -{ - private const int MAJOR = 1; - private const int MINOR = 0; - public const string VERSION_STRING = "1.0"; - - public static ApiSpecDocument Document => new() { - Version = new ApiVersion(MAJOR, MINOR), - VersionName = VERSION_STRING, - SwaggerPath = $"/swagger/{VERSION_STRING}/swagger.json", - OpenApiInfo = new OpenApiInfo { - Title = AppConstants.API_NAME, - Version = VERSION_STRING - } - }; -} diff --git a/server/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs b/server/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs deleted file mode 100644 index 2086619..0000000 --- a/server/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Text; - -namespace IOL.GreatOffice.Api.Endpoints.V1.ApiTokens; - -public class CreateTokenRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - private readonly AppConfiguration _configuration; - private readonly ILogger _logger; - - public CreateTokenRoute(AppDbContext context, VaultService vaultService, ILogger logger) - { - _context = context; - _configuration = vaultService.GetCurrentAppConfiguration(); - _logger = logger; - } - - /// - /// Create a new api token with the provided claims. - /// - /// The claims to set on the api token - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [HttpPost("~/v{version:apiVersion}/api-tokens/create")] - [ProducesResponseType(200, Type = typeof(string))] - [ProducesResponseType(404, Type = typeof(ErrorResult))] - public override ActionResult Handle(ApiAccessToken.ApiAccessTokenDto request) - { - var user = _context.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id); - if (user == default) - { - return NotFound(new ErrorResult("User does not exist")); - } - - var token_entropy = _configuration.APP_AES_KEY; - if (token_entropy.IsNullOrWhiteSpace()) - { - _logger.LogWarning("No token entropy is available, Basic auth is disabled"); - return NotFound(); - } - - var access_token = new ApiAccessToken() - { - Id = Guid.NewGuid(), - User = user, - ExpiryDate = request.ExpiryDate.ToUniversalTime(), - AllowCreate = request.AllowCreate, - AllowRead = request.AllowRead, - AllowDelete = request.AllowDelete, - AllowUpdate = request.AllowUpdate - }; - - _context.AccessTokens.Add(access_token); - _context.SaveChanges(); - return Ok(Convert.ToBase64String(Encoding.UTF8.GetBytes(access_token.Id.ToString().EncryptWithAes(token_entropy)))); - } -} diff --git a/server/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs b/server/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs deleted file mode 100644 index a90b4c0..0000000 --- a/server/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.ApiTokens; - -public class DeleteTokenRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - private readonly ILogger _logger; - - public DeleteTokenRoute(AppDbContext context, ILogger logger) { - _context = context; - _logger = logger; - } - - /// - /// Delete an api token, rendering it unusable - /// - /// Id of the token to delete - /// Nothing - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [HttpDelete("~/v{version:apiVersion}/api-tokens/delete")] - [ProducesResponseType(200)] - [ProducesResponseType(404)] - public override ActionResult Handle(Guid id) { - var token = _context.AccessTokens.SingleOrDefault(c => c.Id == id); - if (token == default) { - _logger.LogWarning("A deletion request of an already deleted (maybe) api token was received."); - return NotFound(); - } - - _context.AccessTokens.Remove(token); - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/ApiTokens/GetTokensRoute.cs b/server/src/Endpoints/V1/ApiTokens/GetTokensRoute.cs deleted file mode 100644 index 59fd077..0000000 --- a/server/src/Endpoints/V1/ApiTokens/GetTokensRoute.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.ApiTokens; - -public class GetTokensRoute : RouteBaseSync.WithoutRequest.WithResult>> -{ - private readonly AppDbContext _context; - - public GetTokensRoute(AppDbContext context) { - _context = context; - } - - /// - /// Get all tokens, both active and inactive. - /// - /// A list of tokens - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [HttpGet("~/v{version:apiVersion}/api-tokens")] - [ProducesResponseType(200, Type = typeof(List))] - [ProducesResponseType(204)] - public override ActionResult> Handle() { - return Ok(_context.AccessTokens.Where(c => c.User.Id == LoggedInUser.Id).Select(c => c.AsDto)); - } -} diff --git a/server/src/Endpoints/V1/BaseRoute.cs b/server/src/Endpoints/V1/BaseRoute.cs deleted file mode 100644 index e7d72ac..0000000 --- a/server/src/Endpoints/V1/BaseRoute.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Net.Http.Headers; - -namespace IOL.GreatOffice.Api.Endpoints.V1; - -/// -[ApiVersion(ApiSpecV1.VERSION_STRING)] -[Authorize(AuthenticationSchemes = AuthSchemes)] -[ApiController] -public class BaseRoute : ControllerBase -{ - private const string AuthSchemes = CookieAuthenticationDefaults.AuthenticationScheme + "," + AppConstants.BASIC_AUTH_SCHEME; - - /// - /// User data for the currently logged on user. - /// - protected LoggedInUserModel LoggedInUser => new() { - Username = User.FindFirstValue(AppClaims.NAME), - Id = User.FindFirstValue(AppClaims.USER_ID).AsGuid(), - }; - - protected bool IsApiCall() { - if (!Request.Headers.ContainsKey("Authorization")) return false; - try { - var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); - if (authHeader.Parameter == null) return false; - } catch { - return false; - } - - return true; - } - - protected bool HasApiPermission(string permission_key) { - var permission_claim = User.Claims.SingleOrDefault(c => c.Type == permission_key); - return permission_claim is { - Value: "True" - }; - } -} diff --git a/server/src/Endpoints/V1/Categories/CreateCategoryRoute.cs b/server/src/Endpoints/V1/Categories/CreateCategoryRoute.cs deleted file mode 100644 index fac2b5e..0000000 --- a/server/src/Endpoints/V1/Categories/CreateCategoryRoute.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Categories; - -public class CreateCategoryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public CreateCategoryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Create a new time entry category. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_CREATE)] - [HttpPost("~/v{version:apiVersion}/categories/create")] - [ProducesResponseType(200, Type = typeof(TimeCategory.TimeCategoryDto))] - public override ActionResult Handle(TimeCategory.TimeCategoryDto categoryTimeCategoryDto) { - var duplicate = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .Any(c => c.Name.Trim() == categoryTimeCategoryDto.Name.Trim()); - if (duplicate) { - var category = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Name.Trim() == categoryTimeCategoryDto.Name.Trim()); - if (category != default) { - return Ok(category.AsDto); - } - } - - var newCategory = new TimeCategory(LoggedInUser.Id) { - Name = categoryTimeCategoryDto.Name.Trim(), - Color = categoryTimeCategoryDto.Color - }; - - _context.TimeCategories.Add(newCategory); - _context.SaveChanges(); - categoryTimeCategoryDto.Id = newCategory.Id; - return Ok(categoryTimeCategoryDto); - } -} diff --git a/server/src/Endpoints/V1/Categories/DeleteCategoryRoute.cs b/server/src/Endpoints/V1/Categories/DeleteCategoryRoute.cs deleted file mode 100644 index 3d438a0..0000000 --- a/server/src/Endpoints/V1/Categories/DeleteCategoryRoute.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Categories; - -public class DeleteCategoryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public DeleteCategoryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Delete a time entry category. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_DELETE)] - [HttpDelete("~/v{version:apiVersion}/categories/{id:guid}/delete")] - [ProducesResponseType(200)] - [ProducesResponseType(404)] - public override ActionResult Handle(Guid id) { - var category = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == id); - - if (category == default) { - return NotFound(); - } - - var entries = _context.TimeEntries - .Include(c => c.Category) - .Where(c => c.Category.Id == category.Id); - _context.TimeEntries.RemoveRange(entries); - _context.TimeCategories.Remove(category); - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/Categories/GetCategoriesRoute.cs b/server/src/Endpoints/V1/Categories/GetCategoriesRoute.cs deleted file mode 100644 index a40a832..0000000 --- a/server/src/Endpoints/V1/Categories/GetCategoriesRoute.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Categories; - -/// -public class GetCategoriesRoute : RouteBaseSync.WithoutRequest.WithActionResult> -{ - private readonly AppDbContext _context; - - /// - public GetCategoriesRoute(AppDbContext context) { - _context = context; - } - - /// - /// Get a minimal list of time entry categories. - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [ProducesResponseType(200, Type = typeof(List))] - [ProducesResponseType(204)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_READ)] - [HttpGet("~/v{version:apiVersion}/categories")] - public override ActionResult> Handle() { - var categories = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .OrderByDescending(c => c.CreatedAt) - .Select(c => c.AsDto) - .ToList(); - - if (categories.Count == 0) { - return NoContent(); - } - - return Ok(categories); - } -} diff --git a/server/src/Endpoints/V1/Categories/UpdateCategoryRoute.cs b/server/src/Endpoints/V1/Categories/UpdateCategoryRoute.cs deleted file mode 100644 index ca7dfdf..0000000 --- a/server/src/Endpoints/V1/Categories/UpdateCategoryRoute.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Categories; - -public class UpdateCategoryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public UpdateCategoryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Update a time entry category. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_UPDATE)] - [HttpPost("~/v{version:apiVersion}/categories/update")] - [ProducesResponseType(200)] - [ProducesResponseType(404)] - [ProducesResponseType(403)] - public override ActionResult Handle(TimeCategory.TimeCategoryDto categoryTimeCategoryDto) { - var category = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == categoryTimeCategoryDto.Id); - if (category == default) { - return NotFound(); - } - - if (LoggedInUser.Id != category.UserId) { - return Forbid(); - } - - category.Name = categoryTimeCategoryDto.Name; - category.Color = categoryTimeCategoryDto.Color; - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/Entries/CreateEntryRoute.cs b/server/src/Endpoints/V1/Entries/CreateEntryRoute.cs deleted file mode 100644 index 362e430..0000000 --- a/server/src/Endpoints/V1/Entries/CreateEntryRoute.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -public class CreateEntryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public CreateEntryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Create a time entry. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_CREATE)] - [ProducesResponseType(200)] - [ProducesResponseType(400, Type = typeof(ErrorResult))] - [ProducesResponseType(404, Type = typeof(ErrorResult))] - [HttpPost("~/v{version:apiVersion}/entries/create")] - public override ActionResult Handle(TimeEntry.TimeEntryDto timeEntryTimeEntryDto) { - if (timeEntryTimeEntryDto.Stop == default) { - return BadRequest(new ErrorResult("Invalid form", "A stop date is required")); - } - - if (timeEntryTimeEntryDto.Start == default) { - return BadRequest(new ErrorResult("Invalid form", "A start date is required")); - } - - if (timeEntryTimeEntryDto.Category == default) { - return BadRequest(new ErrorResult("Invalid form", "A category is required")); - } - - var category = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == timeEntryTimeEntryDto.Category.Id); - if (category == default) { - return NotFound(new ErrorResult("Not found", $"Could not find category {timeEntryTimeEntryDto.Category.Name}")); - } - - var entry = new TimeEntry(LoggedInUser.Id) { - Category = category, - Start = timeEntryTimeEntryDto.Start.ToUniversalTime(), - Stop = timeEntryTimeEntryDto.Stop.ToUniversalTime(), - Description = timeEntryTimeEntryDto.Description, - }; - - if (timeEntryTimeEntryDto.Labels?.Count > 0) { - var labels = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .Where(c => timeEntryTimeEntryDto.Labels.Select(p => p.Id).Contains(c.Id)) - .ToList(); - if (labels.Count != timeEntryTimeEntryDto.Labels.Count) { - return NotFound(new ErrorResult("Not found", "Could not find all of the specified labels")); - } - - entry.Labels = labels; - } - - _context.TimeEntries.Add(entry); - _context.SaveChanges(); - return Ok(entry.AsDto); - } -} diff --git a/server/src/Endpoints/V1/Entries/DeleteEntryRoute.cs b/server/src/Endpoints/V1/Entries/DeleteEntryRoute.cs deleted file mode 100644 index 0850af0..0000000 --- a/server/src/Endpoints/V1/Entries/DeleteEntryRoute.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -/// -public class DeleteEntryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - /// - public DeleteEntryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Delete a time entry. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_DELETE)] - [HttpDelete("~/v{version:apiVersion}/entries/{id:guid}/delete")] - [ProducesResponseType(404)] - [ProducesResponseType(200)] - public override ActionResult Handle(Guid id) { - var entry = _context.TimeEntries - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == id); - if (entry == default) { - return NotFound(); - } - - _context.TimeEntries.Remove(entry); - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/Entries/EntryQueryPayload.cs b/server/src/Endpoints/V1/Entries/EntryQueryPayload.cs deleted file mode 100644 index 763ac8b..0000000 --- a/server/src/Endpoints/V1/Entries/EntryQueryPayload.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -/// -/// Query model for querying time entries. -/// -public class EntryQueryPayload -{ - /// - /// Duration to filter with. - /// - public TimeEntryQueryDuration Duration { get; set; } - - /// - /// List of categories to filter with. - /// - public List Categories { get; set; } - - /// - /// List of labels to filter with. - /// - public List Labels { get; set; } - - /// - /// Date range to filter with, only respected if Duration is set to TimeEntryQueryDuration.DATE_RANGE. - /// - /// - public QueryDateRange DateRange { get; set; } - - /// - /// Spesific date to filter with, only respected if Duration is set to TimeEntryQueryDuration.SPECIFIC_DATE. - /// - /// - public DateTime SpecificDate { get; set; } - - /// - /// Optional page number to show, goes well with PageSize. - /// - public int Page { get; set; } - - /// - /// Optional page size to show, goes well with Page. - /// - public int PageSize { get; set; } - - /// - /// Represents a date range. - /// - public class QueryDateRange - { - /// - /// Range start - /// - public DateTime From { get; set; } - - /// - /// Range end - /// - public DateTime To { get; set; } - } -} diff --git a/server/src/Endpoints/V1/Entries/EntryQueryResponse.cs b/server/src/Endpoints/V1/Entries/EntryQueryResponse.cs deleted file mode 100644 index b1b07a3..0000000 --- a/server/src/Endpoints/V1/Entries/EntryQueryResponse.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -/// -/// Response given for a successful query. -/// -public class EntryQueryResponse -{ - /// - public EntryQueryResponse() { - Results = new List(); - } - - /// - /// List of entries. - /// - public List Results { get; set; } - - /// - /// Current page. - /// - public int Page { get; set; } - - /// - /// Current page size (amount of entries). - /// - public int PageSize { get; set; } - - /// - /// Total amount of entries in query. - /// - public int TotalSize { get; set; } - - /// - /// Total amount of page(s) in query. - /// - public int TotalPageCount { get; set; } -} diff --git a/server/src/Endpoints/V1/Entries/EntryQueryRoute.cs b/server/src/Endpoints/V1/Entries/EntryQueryRoute.cs deleted file mode 100644 index d431ac5..0000000 --- a/server/src/Endpoints/V1/Entries/EntryQueryRoute.cs +++ /dev/null @@ -1,186 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -public class EntryQueryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly ILogger _logger; - private readonly AppDbContext _context; - - public EntryQueryRoute(ILogger logger, AppDbContext context) { - _logger = logger; - _context = context; - } - - /// - /// Get a list of entries based on a given query. - /// - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_READ)] - [HttpPost("~/v{version:apiVersion}/entries/query")] - [ProducesResponseType(204)] - [ProducesResponseType(400, Type = typeof(ErrorResult))] - [ProducesResponseType(200, Type = typeof(EntryQueryResponse))] - public override ActionResult Handle(EntryQueryPayload entryQuery) { - var result = new TimeQueryDto(); - - Request.Headers.TryGetValue(AppHeaders.BROWSER_TIME_ZONE, out var timeZoneHeader); - var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneHeader.ToString().HasValue() ? timeZoneHeader.ToString() : "UTC"); - var offsetInHours = 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)) { - offsetInHours++; - } - - _logger.LogInformation("Request time zone (" + tz.Id + ") offset is: " + offsetInHours + " hours"); - var requestDateTime = TimeZoneInfo.ConvertTimeFromUtc(AppDateTime.UtcNow, tz); - _logger.LogInformation("Querying data with date time: " + requestDateTime.ToString("u")); - - var skipCount = 0; - if (entryQuery.Page > 1) { - skipCount = entryQuery.PageSize * entryQuery.Page; - } - - result.Page = entryQuery.Page; - result.PageSize = entryQuery.PageSize; - - var baseQuery = _context.TimeEntries - .AsNoTracking() - .Include(c => c.Category) - .Include(c => c.Labels) - .Where(c => c.UserId == LoggedInUser.Id) - .ConditionalWhere(entryQuery.Categories?.Any() ?? false, c => entryQuery.Categories.Any(p => p.Id == c.Category.Id)) - .ConditionalWhere(entryQuery.Labels?.Any() ?? false, c => c.Labels.Any(l => entryQuery.Labels.Any(p => p.Id == l.Id))) - .OrderByDescending(c => c.Start); - - switch (entryQuery.Duration) { - case TimeEntryQueryDuration.TODAY: - var baseTodaysEntries = baseQuery - .Where(c => DateTime.Compare(c.Start.AddHours(offsetInHours).Date, AppDateTime.UtcNow.Date) == 0); - var baseTodaysEntriesCount = baseTodaysEntries.Count(); - - if (baseTodaysEntriesCount == 0) { - return NoContent(); - } - - result.TotalSize = baseTodaysEntriesCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseTodaysEntriesCount / entryQuery.PageSize)); - - var pagedTodaysEntries = baseTodaysEntries.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedTodaysEntries.Select(c => c.AsDto)); - break; - case TimeEntryQueryDuration.THIS_WEEK: - var lastMonday = AppDateTime.UtcNow.StartOfWeek(DayOfWeek.Monday); - - var baseEntriesThisWeek = baseQuery - .Where(c => c.Start.AddHours(offsetInHours).Date >= lastMonday.Date && c.Start.AddHours(offsetInHours).Date <= AppDateTime.UtcNow.Date); - - var baseEntriesThisWeekCount = baseEntriesThisWeek.Count(); - - if (baseEntriesThisWeekCount == 0) { - return NoContent(); - } - - result.TotalSize = baseEntriesThisWeekCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseEntriesThisWeekCount / entryQuery.PageSize)); - - var pagedEntriesThisWeek = baseEntriesThisWeek.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedEntriesThisWeek.Select(c => c.AsDto)); - break; - case TimeEntryQueryDuration.THIS_MONTH: - var baseEntriesThisMonth = baseQuery - .Where(c => c.Start.AddHours(offsetInHours).Month == AppDateTime.UtcNow.Month - && c.Start.AddHours(offsetInHours).Year == AppDateTime.UtcNow.Year); - var baseEntriesThisMonthCount = baseEntriesThisMonth.Count(); - if (baseEntriesThisMonthCount == 0) { - return NoContent(); - } - - result.TotalSize = baseEntriesThisMonthCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseEntriesThisMonthCount / entryQuery.PageSize)); - - var pagedEntriesThisMonth = baseEntriesThisMonth.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedEntriesThisMonth.Select(c => c.AsDto)); - break; - case TimeEntryQueryDuration.THIS_YEAR: - var baseEntriesThisYear = baseQuery - .Where(c => c.Start.AddHours(offsetInHours).Year == AppDateTime.UtcNow.Year); - - var baseEntriesThisYearCount = baseEntriesThisYear.Count(); - if (baseEntriesThisYearCount == 0) { - return NoContent(); - } - - result.TotalSize = baseEntriesThisYearCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseEntriesThisYearCount / entryQuery.PageSize)); - - var pagedEntriesThisYear = baseEntriesThisYear.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedEntriesThisYear.Select(c => c.AsDto)); - break; - case TimeEntryQueryDuration.SPECIFIC_DATE: - var date = DateTime.SpecifyKind(entryQuery.SpecificDate, DateTimeKind.Utc); - var baseEntriesOnThisDate = baseQuery.Where(c => c.Start.AddHours(offsetInHours).Date == date.Date); - var baseEntriesOnThisDateCount = baseEntriesOnThisDate.Count(); - - if (baseEntriesOnThisDateCount == 0) { - return NoContent(); - } - - result.TotalSize = baseEntriesOnThisDateCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseEntriesOnThisDateCount / entryQuery.PageSize)); - - var pagedEntriesOnThisDate = baseEntriesOnThisDate.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedEntriesOnThisDate.Select(c => c.AsDto)); - break; - case TimeEntryQueryDuration.DATE_RANGE: - if (entryQuery.DateRange.From == default) { - return BadRequest(new ErrorResult("Invalid query", "From date cannot be empty")); - } - - var fromDate = DateTime.SpecifyKind(entryQuery.DateRange.From, DateTimeKind.Utc); - - if (entryQuery.DateRange.To == default) { - return BadRequest(new ErrorResult("Invalid query", "To date cannot be empty")); - } - - var toDate = DateTime.SpecifyKind(entryQuery.DateRange.To, DateTimeKind.Utc); - - if (DateTime.Compare(fromDate, toDate) > 0) { - return BadRequest(new ErrorResult("Invalid query", "To date cannot be less than From date")); - } - - var baseDateRangeEntries = baseQuery - .Where(c => c.Start.AddHours(offsetInHours).Date > fromDate && c.Start.AddHours(offsetInHours).Date <= toDate); - - var baseDateRangeEntriesCount = baseDateRangeEntries.Count(); - if (baseDateRangeEntriesCount == 0) { - return NoContent(); - } - - result.TotalSize = baseDateRangeEntriesCount; - result.TotalPageCount = Convert.ToInt32(Math.Round((double)baseDateRangeEntriesCount / entryQuery.PageSize)); - - var pagedDateRangeEntries = baseDateRangeEntries.Skip(skipCount).Take(entryQuery.PageSize); - - result.Results.AddRange(pagedDateRangeEntries.Select(c => c.AsDto)); - break; - default: - throw new ArgumentOutOfRangeException(nameof(entryQuery), "Unknown duration for query"); - } - - if (result.Results.Any() && result.Page == 0) { - result.Page = 1; - result.TotalPageCount = 1; - } - - return Ok(result); - } -} diff --git a/server/src/Endpoints/V1/Entries/GetEntryRoute.cs b/server/src/Endpoints/V1/Entries/GetEntryRoute.cs deleted file mode 100644 index 87038db..0000000 --- a/server/src/Endpoints/V1/Entries/GetEntryRoute.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -public class GetEntryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public GetEntryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Get a spesific time entry. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_READ)] - [HttpGet("~/v{version:apiVersion}/entries/{id:guid}")] - [ProducesResponseType(404)] - [ProducesResponseType(200, Type = typeof(TimeEntry.TimeEntryDto))] - public override ActionResult Handle(Guid id) { - var entry = _context.TimeEntries - .Where(c => c.UserId == LoggedInUser.Id) - .Include(c => c.Category) - .Include(c => c.Labels) - .SingleOrDefault(c => c.Id == id); - - if (entry == default) { - return NotFound(); - } - - return Ok(entry); - } -} diff --git a/server/src/Endpoints/V1/Entries/UpdateEntryRoute.cs b/server/src/Endpoints/V1/Entries/UpdateEntryRoute.cs deleted file mode 100644 index ac233e0..0000000 --- a/server/src/Endpoints/V1/Entries/UpdateEntryRoute.cs +++ /dev/null @@ -1,66 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Entries; - -public class UpdateEntryRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - public UpdateEntryRoute(AppDbContext context) { - _context = context; - } - - /// - /// Update a time entry. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_UPDATE)] - [HttpPost("~/v{version:apiVersion}/entries/update")] - [ProducesResponseType(404, Type = typeof(ErrorResult))] - [ProducesResponseType(200, Type = typeof(TimeEntry.TimeEntryDto))] - public override ActionResult Handle(TimeEntry.TimeEntryDto timeEntryTimeEntryDto) { - var entry = _context.TimeEntries - .Where(c => c.UserId == LoggedInUser.Id) - .Include(c => c.Labels) - .SingleOrDefault(c => c.Id == timeEntryTimeEntryDto.Id); - - if (entry == default) { - return NotFound(); - } - - var category = _context.TimeCategories - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == timeEntryTimeEntryDto.Category.Id); - if (category == default) { - return NotFound(new ErrorResult("Not found", $"Could not find category {timeEntryTimeEntryDto.Category.Name}")); - } - - entry.Start = timeEntryTimeEntryDto.Start.ToUniversalTime(); - entry.Stop = timeEntryTimeEntryDto.Stop.ToUniversalTime(); - entry.Description = timeEntryTimeEntryDto.Description; - entry.Category = category; - - if (timeEntryTimeEntryDto.Labels?.Count > 0) { - var labels = new List(); - - foreach (var labelDto in timeEntryTimeEntryDto.Labels) { - var label = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == labelDto.Id); - - if (label == default) { - continue; - } - - labels.Add(label); - } - - entry.Labels = labels; - } else { - entry.Labels = default; - } - - _context.SaveChanges(); - return Ok(entry.AsDto); - } -} diff --git a/server/src/Endpoints/V1/Labels/CreateLabelRoute.cs b/server/src/Endpoints/V1/Labels/CreateLabelRoute.cs deleted file mode 100644 index 31ef7d0..0000000 --- a/server/src/Endpoints/V1/Labels/CreateLabelRoute.cs +++ /dev/null @@ -1,46 +0,0 @@ - -namespace IOL.GreatOffice.Api.Endpoints.V1.Labels; - -/// -public class CreateLabelRoute : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - /// - public CreateLabelRoute(AppDbContext context) { - _context = context; - } - - /// - /// Create a time entry label. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_CREATE)] - [HttpPost("~/v{version:apiVersion}/labels/create")] - public override ActionResult Handle(TimeLabel.TimeLabelDto labelTimeLabelDto) { - var duplicate = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .Any(c => c.Name.Trim() == labelTimeLabelDto.Name.Trim()); - if (duplicate) { - var label = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Name.Trim() == labelTimeLabelDto.Name.Trim()); - - if (label != default) { - return Ok(label.AsDto); - } - } - - var newLabel = new TimeLabel(LoggedInUser.Id) { - Name = labelTimeLabelDto.Name.Trim(), - Color = labelTimeLabelDto.Color - }; - - _context.TimeLabels.Add(newLabel); - _context.SaveChanges(); - labelTimeLabelDto.Id = newLabel.Id; - return Ok(labelTimeLabelDto); - } -} diff --git a/server/src/Endpoints/V1/Labels/DeleteLabelRoute.cs b/server/src/Endpoints/V1/Labels/DeleteLabelRoute.cs deleted file mode 100644 index d845a6f..0000000 --- a/server/src/Endpoints/V1/Labels/DeleteLabelRoute.cs +++ /dev/null @@ -1,35 +0,0 @@ - -namespace IOL.GreatOffice.Api.Endpoints.V1.Labels; - -/// -public class DeleteLabelEndpoint : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - /// - public DeleteLabelEndpoint(AppDbContext context) { - _context = context; - } - - /// - /// Delete a time entry label. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_DELETE)] - [HttpDelete("~/v{version:apiVersion}/labels/{id:guid}/delete")] - public override ActionResult Handle(Guid id) { - var label = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == id); - - if (label == default) { - return NotFound(); - } - - _context.TimeLabels.Remove(label); - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/Labels/GetLabelRoute.cs b/server/src/Endpoints/V1/Labels/GetLabelRoute.cs deleted file mode 100644 index c9ccef3..0000000 --- a/server/src/Endpoints/V1/Labels/GetLabelRoute.cs +++ /dev/null @@ -1,34 +0,0 @@ - -namespace IOL.GreatOffice.Api.Endpoints.V1.Labels; - -/// -public class GetEndpoint : RouteBaseSync.WithoutRequest.WithActionResult> -{ - private readonly AppDbContext _context; - - /// - public GetEndpoint(AppDbContext context) { - _context = context; - } - - /// - /// Get a minimal list of time entry labels. - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_READ)] - [HttpGet("~/v{version:apiVersion}/labels")] - public override ActionResult> Handle() { - var labels = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .OrderByDescending(c => c.CreatedAt) - .Select(c => c.AsDto) - .ToList(); - - if (labels.Count == 0) { - return NoContent(); - } - - return Ok(labels); - } -} diff --git a/server/src/Endpoints/V1/Labels/UpdateLabelRoute.cs b/server/src/Endpoints/V1/Labels/UpdateLabelRoute.cs deleted file mode 100644 index 30d72ec..0000000 --- a/server/src/Endpoints/V1/Labels/UpdateLabelRoute.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1.Labels; - -/// -public class UpdateLabelEndpoint : RouteBaseSync.WithRequest.WithActionResult -{ - private readonly AppDbContext _context; - - /// - public UpdateLabelEndpoint(AppDbContext context) { - _context = context; - } - - /// - /// Update a time entry label. - /// - /// - /// - [ApiVersion(ApiSpecV1.VERSION_STRING)] - [BasicAuthentication(AppConstants.TOKEN_ALLOW_UPDATE)] - [HttpPost("~/v{version:apiVersion}/labels/update")] - public override ActionResult Handle(TimeLabel.TimeLabelDto labelTimeLabelDto) { - var label = _context.TimeLabels - .Where(c => c.UserId == LoggedInUser.Id) - .SingleOrDefault(c => c.Id == labelTimeLabelDto.Id); - if (label == default) { - return NotFound(); - } - - if (LoggedInUser.Id != label.UserId) { - return Forbid(); - } - - label.Name = labelTimeLabelDto.Name; - label.Color = labelTimeLabelDto.Color; - _context.SaveChanges(); - return Ok(); - } -} diff --git a/server/src/Endpoints/V1/RouteBaseAsync.cs b/server/src/Endpoints/V1/RouteBaseAsync.cs deleted file mode 100644 index 1d179f7..0000000 --- a/server/src/Endpoints/V1/RouteBaseAsync.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1; - -/// -/// A base class for an endpoint that accepts parameters. -/// -public static class RouteBaseAsync -{ - public static class WithRequest - { - public abstract class WithResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task> HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task HandleAsync( - TRequest request, - CancellationToken cancellationToken = default - ); - } - } - - public static class WithoutRequest - { - public abstract class WithResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task> HandleAsync( - CancellationToken cancellationToken = default - ); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract Task HandleAsync( - CancellationToken cancellationToken = default - ); - } - } -} diff --git a/server/src/Endpoints/V1/RouteBaseSync.cs b/server/src/Endpoints/V1/RouteBaseSync.cs deleted file mode 100644 index cb27c14..0000000 --- a/server/src/Endpoints/V1/RouteBaseSync.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace IOL.GreatOffice.Api.Endpoints.V1; - -/// -/// A base class for an endpoint that accepts parameters. -/// -public static class RouteBaseSync -{ - public static class WithRequest - { - public abstract class WithResult : BaseRoute - { - public abstract TResponse Handle(TRequest request); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract void Handle(TRequest request); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(TRequest request); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(TRequest request); - } - } - - public static class WithoutRequest - { - public abstract class WithResult : BaseRoute - { - public abstract TResponse Handle(); - } - - public abstract class WithoutResult : BaseRoute - { - public abstract void Handle(); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(); - } - - public abstract class WithActionResult : BaseRoute - { - public abstract ActionResult Handle(); - } - } -} -- cgit v1.3