[backend/core] Add user settings store (ISH-106)

This commit is contained in:
Laura Hausmann 2024-02-29 18:46:22 +01:00
parent 9e0b74f425
commit ad21897928
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
9 changed files with 6363 additions and 8 deletions

View file

@ -66,10 +66,11 @@ public class UserRenderer(IOptions<Config.InstanceSection> config, MfmConverter
//TODO: populate these //TODO: populate these
res.Source = new AccountSource res.Source = new AccountSource
{ {
Fields = [], Fields = [],
Language = "", Language = "",
Note = profile?.Description ?? "", Note = profile?.Description ?? "",
Privacy = StatusEntity.EncodeVisibility(Note.NoteVisibility.Public), Privacy = StatusEntity.EncodeVisibility(user.UserSettings?.DefaultNoteVisibility ??
Note.NoteVisibility.Public),
Sensitive = false Sensitive = false
}; };
} }

View file

@ -85,6 +85,7 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
public virtual DbSet<UserProfile> UserProfiles { get; init; } = null!; public virtual DbSet<UserProfile> UserProfiles { get; init; } = null!;
public virtual DbSet<UserPublickey> UserPublickeys { get; init; } = null!; public virtual DbSet<UserPublickey> UserPublickeys { get; init; } = null!;
public virtual DbSet<UserSecurityKey> UserSecurityKeys { get; init; } = null!; public virtual DbSet<UserSecurityKey> UserSecurityKeys { get; init; } = null!;
public virtual DbSet<UserSettings> UserSettings { get; init; } = null!;
public virtual DbSet<Webhook> Webhooks { get; init; } = null!; public virtual DbSet<Webhook> Webhooks { get; init; } = null!;
public virtual DbSet<AllowedInstance> AllowedInstances { get; init; } = null!; public virtual DbSet<AllowedInstance> AllowedInstances { get; init; } = null!;
public virtual DbSet<BlockedInstance> BlockedInstances { get; init; } = null!; public virtual DbSet<BlockedInstance> BlockedInstances { get; init; } = null!;
@ -1119,6 +1120,13 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
entity.HasOne(d => d.User).WithMany(p => p.UserSecurityKeys); entity.HasOne(d => d.User).WithMany(p => p.UserSecurityKeys);
}); });
modelBuilder.Entity<UserSettings>(entity =>
{
entity.Property(e => e.PrivateMode).HasDefaultValue(false);
entity.Property(e => e.DefaultNoteVisibility).HasDefaultValue(Note.NoteVisibility.Public);
entity.HasOne(e => e.User).WithOne(e => e.UserSettings);
});
modelBuilder.Entity<Webhook>(entity => modelBuilder.Entity<Webhook>(entity =>
{ {
entity.Property(e => e.Active).HasDefaultValue(true); entity.Property(e => e.Active).HasDefaultValue(true);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,41 @@
using Iceshrimp.Backend.Core.Database.Tables;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Iceshrimp.Backend.Core.Database.Migrations
{
/// <inheritdoc />
public partial class AddUserSettingsTable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "user_settings",
columns: table => new
{
userId = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
defaultNoteVisibility = table.Column<Note.NoteVisibility>(type: "note_visibility_enum", nullable: false, defaultValue: Note.NoteVisibility.Public),
privateMode = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false)
},
constraints: table =>
{
table.PrimaryKey("PK_user_settings", x => x.userId);
table.ForeignKey(
name: "FK_user_settings_user_userId",
column: x => x.userId,
principalTable: "user",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "user_settings");
}
}
}

View file

@ -4816,6 +4816,30 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
b.ToTable("user_security_key"); b.ToTable("user_security_key");
}); });
modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.UserSettings", b =>
{
b.Property<string>("UserId")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnName("userId");
b.Property<Note.NoteVisibility>("DefaultNoteVisibility")
.ValueGeneratedOnAdd()
.HasColumnType("note_visibility_enum")
.HasDefaultValue(Note.NoteVisibility.Public)
.HasColumnName("defaultNoteVisibility");
b.Property<bool>("PrivateMode")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false)
.HasColumnName("privateMode");
b.HasKey("UserId");
b.ToTable("user_settings");
});
modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.Webhook", b => modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.Webhook", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
@ -5922,6 +5946,17 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
b.Navigation("User"); b.Navigation("User");
}); });
modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.UserSettings", b =>
{
b.HasOne("Iceshrimp.Backend.Core.Database.Tables.User", "User")
.WithOne("UserSettings")
.HasForeignKey("Iceshrimp.Backend.Core.Database.Tables.UserSettings", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.Webhook", b => modelBuilder.Entity("Iceshrimp.Backend.Core.Database.Tables.Webhook", b =>
{ {
b.HasOne("Iceshrimp.Backend.Core.Database.Tables.User", "User") b.HasOne("Iceshrimp.Backend.Core.Database.Tables.User", "User")
@ -6165,6 +6200,8 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
b.Navigation("UserSecurityKeys"); b.Navigation("UserSecurityKeys");
b.Navigation("UserSettings");
b.Navigation("Webhooks"); b.Navigation("Webhooks");
}); });

