Foxnouns.NET/migrators/NetImporter/ImportUser.cs

192 lines
5.8 KiB
C#

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Database.Models;
using Microsoft.EntityFrameworkCore;
using NodaTime;
using NodaTime.Extensions;
using Serilog;
namespace NetImporter;
public static class Users
{
public static async Task ImportUsers(string filename)
{
await using var db = await NetImporter.GetContextAsync();
await db.Database.ExecuteSqlRawAsync("SELECT 1");
var stopwatch = new Stopwatch();
stopwatch.Start();
var users = NetImporter
.ReadFromFile<ImportUser>(filename)
.Output.Select(ConvertUser)
.ToList();
db.AddRange(users);
await db.SaveChangesAsync();
stopwatch.Stop();
Log.Information(
"Imported {Count} users in {Duration}",
users.Count,
stopwatch.ElapsedDuration()
);
}
private static User ConvertUser(ImportUser oldUser)
{
var user = new User
{
Id = oldUser.Id,
Username = oldUser.Username,
DisplayName = oldUser.DisplayName,
Bio = oldUser.Bio,
MemberTitle = oldUser.MemberTitle,
LastActive = oldUser.LastActive.ToInstant(),
Avatar = oldUser.AvatarHash,
Links = oldUser.Links ?? [],
Role = oldUser.ParseRole(),
Deleted = oldUser.Deleted,
DeletedAt = oldUser.DeletedAt?.ToInstant(),
DeletedBy = null,
};
if (oldUser is { DiscordId: not null, DiscordUsername: not null })
{
user.AuthMethods.Add(
new AuthMethod
{
Id = SnowflakeGenerator.Instance.GenerateSnowflake(),
AuthType = AuthType.Discord,
RemoteId = oldUser.DiscordId,
RemoteUsername = oldUser.DiscordUsername,
}
);
}
if (oldUser is { TumblrId: not null, TumblrUsername: not null })
{
user.AuthMethods.Add(
new AuthMethod
{
Id = SnowflakeGenerator.Instance.GenerateSnowflake(),
AuthType = AuthType.Tumblr,
RemoteId = oldUser.TumblrId,
RemoteUsername = oldUser.TumblrUsername,
}
);
}
if (oldUser is { GoogleId: not null, GoogleUsername: not null })
{
user.AuthMethods.Add(
new AuthMethod
{
Id = SnowflakeGenerator.Instance.GenerateSnowflake(),
AuthType = AuthType.Google,
RemoteId = oldUser.GoogleId,
RemoteUsername = oldUser.GoogleUsername,
}
);
}
// Convert all custom preference UUIDs to snowflakes
var prefMapping = new Dictionary<string, Snowflake>();
foreach (var (key, value) in oldUser.CustomPreferences)
{
var newKey = SnowflakeGenerator.Instance.GenerateSnowflake();
prefMapping[key] = newKey;
user.CustomPreferences[newKey] = value;
}
foreach (var name in oldUser.Names ?? [])
{
user.Names.Add(
new FieldEntry
{
Value = name.Value,
Status = prefMapping.TryGetValue(name.Status, out var newStatus)
? newStatus.ToString()
: name.Status,
}
);
}
foreach (var pronoun in oldUser.Pronouns ?? [])
{
user.Pronouns.Add(
new Pronoun
{
Value = pronoun.Value,
DisplayText = pronoun.DisplayText,
Status = prefMapping.TryGetValue(pronoun.Status, out var newStatus)
? newStatus.ToString()
: pronoun.Status,
}
);
}
foreach (var field in oldUser.Fields ?? [])
{
var entries = field
.Entries.Select(entry => new FieldEntry
{
Value = entry.Value,
Status = prefMapping.TryGetValue(entry.Status, out var newStatus)
? newStatus.ToString()
: entry.Status,
})
.ToList();
user.Fields.Add(new Field { Name = field.Name, Entries = entries.ToArray() });
}
Log.Debug("Converted user {UserId}", oldUser.Id);
return user;
}
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")]
private record ImportUser(
Snowflake Id,
string Sid,
string Username,
string? DisplayName,
string? Bio,
string? MemberTitle,
OffsetDateTime LastActive,
string? AvatarHash,
string[]? Links,
FieldEntry[]? Names,
Pronoun[]? Pronouns,
Field[]? Fields,
string? DiscordId,
string? DiscordUsername,
string? FediverseId,
string? FediverseUsername,
long? FediverseAppId,
string? TumblrId,
string? TumblrUsername,
string? GoogleId,
string? GoogleUsername,
bool MemberListHidden,
string? Timezone,
string Role,
bool Deleted,
OffsetDateTime? DeletedAt,
string? DeleteReason,
Dictionary<string, User.CustomPreference> CustomPreferences
)
{
public UserRole ParseRole() =>
Role switch
{
"USER" => UserRole.User,
"MODERATOR" => UserRole.Moderator,
"ADMIN" => UserRole.Admin,
_ => UserRole.User,
};
}
}