aboutsummaryrefslogtreecommitdiffstats
path: root/code/api
diff options
context:
space:
mode:
authorivar <i@oiee.no>2024-04-28 22:37:48 +0200
committerivar <i@oiee.no>2024-04-28 22:37:48 +0200
commitf356f15d3a7dce1669944d23ab395ec96d042293 (patch)
tree03a82934ec802e2579daa45f748e959dc6598847 /code/api
parentf99db65435f2cac81b5b48eb117991f4acd66a7e (diff)
downloadgreatoffice-f356f15d3a7dce1669944d23ab395ec96d042293.tar.xz
greatoffice-f356f15d3a7dce1669944d23ab395ec96d042293.zip
Misc
Diffstat (limited to 'code/api')
-rwxr-xr-xcode/api/build_and_push.sh2
-rw-r--r--code/api/src/Endpoints/EndpointBase.cs21
-rw-r--r--code/api/src/Endpoints/Internal/Account/GetAccountRoute.cs4
-rw-r--r--code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs4
-rw-r--r--code/api/src/Endpoints/Internal/INT_EndpointBase.cs2
-rw-r--r--code/api/src/Endpoints/Internal/Root/ValidateRoute.cs23
-rw-r--r--code/api/src/Endpoints/Internal/RouteBaseAsync.cs118
-rw-r--r--code/api/src/Endpoints/Internal/RouteBaseSync.cs78
-rw-r--r--code/api/src/Endpoints/V1/ApiSpecV1.cs26
-rw-r--r--code/api/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs4
-rw-r--r--code/api/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs4
-rw-r--r--code/api/src/Endpoints/V1/RouteBaseAsync.cs118
-rw-r--r--code/api/src/Endpoints/V1/RouteBaseSync.cs78
-rw-r--r--code/api/src/Endpoints/V1/V1_EndpointBase.cs8
-rw-r--r--code/api/src/Models/Database/BaseWithOwner.cs59
-rw-r--r--code/api/src/Models/Database/MainAppDatabase.cs200
-rw-r--r--code/api/src/Models/Misc/ApiSpecDocument.cs2
-rw-r--r--code/api/src/Models/Misc/AppConfiguration.cs2
-rw-r--r--code/api/src/Models/Misc/AppPath.cs2
-rw-r--r--code/api/src/Models/Misc/KnownProblemModel.cs2
-rw-r--r--code/api/src/Models/Misc/LoggedInUserModel.cs2
-rw-r--r--code/api/src/Models/Misc/RequestTimeZoneInfo.cs2
-rw-r--r--code/api/src/Models/Static/AppConstants.cs15
-rw-r--r--code/api/src/Program.cs2
-rw-r--r--code/api/src/Services/PasswordResetService.cs4
25 files changed, 382 insertions, 400 deletions
diff --git a/code/api/build_and_push.sh b/code/api/build_and_push.sh
index 163d7f3..820533a 100755
--- a/code/api/build_and_push.sh
+++ b/code/api/build_and_push.sh
@@ -8,10 +8,8 @@ CURRENT_VERSION=$(cat .version)
CURRENT_VERSION_INT=${CURRENT_VERSION//[!0-9]/}
if [ ${1-prod} == "dev" ]; then
NEW_VERSION="v$((CURRENT_DEV_VERSION_INT + 1))-dev"
- OLD_VERSION=$CURRENT_DEV_VERSION
else
NEW_VERSION="v$((CURRENT_VERSION_INT + 1))"
- OLD_VERSION=$CURRENT_VERSION
fi
IMAGE_NAME="greatoffice/server"
HUB_NAME="dr.ivar.systems/greatoffice/server"
diff --git a/code/api/src/Endpoints/EndpointBase.cs b/code/api/src/Endpoints/EndpointBase.cs
index e8e2494..584f43e 100644
--- a/code/api/src/Endpoints/EndpointBase.cs
+++ b/code/api/src/Endpoints/EndpointBase.cs
@@ -8,18 +8,15 @@ public class EndpointBase : ControllerBase
/// <summary>
/// User data for the currently logged on user.
/// </summary>
- protected LoggedInUserModel LoggedInUser => new()
- {
+ protected LoggedInUserModel LoggedInUser => new() {
Username = User.FindFirstValue(AppClaims.NAME),
Id = User.FindFirstValue(AppClaims.USER_ID).AsGuid(),
};
[NonAction]
- protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary<string, string[]> errors = default)
- {
+ protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary<string, string[]> errors = default) {
HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1");
- return BadRequest(new KnownProblemModel
- {
+ return BadRequest(new KnownProblemModel {
Title = title,
Subtitle = subtitle,
Errors = errors,
@@ -28,31 +25,27 @@ public class EndpointBase : ControllerBase
}
[NonAction]
- protected ActionResult KnownProblem(KnownProblemModel problem)
- {
+ protected ActionResult KnownProblem(KnownProblemModel problem) {
HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1");
problem.TraceId = HttpContext.TraceIdentifier;
return BadRequest(problem);
}
[NonAction]
- protected RequestTimeZoneInfo GetRequestTimeZone(ILogger logger = default)
- {
+ protected RequestTimeZoneInfo GetRequestTimeZone(ILogger logger = default) {
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))
- {
+ if (tz.IsDaylightSavingTime(AppDateTime.UtcNow)) {
offset++;
}
logger?.LogInformation("Request time zone (" + tz.Id + ") offset is: " + offset + " hours");
- return new RequestTimeZoneInfo()
- {
+ return new RequestTimeZoneInfo() {
TimeZoneInfo = tz,
Offset = offset,
LocalDateTime = TimeZoneInfo.ConvertTimeFromUtc(AppDateTime.UtcNow, tz)
diff --git a/code/api/src/Endpoints/Internal/Account/GetAccountRoute.cs b/code/api/src/Endpoints/Internal/Account/GetAccountRoute.cs
index 121b40f..67c4d4d 100644
--- a/code/api/src/Endpoints/Internal/Account/GetAccountRoute.cs
+++ b/code/api/src/Endpoints/Internal/Account/GetAccountRoute.cs
@@ -12,7 +12,7 @@ public class GetAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult<Lo
public override async Task<ActionResult<LoggedInUserModel>> HandleAsync(CancellationToken cancellationToken = default) {
var user = _database.Users
.Select(x => new {x.Username, x.Id})
- .SingleOrDefault(c => c.Id == LoggedInUser.Id);
+ .FirstOrDefault(c => c.Id == LoggedInUser.Id);
if (user != default) {
return Ok(new LoggedInUserModel {
Id = LoggedInUser.Id,
@@ -23,4 +23,4 @@ public class GetAccountRoute : RouteBaseAsync.WithoutRequest.WithActionResult<Lo
await HttpContext.SignOutAsync();
return Unauthorized();
}
-} \ 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 1081240..f6e18af 100644
--- a/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs
+++ b/code/api/src/Endpoints/Internal/Account/UpdateAccountRoute.cs
@@ -19,7 +19,7 @@ public class UpdateAccountRoute : RouteBaseAsync.WithRequest<UpdateAccountRoute.
[HttpPost("~/_/account/update")]
public override async Task<ActionResult> HandleAsync(Payload request, CancellationToken cancellationToken = default) {
- var user = _database.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id);
+ var user = _database.Users.FirstOrDefault(c => c.Id == LoggedInUser.Id);
if (user == default) {
await HttpContext.SignOutAsync();
return Unauthorized();
@@ -56,4 +56,4 @@ public class UpdateAccountRoute : RouteBaseAsync.WithRequest<UpdateAccountRoute.
await _database.SaveChangesAsync(cancellationToken);
return Ok();
}
-} \ No newline at end of file
+}
diff --git a/code/api/src/Endpoints/Internal/INT_EndpointBase.cs b/code/api/src/Endpoints/Internal/INT_EndpointBase.cs
index 699a976..0ba6c82 100644
--- a/code/api/src/Endpoints/Internal/INT_EndpointBase.cs
+++ b/code/api/src/Endpoints/Internal/INT_EndpointBase.cs
@@ -6,4 +6,4 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal;
public class INT_EndpointBase : EndpointBase
{
-}
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/Internal/Root/ValidateRoute.cs b/code/api/src/Endpoints/Internal/Root/ValidateRoute.cs
index d8ec85a..f141fe9 100644
--- a/code/api/src/Endpoints/Internal/Root/ValidateRoute.cs
+++ b/code/api/src/Endpoints/Internal/Root/ValidateRoute.cs
@@ -6,8 +6,7 @@ public class ValidateRoute : RouteBaseSync.WithRequest<ValidateRoute.QueryParams
private readonly string CanonicalFrontendUrl;
private readonly ILogger<ValidateRoute> _logger;
- public ValidateRoute(EmailValidationService emailValidation, ILogger<ValidateRoute> logger)
- {
+ public ValidateRoute(EmailValidationService emailValidation, ILogger<ValidateRoute> logger) {
_emailValidation = emailValidation;
_logger = logger;
CanonicalFrontendUrl = Program.AppConfiguration.CANONICAL_FRONTEND_URL;
@@ -20,20 +19,18 @@ public class ValidateRoute : RouteBaseSync.WithRequest<ValidateRoute.QueryParams
}
[HttpGet("~/_/validate")]
- public override ActionResult Handle([FromQuery] QueryParams request)
- {
+ public override ActionResult Handle([FromQuery] QueryParams request) {
var isFulfilled = _emailValidation.FulfillEmailValidationRequest(request.Id, LoggedInUser.Id);
- if (!isFulfilled)
- {
+ if (!isFulfilled) {
_logger.LogError("Email validation fulfillment failed for request {requestId} and user {userId}", request.Id, LoggedInUser.Id);
return StatusCode(400, $"""
-<html>
-<body>
-<h3>The validation could not be completed</h3>
-<p>We are working on fixing this, in the meantime, have patience.</p>
-<a href="{CanonicalFrontendUrl}">Click here to go back to {CanonicalFrontendUrl}</a>
-</body>
-""");
+ <html>
+ <body>
+ <h3>The validation could not be completed</h3>
+ <p>We are working on fixing this, in the meantime, have patience.</p>
+ <a href="{CanonicalFrontendUrl}">Click here to go back to {CanonicalFrontendUrl}</a>
+ </body>
+ """);
}
return Redirect(CanonicalFrontendUrl + "/portal?msg=emailValidated");
diff --git a/code/api/src/Endpoints/Internal/RouteBaseAsync.cs b/code/api/src/Endpoints/Internal/RouteBaseAsync.cs
index a87facf..dc25499 100644
--- a/code/api/src/Endpoints/Internal/RouteBaseAsync.cs
+++ b/code/api/src/Endpoints/Internal/RouteBaseAsync.cs
@@ -5,69 +5,69 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal;
/// </summary>
public static class RouteBaseAsync
{
- public static class WithRequest<TRequest>
- {
- public abstract class WithResult<TResponse> : INT_EndpointBase
- {
- public abstract Task<TResponse> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public static class WithRequest<TRequest>
+ {
+ public abstract class WithResult<TResponse> : INT_EndpointBase
+ {
+ public abstract Task<TResponse> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithoutResult : INT_EndpointBase
- {
- public abstract Task HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithoutResult : INT_EndpointBase
+ {
+ public abstract Task HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult<TResponse> : INT_EndpointBase
- {
- public abstract Task<ActionResult<TResponse>> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithActionResult<TResponse> : INT_EndpointBase
+ {
+ public abstract Task<ActionResult<TResponse>> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult : INT_EndpointBase
- {
- public abstract Task<ActionResult> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
- }
+ public abstract class WithActionResult : INT_EndpointBase
+ {
+ public abstract Task<ActionResult> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
+ }
- public static class WithoutRequest
- {
- public abstract class WithResult<TResponse> : INT_EndpointBase
- {
- public abstract Task<TResponse> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public static class WithoutRequest
+ {
+ public abstract class WithResult<TResponse> : INT_EndpointBase
+ {
+ public abstract Task<TResponse> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithoutResult : INT_EndpointBase
- {
- public abstract Task HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithoutResult : INT_EndpointBase
+ {
+ public abstract Task HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult<TResponse> : INT_EndpointBase
- {
- public abstract Task<ActionResult<TResponse>> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithActionResult<TResponse> : INT_EndpointBase
+ {
+ public abstract Task<ActionResult<TResponse>> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult : INT_EndpointBase
- {
- public abstract Task<ActionResult> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
- }
-}
+ public abstract class WithActionResult : INT_EndpointBase
+ {
+ public abstract Task<ActionResult> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/Internal/RouteBaseSync.cs b/code/api/src/Endpoints/Internal/RouteBaseSync.cs
index 9d9bd5a..4bbfa16 100644
--- a/code/api/src/Endpoints/Internal/RouteBaseSync.cs
+++ b/code/api/src/Endpoints/Internal/RouteBaseSync.cs
@@ -5,49 +5,49 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal;
/// </summary>
public static class RouteBaseSync
{
- public static class WithRequest<TRequest>
- {
- public abstract class WithResult<TResponse> : INT_EndpointBase
- {
- public abstract TResponse Handle(TRequest request);
- }
+ public static class WithRequest<TRequest>
+ {
+ public abstract class WithResult<TResponse> : INT_EndpointBase
+ {
+ public abstract TResponse Handle(TRequest request);
+ }
- public abstract class WithoutResult : INT_EndpointBase
- {
- public abstract void Handle(TRequest request);
- }
+ public abstract class WithoutResult : INT_EndpointBase
+ {
+ public abstract void Handle(TRequest request);
+ }
- public abstract class WithActionResult<TResponse> : INT_EndpointBase
- {
- public abstract ActionResult<TResponse> Handle(TRequest request);
- }
+ public abstract class WithActionResult<TResponse> : INT_EndpointBase
+ {
+ public abstract ActionResult<TResponse> Handle(TRequest request);
+ }
- public abstract class WithActionResult : INT_EndpointBase
- {
- public abstract ActionResult Handle(TRequest request);
- }
- }
+ public abstract class WithActionResult : INT_EndpointBase
+ {
+ public abstract ActionResult Handle(TRequest request);
+ }
+ }
- public static class WithoutRequest
- {
- public abstract class WithResult<TResponse> : INT_EndpointBase
- {
- public abstract TResponse Handle();
- }
+ public static class WithoutRequest
+ {
+ public abstract class WithResult<TResponse> : INT_EndpointBase
+ {
+ public abstract TResponse Handle();
+ }
- public abstract class WithoutResult : INT_EndpointBase
- {
- public abstract void Handle();
- }
+ public abstract class WithoutResult : INT_EndpointBase
+ {
+ public abstract void Handle();
+ }
- public abstract class WithActionResult<TResponse> : INT_EndpointBase
- {
- public abstract ActionResult<TResponse> Handle();
- }
+ public abstract class WithActionResult<TResponse> : INT_EndpointBase
+ {
+ public abstract ActionResult<TResponse> Handle();
+ }
- public abstract class WithActionResult : INT_EndpointBase
- {
- public abstract ActionResult Handle();
- }
- }
-}
+ public abstract class WithActionResult : INT_EndpointBase
+ {
+ public abstract ActionResult Handle();
+ }
+ }
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/V1/ApiSpecV1.cs b/code/api/src/Endpoints/V1/ApiSpecV1.cs
index e4f9cc9..7a54eb0 100644
--- a/code/api/src/Endpoints/V1/ApiSpecV1.cs
+++ b/code/api/src/Endpoints/V1/ApiSpecV1.cs
@@ -2,17 +2,17 @@ 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";
+ 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
- }
- };
-}
+ 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
+ }
+ };
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs b/code/api/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs
index c28f534..b9876c6 100644
--- a/code/api/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs
+++ b/code/api/src/Endpoints/V1/ApiTokens/CreateTokenRoute.cs
@@ -31,7 +31,7 @@ public class CreateTokenRoute : RouteBaseSync.WithRequest<CreateTokenRoute.Paylo
[HttpPost("~/v{version:apiVersion}/api-tokens/create")]
public override ActionResult Handle(Payload request)
{
- var user = _database.Users.SingleOrDefault(c => c.Id == LoggedInUser.Id);
+ var user = _database.Users.FirstOrDefault(c => c.Id == LoggedInUser.Id);
if (user == default)
{
return NotFound(new KnownProblemModel("User does not exist"));
@@ -58,4 +58,4 @@ public class CreateTokenRoute : RouteBaseSync.WithRequest<CreateTokenRoute.Paylo
_database.SaveChanges();
return Ok(Convert.ToBase64String(Encoding.UTF8.GetBytes(accessToken.Id.ToString().EncryptWithAes(tokenEntropy))));
}
-} \ No newline at end of file
+}
diff --git a/code/api/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs b/code/api/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs
index ee19e40..62f7c8d 100644
--- a/code/api/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs
+++ b/code/api/src/Endpoints/V1/ApiTokens/DeleteTokenRoute.cs
@@ -18,7 +18,7 @@ public class DeleteTokenRoute : RouteBaseSync.WithRequest<Guid>.WithActionResult
[ApiVersion(ApiSpecV1.VERSION_STRING)]
[HttpDelete("~/v{version:apiVersion}/api-tokens/delete")]
public override ActionResult Handle(Guid id) {
- var token = _database.AccessTokens.SingleOrDefault(c => c.Id == id);
+ var token = _database.AccessTokens.FirstOrDefault(c => c.Id == id);
if (token == default) {
_logger.LogWarning("A deletion request of an already deleted (maybe) api token was received.");
return NotFound();
@@ -28,4 +28,4 @@ public class DeleteTokenRoute : RouteBaseSync.WithRequest<Guid>.WithActionResult
_database.SaveChanges();
return Ok();
}
-} \ No newline at end of file
+}
diff --git a/code/api/src/Endpoints/V1/RouteBaseAsync.cs b/code/api/src/Endpoints/V1/RouteBaseAsync.cs
index 33b6f5f..cc30aa6 100644
--- a/code/api/src/Endpoints/V1/RouteBaseAsync.cs
+++ b/code/api/src/Endpoints/V1/RouteBaseAsync.cs
@@ -5,69 +5,69 @@ namespace IOL.GreatOffice.Api.Endpoints.V1;
/// </summary>
public class RouteBaseAsync
{
- public class WithRequest<TRequest>
- {
- public abstract class WithResult<TResponse> : V1_EndpointBase
- {
- public abstract Task<TResponse> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public class WithRequest<TRequest>
+ {
+ public abstract class WithResult<TResponse> : V1_EndpointBase
+ {
+ public abstract Task<TResponse> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithoutResult : V1_EndpointBase
- {
- public abstract Task HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithoutResult : V1_EndpointBase
+ {
+ public abstract Task HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult<TResponse> : V1_EndpointBase
- {
- public abstract Task<ActionResult<TResponse>> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithActionResult<TResponse> : V1_EndpointBase
+ {
+ public abstract Task<ActionResult<TResponse>> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult : V1_EndpointBase
- {
- public abstract Task<ActionResult> HandleAsync(
- TRequest request,
- CancellationToken cancellationToken = default
- );
- }
- }
+ public abstract class WithActionResult : V1_EndpointBase
+ {
+ public abstract Task<ActionResult> HandleAsync(
+ TRequest request,
+ CancellationToken cancellationToken = default
+ );
+ }
+ }
- public static class WithoutRequest
- {
- public abstract class WithResult<TResponse> : V1_EndpointBase
- {
- public abstract Task<TResponse> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public static class WithoutRequest
+ {
+ public abstract class WithResult<TResponse> : V1_EndpointBase
+ {
+ public abstract Task<TResponse> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithoutResult : V1_EndpointBase
- {
- public abstract Task HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithoutResult : V1_EndpointBase
+ {
+ public abstract Task HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult<TResponse> : V1_EndpointBase
- {
- public abstract Task<ActionResult<TResponse>> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
+ public abstract class WithActionResult<TResponse> : V1_EndpointBase
+ {
+ public abstract Task<ActionResult<TResponse>> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
- public abstract class WithActionResult : V1_EndpointBase
- {
- public abstract Task<ActionResult> HandleAsync(
- CancellationToken cancellationToken = default
- );
- }
- }
-}
+ public abstract class WithActionResult : V1_EndpointBase
+ {
+ public abstract Task<ActionResult> HandleAsync(
+ CancellationToken cancellationToken = default
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/V1/RouteBaseSync.cs b/code/api/src/Endpoints/V1/RouteBaseSync.cs
index 6a86074..3a06d14 100644
--- a/code/api/src/Endpoints/V1/RouteBaseSync.cs
+++ b/code/api/src/Endpoints/V1/RouteBaseSync.cs
@@ -5,49 +5,49 @@ namespace IOL.GreatOffice.Api.Endpoints.V1;
/// </summary>
public static class RouteBaseSync
{
- public static class WithRequest<TRequest>
- {
- public abstract class WithResult<TResponse> : V1_EndpointBase
- {
- public abstract TResponse Handle(TRequest request);
- }
+ public static class WithRequest<TRequest>
+ {
+ public abstract class WithResult<TResponse> : V1_EndpointBase
+ {
+ public abstract TResponse Handle(TRequest request);
+ }
- public abstract class WithoutResult : V1_EndpointBase
- {
- public abstract void Handle(TRequest request);
- }
+ public abstract class WithoutResult : V1_EndpointBase
+ {
+ public abstract void Handle(TRequest request);
+ }
- public abstract class WithActionResult<TResponse> : V1_EndpointBase
- {
- public abstract ActionResult<TResponse> Handle(TRequest request);
- }
+ public abstract class WithActionResult<TResponse> : V1_EndpointBase
+ {
+ public abstract ActionResult<TResponse> Handle(TRequest request);
+ }
- public abstract class WithActionResult : V1_EndpointBase
- {
- public abstract ActionResult Handle(TRequest request);
- }
- }
+ public abstract class WithActionResult : V1_EndpointBase
+ {
+ public abstract ActionResult Handle(TRequest request);
+ }
+ }
- public static class WithoutRequest
- {
- public abstract class WithResult<TResponse> : V1_EndpointBase
- {
- public abstract TResponse Handle();
- }
+ public static class WithoutRequest
+ {
+ public abstract class WithResult<TResponse> : V1_EndpointBase
+ {
+ public abstract TResponse Handle();
+ }
- public abstract class WithoutResult : V1_EndpointBase
- {
- public abstract void Handle();
- }
+ public abstract class WithoutResult : V1_EndpointBase
+ {
+ public abstract void Handle();
+ }
- public abstract class WithActionResult<TResponse> : V1_EndpointBase
- {
- public abstract ActionResult<TResponse> Handle();
- }
+ public abstract class WithActionResult<TResponse> : V1_EndpointBase
+ {
+ public abstract ActionResult<TResponse> Handle();
+ }
- public abstract class WithActionResult : V1_EndpointBase
- {
- public abstract ActionResult Handle();
- }
- }
-}
+ public abstract class WithActionResult : V1_EndpointBase
+ {
+ public abstract ActionResult Handle();
+ }
+ }
+} \ No newline at end of file
diff --git a/code/api/src/Endpoints/V1/V1_EndpointBase.cs b/code/api/src/Endpoints/V1/V1_EndpointBase.cs
index 08ce4ab..a5835a5 100644
--- a/code/api/src/Endpoints/V1/V1_EndpointBase.cs
+++ b/code/api/src/Endpoints/V1/V1_EndpointBase.cs
@@ -7,11 +7,11 @@ namespace IOL.GreatOffice.Api.Endpoints.V1;
public class V1_EndpointBase : EndpointBase
{
private const string AuthSchemes = CookieAuthenticationDefaults.AuthenticationScheme + "," + AppConstants.BASIC_AUTH_SCHEME;
-
+
protected bool IsApiCall() {
- if (!Request.Headers.ContainsKey("Authorization")) return false;
+ if (!Request.Headers.TryGetValue("Authorization", out var value)) return false;
try {
- var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
+ var authHeader = AuthenticationHeaderValue.Parse(value);
if (authHeader.Parameter == null) return false;
} catch {
return false;
@@ -21,7 +21,7 @@ public class V1_EndpointBase : EndpointBase
}
protected bool HasApiPermission(string permission_key) {
- var permission_claim = User.Claims.SingleOrDefault(c => c.Type == permission_key);
+ var permission_claim = User.Claims.FirstOrDefault(c => c.Type == permission_key);
return permission_claim is {
Value: "True"
};
diff --git a/code/api/src/Models/Database/BaseWithOwner.cs b/code/api/src/Models/Database/BaseWithOwner.cs
index 3c29c76..40789ee 100644
--- a/code/api/src/Models/Database/BaseWithOwner.cs
+++ b/code/api/src/Models/Database/BaseWithOwner.cs
@@ -5,41 +5,36 @@ namespace IOL.GreatOffice.Api.Models.Database;
/// </summary>
public abstract class BaseWithOwner : Base
{
- protected BaseWithOwner() { }
+ protected BaseWithOwner() { }
- protected BaseWithOwner(Guid createdBy)
- {
- CreatedBy = createdBy;
- }
+ protected BaseWithOwner(Guid createdBy) {
+ CreatedBy = createdBy;
+ }
- protected BaseWithOwner(LoggedInUserModel loggedInUser)
- {
- CreatedBy = loggedInUser.Id;
- }
+ protected BaseWithOwner(LoggedInUserModel loggedInUser) {
+ CreatedBy = loggedInUser.Id;
+ }
- public Guid? UserId { get; private set; }
- public Guid? TenantId { get; private set; }
- public Guid? ModifiedBy { get; private set; }
- public Guid? CreatedBy { get; private set; }
- public Guid? DeletedBy { get; private set; }
- public User OwningUser { get; set; }
- public Tenant OwningTenant { get; set; }
+ public Guid? UserId { get; private set; }
+ public Guid? TenantId { get; private set; }
+ public Guid? ModifiedBy { get; private set; }
+ public Guid? CreatedBy { get; private set; }
+ public Guid? DeletedBy { get; private set; }
+ public User OwningUser { get; set; }
+ public Tenant OwningTenant { get; set; }
- public void SetDeleted(Guid userId)
- {
- DeletedBy = userId;
- base.SetDeleted();
- }
+ public void SetDeleted(Guid userId) {
+ DeletedBy = userId;
+ base.SetDeleted();
+ }
- public void SetModified(Guid userId)
- {
- ModifiedBy = userId;
- base.SetModified();
- }
+ public void SetModified(Guid userId) {
+ ModifiedBy = userId;
+ base.SetModified();
+ }
- public void SetOwnerIds(Guid userId = default, Guid tenantId = default)
- {
- if (tenantId != default) TenantId = tenantId;
- if (userId != default) UserId = userId;
- }
-}
+ public void SetOwnerIds(Guid userId = default, Guid tenantId = default) {
+ if (tenantId != default) TenantId = tenantId;
+ if (userId != default) UserId = userId;
+ }
+} \ No newline at end of file
diff --git a/code/api/src/Models/Database/MainAppDatabase.cs b/code/api/src/Models/Database/MainAppDatabase.cs
index cba7269..18f534e 100644
--- a/code/api/src/Models/Database/MainAppDatabase.cs
+++ b/code/api/src/Models/Database/MainAppDatabase.cs
@@ -4,106 +4,106 @@ namespace IOL.GreatOffice.Api.Models.Database;
public class MainAppDatabase : DbContext, IDataProtectionKeyContext
{
- public MainAppDatabase(DbContextOptions<MainAppDatabase> options) : base(options) { }
- public DbSet<User> Users { get; set; }
- public DbSet<PasswordResetRequest> PasswordResetRequests { get; set; }
- public DbSet<ApiAccessToken> AccessTokens { get; set; }
- public DbSet<Tenant> Tenants { get; set; }
- public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
- public DbSet<Project> Projects { get; set; }
- public DbSet<ProjectLabel> ProjectLabels { get; set; }
- public DbSet<Customer> Customers { get; set; }
- public DbSet<CustomerContact> CustomersContacts { get; set; }
- public DbSet<CustomerEvent> CustomerEvents { get; set; }
- public DbSet<CustomerGroup> CustomerGroups { get; set; }
- public DbSet<TodoLabel> TodoLabels { get; set; }
- public DbSet<TodoCollectionAccessControl> TodoProjectAccessControls { get; set; }
- public DbSet<TodoCollection> TodoProjects { get; set; }
- public DbSet<TodoComment> TodoComments { get; set; }
- public DbSet<Todo> Todos { get; set; }
- public DbSet<ValidationEmail> ValidationEmails { get; set; }
+ public MainAppDatabase(DbContextOptions<MainAppDatabase> options) : base(options) { }
+ public DbSet<User> Users { get; set; }
+ public DbSet<PasswordResetRequest> PasswordResetRequests { get; set; }
+ public DbSet<ApiAccessToken> AccessTokens { get; set; }
+ public DbSet<Tenant> Tenants { get; set; }
+ public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
+ public DbSet<Project> Projects { get; set; }
+ public DbSet<ProjectLabel> ProjectLabels { get; set; }
+ public DbSet<Customer> Customers { get; set; }
+ public DbSet<CustomerContact> CustomersContacts { get; set; }
+ public DbSet<CustomerEvent> CustomerEvents { get; set; }
+ public DbSet<CustomerGroup> CustomerGroups { get; set; }
+ public DbSet<TodoLabel> TodoLabels { get; set; }
+ public DbSet<TodoCollectionAccessControl> TodoProjectAccessControls { get; set; }
+ public DbSet<TodoCollection> TodoProjects { get; set; }
+ public DbSet<TodoComment> TodoComments { get; set; }
+ public DbSet<Todo> Todos { get; set; }
+ public DbSet<ValidationEmail> ValidationEmails { get; set; }
- protected override void OnModelCreating(ModelBuilder modelBuilder) {
- modelBuilder.Entity<User>(e => {
- e.HasMany(n => n.Tenants);
- e.ToTable("users");
- });
- modelBuilder.Entity<PasswordResetRequest>(e => {
- e.HasOne(c => c.User);
- e.ToTable("password_reset_requests");
- });
- modelBuilder.Entity<ApiAccessToken>(e => {
- e.HasOne(n => n.User);
- e.ToTable("api_access_tokens");
- });
- modelBuilder.Entity<Tenant>(e => {
- e.HasMany(n => n.Users);
- e.ToTable("tenants");
- });
- modelBuilder.Entity<Project>(e => {
- e.HasMany(n => n.Members);
- e.HasMany(n => n.Customers);
- e.ToTable("projects");
- });
- modelBuilder.Entity<ProjectMember>(e => {
- e.HasOne(n => n.Project);
- e.HasOne(n => n.User);
- e.ToTable("project_members");
- });
- modelBuilder.Entity<ProjectLabel>(e => {
- e.HasOne(n => n.Project);
- e.ToTable("project_labels");
- });
- modelBuilder.Entity<Customer>(e => {
- e.HasOne(n => n.Owner);
- e.HasMany(n => n.Events);
- e.HasMany(n => n.Contacts);
- e.HasMany(n => n.Groups);
- e.HasMany(n => n.Projects);
- e.ToTable("customers");
- });
- modelBuilder.Entity<CustomerContact>(e => {
- e.HasOne(n => n.Customer);
- e.ToTable("customer_contacts");
- });
- modelBuilder.Entity<CustomerEvent>(e => {
- e.HasOne(n => n.Customer);
- e.ToTable("customer_events");
- });
- modelBuilder.Entity<CustomerGroup>(e => {
- e.HasMany(n => n.Customers);
- e.ToTable("customer_groups");
- });
- modelBuilder.Entity<Todo>(e => {
- e.HasOne(n => n.Collection);
- e.HasOne(n => n.AssignedTo);
- e.HasOne(n => n.ClosedBy);
- e.HasMany(n => n.Labels);
- e.HasMany(n => n.Comments);
- e.ToTable("todos");
- });
- modelBuilder.Entity<TodoCollection>(e => {
- e.HasOne(n => n.Project);
- e.HasMany(n => n.AccessControls);
- e.ToTable("todo_collections");
- });
- modelBuilder.Entity<TodoComment>(e => {
- e.HasOne(n => n.Todo);
- e.ToTable("todo_comments");
- });
- modelBuilder.Entity<TodoLabel>(e => {
- e.HasOne(n => n.Todo);
- e.ToTable("todo_labels");
- });
- modelBuilder.Entity<TodoCollectionAccessControl>(e => {
- e.HasOne(n => n.User);
- e.HasOne(n => n.Collection);
- e.ToTable("todo_collection_access_controls");
- });
- modelBuilder.Entity<ValidationEmail>(e => {
- e.ToTable("validation_emails");
- });
+ protected override void OnModelCreating(ModelBuilder modelBuilder) {
+ modelBuilder.Entity<User>(e => {
+ e.HasMany(n => n.Tenants);
+ e.ToTable("users");
+ });
+ modelBuilder.Entity<PasswordResetRequest>(e => {
+ e.HasOne(c => c.User);
+ e.ToTable("password_reset_requests");
+ });
+ modelBuilder.Entity<ApiAccessToken>(e => {
+ e.HasOne(n => n.User);
+ e.ToTable("api_access_tokens");
+ });
+ modelBuilder.Entity<Tenant>(e => {
+ e.HasMany(n => n.Users);
+ e.ToTable("tenants");
+ });
+ modelBuilder.Entity<Project>(e => {
+ e.HasMany(n => n.Members);
+ e.HasMany(n => n.Customers);
+ e.ToTable("projects");
+ });
+ modelBuilder.Entity<ProjectMember>(e => {
+ e.HasOne(n => n.Project);
+ e.HasOne(n => n.User);
+ e.ToTable("project_members");
+ });
+ modelBuilder.Entity<ProjectLabel>(e => {
+ e.HasOne(n => n.Project);
+ e.ToTable("project_labels");
+ });
+ modelBuilder.Entity<Customer>(e => {
+ e.HasOne(n => n.Owner);
+ e.HasMany(n => n.Events);
+ e.HasMany(n => n.Contacts);
+ e.HasMany(n => n.Groups);
+ e.HasMany(n => n.Projects);
+ e.ToTable("customers");
+ });
+ modelBuilder.Entity<CustomerContact>(e => {
+ e.HasOne(n => n.Customer);
+ e.ToTable("customer_contacts");
+ });
+ modelBuilder.Entity<CustomerEvent>(e => {
+ e.HasOne(n => n.Customer);
+ e.ToTable("customer_events");
+ });
+ modelBuilder.Entity<CustomerGroup>(e => {
+ e.HasMany(n => n.Customers);
+ e.ToTable("customer_groups");
+ });
+ modelBuilder.Entity<Todo>(e => {
+ e.HasOne(n => n.Collection);
+ e.HasOne(n => n.AssignedTo);
+ e.HasOne(n => n.ClosedBy);
+ e.HasMany(n => n.Labels);
+ e.HasMany(n => n.Comments);
+ e.ToTable("todos");
+ });
+ modelBuilder.Entity<TodoCollection>(e => {
+ e.HasOne(n => n.Project);
+ e.HasMany(n => n.AccessControls);
+ e.ToTable("todo_collections");
+ });
+ modelBuilder.Entity<TodoComment>(e => {
+ e.HasOne(n => n.Todo);
+ e.ToTable("todo_comments");
+ });
+ modelBuilder.Entity<TodoLabel>(e => {
+ e.HasOne(n => n.Todo);
+ e.ToTable("todo_labels");
+ });
+ modelBuilder.Entity<TodoCollectionAccessControl>(e => {
+ e.HasOne(n => n.User);
+ e.HasOne(n => n.Collection);
+ e.ToTable("todo_collection_access_controls");
+ });
+ modelBuilder.Entity<ValidationEmail>(e => {
+ e.ToTable("validation_emails");
+ });
- base.OnModelCreating(modelBuilder);
- }
+ base.OnModelCreating(modelBuilder);
+ }
}
diff --git a/code/api/src/Models/Misc/ApiSpecDocument.cs b/code/api/src/Models/Misc/ApiSpecDocument.cs
index a515baf..8cf928d 100644
--- a/code/api/src/Models/Misc/ApiSpecDocument.cs
+++ b/code/api/src/Models/Misc/ApiSpecDocument.cs
@@ -1,4 +1,4 @@
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public class ApiSpecDocument
{
diff --git a/code/api/src/Models/Misc/AppConfiguration.cs b/code/api/src/Models/Misc/AppConfiguration.cs
index a71970c..f7fc428 100644
--- a/code/api/src/Models/Misc/AppConfiguration.cs
+++ b/code/api/src/Models/Misc/AppConfiguration.cs
@@ -2,7 +2,7 @@ using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using System.Text;
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public class AppConfiguration
{
diff --git a/code/api/src/Models/Misc/AppPath.cs b/code/api/src/Models/Misc/AppPath.cs
index 5a8c206..c020425 100644
--- a/code/api/src/Models/Misc/AppPath.cs
+++ b/code/api/src/Models/Misc/AppPath.cs
@@ -1,4 +1,4 @@
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public sealed record AppPath
{
diff --git a/code/api/src/Models/Misc/KnownProblemModel.cs b/code/api/src/Models/Misc/KnownProblemModel.cs
index 5a9927f..1c948d8 100644
--- a/code/api/src/Models/Misc/KnownProblemModel.cs
+++ b/code/api/src/Models/Misc/KnownProblemModel.cs
@@ -1,4 +1,4 @@
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public class KnownProblemModel
{
diff --git a/code/api/src/Models/Misc/LoggedInUserModel.cs b/code/api/src/Models/Misc/LoggedInUserModel.cs
index ce2b163..49d05d4 100644
--- a/code/api/src/Models/Misc/LoggedInUserModel.cs
+++ b/code/api/src/Models/Misc/LoggedInUserModel.cs
@@ -1,4 +1,4 @@
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public class LoggedInUserModel
{
diff --git a/code/api/src/Models/Misc/RequestTimeZoneInfo.cs b/code/api/src/Models/Misc/RequestTimeZoneInfo.cs
index 4d9d8c1..9e7201c 100644
--- a/code/api/src/Models/Misc/RequestTimeZoneInfo.cs
+++ b/code/api/src/Models/Misc/RequestTimeZoneInfo.cs
@@ -1,4 +1,4 @@
-namespace IOL.GreatOffice.Api.Models.Models;
+namespace IOL.GreatOffice.Api.Models.Misc;
public class RequestTimeZoneInfo
{
diff --git a/code/api/src/Models/Static/AppConstants.cs b/code/api/src/Models/Static/AppConstants.cs
index edd5bf0..85bf3db 100644
--- a/code/api/src/Models/Static/AppConstants.cs
+++ b/code/api/src/Models/Static/AppConstants.cs
@@ -2,11 +2,10 @@ namespace IOL.GreatOffice.Api.Models.Static;
public static class AppConstants
{
- public const string API_NAME = "Greatoffice API";
- public const string BASIC_AUTH_SCHEME = "BasicAuthenticationScheme";
- public const string TOKEN_ALLOW_READ = "TOKEN_ALLOW_READ";
- public const string TOKEN_ALLOW_CREATE = "TOKEN_ALLOW_CREATE";
- public const string TOKEN_ALLOW_UPDATE = "TOKEN_ALLOW_UPDATE";
- public const string TOKEN_ALLOW_DELETE = "TOKEN_ALLOW_DELETE";
- public const string VAULT_CACHE_KEY = "VAULT_CACHE_KEY";
-}
+ public const string API_NAME = "Greatoffice API";
+ public const string BASIC_AUTH_SCHEME = "BasicAuthenticationScheme";
+ public const string TOKEN_ALLOW_READ = "TOKEN_ALLOW_READ";
+ public const string TOKEN_ALLOW_CREATE = "TOKEN_ALLOW_CREATE";
+ public const string TOKEN_ALLOW_UPDATE = "TOKEN_ALLOW_UPDATE";
+ public const string TOKEN_ALLOW_DELETE = "TOKEN_ALLOW_DELETE";
+} \ No newline at end of file
diff --git a/code/api/src/Program.cs b/code/api/src/Program.cs
index 4fa6c9f..9e4301a 100644
--- a/code/api/src/Program.cs
+++ b/code/api/src/Program.cs
@@ -10,7 +10,7 @@ global using System.Text.Json;
global using System.Text.Json.Serialization;
global using IOL.GreatOffice.Api.Models.Database;
global using IOL.GreatOffice.Api.Models.Enums;
-global using IOL.GreatOffice.Api.Models.Models;
+global using IOL.GreatOffice.Api.Models.Misc;
global using IOL.GreatOffice.Api.Models.Static;
global using IOL.GreatOffice.Api.Services;
global using IOL.GreatOffice.Api.Resources;
diff --git a/code/api/src/Services/PasswordResetService.cs b/code/api/src/Services/PasswordResetService.cs
index 7f70ad1..5dabd4d 100644
--- a/code/api/src/Services/PasswordResetService.cs
+++ b/code/api/src/Services/PasswordResetService.cs
@@ -22,7 +22,7 @@ public class PasswordResetService
{
var request = await _database.PasswordResetRequests
.Include(c => c.User)
- .SingleOrDefaultAsync(c => c.Id == id, cancellationToken);
+ .FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
if (request == default)
{
return default;
@@ -104,4 +104,4 @@ If you did not request a password reset, no action is required.
await _database.SaveChangesAsync(cancellationToken);
_logger.LogInformation($"Deleted {deleteCount} stale password reset requests.");
}
-} \ No newline at end of file
+}