diff --git a/.editorconfig b/.editorconfig
index 22061dc..e6b41f9 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,7 +7,7 @@ resharper_not_accessed_positional_property_local_highlighting = none
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers = false
-csharp_preferred_modifier_order = public, internal, protected, private, file, new, virtual, override, required, abstract, sealed, static, extern, unsafe, volatile, async, readonly:suggestion
+csharp_preferred_modifier_order = public, internal, protected, private, file, new, required, abstract, virtual, sealed, static, override, extern, unsafe, volatile, async, readonly:suggestion
# ReSharper properties
resharper_align_multiline_binary_expressions_chain = false
diff --git a/.gitignore b/.gitignore
index b1e845f..9c16977 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,8 +14,3 @@ docker/proxy-config.json
docker/frontend.env
Foxnouns.DataMigrator/apps.json
-migration-tools/avatar-proxy/config.json
-migration-tools/avatar-migrator/.env
-
-out/
-build/
diff --git a/.husky/task-runner.json b/.husky/task-runner.json
index 72e6fea..576b8bc 100644
--- a/.husky/task-runner.json
+++ b/.husky/task-runner.json
@@ -3,8 +3,12 @@
"tasks": [
{
"name": "run-prettier",
- "command": "npx",
- "args": ["prettier", "-w", "${staged}"],
+ "command": "pnpm",
+ "args": [
+ "prettier",
+ "-w",
+ "${staged}"
+ ],
"include": [
"Foxnouns.Frontend/**/*.ts",
"Foxnouns.Frontend/**/*.json",
@@ -18,8 +22,13 @@
{
"name": "run-csharpier",
"command": "dotnet",
- "args": ["csharpier", "${staged}"],
- "include": ["**/*.cs"]
+ "args": [
+ "csharpier",
+ "${staged}"
+ ],
+ "include": [
+ "**/*.cs"
+ ]
}
]
}
diff --git a/DOCKER.md b/DOCKER.md
index b670743..b485eb7 100644
--- a/DOCKER.md
+++ b/DOCKER.md
@@ -1,29 +1,10 @@
-# Running with Docker (pre-built backend and rate limiter) *(linux/arm64 only)*
-
-Because SvelteKit is a pain in the ass to build in a container, and processes secrets at build time,
-there is no pre-built frontend image available.
-If you don't want to build images on your server, I recommend running the frontend outside of Docker.
-This is preconfigured in `docker-compose.prebuilt.yml`: the backend, database, and rate limiter will run in Docker,
-while the frontend is run as a normal, non-containerized service.
+# Running with Docker
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. Run with `docker compose up -f docker-compose.prebuilt.yml`
-
-The backend will listen on port 5001 and metrics will be available on port 5002.
-The rate limiter (which is what should be exposed to the outside) will listen on port 5003.
-You can use `docker/Caddyfile` as an example for your reverse proxy. If you use nginx, good luck.
-
-# Running with Docker (local builds)
-
-In order to run *everything* in Docker, you'll have to build every container yourself.
-The advantage of this is that it's an all-in-one solution, where you only have to point your reverse proxy at a single container.
-The disadvantage is that you'll likely have to build the images on the server you'll be running them on.
-
-1. Configure the backend and rate limiter as in the section above.
-2. Copy `docker/frontend.example.env` to `docker/frontend.env`, and configure it.
-3. Build with `docker compose build -f docker-compose.local.yml`
-4. Run with `docker compose up -f docker-compose.local.yml`
+3. Copy `docker/frontend.example.env` to `docker/frontend.env`, and do th esame.
+4. Build with `docker compose build`
+5. Run with `docker compose up`
The Caddy server will listen on `localhost:5004` for the frontend and API,
and on `localhost:5005` for the profile URL shortener.
diff --git a/Foxnouns.Backend/Config.cs b/Foxnouns.Backend/Config.cs
index 461e55e..0ed8b7a 100644
--- a/Foxnouns.Backend/Config.cs
+++ b/Foxnouns.Backend/Config.cs
@@ -26,6 +26,7 @@ public class Config
public string MediaBaseUrl { get; init; } = null!;
public string Address => $"http://{Host}:{Port}";
+ public string MetricsAddress => $"http://{Host}:{Logging.MetricsPort}";
public LoggingConfig Logging { get; init; } = new();
public DatabaseConfig Database { get; init; } = new();
@@ -54,7 +55,6 @@ public class Config
public bool? EnablePooling { get; init; }
public int? Timeout { get; init; }
public int? MaxPoolSize { get; init; }
- public string Redis { get; init; } = string.Empty;
}
public class StorageConfig
@@ -99,11 +99,6 @@ 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/Authentication/AuthController.cs b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs
index 39d3b11..0d95eb2 100644
--- a/Foxnouns.Backend/Controllers/Authentication/AuthController.cs
+++ b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs
@@ -46,7 +46,7 @@ public class AuthController(
config.GoogleAuth.Enabled,
config.TumblrAuth.Enabled
);
- string state = HttpUtility.UrlEncode(await keyCacheService.GenerateAuthStateAsync());
+ string state = HttpUtility.UrlEncode(await keyCacheService.GenerateAuthStateAsync(ct));
string? discord = null;
string? google = null;
string? tumblr = null;
diff --git a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs
index 8024ee6..bdf4b9a 100644
--- a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs
+++ b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs
@@ -56,7 +56,7 @@ public class EmailAuthController(
if (!req.Email.Contains('@'))
throw new ApiError.BadRequest("Email is invalid", "email", req.Email);
- string state = await keyCacheService.GenerateRegisterEmailStateAsync(req.Email, null);
+ string state = await keyCacheService.GenerateRegisterEmailStateAsync(req.Email, null, ct);
// If there's already a user with that email address, pretend we sent an email but actually ignore it
if (
diff --git a/Foxnouns.Backend/Controllers/ExportsController.cs b/Foxnouns.Backend/Controllers/ExportsController.cs
index 0442386..7f40625 100644
--- a/Foxnouns.Backend/Controllers/ExportsController.cs
+++ b/Foxnouns.Backend/Controllers/ExportsController.cs
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+using Coravel.Queuing.Interfaces;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
using Foxnouns.Backend.Dto;
@@ -27,8 +28,13 @@ namespace Foxnouns.Backend.Controllers;
[Authorize("identify")]
[Limit(UsableByDeletedUsers = true)]
[ApiExplorerSettings(IgnoreApi = true)]
-public class ExportsController(ILogger logger, Config config, IClock clock, DatabaseContext db)
- : ApiControllerBase
+public class ExportsController(
+ ILogger logger,
+ Config config,
+ IClock clock,
+ DatabaseContext db,
+ IQueue queue
+) : ApiControllerBase
{
private static readonly Duration MinimumTimeBetween = Duration.FromDays(1);
private readonly ILogger _logger = logger.ForContext();
@@ -74,7 +80,10 @@ public class ExportsController(ILogger logger, Config config, IClock clock, Data
throw new ApiError.BadRequest("You can't request a new data export so soon.");
}
- CreateDataExportJob.Enqueue(CurrentUser.Id);
+ queue.QueueInvocableWithPayload(
+ new CreateDataExportPayload(CurrentUser.Id)
+ );
+
return NoContent();
}
}
diff --git a/Foxnouns.Backend/Controllers/FlagsController.cs b/Foxnouns.Backend/Controllers/FlagsController.cs
index bed022a..e976072 100644
--- a/Foxnouns.Backend/Controllers/FlagsController.cs
+++ b/Foxnouns.Backend/Controllers/FlagsController.cs
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+using Coravel.Queuing.Interfaces;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
using Foxnouns.Backend.Dto;
@@ -29,7 +30,8 @@ namespace Foxnouns.Backend.Controllers;
public class FlagsController(
DatabaseContext db,
UserRendererService userRenderer,
- ISnowflakeGenerator snowflakeGenerator
+ ISnowflakeGenerator snowflakeGenerator,
+ IQueue queue
) : ApiControllerBase
{
[HttpGet]
@@ -72,7 +74,10 @@ public class FlagsController(
db.Add(flag);
await db.SaveChangesAsync();
- CreateFlagJob.Enqueue(new CreateFlagPayload(flag.Id, CurrentUser!.Id, req.Image));
+ queue.QueueInvocableWithPayload(
+ new CreateFlagPayload(flag.Id, CurrentUser!.Id, req.Image)
+ );
+
return Accepted(userRenderer.RenderPrideFlag(flag));
}
diff --git a/Foxnouns.Backend/Controllers/MembersController.cs b/Foxnouns.Backend/Controllers/MembersController.cs
index 635dab9..8f832c1 100644
--- a/Foxnouns.Backend/Controllers/MembersController.cs
+++ b/Foxnouns.Backend/Controllers/MembersController.cs
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+using Coravel.Queuing.Interfaces;
using EntityFramework.Exceptions.Common;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
@@ -36,6 +37,7 @@ public class MembersController(
MemberRendererService memberRenderer,
ISnowflakeGenerator snowflakeGenerator,
ObjectStorageService objectStorageService,
+ IQueue queue,
IClock clock,
ValidationService validationService,
Config config
@@ -79,13 +81,13 @@ public class MembersController(
("display_name", validationService.ValidateDisplayName(req.DisplayName)),
("bio", validationService.ValidateBio(req.Bio)),
("avatar", validationService.ValidateAvatar(req.Avatar)),
- .. validationService.ValidateFields(req.Fields, CurrentUser!.CustomPreferences),
- .. validationService.ValidateFieldEntries(
+ .. ValidationUtils.ValidateFields(req.Fields, CurrentUser!.CustomPreferences),
+ .. ValidationUtils.ValidateFieldEntries(
req.Names?.ToArray(),
CurrentUser!.CustomPreferences,
"names"
),
- .. validationService.ValidatePronouns(
+ .. ValidationUtils.ValidatePronouns(
req.Pronouns?.ToArray(),
CurrentUser!.CustomPreferences
),
@@ -121,9 +123,6 @@ public class MembersController(
CurrentUser!.Id
);
- CurrentUser.LastActive = clock.GetCurrentInstant();
- db.Update(CurrentUser);
-
try
{
await db.SaveChangesAsync(ct);
@@ -140,7 +139,9 @@ public class MembersController(
if (req.Avatar != null)
{
- MemberAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(member.Id, req.Avatar));
+ queue.QueueInvocableWithPayload(
+ new AvatarUpdatePayload(member.Id, req.Avatar)
+ );
}
return Ok(memberRenderer.RenderMember(member, CurrentToken));
@@ -190,7 +191,7 @@ public class MembersController(
if (req.Names != null)
{
errors.AddRange(
- validationService.ValidateFieldEntries(
+ ValidationUtils.ValidateFieldEntries(
req.Names,
CurrentUser!.CustomPreferences,
"names"
@@ -202,7 +203,7 @@ public class MembersController(
if (req.Pronouns != null)
{
errors.AddRange(
- validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
+ ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
);
member.Pronouns = req.Pronouns.ToList();
}
@@ -210,10 +211,7 @@ public class MembersController(
if (req.Fields != null)
{
errors.AddRange(
- validationService.ValidateFields(
- req.Fields.ToList(),
- CurrentUser!.CustomPreferences
- )
+ ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences)
);
member.Fields = req.Fields.ToList();
}
@@ -238,12 +236,11 @@ public class MembersController(
// so it's in a separate block to the validation above.
if (req.HasProperty(nameof(req.Avatar)))
{
- MemberAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(member.Id, req.Avatar));
+ queue.QueueInvocableWithPayload(
+ new AvatarUpdatePayload(member.Id, req.Avatar)
+ );
}
- CurrentUser.LastActive = clock.GetCurrentInstant();
- db.Update(CurrentUser);
-
try
{
await db.SaveChangesAsync();
diff --git a/Foxnouns.Backend/Controllers/MetaController.cs b/Foxnouns.Backend/Controllers/MetaController.cs
index 0166e86..1f00a7a 100644
--- a/Foxnouns.Backend/Controllers/MetaController.cs
+++ b/Foxnouns.Backend/Controllers/MetaController.cs
@@ -13,23 +13,20 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
using System.Text.RegularExpressions;
-using Foxnouns.Backend.Database.Models;
using Foxnouns.Backend.Dto;
-using Foxnouns.Backend.Services.Caching;
using Foxnouns.Backend.Utils;
using Microsoft.AspNetCore.Mvc;
namespace Foxnouns.Backend.Controllers;
[Route("/api/v2/meta")]
-public partial class MetaController(Config config, NoticeCacheService noticeCache)
- : ApiControllerBase
+public partial class MetaController(Config config) : ApiControllerBase
{
private const string Repository = "https://codeberg.org/pronounscc/pronouns.cc";
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task GetMeta(CancellationToken ct = default) =>
+ public IActionResult GetMeta() =>
Ok(
new MetaResponse(
Repository,
@@ -48,14 +45,10 @@ public partial class MetaController(Config config, NoticeCacheService noticeCach
ValidationUtils.MaxCustomPreferences,
AuthUtils.MaxAuthMethodsPerType,
FlagsController.MaxFlagCount
- ),
- Notice: NoticeResponse(await noticeCache.GetAsync(ct))
+ )
)
);
- private static MetaNoticeResponse? NoticeResponse(Notice? notice) =>
- notice == null ? null : new MetaNoticeResponse(notice.Id, notice.Message);
-
[HttpGet("page/{page}")]
public async Task GetStaticPageAsync(string page, CancellationToken ct = default)
{
@@ -78,7 +71,7 @@ public partial class MetaController(Config config, NoticeCacheService noticeCach
[HttpGet("/api/v2/coffee")]
public IActionResult BrewCoffee() =>
- StatusCode(StatusCodes.Status418ImATeapot, "Sorry, I'm a teapot!");
+ Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot);
[GeneratedRegex(@"^[a-z\-_]+$")]
private static partial Regex PageRegex();
diff --git a/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs b/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs
deleted file mode 100644
index 3d2d6bb..0000000
--- a/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using Foxnouns.Backend.Database;
-using Foxnouns.Backend.Database.Models;
-using Foxnouns.Backend.Dto;
-using Foxnouns.Backend.Middleware;
-using Foxnouns.Backend.Services;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.EntityFrameworkCore;
-using NodaTime;
-
-namespace Foxnouns.Backend.Controllers.Moderation;
-
-[Route("/api/v2/notices")]
-[Authorize("user.moderation")]
-[Limit(RequireModerator = true)]
-public class NoticesController(
- DatabaseContext db,
- UserRendererService userRenderer,
- ISnowflakeGenerator snowflakeGenerator,
- IClock clock
-) : ApiControllerBase
-{
- [HttpGet]
- public async Task GetNoticesAsync(CancellationToken ct = default)
- {
- List notices = await db
- .Notices.Include(n => n.Author)
- .OrderByDescending(n => n.Id)
- .ToListAsync(ct);
- return Ok(notices.Select(RenderNotice));
- }
-
- [HttpPost]
- public async Task CreateNoticeAsync(CreateNoticeRequest req)
- {
- Instant now = clock.GetCurrentInstant();
- if (req.StartTime < now)
- {
- throw new ApiError.BadRequest(
- "Start time cannot be in the past",
- "start_time",
- req.StartTime
- );
- }
-
- if (req.EndTime < now)
- {
- throw new ApiError.BadRequest(
- "End time cannot be in the past",
- "end_time",
- req.EndTime
- );
- }
-
- var notice = new Notice
- {
- Id = snowflakeGenerator.GenerateSnowflake(),
- Message = req.Message,
- StartTime = req.StartTime ?? clock.GetCurrentInstant(),
- EndTime = req.EndTime,
- Author = CurrentUser!,
- };
-
- db.Add(notice);
- await db.SaveChangesAsync();
-
- return Ok(RenderNotice(notice));
- }
-
- private NoticeResponse RenderNotice(Notice notice) =>
- new(
- notice.Id,
- notice.Message,
- notice.StartTime,
- notice.EndTime,
- userRenderer.RenderPartialUser(notice.Author)
- );
-}
diff --git a/Foxnouns.Backend/Controllers/UsersController.cs b/Foxnouns.Backend/Controllers/UsersController.cs
index ed9a48f..6ccbff0 100644
--- a/Foxnouns.Backend/Controllers/UsersController.cs
+++ b/Foxnouns.Backend/Controllers/UsersController.cs
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+using Coravel.Queuing.Interfaces;
using EntityFramework.Exceptions.Common;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
@@ -33,6 +34,7 @@ public class UsersController(
ILogger logger,
UserRendererService userRenderer,
ISnowflakeGenerator snowflakeGenerator,
+ IQueue queue,
IClock clock,
ValidationService validationService
) : ApiControllerBase
@@ -46,15 +48,7 @@ public class UsersController(
{
User user = await db.ResolveUserAsync(userRef, CurrentToken, ct);
return Ok(
- await userRenderer.RenderUserAsync(
- user,
- CurrentUser,
- CurrentToken,
- renderMembers: true,
- renderAuthMethods: true,
- renderSettings: true,
- ct: ct
- )
+ await userRenderer.RenderUserAsync(user, CurrentUser, CurrentToken, true, true, ct: ct)
);
}
@@ -97,7 +91,7 @@ public class UsersController(
if (req.Names != null)
{
errors.AddRange(
- validationService.ValidateFieldEntries(
+ ValidationUtils.ValidateFieldEntries(
req.Names,
CurrentUser!.CustomPreferences,
"names"
@@ -109,7 +103,7 @@ public class UsersController(
if (req.Pronouns != null)
{
errors.AddRange(
- validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
+ ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences)
);
user.Pronouns = req.Pronouns.ToList();
}
@@ -117,10 +111,7 @@ public class UsersController(
if (req.Fields != null)
{
errors.AddRange(
- validationService.ValidateFields(
- req.Fields.ToList(),
- CurrentUser!.CustomPreferences
- )
+ ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences)
);
user.Fields = req.Fields.ToList();
}
@@ -183,11 +174,11 @@ public class UsersController(
// so it's in a separate block to the validation above.
if (req.HasProperty(nameof(req.Avatar)))
{
- UserAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(CurrentUser!.Id, req.Avatar));
+ queue.QueueInvocableWithPayload(
+ new AvatarUpdatePayload(CurrentUser!.Id, req.Avatar)
+ );
}
- user.LastActive = clock.GetCurrentInstant();
-
try
{
await db.SaveChangesAsync(ct);
@@ -263,12 +254,20 @@ public class UsersController(
}
user.CustomPreferences = preferences;
- user.LastActive = clock.GetCurrentInstant();
await db.SaveChangesAsync(ct);
return Ok(user.CustomPreferences);
}
+ [HttpGet("@me/settings")]
+ [Authorize("user.read_hidden")]
+ [ProducesResponseType(statusCode: StatusCodes.Status200OK)]
+ public async Task GetUserSettingsAsync(CancellationToken ct = default)
+ {
+ User user = await db.Users.FirstAsync(u => u.Id == CurrentUser!.Id, ct);
+ return Ok(user.Settings);
+ }
+
[HttpPatch("@me/settings")]
[Authorize("user.read_hidden", "user.update")]
[ProducesResponseType(statusCode: StatusCodes.Status200OK)]
@@ -281,10 +280,7 @@ public class UsersController(
if (req.HasProperty(nameof(req.DarkMode)))
user.Settings.DarkMode = req.DarkMode;
- if (req.HasProperty(nameof(req.LastReadNotice)))
- user.Settings.LastReadNotice = req.LastReadNotice;
- user.LastActive = clock.GetCurrentInstant();
db.Update(user);
await db.SaveChangesAsync(ct);
diff --git a/Foxnouns.Backend/Database/DatabaseContext.cs b/Foxnouns.Backend/Database/DatabaseContext.cs
index 2bbcbc7..ae620f2 100644
--- a/Foxnouns.Backend/Database/DatabaseContext.cs
+++ b/Foxnouns.Backend/Database/DatabaseContext.cs
@@ -64,6 +64,7 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options)
public DbSet FediverseApplications { get; init; } = null!;
public DbSet Tokens { get; init; } = null!;
public DbSet Applications { get; init; } = null!;
+ public DbSet TemporaryKeys { get; init; } = null!;
public DbSet DataExports { get; init; } = null!;
public DbSet PrideFlags { get; init; } = null!;
@@ -73,7 +74,6 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options)
public DbSet Reports { get; init; } = null!;
public DbSet AuditLog { get; init; } = null!;
public DbSet Notifications { get; init; } = null!;
- public DbSet Notices { get; init; } = null!;
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
@@ -87,6 +87,7 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options)
modelBuilder.Entity().HasIndex(u => u.Sid).IsUnique();
modelBuilder.Entity().HasIndex(m => new { m.UserId, m.Name }).IsUnique();
modelBuilder.Entity().HasIndex(m => m.Sid).IsUnique();
+ modelBuilder.Entity().HasIndex(k => k.Key).IsUnique();
modelBuilder.Entity().HasIndex(d => d.Filename).IsUnique();
// Two indexes on auth_methods, one for fediverse auth and one for all other types.
diff --git a/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs b/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs
deleted file mode 100644
index 27a8ada..0000000
--- a/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using NodaTime;
-using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
-
-#nullable disable
-
-namespace Foxnouns.Backend.Database.Migrations
-{
- ///
- [DbContext(typeof(DatabaseContext))]
- [Migration("20250304155708_RemoveTemporaryKeys")]
- public partial class RemoveTemporaryKeys : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(name: "temporary_keys");
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "temporary_keys",
- columns: table => new
- {
- id = table
- .Column(type: "bigint", nullable: false)
- .Annotation(
- "Npgsql:ValueGenerationStrategy",
- NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
- ),
- expires = table.Column(
- type: "timestamp with time zone",
- nullable: false
- ),
- key = table.Column(type: "text", nullable: false),
- value = table.Column(type: "text", nullable: false),
- },
- constraints: table =>
- {
- table.PrimaryKey("pk_temporary_keys", x => x.id);
- }
- );
-
- migrationBuilder.CreateIndex(
- name: "ix_temporary_keys_key",
- table: "temporary_keys",
- column: "key",
- unique: true
- );
- }
- }
-}
diff --git a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs b/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs
deleted file mode 100644
index d2df141..0000000
--- a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs
+++ /dev/null
@@ -1,915 +0,0 @@
-//
-using System.Collections.Generic;
-using Foxnouns.Backend.Database;
-using Foxnouns.Backend.Database.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using NodaTime;
-using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
-
-#nullable disable
-
-namespace Foxnouns.Backend.Database.Migrations
-{
- [DbContext(typeof(DatabaseContext))]
- [Migration("20250329131053_AddNotices")]
- partial class AddNotices
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "9.0.2")
- .HasAnnotation("Relational:MaxIdentifierLength", 63);
-
- NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
- NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Application", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ClientId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_id");
-
- b.Property("ClientSecret")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_secret");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.PrimitiveCollection("RedirectUris")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("redirect_uris");
-
- b.PrimitiveCollection("Scopes")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("scopes");
-
- b.HasKey("Id")
- .HasName("pk_applications");
-
- b.ToTable("applications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.PrimitiveCollection("ClearedFields")
- .HasColumnType("text[]")
- .HasColumnName("cleared_fields");
-
- b.Property("ModeratorId")
- .HasColumnType("bigint")
- .HasColumnName("moderator_id");
-
- b.Property("ModeratorUsername")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("moderator_username");
-
- b.Property("Reason")
- .HasColumnType("text")
- .HasColumnName("reason");
-
- b.Property("ReportId")
- .HasColumnType("bigint")
- .HasColumnName("report_id");
-
- b.Property("TargetMemberId")
- .HasColumnType("bigint")
- .HasColumnName("target_member_id");
-
- b.Property("TargetMemberName")
- .HasColumnType("text")
- .HasColumnName("target_member_name");
-
- b.Property("TargetUserId")
- .HasColumnType("bigint")
- .HasColumnName("target_user_id");
-
- b.Property("TargetUsername")
- .HasColumnType("text")
- .HasColumnName("target_username");
-
- b.Property("Type")
- .HasColumnType("integer")
- .HasColumnName("type");
-
- b.HasKey("Id")
- .HasName("pk_audit_log");
-
- b.HasIndex("ReportId")
- .IsUnique()
- .HasDatabaseName("ix_audit_log_report_id");
-
- b.ToTable("audit_log", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AuthType")
- .HasColumnType("integer")
- .HasColumnName("auth_type");
-
- b.Property("FediverseApplicationId")
- .HasColumnType("bigint")
- .HasColumnName("fediverse_application_id");
-
- b.Property("RemoteId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("remote_id");
-
- b.Property("RemoteUsername")
- .HasColumnType("text")
- .HasColumnName("remote_username");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_auth_methods");
-
- b.HasIndex("FediverseApplicationId")
- .HasDatabaseName("ix_auth_methods_fediverse_application_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_auth_methods_user_id");
-
- b.HasIndex("AuthType", "RemoteId")
- .IsUnique()
- .HasDatabaseName("ix_auth_methods_auth_type_remote_id")
- .HasFilter("fediverse_application_id IS NULL");
-
- b.HasIndex("AuthType", "RemoteId", "FediverseApplicationId")
- .IsUnique()
- .HasDatabaseName("ix_auth_methods_auth_type_remote_id_fediverse_application_id")
- .HasFilter("fediverse_application_id IS NOT NULL");
-
- b.ToTable("auth_methods", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Filename")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("filename");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_data_exports");
-
- b.HasIndex("Filename")
- .IsUnique()
- .HasDatabaseName("ix_data_exports_filename");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_data_exports_user_id");
-
- b.ToTable("data_exports", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.FediverseApplication", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ClientId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_id");
-
- b.Property("ClientSecret")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_secret");
-
- b.Property("Domain")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("domain");
-
- b.Property("ForceRefresh")
- .HasColumnType("boolean")
- .HasColumnName("force_refresh");
-
- b.Property("InstanceType")
- .HasColumnType("integer")
- .HasColumnName("instance_type");
-
- b.HasKey("Id")
- .HasName("pk_fediverse_applications");
-
- b.ToTable("fediverse_applications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Avatar")
- .HasColumnType("text")
- .HasColumnName("avatar");
-
- b.Property("Bio")
- .HasColumnType("text")
- .HasColumnName("bio");
-
- b.Property("DisplayName")
- .HasColumnType("text")
- .HasColumnName("display_name");
-
- b.Property>("Fields")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("fields");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.PrimitiveCollection("Links")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("links");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property>("Names")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("names");
-
- b.Property>("Pronouns")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("pronouns");
-
- b.Property("Sid")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("sid")
- .HasDefaultValueSql("find_free_member_sid()");
-
- b.Property("Unlisted")
- .HasColumnType("boolean")
- .HasColumnName("unlisted");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_members");
-
- b.HasIndex("LegacyId")
- .IsUnique()
- .HasDatabaseName("ix_members_legacy_id");
-
- b.HasIndex("Sid")
- .IsUnique()
- .HasDatabaseName("ix_members_sid");
-
- b.HasIndex("UserId", "Name")
- .IsUnique()
- .HasDatabaseName("ix_members_user_id_name");
-
- b.ToTable("members", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("MemberId")
- .HasColumnType("bigint")
- .HasColumnName("member_id");
-
- b.Property("PrideFlagId")
- .HasColumnType("bigint")
- .HasColumnName("pride_flag_id");
-
- b.HasKey("Id")
- .HasName("pk_member_flags");
-
- b.HasIndex("MemberId")
- .HasDatabaseName("ix_member_flags_member_id");
-
- b.HasIndex("PrideFlagId")
- .HasDatabaseName("ix_member_flags_pride_flag_id");
-
- b.ToTable("member_flags", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AuthorId")
- .HasColumnType("bigint")
- .HasColumnName("author_id");
-
- b.Property("EndTime")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("end_time");
-
- b.Property("Message")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("message");
-
- b.Property("StartTime")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("start_time");
-
- b.HasKey("Id")
- .HasName("pk_notices");
-
- b.HasIndex("AuthorId")
- .HasDatabaseName("ix_notices_author_id");
-
- b.ToTable("notices", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AcknowledgedAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("acknowledged_at");
-
- b.Property("LocalizationKey")
- .HasColumnType("text")
- .HasColumnName("localization_key");
-
- b.Property>("LocalizationParams")
- .IsRequired()
- .HasColumnType("hstore")
- .HasColumnName("localization_params");
-
- b.Property("Message")
- .HasColumnType("text")
- .HasColumnName("message");
-
- b.Property("TargetId")
- .HasColumnType("bigint")
- .HasColumnName("target_id");
-
- b.Property("Type")
- .HasColumnType("integer")
- .HasColumnName("type");
-
- b.HasKey("Id")
- .HasName("pk_notifications");
-
- b.HasIndex("TargetId")
- .HasDatabaseName("ix_notifications_target_id");
-
- b.ToTable("notifications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Description")
- .HasColumnType("text")
- .HasColumnName("description");
-
- b.Property("Hash")
- .HasColumnType("text")
- .HasColumnName("hash");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_pride_flags");
-
- b.HasIndex("LegacyId")
- .IsUnique()
- .HasDatabaseName("ix_pride_flags_legacy_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_pride_flags_user_id");
-
- b.ToTable("pride_flags", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Context")
- .HasColumnType("text")
- .HasColumnName("context");
-
- b.Property("Reason")
- .HasColumnType("integer")
- .HasColumnName("reason");
-
- b.Property("ReporterId")
- .HasColumnType("bigint")
- .HasColumnName("reporter_id");
-
- b.Property("Status")
- .HasColumnType("integer")
- .HasColumnName("status");
-
- b.Property("TargetMemberId")
- .HasColumnType("bigint")
- .HasColumnName("target_member_id");
-
- b.Property("TargetSnapshot")
- .HasColumnType("text")
- .HasColumnName("target_snapshot");
-
- b.Property("TargetType")
- .HasColumnType("integer")
- .HasColumnName("target_type");
-
- b.Property("TargetUserId")
- .HasColumnType("bigint")
- .HasColumnName("target_user_id");
-
- b.HasKey("Id")
- .HasName("pk_reports");
-
- b.HasIndex("ReporterId")
- .HasDatabaseName("ix_reports_reporter_id");
-
- b.HasIndex("TargetMemberId")
- .HasDatabaseName("ix_reports_target_member_id");
-
- b.HasIndex("TargetUserId")
- .HasDatabaseName("ix_reports_target_user_id");
-
- b.ToTable("reports", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ApplicationId")
- .HasColumnType("bigint")
- .HasColumnName("application_id");
-
- b.Property("ExpiresAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("expires_at");
-
- b.Property("Hash")
- .IsRequired()
- .HasColumnType("bytea")
- .HasColumnName("hash");
-
- b.Property("ManuallyExpired")
- .HasColumnType("boolean")
- .HasColumnName("manually_expired");
-
- b.PrimitiveCollection("Scopes")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("scopes");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_tokens");
-
- b.HasIndex("ApplicationId")
- .HasDatabaseName("ix_tokens_application_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_tokens_user_id");
-
- b.ToTable("tokens", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Avatar")
- .HasColumnType("text")
- .HasColumnName("avatar");
-
- b.Property("Bio")
- .HasColumnType("text")
- .HasColumnName("bio");
-
- b.Property>("CustomPreferences")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("custom_preferences");
-
- b.Property("Deleted")
- .HasColumnType("boolean")
- .HasColumnName("deleted");
-
- b.Property("DeletedAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("deleted_at");
-
- b.Property("DeletedBy")
- .HasColumnType("bigint")
- .HasColumnName("deleted_by");
-
- b.Property("DisplayName")
- .HasColumnType("text")
- .HasColumnName("display_name");
-
- b.Property>("Fields")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("fields");
-
- b.Property("LastActive")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("last_active");
-
- b.Property("LastSidReroll")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("last_sid_reroll");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.PrimitiveCollection("Links")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("links");
-
- b.Property("ListHidden")
- .HasColumnType("boolean")
- .HasColumnName("list_hidden");
-
- b.Property("MemberTitle")
- .HasColumnType("text")
- .HasColumnName("member_title");
-
- b.Property>("Names")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("names");
-
- b.Property("Password")
- .HasColumnType("text")
- .HasColumnName("password");
-
- b.Property>("Pronouns")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("pronouns");
-
- b.Property("Role")
- .HasColumnType("integer")
- .HasColumnName("role");
-
- b.Property("Settings")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("settings");
-
- b.Property("Sid")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("sid")
- .HasDefaultValueSql("find_free_user_sid()");
-
- b.Property("Timezone")
- .HasColumnType("text")
- .HasColumnName("timezone");
-
- b.Property("Username")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("username");
-
- b.HasKey("Id")
- .HasName("pk_users");
-
- b.HasIndex("LegacyId")
- .IsUnique()
- .HasDatabaseName("ix_users_legacy_id");
-
- b.HasIndex("Sid")
- .IsUnique()
- .HasDatabaseName("ix_users_sid");
-
- b.HasIndex("Username")
- .IsUnique()
- .HasDatabaseName("ix_users_username");
-
- b.ToTable("users", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("PrideFlagId")
- .HasColumnType("bigint")
- .HasColumnName("pride_flag_id");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_user_flags");
-
- b.HasIndex("PrideFlagId")
- .HasDatabaseName("ix_user_flags_pride_flag_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_user_flags_user_id");
-
- b.ToTable("user_flags", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.Report", "Report")
- .WithOne("AuditLogEntry")
- .HasForeignKey("Foxnouns.Backend.Database.Models.AuditLogEntry", "ReportId")
- .OnDelete(DeleteBehavior.SetNull)
- .HasConstraintName("fk_audit_log_reports_report_id");
-
- b.Navigation("Report");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.FediverseApplication", "FediverseApplication")
- .WithMany()
- .HasForeignKey("FediverseApplicationId")
- .HasConstraintName("fk_auth_methods_fediverse_applications_fediverse_application_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.User", "User")
- .WithMany("AuthMethods")
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_auth_methods_users_user_id");
-
- b.Navigation("FediverseApplication");
-
- b.Navigation("User");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", "User")
- .WithMany("DataExports")
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_data_exports_users_user_id");
-
- b.Navigation("User");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", "User")
- .WithMany("Members")
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_members_users_user_id");
-
- b.Navigation("User");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.Member", null)
- .WithMany("ProfileFlags")
- .HasForeignKey("MemberId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_member_flags_members_member_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag")
- .WithMany()
- .HasForeignKey("PrideFlagId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_member_flags_pride_flags_pride_flag_id");
-
- b.Navigation("PrideFlag");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", "Author")
- .WithMany()
- .HasForeignKey("AuthorId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_notices_users_author_id");
-
- b.Navigation("Author");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", "Target")
- .WithMany()
- .HasForeignKey("TargetId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_notifications_users_target_id");
-
- b.Navigation("Target");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", null)
- .WithMany("Flags")
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_pride_flags_users_user_id");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.User", "Reporter")
- .WithMany()
- .HasForeignKey("ReporterId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_reports_users_reporter_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.Member", "TargetMember")
- .WithMany()
- .HasForeignKey("TargetMemberId")
- .HasConstraintName("fk_reports_members_target_member_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.User", "TargetUser")
- .WithMany()
- .HasForeignKey("TargetUserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_reports_users_target_user_id");
-
- b.Navigation("Reporter");
-
- b.Navigation("TargetMember");
-
- b.Navigation("TargetUser");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.Application", "Application")
- .WithMany()
- .HasForeignKey("ApplicationId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_tokens_applications_application_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.User", "User")
- .WithMany()
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_tokens_users_user_id");
-
- b.Navigation("Application");
-
- b.Navigation("User");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b =>
- {
- b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag")
- .WithMany()
- .HasForeignKey("PrideFlagId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_user_flags_pride_flags_pride_flag_id");
-
- b.HasOne("Foxnouns.Backend.Database.Models.User", null)
- .WithMany("ProfileFlags")
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_user_flags_users_user_id");
-
- b.Navigation("PrideFlag");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b =>
- {
- b.Navigation("ProfileFlags");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
- {
- b.Navigation("AuditLogEntry");
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b =>
- {
- b.Navigation("AuthMethods");
-
- b.Navigation("DataExports");
-
- b.Navigation("Flags");
-
- b.Navigation("Members");
-
- b.Navigation("ProfileFlags");
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs b/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs
deleted file mode 100644
index 24c5166..0000000
--- a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Microsoft.EntityFrameworkCore.Migrations;
-using NodaTime;
-
-#nullable disable
-
-namespace Foxnouns.Backend.Database.Migrations
-{
- ///
- public partial class AddNotices : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "notices",
- columns: table => new
- {
- id = table.Column(type: "bigint", nullable: false),
- message = table.Column(type: "text", nullable: false),
- start_time = table.Column(
- type: "timestamp with time zone",
- nullable: false
- ),
- end_time = table.Column(
- type: "timestamp with time zone",
- nullable: false
- ),
- author_id = table.Column(type: "bigint", nullable: false),
- },
- constraints: table =>
- {
- table.PrimaryKey("pk_notices", x => x.id);
- table.ForeignKey(
- name: "fk_notices_users_author_id",
- column: x => x.author_id,
- principalTable: "users",
- principalColumn: "id",
- onDelete: ReferentialAction.Cascade
- );
- }
- );
-
- migrationBuilder.CreateIndex(
- name: "ix_notices_author_id",
- table: "notices",
- column: "author_id"
- );
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(name: "notices");
- }
- }
-}
diff --git a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs b/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs
deleted file mode 100644
index cb9377d..0000000
--- a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs
+++ /dev/null
@@ -1,923 +0,0 @@
-//
-using System.Collections.Generic;
-using Foxnouns.Backend.Database;
-using Foxnouns.Backend.Database.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using NodaTime;
-using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
-
-#nullable disable
-
-namespace Foxnouns.Backend.Database.Migrations
-{
- [DbContext(typeof(DatabaseContext))]
- [Migration("20250410192220_AddAvatarMigrations")]
- partial class AddAvatarMigrations
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "9.0.2")
- .HasAnnotation("Relational:MaxIdentifierLength", 63);
-
- NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
- NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Application", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ClientId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_id");
-
- b.Property("ClientSecret")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_secret");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.PrimitiveCollection("RedirectUris")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("redirect_uris");
-
- b.PrimitiveCollection("Scopes")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("scopes");
-
- b.HasKey("Id")
- .HasName("pk_applications");
-
- b.ToTable("applications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.PrimitiveCollection("ClearedFields")
- .HasColumnType("text[]")
- .HasColumnName("cleared_fields");
-
- b.Property("ModeratorId")
- .HasColumnType("bigint")
- .HasColumnName("moderator_id");
-
- b.Property("ModeratorUsername")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("moderator_username");
-
- b.Property("Reason")
- .HasColumnType("text")
- .HasColumnName("reason");
-
- b.Property("ReportId")
- .HasColumnType("bigint")
- .HasColumnName("report_id");
-
- b.Property("TargetMemberId")
- .HasColumnType("bigint")
- .HasColumnName("target_member_id");
-
- b.Property("TargetMemberName")
- .HasColumnType("text")
- .HasColumnName("target_member_name");
-
- b.Property("TargetUserId")
- .HasColumnType("bigint")
- .HasColumnName("target_user_id");
-
- b.Property("TargetUsername")
- .HasColumnType("text")
- .HasColumnName("target_username");
-
- b.Property("Type")
- .HasColumnType("integer")
- .HasColumnName("type");
-
- b.HasKey("Id")
- .HasName("pk_audit_log");
-
- b.HasIndex("ReportId")
- .IsUnique()
- .HasDatabaseName("ix_audit_log_report_id");
-
- b.ToTable("audit_log", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AuthType")
- .HasColumnType("integer")
- .HasColumnName("auth_type");
-
- b.Property("FediverseApplicationId")
- .HasColumnType("bigint")
- .HasColumnName("fediverse_application_id");
-
- b.Property("RemoteId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("remote_id");
-
- b.Property("RemoteUsername")
- .HasColumnType("text")
- .HasColumnName("remote_username");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_auth_methods");
-
- b.HasIndex("FediverseApplicationId")
- .HasDatabaseName("ix_auth_methods_fediverse_application_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_auth_methods_user_id");
-
- b.HasIndex("AuthType", "RemoteId")
- .IsUnique()
- .HasDatabaseName("ix_auth_methods_auth_type_remote_id")
- .HasFilter("fediverse_application_id IS NULL");
-
- b.HasIndex("AuthType", "RemoteId", "FediverseApplicationId")
- .IsUnique()
- .HasDatabaseName("ix_auth_methods_auth_type_remote_id_fediverse_application_id")
- .HasFilter("fediverse_application_id IS NOT NULL");
-
- b.ToTable("auth_methods", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Filename")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("filename");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_data_exports");
-
- b.HasIndex("Filename")
- .IsUnique()
- .HasDatabaseName("ix_data_exports_filename");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_data_exports_user_id");
-
- b.ToTable("data_exports", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.FediverseApplication", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ClientId")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_id");
-
- b.Property("ClientSecret")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("client_secret");
-
- b.Property("Domain")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("domain");
-
- b.Property("ForceRefresh")
- .HasColumnType("boolean")
- .HasColumnName("force_refresh");
-
- b.Property("InstanceType")
- .HasColumnType("integer")
- .HasColumnName("instance_type");
-
- b.HasKey("Id")
- .HasName("pk_fediverse_applications");
-
- b.ToTable("fediverse_applications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Avatar")
- .HasColumnType("text")
- .HasColumnName("avatar");
-
- b.Property("AvatarMigrated")
- .HasColumnType("boolean")
- .HasColumnName("avatar_migrated");
-
- b.Property("Bio")
- .HasColumnType("text")
- .HasColumnName("bio");
-
- b.Property("DisplayName")
- .HasColumnType("text")
- .HasColumnName("display_name");
-
- b.Property>("Fields")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("fields");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.PrimitiveCollection("Links")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("links");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property>("Names")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("names");
-
- b.Property>("Pronouns")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("pronouns");
-
- b.Property("Sid")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("sid")
- .HasDefaultValueSql("find_free_member_sid()");
-
- b.Property("Unlisted")
- .HasColumnType("boolean")
- .HasColumnName("unlisted");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_members");
-
- b.HasIndex("LegacyId")
- .IsUnique()
- .HasDatabaseName("ix_members_legacy_id");
-
- b.HasIndex("Sid")
- .IsUnique()
- .HasDatabaseName("ix_members_sid");
-
- b.HasIndex("UserId", "Name")
- .IsUnique()
- .HasDatabaseName("ix_members_user_id_name");
-
- b.ToTable("members", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("MemberId")
- .HasColumnType("bigint")
- .HasColumnName("member_id");
-
- b.Property("PrideFlagId")
- .HasColumnType("bigint")
- .HasColumnName("pride_flag_id");
-
- b.HasKey("Id")
- .HasName("pk_member_flags");
-
- b.HasIndex("MemberId")
- .HasDatabaseName("ix_member_flags_member_id");
-
- b.HasIndex("PrideFlagId")
- .HasDatabaseName("ix_member_flags_pride_flag_id");
-
- b.ToTable("member_flags", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AuthorId")
- .HasColumnType("bigint")
- .HasColumnName("author_id");
-
- b.Property("EndTime")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("end_time");
-
- b.Property("Message")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("message");
-
- b.Property("StartTime")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("start_time");
-
- b.HasKey("Id")
- .HasName("pk_notices");
-
- b.HasIndex("AuthorId")
- .HasDatabaseName("ix_notices_author_id");
-
- b.ToTable("notices", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("AcknowledgedAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("acknowledged_at");
-
- b.Property("LocalizationKey")
- .HasColumnType("text")
- .HasColumnName("localization_key");
-
- b.Property>("LocalizationParams")
- .IsRequired()
- .HasColumnType("hstore")
- .HasColumnName("localization_params");
-
- b.Property("Message")
- .HasColumnType("text")
- .HasColumnName("message");
-
- b.Property("TargetId")
- .HasColumnType("bigint")
- .HasColumnName("target_id");
-
- b.Property("Type")
- .HasColumnType("integer")
- .HasColumnName("type");
-
- b.HasKey("Id")
- .HasName("pk_notifications");
-
- b.HasIndex("TargetId")
- .HasDatabaseName("ix_notifications_target_id");
-
- b.ToTable("notifications", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Description")
- .HasColumnType("text")
- .HasColumnName("description");
-
- b.Property("Hash")
- .HasColumnType("text")
- .HasColumnName("hash");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.Property("Name")
- .IsRequired()
- .HasColumnType("text")
- .HasColumnName("name");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_pride_flags");
-
- b.HasIndex("LegacyId")
- .IsUnique()
- .HasDatabaseName("ix_pride_flags_legacy_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_pride_flags_user_id");
-
- b.ToTable("pride_flags", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Context")
- .HasColumnType("text")
- .HasColumnName("context");
-
- b.Property("Reason")
- .HasColumnType("integer")
- .HasColumnName("reason");
-
- b.Property("ReporterId")
- .HasColumnType("bigint")
- .HasColumnName("reporter_id");
-
- b.Property("Status")
- .HasColumnType("integer")
- .HasColumnName("status");
-
- b.Property("TargetMemberId")
- .HasColumnType("bigint")
- .HasColumnName("target_member_id");
-
- b.Property("TargetSnapshot")
- .HasColumnType("text")
- .HasColumnName("target_snapshot");
-
- b.Property("TargetType")
- .HasColumnType("integer")
- .HasColumnName("target_type");
-
- b.Property("TargetUserId")
- .HasColumnType("bigint")
- .HasColumnName("target_user_id");
-
- b.HasKey("Id")
- .HasName("pk_reports");
-
- b.HasIndex("ReporterId")
- .HasDatabaseName("ix_reports_reporter_id");
-
- b.HasIndex("TargetMemberId")
- .HasDatabaseName("ix_reports_target_member_id");
-
- b.HasIndex("TargetUserId")
- .HasDatabaseName("ix_reports_target_user_id");
-
- b.ToTable("reports", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("ApplicationId")
- .HasColumnType("bigint")
- .HasColumnName("application_id");
-
- b.Property("ExpiresAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("expires_at");
-
- b.Property("Hash")
- .IsRequired()
- .HasColumnType("bytea")
- .HasColumnName("hash");
-
- b.Property("ManuallyExpired")
- .HasColumnType("boolean")
- .HasColumnName("manually_expired");
-
- b.PrimitiveCollection("Scopes")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("scopes");
-
- b.Property("UserId")
- .HasColumnType("bigint")
- .HasColumnName("user_id");
-
- b.HasKey("Id")
- .HasName("pk_tokens");
-
- b.HasIndex("ApplicationId")
- .HasDatabaseName("ix_tokens_application_id");
-
- b.HasIndex("UserId")
- .HasDatabaseName("ix_tokens_user_id");
-
- b.ToTable("tokens", (string)null);
- });
-
- modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b =>
- {
- b.Property("Id")
- .HasColumnType("bigint")
- .HasColumnName("id");
-
- b.Property("Avatar")
- .HasColumnType("text")
- .HasColumnName("avatar");
-
- b.Property("AvatarMigrated")
- .HasColumnType("boolean")
- .HasColumnName("avatar_migrated");
-
- b.Property("Bio")
- .HasColumnType("text")
- .HasColumnName("bio");
-
- b.Property>("CustomPreferences")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("custom_preferences");
-
- b.Property("Deleted")
- .HasColumnType("boolean")
- .HasColumnName("deleted");
-
- b.Property("DeletedAt")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("deleted_at");
-
- b.Property("DeletedBy")
- .HasColumnType("bigint")
- .HasColumnName("deleted_by");
-
- b.Property("DisplayName")
- .HasColumnType("text")
- .HasColumnName("display_name");
-
- b.Property>("Fields")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("fields");
-
- b.Property("LastActive")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("last_active");
-
- b.Property("LastSidReroll")
- .HasColumnType("timestamp with time zone")
- .HasColumnName("last_sid_reroll");
-
- b.Property("LegacyId")
- .IsRequired()
- .ValueGeneratedOnAdd()
- .HasColumnType("text")
- .HasColumnName("legacy_id")
- .HasDefaultValueSql("gen_random_uuid()");
-
- b.PrimitiveCollection("Links")
- .IsRequired()
- .HasColumnType("text[]")
- .HasColumnName("links");
-
- b.Property("ListHidden")
- .HasColumnType("boolean")
- .HasColumnName("list_hidden");
-
- b.Property("MemberTitle")
- .HasColumnType("text")
- .HasColumnName("member_title");
-
- b.Property>("Names")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("names");
-
- b.Property("Password")
- .HasColumnType("text")
- .HasColumnName("password");
-
- b.Property>("Pronouns")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("pronouns");
-
- b.Property("Role")
- .HasColumnType("integer")
- .HasColumnName("role");
-
- b.Property("Settings")
- .IsRequired()
- .HasColumnType("jsonb")
- .HasColumnName("settings");
-
- b.Property