diff --git a/Cajetan.OF-DL/Services/CajetanApiService.cs b/Cajetan.OF-DL/Services/CajetanApiService.cs index 79e7d52..fb4217a 100644 --- a/Cajetan.OF-DL/Services/CajetanApiService.cs +++ b/Cajetan.OF-DL/Services/CajetanApiService.cs @@ -52,6 +52,91 @@ public class CajetanApiService(IAuthService authService, IConfigService configSe return null; } + public async Task> GetUsersWithProgressAsync(string typeDisplay, string endpoint, string? typeParam, bool offsetByCount) + { + Dictionary usersOfType = await _eventHandler.WithStatusAsync( + statusMessage: $"Getting {typeDisplay} Users", + work: FetchAsync + ); + + return usersOfType; + + async Task> FetchAsync(IStatusReporter statusReporter) + { + Dictionary users = []; + + int limit = 50; + int offset = 0; + bool includeRestricted = true; + + Dictionary getParams = new() + { + ["format"] = "infinite", + ["limit"] = limit.ToString(), + ["offset"] = offset.ToString() + }; + + if (!string.IsNullOrWhiteSpace(typeParam)) + getParams["type"] = typeParam; + + try + { + Log.Debug("Calling GetUsersWithProgress"); + + HttpClient client = GetHttpClient(); + + bool isLastLoop = false; + while (true) + { + string? body = await BuildHeaderAndExecuteRequests(getParams, endpoint, client); + + if (string.IsNullOrWhiteSpace(body)) + break; + + SubscriptionDtos.SubscriptionsDto? subscriptions = DeserializeJson(body, s_mJsonSerializerSettings); + + if (subscriptions?.List is null) + break; + + foreach (SubscriptionDtos.ListItemDto item in subscriptions.List) + { + if (string.IsNullOrWhiteSpace(item?.Username)) + continue; + + if (users.ContainsKey(item.Username)) + continue; + + bool isRestricted = item.IsRestricted ?? false; + bool isRestrictedButAllowed = isRestricted && includeRestricted; + + if (!isRestricted || isRestrictedButAllowed) + users.Add(item.Username, item.Id); + } + + statusReporter.ReportStatus($"[blue]Getting {typeDisplay} Users\n[/] [blue]Found {users.Count}[/]"); + + if (isLastLoop) + break; + + if (!subscriptions.HasMore || subscriptions.List.Count == 0) + isLastLoop = true; + + offset += offsetByCount + ? subscriptions.List.Count + : limit; + + getParams["offset"] = offset.ToString(); + } + } + catch (Exception ex) + { + ExceptionLoggerHelper.LogException(ex); + } + + return users; + } + } + public new async Task GetMessages(string endpoint, string folder, IStatusReporter statusReporter) { (bool couldExtract, long userId) = ExtractUserId(endpoint); diff --git a/Cajetan.OF-DL/Worker.cs b/Cajetan.OF-DL/Worker.cs index cd93c8a..ab4d71f 100644 --- a/Cajetan.OF-DL/Worker.cs +++ b/Cajetan.OF-DL/Worker.cs @@ -225,7 +225,29 @@ internal class Worker(IServiceProvider serviceProvider) private async Task OutputBlockedUsersAsync() { + const string OUTPUT_FILE_BLOCKED = "blocked-users.json"; + const string OUTPUT_FILE_EXPIRED = "expired-users.json"; + await GetUsersAsync("Blocked", "/users/blocked", OUTPUT_FILE_BLOCKED); + await GetUsersAsync("Expired", "/subscriptions/subscribes", OUTPUT_FILE_EXPIRED, typeParam: "expired", offsetByCount: false); + + async Task GetUsersAsync(string typeDisplay, string uri, string outputFile, string? typeParam = null, bool offsetByCount = true) + { + Dictionary users = await _apiService.GetUsersWithProgressAsync(typeDisplay, uri, typeParam, offsetByCount); + + Console.WriteLine(); + + if (users is null || users.Count == 0) + { + AnsiConsole.Markup($"[green]No {typeDisplay} Users found.\n[/]"); + } + else + { + AnsiConsole.Markup($"[green]Found {users.Count} {typeDisplay} Users, saving to '{outputFile}'\n[/]"); + string json = JsonConvert.SerializeObject(users, Formatting.Indented); + await File.WriteAllTextAsync(outputFile, json); + } + } } private async Task UpdateUserInfoAsync()