From 6fe816404f348f50219296d0a74a5a571709b1b1 Mon Sep 17 00:00:00 2001
From: sam
Date: Mon, 24 Feb 2025 17:47:37 +0100
Subject: [PATCH 01/29] rename rate/ to Foxnouns.RateLimiter/ for consistency
---
{rate => Foxnouns.RateLimiter}/Dockerfile | 0
{rate => Foxnouns.RateLimiter}/README.md | 0
{rate => Foxnouns.RateLimiter}/go.mod | 0
{rate => Foxnouns.RateLimiter}/go.sum | 0
{rate => Foxnouns.RateLimiter}/handler.go | 0
{rate => Foxnouns.RateLimiter}/main.go | 0
{rate => Foxnouns.RateLimiter}/proxy-config.example.json | 0
{rate => Foxnouns.RateLimiter}/rate_limiter.go | 0
8 files changed, 0 insertions(+), 0 deletions(-)
rename {rate => Foxnouns.RateLimiter}/Dockerfile (100%)
rename {rate => Foxnouns.RateLimiter}/README.md (100%)
rename {rate => Foxnouns.RateLimiter}/go.mod (100%)
rename {rate => Foxnouns.RateLimiter}/go.sum (100%)
rename {rate => Foxnouns.RateLimiter}/handler.go (100%)
rename {rate => Foxnouns.RateLimiter}/main.go (100%)
rename {rate => Foxnouns.RateLimiter}/proxy-config.example.json (100%)
rename {rate => Foxnouns.RateLimiter}/rate_limiter.go (100%)
diff --git a/rate/Dockerfile b/Foxnouns.RateLimiter/Dockerfile
similarity index 100%
rename from rate/Dockerfile
rename to Foxnouns.RateLimiter/Dockerfile
diff --git a/rate/README.md b/Foxnouns.RateLimiter/README.md
similarity index 100%
rename from rate/README.md
rename to Foxnouns.RateLimiter/README.md
diff --git a/rate/go.mod b/Foxnouns.RateLimiter/go.mod
similarity index 100%
rename from rate/go.mod
rename to Foxnouns.RateLimiter/go.mod
diff --git a/rate/go.sum b/Foxnouns.RateLimiter/go.sum
similarity index 100%
rename from rate/go.sum
rename to Foxnouns.RateLimiter/go.sum
diff --git a/rate/handler.go b/Foxnouns.RateLimiter/handler.go
similarity index 100%
rename from rate/handler.go
rename to Foxnouns.RateLimiter/handler.go
diff --git a/rate/main.go b/Foxnouns.RateLimiter/main.go
similarity index 100%
rename from rate/main.go
rename to Foxnouns.RateLimiter/main.go
diff --git a/rate/proxy-config.example.json b/Foxnouns.RateLimiter/proxy-config.example.json
similarity index 100%
rename from rate/proxy-config.example.json
rename to Foxnouns.RateLimiter/proxy-config.example.json
diff --git a/rate/rate_limiter.go b/Foxnouns.RateLimiter/rate_limiter.go
similarity index 100%
rename from rate/rate_limiter.go
rename to Foxnouns.RateLimiter/rate_limiter.go
From a72c0f41c3965288e2fa159d410719d5c83579df Mon Sep 17 00:00:00 2001
From: sam
Date: Mon, 24 Feb 2025 18:25:49 +0100
Subject: [PATCH 02/29] add build script
---
.gitignore | 3 +++
build.sh | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
create mode 100755 build.sh
diff --git a/.gitignore b/.gitignore
index 9c16977..9037fa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,6 @@ docker/proxy-config.json
docker/frontend.env
Foxnouns.DataMigrator/apps.json
+
+out/
+build/
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..e14eb53
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+set -euxo pipefail
+
+ROOT_DIR=$(pwd)
+
+echo "Cleaning output directory ($ROOT_DIR/build)"
+
+[ -d "$ROOT_DIR/build" ] && rm -r "$ROOT_DIR/build"
+mkdir "$ROOT_DIR/build"
+
+echo "Building .NET backend"
+
+cd "$ROOT_DIR/Foxnouns.Backend"
+[ -d "$ROOT_DIR/Foxnouns.Backend/out" ] && rm -r "$ROOT_DIR/Foxnouns.Backend/out"
+dotnet publish --artifacts-path "$ROOT_DIR/Foxnouns.Backend/out"
+mv "$ROOT_DIR/Foxnouns.Backend/out/publish/Foxnouns.Backend/"* "$ROOT_DIR/build/bin"
+
+echo "Building Go rate limiter"
+
+cd "$ROOT_DIR/Foxnouns.RateLimiter"
+go build -o rate -v .
+mv rate "$ROOT_DIR/build/rate"
+
+echo "Building Node.js frontend"
+
+cd "$ROOT_DIR/Foxnouns.Frontend"
+[ -d "$ROOT_DIR/Foxnouns.Frontend/build" ] && rm -r "$ROOT_DIR/Foxnouns.Frontend/build"
+pnpm install
+pnpm build
+
+mkdir "$ROOT_DIR/build/fe"
+cp -r build .env* package.json pnpm-lock.yaml "$ROOT_DIR/build/fe"
+cd "$ROOT_DIR/build/fe"
+pnpm install -P
+
+echo "Finished building Foxnouns.NET"
From f1f777ff823b9cf2f4a33cb6ec157696f8e62e82 Mon Sep 17 00:00:00 2001
From: sam
Date: Mon, 24 Feb 2025 20:37:51 +0100
Subject: [PATCH 03/29] fix(frontend): localize footer
---
.../src/lib/components/Footer.svelte | 21 ++++++++++---------
.../src/lib/i18n/locales/en.json | 12 +++++++++++
2 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/Foxnouns.Frontend/src/lib/components/Footer.svelte b/Foxnouns.Frontend/src/lib/components/Footer.svelte
index 6fd6564..857c07c 100644
--- a/Foxnouns.Frontend/src/lib/components/Footer.svelte
+++ b/Foxnouns.Frontend/src/lib/components/Footer.svelte
@@ -8,6 +8,7 @@
import Envelope from "svelte-bootstrap-icons/lib/Envelope.svelte";
import CashCoin from "svelte-bootstrap-icons/lib/CashCoin.svelte";
import Logo from "./Logo.svelte";
+ import { t } from "$lib/i18n";
type Props = { meta: Meta };
let { meta }: Props = $props();
@@ -18,13 +19,13 @@
- - Version {meta.version}
+ - {$t("footer.version")} {meta.version}
- - {meta.users.total.toLocaleString()} users
- - {meta.members.toLocaleString()} members
+ - {meta.users.total.toLocaleString()} {$t("footer.users")}
+ - {meta.members.toLocaleString()} {$t("footer.members")}
@@ -36,7 +37,7 @@
>
- Source code
+ {$t("footer.source")}
- Status
+ {$t("footer.status")}
- About and contact
+ {$t("footer.about-contact")}
- Terms of service
+ {$t("footer.terms")}
- Privacy policy
+ {$t("footer.privacy")}
- Changelog
+ {$t("footer.changelog")}
- Donate
+ {$t("footer.donate")}
diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
index 1c15a83..7f2b2ab 100644
--- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json
+++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
@@ -327,5 +327,17 @@
"alert": {
"auth-method-remove-success": "Successfully unlinked account!",
"auth-required": "You must log in to access this page."
+ },
+ "footer": {
+ "version": "Version",
+ "users": "users",
+ "members": "members",
+ "source": "Source code",
+ "status": "Status",
+ "terms": "Terms of service",
+ "privacy": "Privacy policy",
+ "changelog": "Changelog",
+ "donate": "Donate",
+ "about-contact": "About and contact"
}
}
From 64ea25e89e4bdcafd7209fc1300cb7a46a34ffdb Mon Sep 17 00:00:00 2001
From: sam
Date: Mon, 24 Feb 2025 21:32:20 +0100
Subject: [PATCH 04/29] feat(frontend): avatar cropping
---
Foxnouns.Frontend/package.json | 3 +-
Foxnouns.Frontend/pnpm-lock.yaml | 22 +++--
.../lib/components/editor/AvatarEditor.svelte | 89 ++++++++++++++++++-
.../src/lib/i18n/locales/en.json | 4 +-
4 files changed, 108 insertions(+), 10 deletions(-)
diff --git a/Foxnouns.Frontend/package.json b/Foxnouns.Frontend/package.json
index d140f11..a76a918 100644
--- a/Foxnouns.Frontend/package.json
+++ b/Foxnouns.Frontend/package.json
@@ -15,7 +15,7 @@
"@sveltejs/adapter-node": "^5.2.10",
"@sveltejs/kit": "^2.12.1",
"@sveltejs/vite-plugin-svelte": "^5.0.2",
- "@sveltestrap/sveltestrap": "^6.2.7",
+ "@sveltestrap/sveltestrap": "^7.1.0",
"@types/eslint": "^9.6.1",
"@types/luxon": "^3.4.2",
"@types/markdown-it": "^14.1.2",
@@ -31,6 +31,7 @@
"svelte": "^5.14.3",
"svelte-bootstrap-icons": "^3.1.1",
"svelte-check": "^4.1.1",
+ "svelte-easy-crop": "^4.0.0",
"sveltekit-i18n": "^2.4.2",
"typescript": "^5.7.2",
"typescript-eslint": "^8.18.1",
diff --git a/Foxnouns.Frontend/pnpm-lock.yaml b/Foxnouns.Frontend/pnpm-lock.yaml
index c77b36c..46b0010 100644
--- a/Foxnouns.Frontend/pnpm-lock.yaml
+++ b/Foxnouns.Frontend/pnpm-lock.yaml
@@ -55,8 +55,8 @@ importers:
specifier: ^5.0.2
version: 5.0.2(svelte@5.14.3)(vite@6.0.3(@types/node@22.12.0)(sass@1.83.0))
'@sveltestrap/sveltestrap':
- specifier: ^6.2.7
- version: 6.2.7(svelte@5.14.3)
+ specifier: ^7.1.0
+ version: 7.1.0(svelte@5.14.3)
'@types/eslint':
specifier: ^9.6.1
version: 9.6.1
@@ -102,6 +102,9 @@ importers:
svelte-check:
specifier: ^4.1.1
version: 4.1.1(picomatch@4.0.2)(svelte@5.14.3)(typescript@5.7.2)
+ svelte-easy-crop:
+ specifier: ^4.0.0
+ version: 4.0.0(svelte@5.14.3)
sveltekit-i18n:
specifier: ^2.4.2
version: 2.4.2(svelte@5.14.3)
@@ -1002,8 +1005,8 @@ packages:
'@sveltekit-i18n/parser-default@1.1.1':
resolution: {integrity: sha512-/gtzLlqm/sox7EoPKD56BxGZktK/syGc79EbJAPWY5KVitQD9SM0TP8yJCqDxTVPk7Lk0WJhrBGUE2Nn0f5M1w==}
- '@sveltestrap/sveltestrap@6.2.7':
- resolution: {integrity: sha512-WwLLfAFUb42BGuRrf3Vbct30bQMzlEMMipN/MfxhjuLTmLQeW9muVJfPyvjtWS+mY+RjkSCoHvAp/ZobP1NLlQ==}
+ '@sveltestrap/sveltestrap@7.1.0':
+ resolution: {integrity: sha512-TpIx25kqLV+z+VD3yfqYayOI1IaCeWFbT0uqM6NfA4vQgDs9PjFwmjkU4YEAlV/ngs9e7xPmaRWE7lkrg4Miow==}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0 || ^5.0.0-next.0
@@ -1967,6 +1970,11 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
typescript: '>=5.0.0'
+ svelte-easy-crop@4.0.0:
+ resolution: {integrity: sha512-/asrrCYypXwCsPqJ07m7s7QArJwrdfEt7D1UN9hC4WF3GgEtuqmGuVi5DGeJVtBpKu5388gYFtCgQz9lA+/Rtg==}
+ peerDependencies:
+ svelte: ^4.0.0 || ^5.0.0
+
svelte-eslint-parser@0.43.0:
resolution: {integrity: sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3079,7 +3087,7 @@ snapshots:
'@sveltekit-i18n/parser-default@1.1.1': {}
- '@sveltestrap/sveltestrap@6.2.7(svelte@5.14.3)':
+ '@sveltestrap/sveltestrap@7.1.0(svelte@5.14.3)':
dependencies:
'@popperjs/core': 2.11.8
svelte: 5.14.3
@@ -4051,6 +4059,10 @@ snapshots:
transitivePeerDependencies:
- picomatch
+ svelte-easy-crop@4.0.0(svelte@5.14.3):
+ dependencies:
+ svelte: 5.14.3
+
svelte-eslint-parser@0.43.0(svelte@5.14.3):
dependencies:
eslint-scope: 7.2.2
diff --git a/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte
index e18c6b6..a945bbf 100644
--- a/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte
+++ b/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte
@@ -1,7 +1,8 @@
@@ -44,6 +86,41 @@
+ (cropperOpen = !cropperOpen)}
+>
+
+
+ {#if uncroppedAvatar}
+
+ {/if}
+
+
+
+
{/if}
+
+
diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
index 7f2b2ab..7145181 100644
--- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json
+++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
@@ -291,7 +291,9 @@
"custom-preference-muted": "Show as muted text",
"custom-preference-favourite": "Treat like favourite",
"custom-preference-notice": "Want to edit your custom preferences?",
- "custom-preference-notice-link": "Go to settings"
+ "custom-preference-notice-link": "Go to settings",
+ "crop-avatar-header": "Crop avatar",
+ "crop-avatar-button": "Crop"
},
"cancel": "Cancel",
"report": {
From 7ea6c62d67bd01820530703a324500e4bf981137 Mon Sep 17 00:00:00 2001
From: sam
Date: Fri, 28 Feb 2025 16:36:45 +0100
Subject: [PATCH 05/29] chore(backend): update dependencies
---
Foxnouns.Backend/Foxnouns.Backend.csproj | 36 +-
Foxnouns.Backend/Program.cs | 24 +-
.../OpenApi/PropertyKeySchemaTransformer.cs | 6 +-
Foxnouns.Backend/packages.lock.json | 371 +++++++++---------
.../Foxnouns.DataMigrator.csproj | 6 +-
5 files changed, 224 insertions(+), 219 deletions(-)
diff --git a/Foxnouns.Backend/Foxnouns.Backend.csproj b/Foxnouns.Backend/Foxnouns.Backend.csproj
index 6f6d69f..c30f2b9 100644
--- a/Foxnouns.Backend/Foxnouns.Backend.csproj
+++ b/Foxnouns.Backend/Foxnouns.Backend.csproj
@@ -8,41 +8,41 @@
-
-
+
+
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
-
+
-
+
diff --git a/Foxnouns.Backend/Program.cs b/Foxnouns.Backend/Program.cs
index 66e57a6..0f1d9f1 100644
--- a/Foxnouns.Backend/Program.cs
+++ b/Foxnouns.Backend/Program.cs
@@ -23,7 +23,6 @@ using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Prometheus;
-using Scalar.AspNetCore;
using Sentry.Extensibility;
using Serilog;
@@ -46,7 +45,8 @@ builder
// No valid request body will ever come close to this limit,
// but the limit is slightly higher to prevent valid requests from being rejected.
opts.Limits.MaxRequestBodySize = 2 * 1024 * 1024;
- });
+ })
+ .UseUrls(config.Address);
builder
.Services.AddControllers()
@@ -109,16 +109,18 @@ if (config.Logging.SentryTracing)
app.UseCors();
app.UseCustomMiddleware();
app.MapControllers();
-app.MapOpenApi("/api-docs/openapi/{documentName}.json");
-app.MapScalarApiReference(options =>
-{
- options.Title = "pronouns.cc API";
- options.OpenApiRoutePattern = "/api-docs/openapi/{documentName}.json";
- options.EndpointPathPrefix = "/api-docs/{documentName}";
-});
-app.Urls.Clear();
-app.Urls.Add(config.Address);
+// TODO: I can't figure out why this doesn't work yet
+// TODO: Manually write API docs in the meantime
+// app.MapOpenApi("/api-docs/openapi/{documentName}.json");
+// app.MapScalarApiReference(
+// "/api-docs/",
+// options =>
+// {
+// options.Title = "pronouns.cc API";
+// options.OpenApiRoutePattern = "/api-docs/openapi/{documentName}.json";
+// }
+// );
// Make sure metrics are updated whenever Prometheus scrapes them
Metrics.DefaultRegistry.AddBeforeCollectCallback(async ct =>
diff --git a/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs b/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs
index 92c1f7c..9835b50 100644
--- a/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs
+++ b/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs
@@ -22,8 +22,10 @@ namespace Foxnouns.Backend.Utils.OpenApi;
public class PropertyKeySchemaTransformer : IOpenApiSchemaTransformer
{
- private static readonly DefaultContractResolver SnakeCaseConverter =
- new() { NamingStrategy = new SnakeCaseNamingStrategy() };
+ private static readonly DefaultContractResolver SnakeCaseConverter = new()
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy(),
+ };
public Task TransformAsync(
OpenApiSchema schema,
diff --git a/Foxnouns.Backend/packages.lock.json b/Foxnouns.Backend/packages.lock.json
index dc238f7..e3799c6 100644
--- a/Foxnouns.Backend/packages.lock.json
+++ b/Foxnouns.Backend/packages.lock.json
@@ -4,9 +4,9 @@
"net9.0": {
"Coravel": {
"type": "Direct",
- "requested": "[6.0.0, )",
- "resolved": "6.0.0",
- "contentHash": "U16V/IxGL2TcpU9sT1gUA3pqoVIlz+WthC4idn8OTPiEtLElTcmNF6sHt+gOx8DRU8TBgN5vjfL4AHetjacOWQ==",
+ "requested": "[6.0.2, )",
+ "resolved": "6.0.2",
+ "contentHash": "/XZiRId4Ilar/OqjGKdxkZWfW97ekeT0wgiWNjGdqf8pPxiK508//Zkc0xrKMDOqchFT7B/oqAoQ+Vrx1txpPQ==",
"dependencies": {
"Microsoft.Extensions.Caching.Memory": "3.1.0",
"Microsoft.Extensions.Configuration.Binder": "6.0.0",
@@ -17,12 +17,12 @@
},
"Coravel.Mailer": {
"type": "Direct",
- "requested": "[7.0.0, )",
- "resolved": "7.0.0",
- "contentHash": "mxSlOOBxPjCAZruOpgXtubnZA9lD0DRgutApQmAsts7DoRfe0wTzqWrYjeZTiIzgVJZKZxJglN8duTvbPrw3jQ==",
+ "requested": "[7.1.0, )",
+ "resolved": "7.1.0",
+ "contentHash": "yMbUrwKl5/HbJeX8JkHa8Q3CPTJ3OmPyDSG7sULbXGEhzc2GiYIh7pmVhI1FFeL3VUtFavMDkS8PTwEeCpiwlg==",
"dependencies": {
- "MailKit": "4.3.0",
- "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": "6.0.27"
+ "MailKit": "4.8.0",
+ "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": "6.0.36"
}
},
"EFCore.NamingConventions": {
@@ -60,41 +60,41 @@
},
"Microsoft.AspNetCore.Mvc.NewtonsoftJson": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "pTFDEmZi3GheCSPrBxzyE63+d5unln2vYldo/nOm1xet/4rpEk2oJYcwpclPQ13E+LZBF9XixkgwYTUwqznlWg==",
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "cCnaxji6nqIHHLAEhZ6QirXCvwJNi0Q/qCPLkRW5SqMYNuOwoQdGk1KAhW65phBq1VHGt7wLbadpuGPGqfiZuA==",
"dependencies": {
- "Microsoft.AspNetCore.JsonPatch": "9.0.0",
+ "Microsoft.AspNetCore.JsonPatch": "9.0.2",
"Newtonsoft.Json": "13.0.3",
"Newtonsoft.Json.Bson": "1.0.2"
}
},
"Microsoft.AspNetCore.OpenApi": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "FqUK5j1EOPNuFT7IafltZQ3cakqhSwVzH5ZW1MhZDe4pPXs9sJ2M5jom1Omsu+mwF2tNKKlRAzLRHQTZzbd+6Q==",
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "JUndpjRNdG8GvzBLH/J4hen4ehWaPcshtiQ6+sUs1Bcj3a7dOsmWpDloDlpPeMOVSlhHwUJ3Xld0ClZjsFLgFQ==",
"dependencies": {
"Microsoft.OpenApi": "1.6.17"
}
},
"Microsoft.EntityFrameworkCore": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "wpG+nfnfDAw87R3ovAsUmjr3MZ4tYXf6bFqEPVAIKE6IfPml3DS//iX0DBnf8kWn5ZHSO5oi1m4d/Jf+1LifJQ==",
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "P90ZuybgcpW32y985eOYxSoZ9IiL0UTYQlY0y1Pt1iHAnpZj/dQHREpSpry1RNvk8YjAeoAkWFdem5conqB9zQ==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Abstractions": "9.0.0",
- "Microsoft.EntityFrameworkCore.Analyzers": "9.0.0",
- "Microsoft.Extensions.Caching.Memory": "9.0.0",
- "Microsoft.Extensions.Logging": "9.0.0"
+ "Microsoft.EntityFrameworkCore.Abstractions": "9.0.2",
+ "Microsoft.EntityFrameworkCore.Analyzers": "9.0.2",
+ "Microsoft.Extensions.Caching.Memory": "9.0.2",
+ "Microsoft.Extensions.Logging": "9.0.2"
}
},
"Microsoft.EntityFrameworkCore.Design": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "Pqo8I+yHJ3VQrAoY0hiSncf+5P7gN/RkNilK5e+/K/yKh+yAWxdUAI6t0TG26a9VPlCa9FhyklzyFvRyj3YG9A==",
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "WWRmTxb/yd05cTW+k32lLvIhffxilgYvwKHDxiqe7GRLKeceyMspuf5BRpW65sFF7S2G+Be9JgjUe1ypGqt9tg==",
"dependencies": {
"Humanizer.Core": "2.14.1",
"Microsoft.Build.Framework": "17.8.3",
@@ -102,33 +102,33 @@
"Microsoft.CodeAnalysis.CSharp": "4.8.0",
"Microsoft.CodeAnalysis.CSharp.Workspaces": "4.8.0",
"Microsoft.CodeAnalysis.Workspaces.MSBuild": "4.8.0",
- "Microsoft.EntityFrameworkCore.Relational": "9.0.0",
- "Microsoft.Extensions.Caching.Memory": "9.0.0",
- "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
- "Microsoft.Extensions.DependencyModel": "9.0.0",
- "Microsoft.Extensions.Logging": "9.0.0",
+ "Microsoft.EntityFrameworkCore.Relational": "9.0.2",
+ "Microsoft.Extensions.Caching.Memory": "9.0.2",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.2",
+ "Microsoft.Extensions.DependencyModel": "9.0.2",
+ "Microsoft.Extensions.Logging": "9.0.2",
"Mono.TextTemplating": "3.0.0",
- "System.Text.Json": "9.0.0"
+ "System.Text.Json": "9.0.2"
}
},
"Microsoft.Extensions.Caching.Memory": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "zbnPX/JQ0pETRSUG9fNPBvpIq42Aufvs15gGYyNIMhCun9yhmWihz0WgsI7bSDPjxWTKBf8oX/zv6v2uZ3W9OQ==",
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "AlEfp0DMz8E1h1Exi8LBrUCNmCYcGDfSM4F/uK1D1cYx/R3w0LVvlmjICqxqXTsy7BEZaCf5leRZY2FuPEiFaw==",
"dependencies": {
- "Microsoft.Extensions.Caching.Abstractions": "9.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "9.0.0",
- "Microsoft.Extensions.Options": "9.0.0",
- "Microsoft.Extensions.Primitives": "9.0.0"
+ "Microsoft.Extensions.Caching.Abstractions": "9.0.2",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2",
+ "Microsoft.Extensions.Logging.Abstractions": "9.0.2",
+ "Microsoft.Extensions.Options": "9.0.2",
+ "Microsoft.Extensions.Primitives": "9.0.2"
}
},
"MimeKit": {
"type": "Direct",
- "requested": "[4.9.0, )",
- "resolved": "4.9.0",
- "contentHash": "DZXXMZzmAABDxFhOSMb6SE8KKxcRd/sk1E6aJTUE5ys2FWOQhznYV2Gl3klaaSfqKn27hQ32haqquH1J8Z6kJw==",
+ "requested": "[4.10.0, )",
+ "resolved": "4.10.0",
+ "contentHash": "GQofI17cH55XSh109hJmHaYMtSFqTX/eUek3UcV7hTnYayAIXZ6eHlv345tfdc+bQ/BrEnYOSZVzx9I3wpvvpg==",
"dependencies": {
"BouncyCastle.Cryptography": "2.5.0",
"System.Formats.Asn1": "8.0.1",
@@ -137,11 +137,11 @@
},
"Minio": {
"type": "Direct",
- "requested": "[6.0.3, )",
- "resolved": "6.0.3",
- "contentHash": "WHlkouclHtiK/pIXPHcjVmbeELHPtElj2qRSopFVpSmsFhZXeM10sPvczrkSPePsmwuvZdFryJ/hJzKu3XeLVg==",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "JckRL95hQ/eDHTQZ/BB7jeR0JyF+bOctMW6uriXHY5YPjCX61hiJGsswGjuDSEViKJEPxtPi3e4IwD/1TJ7PIw==",
"dependencies": {
- "CommunityToolkit.HighPerformance": "8.2.2",
+ "CommunityToolkit.HighPerformance": "8.3.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1",
"Microsoft.Extensions.Logging": "8.0.0",
"System.IO.Hashing": "8.0.0",
@@ -156,39 +156,39 @@
},
"NodaTime": {
"type": "Direct",
- "requested": "[3.2.0, )",
- "resolved": "3.2.0",
- "contentHash": "yoRA3jEJn8NM0/rQm78zuDNPA3DonNSZdsorMUj+dltc1D+/Lc5h9YXGqbEEZozMGr37lAoYkcSM/KjTVqD0ow=="
+ "requested": "[3.2.1, )",
+ "resolved": "3.2.1",
+ "contentHash": "D1aHhUfPQUxU2nfDCVuSLahpp0xCYZTmj/KNH3mSK/tStJYcx9HO9aJ0qbOP3hzjGPV/DXOqY2AHe27Nt4xs4g=="
},
"Npgsql.EntityFrameworkCore.PostgreSQL": {
"type": "Direct",
- "requested": "[9.0.2, )",
- "resolved": "9.0.2",
- "contentHash": "cYdOGplIvr9KgsG8nJ8xnzBTImeircbgetlzS1OmepS5dAQW6PuGpVrLOKBNEwEvGYZPsV8037X5vZ/Dmpwz7Q==",
+ "requested": "[9.0.3, )",
+ "resolved": "9.0.3",
+ "contentHash": "1A6HpMPbzK+quxdtug1aDHI4BSRTgpi7OaDt8WQh7SFJd2sSQ0nNTZ7sYrwyxVf4AdKdN7XJL9tpiiJjRUaa4g==",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "[9.0.0, 10.0.0)",
- "Microsoft.EntityFrameworkCore.Relational": "[9.0.0, 10.0.0)",
+ "Microsoft.EntityFrameworkCore": "[9.0.1, 10.0.0)",
+ "Microsoft.EntityFrameworkCore.Relational": "[9.0.1, 10.0.0)",
"Npgsql": "9.0.2"
}
},
"Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime": {
"type": "Direct",
- "requested": "[9.0.2, )",
- "resolved": "9.0.2",
- "contentHash": "+mfwiRCK+CAKTkeBZCuQuMaOwM/yMX8B65515PS1le9TUjlG8DobuAmb48MSR/Pr/YMvU1tV8FFEFlyQviQzrg==",
+ "requested": "[9.0.3, )",
+ "resolved": "9.0.3",
+ "contentHash": "Eks1o3NfIbS3EHhrXC0QABrQab7CJ64C2+kF0YJWLwlH/tu3ExrgrSLpLI6INdeMYcLr2PXu71LjJsrQNVciYg==",
"dependencies": {
- "Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.2",
+ "Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.3",
"Npgsql.NodaTime": "9.0.2"
}
},
"Npgsql.Json.NET": {
"type": "Direct",
- "requested": "[9.0.2, )",
- "resolved": "9.0.2",
- "contentHash": "E81dvvpNtS4WigxZu16OAFxVvPvbEkXI7vJXZzEp7GQ03MArF5V4HBb7KXDzTaE5ZQ0bhCUFoMTODC6Z8mu27g==",
+ "requested": "[9.0.3, )",
+ "resolved": "9.0.3",
+ "contentHash": "lN8p9UKkoXaGUhX3DHg/1W6YeEfbjQiQ7XrJSGREUoDHXOLxDQHJnZ49P/9P2s/pH6HTVgTgT5dijpKoRLN0vQ==",
"dependencies": {
"Newtonsoft.Json": "13.0.3",
- "Npgsql": "9.0.2"
+ "Npgsql": "9.0.3"
}
},
"prometheus-net": {
@@ -212,24 +212,24 @@
},
"Roslynator.Analyzers": {
"type": "Direct",
- "requested": "[4.12.9, )",
- "resolved": "4.12.9",
- "contentHash": "X6lDpN/D5wuinq37KIx+l3GSUe9No+8bCjGBTI5sEEtxapLztkHg6gzNVhMXpXw8P+/5gFYxTXJ5Pf8O4iNz/w=="
+ "requested": "[4.13.1, )",
+ "resolved": "4.13.1",
+ "contentHash": "KZpLy6ZlCebMk+d/3I5KU2R7AOb4LNJ6tPJqPtvFXmO8bEBHQvCIAvJOnY2tu4C9/aVOROTDYUFADxFqw1gh/g=="
},
"Scalar.AspNetCore": {
"type": "Direct",
- "requested": "[1.2.55, )",
- "resolved": "1.2.55",
- "contentHash": "zArlr6nfPQMRwyia0WFirsyczQby51GhNgWITiEIRkot+CVGZSGQ4oWGqExO11/6x26G+mcQo9Oft1mGpN0/ZQ=="
+ "requested": "[2.0.18, )",
+ "resolved": "2.0.18",
+ "contentHash": "nS8Sw6wRO1A/dARn3q9R6znIBfddJcmAczI5uMROBGWkO2KG/ad/Ld+UeUePTxGr1+6humJSOxI7An+q4q3oGA=="
},
"Sentry.AspNetCore": {
"type": "Direct",
- "requested": "[4.13.0, )",
- "resolved": "4.13.0",
- "contentHash": "1cH9hSvjRbTkcpjUejFTrTC3jMIiOrcZ0DIvt16+AYqXhuxPEnI56npR1nhv+7WUGyhyp5cHFIZqrKnyrrGP0w==",
+ "requested": "[5.2.0, )",
+ "resolved": "5.2.0",
+ "contentHash": "vEKanBDOxCnEQrcMq3j47z8HOblRfiyJotdm9Fyc24cmLrLsTYZnWWprCYstt++M9bGSXYf4jrM2aaWxgJ8aww==",
"dependencies": {
- "Microsoft.Extensions.Configuration.Binder": "8.0.0",
- "Sentry.Extensions.Logging": "4.13.0"
+ "Microsoft.Extensions.Configuration.Binder": "9.0.0",
+ "Sentry.Extensions.Logging": "5.2.0"
}
},
"Serilog": {
@@ -264,12 +264,12 @@
},
"Serilog.Sinks.Seq": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "z5ig56/qzjkX6Fj4U/9m1g8HQaQiYPMZS4Uevtjg1I+WWzoGSf5t/E+6JbMP/jbZYhU63bA5NJN5y0x+qqx2Bw==",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "aNU8A0K322q7+voPNmp1/qNPH+9QK8xvM1p72sMmCG0wGlshFzmtDW9QnVSoSYCj0MgQKcMOlgooovtBhRlNHw==",
"dependencies": {
- "Serilog": "4.0.0",
- "Serilog.Sinks.File": "5.0.0"
+ "Serilog": "4.2.0",
+ "Serilog.Sinks.File": "6.0.0"
}
},
"SixLabors.ImageSharp": {
@@ -280,9 +280,9 @@
},
"System.Text.Json": {
"type": "Direct",
- "requested": "[9.0.0, )",
- "resolved": "9.0.0",
- "contentHash": "js7+qAu/9mQvnhA4EfGMZNEzXtJCDxgkgj8ohuxq/Qxv+R56G+ljefhiJHOxTNiw54q8vmABCWUwkMulNdlZ4A=="
+ "requested": "[9.0.2, )",
+ "resolved": "9.0.2",
+ "contentHash": "4TY2Yokh5Xp8XHFhsY9y84yokS7B0rhkaZCXuRiKppIiKwPVH4lVSFD9EEFzRpXdBM5ZeZXD43tc2vB6njEwwQ=="
},
"System.Text.RegularExpressions": {
"type": "Direct",
@@ -306,8 +306,8 @@
},
"CommunityToolkit.HighPerformance": {
"type": "Transitive",
- "resolved": "8.2.2",
- "contentHash": "+zIp8d3sbtYaRbM6hqDs4Ui/z34j7DcUmleruZlYLE4CVxXq+MO8XJyIs42vzeTYFX+k0Iq1dEbBUnQ4z/Gnrw=="
+ "resolved": "8.3.0",
+ "contentHash": "2zc0Wfr9OtEbLqm6J1Jycim/nKmYv+v12CytJ3tZGNzw7n3yjh1vNCMX0kIBaFBk3sw8g0pMR86QJGXGlArC+A=="
},
"EntityFrameworkCore.Exceptions.Common": {
"type": "Transitive",
@@ -319,16 +319,17 @@
},
"MailKit": {
"type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "jVmB3Nr0JpqhyMiXOGWMin+QvRKpucGpSFBCav9dG6jEJPdBV+yp1RHVpKzxZPfT+0adaBuZlMFdbIciZo1EWA==",
+ "resolved": "4.8.0",
+ "contentHash": "zZ1UoM4FUnSFUJ9fTl5CEEaejR0DNP6+FDt1OfXnjg4igZntcir1tg/8Ufd6WY5vrpmvToAjluYqjVM24A+5lA==",
"dependencies": {
- "MimeKit": "4.3.0"
+ "MimeKit": "4.8.0",
+ "System.Formats.Asn1": "8.0.1"
}
},
"Microsoft.AspNetCore.JsonPatch": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "/4UONYoAIeexPoAmbzBPkVGA6KAY7t0BM+1sr0fKss2V1ERCdcM+Llub4X5Ma+LJ60oPp6KzM0e3j+Pp/JHCNw==",
+ "resolved": "9.0.2",
+ "contentHash": "bZMRhazEBgw9aZ5EBGYt0017CSd+aecsUCnppVjSa1SzWH6C1ieTSQZRAe+H0DzAVzWAoK7HLwKnQUPioopPrA==",
"dependencies": {
"Microsoft.CSharp": "4.7.0",
"Newtonsoft.Json": "13.0.3"
@@ -336,27 +337,27 @@
},
"Microsoft.AspNetCore.Mvc.Razor.Extensions": {
"type": "Transitive",
- "resolved": "6.0.27",
- "contentHash": "trwJhFrTQuJTImmixMsDnDgRE8zuTzAUAot7WqiUlmjNzlJWLOaXXBpeA/xfNJvZuOsyGjC7RIzEyNyDGhDTLg==",
+ "resolved": "6.0.36",
+ "contentHash": "KFHRhrGAnd80310lpuWzI7Cf+GidS/h3JaPDFFnSmSGjCxB5vkBv5E+TXclJCJhqPtgNxg+keTC5SF1T9ieG5w==",
"dependencies": {
- "Microsoft.AspNetCore.Razor.Language": "6.0.27",
- "Microsoft.CodeAnalysis.Razor": "6.0.27"
+ "Microsoft.AspNetCore.Razor.Language": "6.0.36",
+ "Microsoft.CodeAnalysis.Razor": "6.0.36"
}
},
"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": {
"type": "Transitive",
- "resolved": "6.0.27",
- "contentHash": "C6Gh/sAuUACxNtllcH4ZniWtPcGbixJuB1L5RXwoUe1a1wM6rpQ2TVMWpX2+cgeBj8U/izJyWY+nJ4Lz8mmMKA==",
+ "resolved": "6.0.36",
+ "contentHash": "0OG/wNedsQ9kTMrFuvrUDoJvp6Fxj6BzWgi7AUCluOENxu/0PzbjY9AC5w6mZJ22/AFxn2gFc2m0yOBTfQbiPg==",
"dependencies": {
- "Microsoft.AspNetCore.Mvc.Razor.Extensions": "6.0.27",
- "Microsoft.CodeAnalysis.Razor": "6.0.27",
- "Microsoft.Extensions.DependencyModel": "6.0.0"
+ "Microsoft.AspNetCore.Mvc.Razor.Extensions": "6.0.36",
+ "Microsoft.CodeAnalysis.Razor": "6.0.36",
+ "Microsoft.Extensions.DependencyModel": "6.0.2"
}
},
"Microsoft.AspNetCore.Razor.Language": {
"type": "Transitive",
- "resolved": "6.0.27",
- "contentHash": "bI1kIZBgx7oJIB7utPrw4xIgcj7Pdx1jnHMTdsG54U602OcGpBzbfAuKaWs+LVdj+zZVuZsCSoRIZNJKTDP7Hw=="
+ "resolved": "6.0.36",
+ "contentHash": "n5Mg5D0aRrhHJJ6bJcwKqQydIFcgUq0jTlvuynoJjwA2IvAzh8Aqf9cpYagofQbIlIXILkCP6q6FgbngyVtpYA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
@@ -410,10 +411,10 @@
},
"Microsoft.CodeAnalysis.Razor": {
"type": "Transitive",
- "resolved": "6.0.27",
- "contentHash": "NAUvSjH8QY8gPp/fXjHhi3MnQEGtSJA0iRT/dT3RKO3AdGACPJyGmKEKxLag9+Kf2On51yGHT9DEPPnK3hyezg==",
+ "resolved": "6.0.36",
+ "contentHash": "RTLNJglWezr/1IkiWdtDpPYW7X7lwa4ow8E35cHt+sWdWxOnl+ayQqMy1RfbaLp7CLmRmgXSzMMZZU3D4vZi9Q==",
"dependencies": {
- "Microsoft.AspNetCore.Razor.Language": "6.0.27",
+ "Microsoft.AspNetCore.Razor.Language": "6.0.36",
"Microsoft.CodeAnalysis.CSharp": "4.0.0",
"Microsoft.CodeAnalysis.Common": "4.0.0"
}
@@ -449,48 +450,48 @@
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "fnmifFL8KaA4ZNLCVgfjCWhZUFxkrDInx5hR4qG7Q8IEaSiy/6VOSRFyx55oH7MV4y7wM3J3EE90nSpcVBI44Q=="
+ "resolved": "9.0.2",
+ "contentHash": "oVSjNSIYHsk0N66eqAWgDcyo9etEFbUswbz7SmlYR6nGp05byHrJAYM5N8U2aGWJWJI6WvIC2e4TXJgH6GZ6HQ=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "Qje+DzXJOKiXF72SL0XxNlDtTkvWWvmwknuZtFahY5hIQpRKO59qnGuERIQ3qlzuq5x4bAJ8WMbgU5DLhBgeOQ=="
+ "resolved": "9.0.2",
+ "contentHash": "w4jzX7XI+L3erVGzbHXpx64A3QaLXxqG3f1vPpGYYZGpxOIHkh7e4iLLD7cq4Ng1vjkwzWl5ZJp0Kj/nHsgFYg=="
},
"Microsoft.EntityFrameworkCore.Relational": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "j+msw6fWgAE9M3Q/5B9Uhv7pdAdAQUvFPJAiBJmoy+OXvehVbfbCE8ftMAa51Uo2ZeiqVnHShhnv4Y4UJJmUzA==",
+ "resolved": "9.0.2",
+ "contentHash": "r7O4N5uaM95InVSGUj7SMOQWN0f1PBF2Y30ow7Jg+pGX5GJCRVd/1fq83lQ50YMyq+EzyHac5o4CDQA2RsjKJQ==",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "9.0.0",
- "Microsoft.Extensions.Caching.Memory": "9.0.0",
- "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
- "Microsoft.Extensions.Logging": "9.0.0"
+ "Microsoft.EntityFrameworkCore": "9.0.2",
+ "Microsoft.Extensions.Caching.Memory": "9.0.2",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.2",
+ "Microsoft.Extensions.Logging": "9.0.2"
}
},
"Microsoft.Extensions.Caching.Abstractions": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "FPWZAa9c0H4dvOj351iR1jkUIs4u9ykL4Bm592yhjDyO5lCoWd+TMAHx2EMbarzUvCvgjWjJIoC6//Q9kH6YhA==",
+ "resolved": "9.0.2",
+ "contentHash": "a7QhA25n+BzSM5r5d7JznfyluMBGI7z3qyLlFviZ1Eiqv6DdiK27sLZdP/rpYirBM6UYAKxu5TbmfhIy13GN9A==",
"dependencies": {
- "Microsoft.Extensions.Primitives": "9.0.0"
+ "Microsoft.Extensions.Primitives": "9.0.2"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
+ "resolved": "9.0.0",
+ "contentHash": "YIMO9T3JL8MeEXgVozKt2v79hquo/EFtnY0vgxmLnUvk1Rei/halI7kOWZL2RBeV9FMGzgM9LZA8CVaNwFMaNA==",
"dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.Primitives": "8.0.0"
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Primitives": "9.0.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "lqvd7W3FGKUO1+ZoUEMaZ5XDJeWvjpy2/M/ptCGz3tXLD4HWVaSzjufsAsjemasBEg+2SxXVtYVvGt5r2nKDlg==",
+ "resolved": "9.0.2",
+ "contentHash": "I0O/270E/lUNqbBxlRVjxKOMZyYjP88dpEgQTveml+h2lTzAP4vbawLVwjS9SC7lKaU893bwyyNz0IVJYsm9EA==",
"dependencies": {
- "Microsoft.Extensions.Primitives": "9.0.0"
+ "Microsoft.Extensions.Primitives": "9.0.2"
}
},
"Microsoft.Extensions.Configuration.Binder": {
@@ -503,30 +504,30 @@
},
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "MCPrg7v3QgNMr0vX4vzRXvkNGgLg8vKWX0nKCWUxu2uPyMsaRgiRc1tHBnbTcfJMhMKj2slE/j2M9oGkd25DNw==",
+ "resolved": "9.0.2",
+ "contentHash": "ZffbJrskOZ40JTzcTyKwFHS5eACSWp2bUQBBApIgGV+es8RaTD4OxUG7XxFr3RIPLXtYQ1jQzF2DjKB5fZn7Qg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "+6f2qv2a3dLwd5w6JanPIPs47CxRbnk+ZocMJUhv9NxP88VlOcJYZs9jY+MYSjxvady08bUZn6qgiNh7DadGgg=="
+ "resolved": "9.0.2",
+ "contentHash": "MNe7GSTBf3jQx5vYrXF0NZvn6l7hUKF6J54ENfAgCO8y6xjN1XUmKKWG464LP2ye6QqDiA1dkaWEZBYnhoZzjg=="
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "saxr2XzwgDU77LaQfYFXmddEDRUKHF4DaGMZkNB3qjdVSZlax3//dGJagJkKrGMIPNZs2jVFXITyCCR6UHJNdA=="
+ "resolved": "9.0.2",
+ "contentHash": "3ImbcbS68jy9sKr9Z9ToRbEEX0bvIRdb8zyf5ebtL9Av2CUCGHvaO5wsSXfRfAjr60Vrq0tlmNji9IzAxW6EOw=="
},
"Microsoft.Extensions.Diagnostics": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
+ "resolved": "9.0.0",
+ "contentHash": "0CF9ZrNw5RAlRfbZuVIvzzhP8QeWqHiUmMBU/2H7Nmit8/vwP3/SbHeEctth7D4Gz2fBnEbokPc1NU8/j/1ZLw==",
"dependencies": {
- "Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
+ "Microsoft.Extensions.Configuration": "9.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.0"
}
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
@@ -559,49 +560,49 @@
}
},
"Microsoft.Extensions.Http": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Diagnostics": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
- }
- },
- "Microsoft.Extensions.Logging": {
"type": "Transitive",
"resolved": "9.0.0",
- "contentHash": "crjWyORoug0kK7RSNJBTeSE6VX8IQgLf3nUpTB9m62bPXp/tzbnOsnbe8TXEG0AASNaKZddnpHKw7fET8E++Pg==",
+ "contentHash": "DqI4q54U4hH7bIAq9M5a/hl5Odr/KBAoaZ0dcT4OgutD8dook34CbkvAfAIzkMVjYXiL+E5ul9etwwqiX4PHGw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection": "9.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Diagnostics": "9.0.0",
+ "Microsoft.Extensions.Logging": "9.0.0",
"Microsoft.Extensions.Logging.Abstractions": "9.0.0",
"Microsoft.Extensions.Options": "9.0.0"
}
},
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "9.0.2",
+ "contentHash": "loV/0UNpt2bD+6kCDzFALVE63CDtqzPeC0LAetkdhiEr/tTNbvOlQ7CBResH7BQBd3cikrwiBfaHdyHMFUlc2g==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "9.0.2",
+ "Microsoft.Extensions.Logging.Abstractions": "9.0.2",
+ "Microsoft.Extensions.Options": "9.0.2"
+ }
+ },
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "g0UfujELzlLbHoVG8kPKVBaW470Ewi+jnptGS9KUi6jcb+k2StujtK3m26DFSGGwQ/+bVgZfsWqNzlP6YOejvw==",
+ "resolved": "9.0.2",
+ "contentHash": "dV9s2Lamc8jSaqhl2BQSPn/AryDIH2sSbQUyLitLXV0ROmsb+SROnn2cH939JFbsNrnf3mIM3GNRKT7P0ldwLg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2"
}
},
"Microsoft.Extensions.Logging.Configuration": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==",
+ "resolved": "9.0.0",
+ "contentHash": "H05HiqaNmg6GjH34ocYE9Wm1twm3Oz2aXZko8GTwGBzM7op2brpAA8pJ5yyD1OpS1mXUtModBYOlcZ/wXeWsSg==",
"dependencies": {
- "Microsoft.Extensions.Configuration": "8.0.0",
- "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.Configuration.Binder": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Logging": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
+ "Microsoft.Extensions.Configuration": "9.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "9.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Logging": "9.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Options": "9.0.0",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.0"
}
},
"Microsoft.Extensions.ObjectPool": {
@@ -611,29 +612,29 @@
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "y2146b3jrPI3Q0lokKXdKLpmXqakYbDIPDV6r3M8SqvSf45WwOTzkyfDpxnZXJsJQEpAsAqjUq5Pu8RCJMjubg==",
+ "resolved": "9.0.2",
+ "contentHash": "zr98z+AN8+isdmDmQRuEJ/DAKZGUTHmdv3t0ZzjHvNqvA44nAgkXE9kYtfoN6581iALChhVaSw2Owt+Z2lVbkQ==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
- "Microsoft.Extensions.Primitives": "9.0.0"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2",
+ "Microsoft.Extensions.Primitives": "9.0.2"
}
},
"Microsoft.Extensions.Options.ConfigurationExtensions": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==",
+ "resolved": "9.0.0",
+ "contentHash": "Ob3FXsXkcSMQmGZi7qP07EQ39kZpSBlTcAZLbJLdI4FIf0Jug8biv2HTavWmnTirchctPlq9bl/26CXtQRguzA==",
"dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
- "Microsoft.Extensions.Configuration.Binder": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "Microsoft.Extensions.Primitives": "8.0.0"
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "9.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
+ "Microsoft.Extensions.Options": "9.0.0",
+ "Microsoft.Extensions.Primitives": "9.0.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "N3qEBzmLMYiASUlKxxFIISP4AiwuPTHF5uCh+2CWSwwzAJiIYx0kBJsS30cp1nvhSySFAVi30jecD307jV+8Kg=="
+ "resolved": "9.0.2",
+ "contentHash": "puBMtKe/wLuYa7H6docBkLlfec+h8L35DXqsDKKJgW0WY5oCwJ3cBJKcDaZchv6knAyqOMfsl6VUbaR++E5LXA=="
},
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
@@ -668,8 +669,8 @@
},
"Npgsql": {
"type": "Transitive",
- "resolved": "9.0.2",
- "contentHash": "hCbO8box7i/XXiTFqCJ3GoowyLqx3JXxyrbOJ6om7dr+eAknvBNhhUHeJVGAQo44sySZTfdVffp4BrtPeLZOAA==",
+ "resolved": "9.0.3",
+ "contentHash": "tPvY61CxOAWxNsKLEBg+oR646X4Bc8UmyQ/tJszL/7mEmIXQnnBhVJZrZEEUv0Bstu0mEsHZD5At3EO8zQRAYw==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
}
@@ -685,18 +686,18 @@
},
"Sentry": {
"type": "Transitive",
- "resolved": "4.13.0",
- "contentHash": "Wfw3M1WpFcrYaGzPm7QyUTfIOYkVXQ1ry6p4WYjhbLz9fPwV23SGQZTFDpdox67NHM0V0g1aoQ4YKLm4ANtEEg=="
+ "resolved": "5.2.0",
+ "contentHash": "b3aZSOU2CjlIIFRtPRbXParKQ+9PF+JOqkSD7Gxq6PiR07t1rnK+crPtdrWMXfW6PVo/s67trCJ+fuLsgTeADw=="
},
"Sentry.Extensions.Logging": {
"type": "Transitive",
- "resolved": "4.13.0",
- "contentHash": "yZ5+TtJKWcss6cG17YjnovImx4X56T8O6Qy6bsMC8tMDttYy8J7HJ2F+WdaZNyjOCo0Rfi6N2gc+Clv/5pf+TQ==",
+ "resolved": "5.2.0",
+ "contentHash": "546bHsERKY7/pG5T4mVIp6WbHnQPMst6VDuxSaeU5DhQHLfh7KhgMmkdZ4Xvdlr95fvWk5/bX2xbipy6qoh/1A==",
"dependencies": {
- "Microsoft.Extensions.Configuration.Binder": "8.0.0",
- "Microsoft.Extensions.Http": "8.0.0",
- "Microsoft.Extensions.Logging.Configuration": "8.0.0",
- "Sentry": "4.13.0"
+ "Microsoft.Extensions.Configuration.Binder": "9.0.0",
+ "Microsoft.Extensions.Http": "9.0.0",
+ "Microsoft.Extensions.Logging.Configuration": "9.0.0",
+ "Sentry": "5.2.0"
}
},
"Serilog.Extensions.Hosting": {
diff --git a/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj b/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj
index 5fde110..ead15ce 100644
--- a/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj
+++ b/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj
@@ -12,9 +12,9 @@
-
-
-
+
+
+
From 218c756a7075902bc3d6a4a762639ce9013b2ddd Mon Sep 17 00:00:00 2001
From: sam
Date: Fri, 28 Feb 2025 16:37:15 +0100
Subject: [PATCH 06/29] feat(backend): make field limits configurable
---
Foxnouns.Backend/Config.cs | 5 +
.../Controllers/MembersController.cs | 15 +-
.../Controllers/UsersController.cs | 9 +-
.../ValidationService.Fields.cs} | 224 +++++++++---------
Foxnouns.Backend/Utils/Limits.cs | 23 --
.../Utils/ValidationUtils.Strings.cs | 2 +-
Foxnouns.DataMigrator/UserMigrator.cs | 4 +-
7 files changed, 133 insertions(+), 149 deletions(-)
rename Foxnouns.Backend/{Utils/ValidationUtils.Fields.cs => Services/ValidationService.Fields.cs} (56%)
delete mode 100644 Foxnouns.Backend/Utils/Limits.cs
diff --git a/Foxnouns.Backend/Config.cs b/Foxnouns.Backend/Config.cs
index 0ed8b7a..d1e6df5 100644
--- a/Foxnouns.Backend/Config.cs
+++ b/Foxnouns.Backend/Config.cs
@@ -99,6 +99,11 @@ public class Config
{
public int MaxMemberCount { get; init; } = 1000;
+ public int MaxFields { get; init; } = 25;
+ public int MaxFieldNameLength { get; init; } = 100;
+ public int MaxFieldEntryTextLength { get; init; } = 100;
+ public int MaxFieldEntries { get; init; } = 100;
+
public int MaxUsernameLength { get; init; } = 40;
public int MaxMemberNameLength { get; init; } = 100;
public int MaxDisplayNameLength { get; init; } = 100;
diff --git a/Foxnouns.Backend/Controllers/MembersController.cs b/Foxnouns.Backend/Controllers/MembersController.cs
index 8f832c1..dbea99c 100644
--- a/Foxnouns.Backend/Controllers/MembersController.cs
+++ b/Foxnouns.Backend/Controllers/MembersController.cs
@@ -81,13 +81,13 @@ public class MembersController(
("display_name", validationService.ValidateDisplayName(req.DisplayName)),
("bio", validationService.ValidateBio(req.Bio)),
("avatar", validationService.ValidateAvatar(req.Avatar)),
- .. ValidationUtils.ValidateFields(req.Fields, CurrentUser!.CustomPreferences),
- .. ValidationUtils.ValidateFieldEntries(
+ .. validationService.ValidateFields(req.Fields, CurrentUser!.CustomPreferences),
+ .. validationService.ValidateFieldEntries(
req.Names?.ToArray(),
CurrentUser!.CustomPreferences,
"names"
),
- .. ValidationUtils.ValidatePronouns(
+ .. validationService.ValidatePronouns(
req.Pronouns?.ToArray(),
CurrentUser!.CustomPreferences
),
@@ -191,7 +191,7 @@ public class MembersController(
if (req.Names != null)
{
errors.AddRange(
- ValidationUtils.ValidateFieldEntries(
+ validationService.ValidateFieldEntries(
req.Names,
CurrentUser!.CustomPreferences,
"names"
@@ -203,7 +203,7 @@ public class MembersController(
if (req.Pronouns != null)
{
errors.AddRange(
- ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
+ validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
);
member.Pronouns = req.Pronouns.ToList();
}
@@ -211,7 +211,10 @@ public class MembersController(
if (req.Fields != null)
{
errors.AddRange(
- ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences)
+ validationService.ValidateFields(
+ req.Fields.ToList(),
+ CurrentUser!.CustomPreferences
+ )
);
member.Fields = req.Fields.ToList();
}
diff --git a/Foxnouns.Backend/Controllers/UsersController.cs b/Foxnouns.Backend/Controllers/UsersController.cs
index 6ccbff0..f7e3115 100644
--- a/Foxnouns.Backend/Controllers/UsersController.cs
+++ b/Foxnouns.Backend/Controllers/UsersController.cs
@@ -91,7 +91,7 @@ public class UsersController(
if (req.Names != null)
{
errors.AddRange(
- ValidationUtils.ValidateFieldEntries(
+ validationService.ValidateFieldEntries(
req.Names,
CurrentUser!.CustomPreferences,
"names"
@@ -103,7 +103,7 @@ public class UsersController(
if (req.Pronouns != null)
{
errors.AddRange(
- ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
+ validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
);
user.Pronouns = req.Pronouns.ToList();
}
@@ -111,7 +111,10 @@ public class UsersController(
if (req.Fields != null)
{
errors.AddRange(
- ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences)
+ validationService.ValidateFields(
+ req.Fields.ToList(),
+ CurrentUser!.CustomPreferences
+ )
);
user.Fields = req.Fields.ToList();
}
diff --git a/Foxnouns.Backend/Utils/ValidationUtils.Fields.cs b/Foxnouns.Backend/Services/ValidationService.Fields.cs
similarity index 56%
rename from Foxnouns.Backend/Utils/ValidationUtils.Fields.cs
rename to Foxnouns.Backend/Services/ValidationService.Fields.cs
index 0235eb6..e2cbff3 100644
--- a/Foxnouns.Backend/Utils/ValidationUtils.Fields.cs
+++ b/Foxnouns.Backend/Services/ValidationService.Fields.cs
@@ -15,9 +15,9 @@
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
-namespace Foxnouns.Backend.Utils;
+namespace Foxnouns.Backend.Services;
-public static partial class ValidationUtils
+public partial class ValidationService
{
public static readonly string[] DefaultStatusOptions =
[
@@ -28,7 +28,7 @@ public static partial class ValidationUtils
"avoid",
];
- public static IEnumerable<(string, ValidationError?)> ValidateFields(
+ public IEnumerable<(string, ValidationError?)> ValidateFields(
List? fields,
IReadOnlyDictionary customPreferences
)
@@ -37,7 +37,7 @@ public static partial class ValidationUtils
return [];
var errors = new List<(string, ValidationError?)>();
- if (fields.Count > 25)
+ if (fields.Count > _limits.MaxFields)
{
errors.Add(
(
@@ -45,7 +45,7 @@ public static partial class ValidationUtils
ValidationError.LengthError(
"Too many fields",
0,
- Limits.FieldLimit,
+ _limits.MaxFields,
fields.Count
)
)
@@ -53,39 +53,38 @@ public static partial class ValidationUtils
}
// No overwhelming this function, thank you
- if (fields.Count > 100)
+ if (fields.Count > _limits.MaxFields + 50)
return errors;
foreach ((Field? field, int index) in fields.Select((field, index) => (field, index)))
{
- switch (field.Name.Length)
+ if (field.Name.Length > _limits.MaxFieldNameLength)
{
- case > Limits.FieldNameLimit:
- errors.Add(
- (
- $"fields.{index}.name",
- ValidationError.LengthError(
- "Field name is too long",
- 1,
- Limits.FieldNameLimit,
- field.Name.Length
- )
+ errors.Add(
+ (
+ $"fields.{index}.name",
+ ValidationError.LengthError(
+ "Field name is too long",
+ 1,
+ _limits.MaxFieldNameLength,
+ field.Name.Length
)
- );
- break;
- case < 1:
- errors.Add(
- (
- $"fields.{index}.name",
- ValidationError.LengthError(
- "Field name is too short",
- 1,
- Limits.FieldNameLimit,
- field.Name.Length
- )
+ )
+ );
+ }
+ else if (field.Name.Length < 1)
+ {
+ errors.Add(
+ (
+ $"fields.{index}.name",
+ ValidationError.LengthError(
+ "Field name is too short",
+ 1,
+ _limits.MaxFieldNameLength,
+ field.Name.Length
)
- );
- break;
+ )
+ );
}
errors = errors
@@ -102,7 +101,7 @@ public static partial class ValidationUtils
return errors;
}
- public static IEnumerable<(string, ValidationError?)> ValidateFieldEntries(
+ public IEnumerable<(string, ValidationError?)> ValidateFieldEntries(
FieldEntry[]? entries,
IReadOnlyDictionary customPreferences,
string errorPrefix = "fields"
@@ -112,7 +111,7 @@ public static partial class ValidationUtils
return [];
var errors = new List<(string, ValidationError?)>();
- if (entries.Length > Limits.FieldEntriesLimit)
+ if (entries.Length > _limits.MaxFieldEntries)
{
errors.Add(
(
@@ -120,7 +119,7 @@ public static partial class ValidationUtils
ValidationError.LengthError(
"Field has too many entries",
0,
- Limits.FieldEntriesLimit,
+ _limits.MaxFieldEntries,
entries.Length
)
)
@@ -128,7 +127,7 @@ public static partial class ValidationUtils
}
// Same as above, no overwhelming this function with a ridiculous amount of entries
- if (entries.Length > Limits.FieldEntriesLimit + 50)
+ if (entries.Length > _limits.MaxFieldEntries + 50)
return errors;
string[] customPreferenceIds = customPreferences.Keys.Select(id => id.ToString()).ToArray();
@@ -139,34 +138,33 @@ public static partial class ValidationUtils
)
)
{
- switch (entry.Value.Length)
+ if (entry.Value.Length > _limits.MaxFieldEntryTextLength)
{
- case > Limits.FieldEntryTextLimit:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.value",
- ValidationError.LengthError(
- "Field value is too long",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.value",
+ ValidationError.LengthError(
+ "Field value is too long",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
- case < 1:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.value",
- ValidationError.LengthError(
- "Field value is too short",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ )
+ );
+ }
+ else if (entry.Value.Length < 1)
+ {
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.value",
+ ValidationError.LengthError(
+ "Field value is too short",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
+ )
+ );
}
if (
@@ -186,7 +184,7 @@ public static partial class ValidationUtils
return errors;
}
- public static IEnumerable<(string, ValidationError?)> ValidatePronouns(
+ public IEnumerable<(string, ValidationError?)> ValidatePronouns(
Pronoun[]? entries,
IReadOnlyDictionary customPreferences,
string errorPrefix = "pronouns"
@@ -196,7 +194,7 @@ public static partial class ValidationUtils
return [];
var errors = new List<(string, ValidationError?)>();
- if (entries.Length > Limits.FieldEntriesLimit)
+ if (entries.Length > _limits.MaxFieldEntries)
{
errors.Add(
(
@@ -204,7 +202,7 @@ public static partial class ValidationUtils
ValidationError.LengthError(
"Too many pronouns",
0,
- Limits.FieldEntriesLimit,
+ _limits.MaxFieldEntries,
entries.Length
)
)
@@ -212,7 +210,7 @@ public static partial class ValidationUtils
}
// Same as above, no overwhelming this function with a ridiculous amount of entries
- if (entries.Length > Limits.FieldEntriesLimit + 50)
+ if (entries.Length > _limits.MaxFieldEntries + 50)
return errors;
string[] customPreferenceIds = customPreferences.Keys.Select(id => id.ToString()).ToArray();
@@ -221,66 +219,64 @@ public static partial class ValidationUtils
(Pronoun? entry, int entryIdx) in entries.Select((entry, entryIdx) => (entry, entryIdx))
)
{
- switch (entry.Value.Length)
+ if (entry.Value.Length > _limits.MaxFieldEntryTextLength)
{
- case > Limits.FieldEntryTextLimit:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.value",
- ValidationError.LengthError(
- "Pronoun value is too long",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.value",
+ ValidationError.LengthError(
+ "Pronoun value is too long",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
- case < 1:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.value",
- ValidationError.LengthError(
- "Pronoun value is too short",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ )
+ );
+ }
+ else if (entry.Value.Length < 1)
+ {
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.value",
+ ValidationError.LengthError(
+ "Pronoun value is too short",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
+ )
+ );
}
if (entry.DisplayText != null)
{
- switch (entry.DisplayText.Length)
+ if (entry.DisplayText.Length > _limits.MaxFieldEntryTextLength)
{
- case > Limits.FieldEntryTextLimit:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.display_text",
- ValidationError.LengthError(
- "Pronoun display text is too long",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.display_text",
+ ValidationError.LengthError(
+ "Pronoun display text is too long",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
- case < 1:
- errors.Add(
- (
- $"{errorPrefix}.{entryIdx}.display_text",
- ValidationError.LengthError(
- "Pronoun display text is too short",
- 1,
- Limits.FieldEntryTextLimit,
- entry.Value.Length
- )
+ )
+ );
+ }
+ else if (entry.DisplayText.Length < 1)
+ {
+ errors.Add(
+ (
+ $"{errorPrefix}.{entryIdx}.display_text",
+ ValidationError.LengthError(
+ "Pronoun display text is too short",
+ 1,
+ _limits.MaxFieldEntryTextLength,
+ entry.Value.Length
)
- );
- break;
+ )
+ );
}
}
diff --git a/Foxnouns.Backend/Utils/Limits.cs b/Foxnouns.Backend/Utils/Limits.cs
deleted file mode 100644
index 3010d46..0000000
--- a/Foxnouns.Backend/Utils/Limits.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-namespace Foxnouns.Backend.Utils;
-
-public static class Limits
-{
- public const int FieldLimit = 25;
- public const int FieldNameLimit = 100;
- public const int FieldEntryTextLimit = 100;
- public const int FieldEntriesLimit = 100;
-}
diff --git a/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs b/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs
index 1a99993..82ee485 100644
--- a/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs
+++ b/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs
@@ -20,7 +20,7 @@ public static partial class ValidationUtils
public static ValidationError? ValidateReportContext(string? context) =>
context?.Length > MaximumReportContextLength
- ? ValidationError.GenericValidationError("Avatar is too large", null)
+ ? ValidationError.GenericValidationError("Report context is too long", null)
: null;
public const int MinimumPasswordLength = 12;
diff --git a/Foxnouns.DataMigrator/UserMigrator.cs b/Foxnouns.DataMigrator/UserMigrator.cs
index df895b9..ee46878 100644
--- a/Foxnouns.DataMigrator/UserMigrator.cs
+++ b/Foxnouns.DataMigrator/UserMigrator.cs
@@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using Dapper;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
-using Foxnouns.Backend.Utils;
+using Foxnouns.Backend.Services;
using Foxnouns.DataMigrator.Models;
using NodaTime.Extensions;
using Npgsql;
@@ -260,6 +260,6 @@ public class UserMigrator(
{
if (_preferenceIds.TryGetValue(id, out Snowflake preferenceId))
return preferenceId.ToString();
- return ValidationUtils.DefaultStatusOptions.Contains(id) ? id : "okay";
+ return ValidationService.DefaultStatusOptions.Contains(id) ? id : "okay";
}
}
From a2485367894f52793227b0470d8e2e966b47b406 Mon Sep 17 00:00:00 2001
From: sam
Date: Fri, 28 Feb 2025 16:47:21 +0100
Subject: [PATCH 07/29] fix typo in DOCKER.md
---
DOCKER.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/DOCKER.md b/DOCKER.md
index b485eb7..a007aab 100644
--- a/DOCKER.md
+++ b/DOCKER.md
@@ -2,7 +2,7 @@
1. Copy `docker/config.example.ini` to `docker/config.ini`, and change the settings to your liking.
2. Copy `docker/proxy-config.example.json` to `docker/proxy-config.json`, and do the same.
-3. Copy `docker/frontend.example.env` to `docker/frontend.env`, and do th esame.
+3. Copy `docker/frontend.example.env` to `docker/frontend.env`, and do the same.
4. Build with `docker compose build`
5. Run with `docker compose up`
From 7d6d4631b81168bf67df25c34d4d8cf2750a9942 Mon Sep 17 00:00:00 2001
From: sam
Date: Fri, 28 Feb 2025 16:50:57 +0100
Subject: [PATCH 08/29] fix(frontend): don't reference email auth in text if
it's disabled
---
Foxnouns.Frontend/src/lib/i18n/locales/en.json | 3 ++-
Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte | 9 +++++++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
index 7145181..fe10b04 100644
--- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json
+++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
@@ -86,7 +86,8 @@
"unlink-discord-header": "Unlink Discord account",
"unlink-confirmation-1": "Are you sure you want to unlink {{username}} from your account?",
"unlink-confirmation-2": "You will no longer be able to use this account to log in. Please make sure at least one of your other linked accounts is accessible before continuing.",
- "unlink-button": "Unlink account"
+ "unlink-button": "Unlink account",
+ "log-in-3rd-party-desc-no-email": "You can use any of the following services to log in. You can add or remove others at any time."
},
"error": {
"bad-request-header": "Something was wrong with your input",
diff --git a/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte b/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte
index ee4d040..3efbfa0 100644
--- a/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte
+++ b/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte
@@ -50,8 +50,13 @@
{/if}
-
{$t("auth.log-in-3rd-party-header")}
-
{$t("auth.log-in-3rd-party-desc")}
+ {#if data.urls.email_enabled}
+
{$t("auth.log-in-3rd-party-header")}
+
{$t("auth.log-in-3rd-party-desc")}
+ {:else}
+
{$t("title.log-in")}
+
{$t("auth.log-in-3rd-party-desc-no-email")}
+ {/if}