From 78656d71655db2188393e5af17e32dd0da236241 Mon Sep 17 00:00:00 2001 From: Rhywden Date: Wed, 26 Aug 2026 06:40:16 +0200 Subject: [PATCH] Bugfix for AdminView --- Wollmilchsau/Store/AdminStore/AdminEffects.cs | 85 ++++++++++++++----- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/Wollmilchsau/Store/AdminStore/AdminEffects.cs b/Wollmilchsau/Store/AdminStore/AdminEffects.cs index 22aa723..b022062 100644 --- a/Wollmilchsau/Store/AdminStore/AdminEffects.cs +++ b/Wollmilchsau/Store/AdminStore/AdminEffects.cs @@ -129,9 +129,10 @@ public sealed class AdminEffects(IMoodleService moodleService, ILdapService ldap { await cache.RemoveAsync(MoodleUsersCacheKey); } - catch (RedisException) + catch (RedisException exception) { - ReportMoodleDeletionFailure(dispatcher, "Moodle deletion did not start because the cache could not be invalidated."); + dispatcher.Dispatch(new MoodleUsersDeletionFailed()); + snackbar.Add($"Moodle deletion did not start because the cache could not be invalidated: {exception.Message}", Severity.Error); return; } @@ -162,37 +163,83 @@ public sealed class AdminEffects(IMoodleService moodleService, ILdapService ldap await moodleService.DeleteUsers(userIds); return true; } - catch (HttpRequestException) + catch (HttpRequestException exception) { - ReportMoodleDeletionFailure(dispatcher, deletedUserCount, totalUserCount); + await ReportMoodleDeletionFailure(dispatcher, exception, userIds, deletedUserCount, totalUserCount); } - catch (InvalidOperationException) + catch (InvalidOperationException exception) { - ReportMoodleDeletionFailure(dispatcher, deletedUserCount, totalUserCount); + await ReportMoodleDeletionFailure(dispatcher, exception, userIds, deletedUserCount, totalUserCount); } - catch (TaskCanceledException) + catch (TaskCanceledException exception) { - ReportMoodleDeletionFailure(dispatcher, deletedUserCount, totalUserCount); + await ReportMoodleDeletionFailure(dispatcher, exception, userIds, deletedUserCount, totalUserCount); } - catch (JsonException) + catch (JsonException exception) { - ReportMoodleDeletionFailure(dispatcher, deletedUserCount, totalUserCount); + await ReportMoodleDeletionFailure(dispatcher, exception, userIds, deletedUserCount, totalUserCount); } return false; } - private void ReportMoodleDeletionFailure(IDispatcher dispatcher, int deletedUserCount, int totalUserCount) - { - ReportMoodleDeletionFailure( - dispatcher, - $"Moodle deletion stopped after deleting {deletedUserCount} of {totalUserCount} user(s). Later users were not processed."); - } - - private void ReportMoodleDeletionFailure(IDispatcher dispatcher, string message) + private async Task ReportMoodleDeletionFailure( + IDispatcher dispatcher, + Exception exception, + IReadOnlyCollection failedUserIds, + int deletedUserCount, + int totalUserCount) { dispatcher.Dispatch(new MoodleUsersDeletionFailed()); - snackbar.Add(message, Severity.Error); + + var reconciliationMessage = await ReconcileMoodleUsersAfterDeletionFailure(dispatcher, failedUserIds); + snackbar.Add( + $"Moodle deletion stopped after confirming {deletedUserCount} of {totalUserCount} user(s). Reason: {exception.Message}.{reconciliationMessage}", + Severity.Error); + } + + private async Task ReconcileMoodleUsersAfterDeletionFailure( + IDispatcher dispatcher, + IReadOnlyCollection failedUserIds) + { + try + { + var users = await moodleService.GetAllUsers(); + dispatcher.Dispatch(new SetMoodleUsers(users)); + + try + { + await cache.SetStringAsync( + MoodleUsersCacheKey, + JsonSerializer.Serialize(users), + new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(10) }); + } + catch (RedisException exception) + { + return $" The user list was refreshed from Moodle, but Redis could not be updated: {exception.Message}"; + } + + var deletedFromFailedRequest = failedUserIds.Count(userId => !users.Any(user => user.Id == userId)); + return deletedFromFailedRequest == 0 + ? " The user list was refreshed from Moodle." + : $" The user list was refreshed from Moodle; {deletedFromFailedRequest} user(s) from the failed request were deleted server-side."; + } + catch (HttpRequestException exception) + { + return $" The user list could not be refreshed: {exception.Message}"; + } + catch (InvalidOperationException exception) + { + return $" The user list could not be refreshed: {exception.Message}"; + } + catch (TaskCanceledException exception) + { + return $" The user list could not be refreshed: {exception.Message}"; + } + catch (JsonException exception) + { + return $" The user list could not be refreshed: {exception.Message}"; + } } [EffectMethod]