View file

@ -484,6 +484,9 @@ public class User : IEntity
[InverseProperty(nameof(Tables.UserPublickey.User))] [InverseProperty(nameof(Tables.UserPublickey.User))]
public virtual UserPublickey? UserPublickey { get; set; } public virtual UserPublickey? UserPublickey { get; set; }
[InverseProperty(nameof(Tables.UserSettings.User))]
public virtual UserSettings? UserSettings { get; set; }
[InverseProperty(nameof(UserSecurityKey.User))] [InverseProperty(nameof(UserSecurityKey.User))]
public virtual ICollection<UserSecurityKey> UserSecurityKeys { get; set; } = new List<UserSecurityKey>(); public virtual ICollection<UserSecurityKey> UserSecurityKeys { get; set; } = new List<UserSecurityKey>();

View file

@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using NpgsqlTypes;
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace Iceshrimp.Backend.Core.Database.Tables;
[Table("user_settings")]
public class UserSettings
{
[Key]
[Column("userId")]
[StringLength(32)]
public string UserId { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty(nameof(Tables.User.UserSettings))]
public virtual User User { get; set; } = null!;
[Column("defaultNoteVisibility")] public Note.NoteVisibility DefaultNoteVisibility { get; set; }
[Column("privateMode")] public bool PrivateMode { get; set; }
}

View file

@ -30,8 +30,8 @@ public class AuthenticationMiddleware(DatabaseContext db, UserService userSvc) :
if (isMastodon) if (isMastodon)
{ {
var oauthToken = await db.OauthTokens var oauthToken = await db.OauthTokens
.Include(p => p.User) .Include(p => p.User.UserProfile)
.ThenInclude(p => p.UserProfile) .Include(p => p.User.UserSettings)
.Include(p => p.App) .Include(p => p.App)
.FirstOrDefaultAsync(p => p.Token == token && p.Active); .FirstOrDefaultAsync(p => p.Token == token && p.Active);
@ -62,8 +62,8 @@ public class AuthenticationMiddleware(DatabaseContext db, UserService userSvc) :
else else
{ {
var session = await db.Sessions var session = await db.Sessions
.Include(p => p.User) .Include(p => p.User.UserProfile)
.ThenInclude(p => p.UserProfile) .Include(p => p.User.UserSettings)
.FirstOrDefaultAsync(p => p.Token == token && p.Active); .FirstOrDefaultAsync(p => p.Token == token && p.Active);
if (session == null) if (session == null)

View file

@ -72,6 +72,9 @@ public class NoteService(
if (cw != null && string.IsNullOrWhiteSpace(cw)) if (cw != null && string.IsNullOrWhiteSpace(cw))
cw = null; cw = null;
if ((user.UserSettings?.PrivateMode ?? false) && visibility < Note.NoteVisibility.Followers)
visibility = Note.NoteVisibility.Followers;
var note = new Note var note = new Note
{ {
Id = IdHelpers.GenerateSlowflakeId(), Id = IdHelpers.GenerateSlowflakeId(),