feat: so much more frontend stuff

This commit is contained in:
sam 2024-11-24 22:19:53 +01:00
parent c179669799
commit 261435c252
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
24 changed files with 682 additions and 107 deletions

View file

@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Coravel.Mailer.Mail.Helpers;
using Coravel.Queuing.Interfaces;
using EntityFramework.Exceptions.Common;
using Foxnouns.Backend.Database;
@ -116,6 +117,42 @@ public class UsersController(
if (req.HasProperty(nameof(req.Avatar)))
errors.Add(("avatar", ValidationUtils.ValidateAvatar(req.Avatar)));
if (req.HasProperty(nameof(req.MemberTitle)))
{
if (string.IsNullOrEmpty(req.MemberTitle))
{
user.MemberTitle = null;
}
else
{
errors.Add(("member_title", ValidationUtils.ValidateDisplayName(req.MemberTitle)));
user.MemberTitle = req.MemberTitle;
}
}
if (req.HasProperty(nameof(req.MemberListHidden)))
user.ListHidden = req.MemberListHidden == true;
if (req.HasProperty(nameof(req.Timezone)))
{
if (string.IsNullOrEmpty(req.Timezone))
{
user.Timezone = null;
}
else
{
if (TimeZoneInfo.TryFindSystemTimeZoneById(req.Timezone, out _))
user.Timezone = req.Timezone;
else
errors.Add(
(
"timezone",
ValidationError.GenericValidationError("Invalid timezone", req.Timezone)
)
);
}
}
ValidationUtils.Validate(errors);
// This is fired off regardless of whether the transaction is committed
// (atomic operations are hard when combined with background jobs)
@ -253,6 +290,9 @@ public class UsersController(
public Pronoun[]? Pronouns { get; init; }
public Field[]? Fields { get; init; }
public Snowflake[]? Flags { get; init; }
public string? MemberTitle { get; init; }
public bool? MemberListHidden { get; init; }
public string? Timezone { get; init; }
}
[HttpGet("@me/settings")]

View file

@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Foxnouns.Backend.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(DatabaseContext))]
[Migration("20241124201309_AddUserTimezone")]
public partial class AddUserTimezone : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "timezone",
table: "users",
type: "text",
nullable: true
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "timezone", table: "users");
}
}
}

View file

@ -434,6 +434,10 @@ namespace Foxnouns.Backend.Database.Migrations
.HasColumnName("sid")
.HasDefaultValueSql("find_free_user_sid()");
b.Property<string>("Timezone")
.HasColumnType("text")
.HasColumnName("timezone");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("text")

View file

@ -15,6 +15,7 @@ public class User : BaseModel
public string? Avatar { get; set; }
public string[] Links { get; set; } = [];
public bool ListHidden { get; set; }
public string? Timezone { get; set; }
public List<FieldEntry> Names { get; set; } = [];
public List<Pronoun> Pronouns { get; set; } = [];

View file

@ -4,6 +4,7 @@
"Development": {
"commandName": "Project",
"dotnetRunMessages": true,
"hotReloadEnabled": false,
"launchBrowser": false,
"externalUrlConfiguration": true,
"environmentVariables": {
@ -13,6 +14,7 @@
"Production": {
"commandName": "Project",
"dotnetRunMessages": true,
"hotReloadEnabled": false,
"launchBrowser": false,
"externalUrlConfiguration": true,
"environmentVariables": {

View file

@ -4,6 +4,7 @@ using Foxnouns.Backend.Utils;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NodaTime;
using Org.BouncyCastle.Ocsp;
namespace Foxnouns.Backend.Services;
@ -49,6 +50,13 @@ public class UserRendererService(
.ToListAsync(ct)
: [];
int? utcOffset = null;
if (
user.Timezone != null
&& TimeZoneInfo.TryFindSystemTimeZoneById(user.Timezone, out var tz)
)
utcOffset = (int)tz.GetUtcOffset(DateTimeOffset.UtcNow).TotalSeconds;
return new UserResponse(
user.Id,
user.Sid,
@ -63,6 +71,7 @@ public class UserRendererService(
user.Fields,
user.CustomPreferences,
flags.Select(f => RenderPrideFlag(f.PrideFlag)),
utcOffset,
user.Role,
renderMembers
? members.Select(m => memberRenderer.RenderPartialMember(m, tokenHidden))
@ -70,7 +79,8 @@ public class UserRendererService(
renderAuthMethods ? authMethods.Select(RenderAuthMethod) : null,
tokenHidden ? user.ListHidden : null,
tokenHidden ? user.LastActive : null,
tokenHidden ? user.LastSidReroll : null
tokenHidden ? user.LastSidReroll : null,
tokenHidden ? user.Timezone ?? "<none>" : null
);
}
@ -115,6 +125,7 @@ public class UserRendererService(
IEnumerable<Field> Fields,
Dictionary<Snowflake, User.CustomPreference> CustomPreferences,
IEnumerable<PrideFlagResponse> Flags,
int? UtcOffset,
[property: JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] UserRole Role,
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
IEnumerable<MemberRendererService.PartialMember>? Members,
@ -124,7 +135,8 @@ public class UserRendererService(
bool? MemberListHidden,
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] Instant? LastActive,
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Instant? LastSidReroll
Instant? LastSidReroll,
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? Timezone
);
public record AuthMethodResponse(