diff --git a/DysonNetwork.Pass/Auth/AuthService.cs b/DysonNetwork.Pass/Auth/AuthService.cs index 32f004a..fa7c519 100644 --- a/DysonNetwork.Pass/Auth/AuthService.cs +++ b/DysonNetwork.Pass/Auth/AuthService.cs @@ -12,7 +12,8 @@ public class AuthService( IConfiguration config, IHttpClientFactory httpClientFactory, IHttpContextAccessor httpContextAccessor, - ICacheService cache + ICacheService cache, + ILogger logger ) { private HttpContext HttpContext => httpContextAccessor.HttpContext!; @@ -301,6 +302,49 @@ public class AuthService( } } + public async Task MigrateDeviceIdToClient() + { + logger.LogInformation("Migrating device IDs to clients..."); + + await using var transaction = await db.Database.BeginTransactionAsync(); + + try + { + var challenges = await db.AuthChallenges + .Where(c => c.DeviceId != null && c.ClientId == null) + .ToListAsync(); + var clients = challenges.GroupBy(c => c.DeviceId) + .Select(c => new AuthClient + { + DeviceId = c.Key!, + AccountId = c.First().AccountId, + DeviceName = c.First().UserAgent ?? string.Empty, + Platform = ClientPlatform.Unidentified + }) + .ToList(); + await db.AuthClients.AddRangeAsync(clients); + await db.SaveChangesAsync(); + + var clientsMap = clients.ToDictionary(c => c.DeviceId, c => c.Id); + foreach (var challenge in challenges.Where(challenge => challenge.ClientId == null && challenge.DeviceId != null)) + { + if (clientsMap.TryGetValue(challenge.DeviceId!, out var clientId)) + challenge.ClientId = clientId; + db.AuthChallenges.Update(challenge); + } + + await db.SaveChangesAsync(); + await transaction.CommitAsync(); + logger.LogInformation("Migrated {Count} device IDs to clients", challenges.Count); + } + catch + { + logger.LogError("Failed to migrate device IDs to clients"); + await transaction.RollbackAsync(); + throw; + } + } + // Helper methods for Base64Url encoding/decoding private static string Base64UrlEncode(byte[] data) { diff --git a/DysonNetwork.Pass/Handlers/ActionLogFlushHandler.cs b/DysonNetwork.Pass/Handlers/ActionLogFlushHandler.cs index d5e9f49..1534a64 100644 --- a/DysonNetwork.Pass/Handlers/ActionLogFlushHandler.cs +++ b/DysonNetwork.Pass/Handlers/ActionLogFlushHandler.cs @@ -1,6 +1,7 @@ using DysonNetwork.Pass.Account; using DysonNetwork.Shared.Cache; using EFCore.BulkExtensions; +using NodaTime; using Quartz; namespace DysonNetwork.Pass.Handlers; @@ -11,8 +12,13 @@ public class ActionLogFlushHandler(IServiceProvider serviceProvider) : IFlushHan { using var scope = serviceProvider.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); - - await db.BulkInsertAsync(items, config => config.ConflictOption = ConflictOption.Ignore); + + await db.BulkInsertAsync(items.Select(x => + { + x.CreatedAt = SystemClock.Instance.GetCurrentInstant(); + x.UpdatedAt = x.CreatedAt; + return x; + }), config => config.ConflictOption = ConflictOption.Ignore); } } diff --git a/DysonNetwork.Pass/Program.cs b/DysonNetwork.Pass/Program.cs index 15619dd..dfbd67e 100644 --- a/DysonNetwork.Pass/Program.cs +++ b/DysonNetwork.Pass/Program.cs @@ -1,4 +1,5 @@ using DysonNetwork.Pass; +using DysonNetwork.Pass.Auth; using DysonNetwork.Pass.Pages.Data; using DysonNetwork.Pass.Startup; using DysonNetwork.Shared.Http; @@ -44,6 +45,13 @@ using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); await db.Database.MigrateAsync(); + + _ = Task.Run(async () => + { + var migrationScope = app.Services.CreateScope(); + var migrationAuthService = migrationScope.ServiceProvider.GetRequiredService(); + await migrationAuthService.MigrateDeviceIdToClient(); + }); } // Configure application middleware pipeline