feat(backend): add pride flag models
This commit is contained in:
parent
39b0917585
commit
a70078995b
9 changed files with 346 additions and 0 deletions
28
Foxnouns.Backend/Controllers/FlagsController.cs
Normal file
28
Foxnouns.Backend/Controllers/FlagsController.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using Foxnouns.Backend.Database;
|
||||
using Foxnouns.Backend.Middleware;
|
||||
using Foxnouns.Backend.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Foxnouns.Backend.Controllers;
|
||||
|
||||
[Route("/api/v2/users/@me/flags")]
|
||||
public class FlagsController(DatabaseContext db, UserRendererService userRenderer) : ApiControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[Authorize("identify")]
|
||||
[ProducesResponseType<IEnumerable<PrideFlagResponse>>(statusCode: StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetFlagsAsync(CancellationToken ct = default)
|
||||
{
|
||||
var flags = await db.PrideFlags.Where(f => f.UserId == CurrentUser!.Id).ToListAsync(ct);
|
||||
|
||||
return Ok(flags.Select(f => new PrideFlagResponse(
|
||||
f.Id, userRenderer.ImageUrlFor(f), f.Name, f.Description)));
|
||||
}
|
||||
|
||||
private record PrideFlagResponse(
|
||||
Snowflake Id,
|
||||
string ImageUrl,
|
||||
string Name,
|
||||
string? Description);
|
||||
}
|
|
@ -21,6 +21,10 @@ public class DatabaseContext : DbContext
|
|||
public DbSet<Token> Tokens { get; set; }
|
||||
public DbSet<Application> Applications { get; set; }
|
||||
public DbSet<TemporaryKey> TemporaryKeys { get; set; }
|
||||
|
||||
public DbSet<PrideFlag> PrideFlags { get; set; }
|
||||
public DbSet<UserFlag> UserFlags { get; set; }
|
||||
public DbSet<MemberFlag> MemberFlags { get; set; }
|
||||
|
||||
public DatabaseContext(Config config, ILoggerFactory? loggerFactory)
|
||||
{
|
||||
|
@ -77,6 +81,9 @@ public class DatabaseContext : DbContext
|
|||
modelBuilder.Entity<Member>().Property(m => m.Names).HasColumnType("jsonb");
|
||||
modelBuilder.Entity<Member>().Property(m => m.Pronouns).HasColumnType("jsonb");
|
||||
|
||||
modelBuilder.Entity<UserFlag>().Navigation(f => f.PrideFlag).AutoInclude();
|
||||
modelBuilder.Entity<MemberFlag>().Navigation(f => f.PrideFlag).AutoInclude();
|
||||
|
||||
modelBuilder.HasDbFunction(typeof(DatabaseContext).GetMethod(nameof(FindFreeUserSid))!)
|
||||
.HasName("find_free_user_sid");
|
||||
|
||||
|
|
129
Foxnouns.Backend/Database/Migrations/20240926180037_AddFlags.cs
Normal file
129
Foxnouns.Backend/Database/Migrations/20240926180037_AddFlags.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Foxnouns.Backend.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20240926180037_AddFlags")]
|
||||
public partial class AddFlags : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "pride_flags",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false),
|
||||
user_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
hash = table.Column<string>(type: "text", nullable: false),
|
||||
name = table.Column<string>(type: "text", nullable: false),
|
||||
description = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_pride_flags", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_pride_flags_users_user_id",
|
||||
column: x => x.user_id,
|
||||
principalTable: "users",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "member_flags",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
member_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
pride_flag_id = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_member_flags", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_member_flags_members_member_id",
|
||||
column: x => x.member_id,
|
||||
principalTable: "members",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_member_flags_pride_flags_pride_flag_id",
|
||||
column: x => x.pride_flag_id,
|
||||
principalTable: "pride_flags",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "user_flags",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
user_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
pride_flag_id = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_user_flags", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_user_flags_pride_flags_pride_flag_id",
|
||||
column: x => x.pride_flag_id,
|
||||
principalTable: "pride_flags",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_user_flags_users_user_id",
|
||||
column: x => x.user_id,
|
||||
principalTable: "users",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_member_flags_member_id",
|
||||
table: "member_flags",
|
||||
column: "member_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_member_flags_pride_flag_id",
|
||||
table: "member_flags",
|
||||
column: "pride_flag_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_pride_flags_user_id",
|
||||
table: "pride_flags",
|
||||
column: "user_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_flags_pride_flag_id",
|
||||
table: "user_flags",
|
||||
column: "pride_flag_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_user_flags_user_id",
|
||||
table: "user_flags",
|
||||
column: "user_id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "member_flags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "user_flags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "pride_flags");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -204,6 +204,68 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("members", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<long>("MemberId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("member_id");
|
||||
|
||||
b.Property<long>("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.PrideFlag", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<string>("Hash")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("hash");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_pride_flags");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.HasDatabaseName("ix_pride_flags_user_id");
|
||||
|
||||
b.ToTable("pride_flags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.TemporaryKey", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
@ -391,6 +453,35 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<long>("PrideFlagId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("pride_flag_id");
|
||||
|
||||
b.Property<long>("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.AuthMethod", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.FediverseApplication", "FediverseApplication")
|
||||
|
@ -422,6 +513,35 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
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.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.Token", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.Application", "Application")
|
||||
|
@ -443,11 +563,39 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
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.User", b =>
|
||||
{
|
||||
b.Navigation("AuthMethods");
|
||||
|
||||
b.Navigation("Flags");
|
||||
|
||||
b.Navigation("Members");
|
||||
|
||||
b.Navigation("ProfileFlags");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ public class Member : BaseModel
|
|||
public List<Pronoun> Pronouns { get; set; } = [];
|
||||
public List<Field> Fields { get; set; } = [];
|
||||
|
||||
public List<MemberFlag> ProfileFlags { get; set; } = [];
|
||||
|
||||
public Snowflake UserId { get; init; }
|
||||
public User User { get; init; } = null!;
|
||||
}
|
25
Foxnouns.Backend/Database/Models/PrideFlag.cs
Normal file
25
Foxnouns.Backend/Database/Models/PrideFlag.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
namespace Foxnouns.Backend.Database.Models;
|
||||
|
||||
public class PrideFlag : BaseModel
|
||||
{
|
||||
public required Snowflake UserId { get; init; }
|
||||
public required string Hash { get; init; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
|
||||
public class UserFlag
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public required Snowflake UserId { get; init; }
|
||||
public required Snowflake PrideFlagId { get; init; }
|
||||
public PrideFlag PrideFlag { get; init; } = null!;
|
||||
}
|
||||
|
||||
public class MemberFlag
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public required Snowflake MemberId { get; init; }
|
||||
public required Snowflake PrideFlagId { get; init; }
|
||||
public PrideFlag PrideFlag { get; init; } = null!;
|
||||
}
|
|
@ -21,6 +21,9 @@ public class User : BaseModel
|
|||
public List<Field> Fields { get; set; } = [];
|
||||
public Dictionary<Snowflake, CustomPreference> CustomPreferences { get; set; } = [];
|
||||
|
||||
public List<PrideFlag> Flags { get; set; } = [];
|
||||
public List<UserFlag> ProfileFlags { get; set; } = [];
|
||||
|
||||
public UserRole Role { get; set; } = UserRole.User;
|
||||
public string? Password { get; set; } // Password may be null if the user doesn't authenticate with an email address
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ public class MemberRendererService(DatabaseContext db, Config config)
|
|||
private string? AvatarUrlFor(User user) =>
|
||||
user.Avatar != null ? $"{config.MediaBaseUrl}/users/{user.Id}/avatars/{user.Avatar}.webp" : null;
|
||||
|
||||
private string ImageUrlFor(PrideFlag flag) => $"{config.MediaBaseUrl}/flags/{flag.Hash}.webp";
|
||||
|
||||
public record PartialMember(
|
||||
Snowflake Id,
|
||||
string Sid,
|
||||
|
|
|
@ -58,6 +58,8 @@ public class UserRendererService(DatabaseContext db, MemberRendererService membe
|
|||
|
||||
private string? AvatarUrlFor(User user) =>
|
||||
user.Avatar != null ? $"{config.MediaBaseUrl}/users/{user.Id}/avatars/{user.Avatar}.webp" : null;
|
||||
|
||||
public string ImageUrlFor(PrideFlag flag) => $"{config.MediaBaseUrl}/flags/{flag.Hash}.webp";
|
||||
|
||||
public record UserResponse(
|
||||
Snowflake Id,
|
||||
|
|
Loading…
Reference in a new issue