feat: Implement Authentik group synchronization and add confirmation dialogs for service management
This commit is contained in:
@@ -95,7 +95,7 @@ public class AuthentikService : IAuthentikService
|
||||
}
|
||||
|
||||
// ── 4. Create application linked to provider ──────────────────
|
||||
await CreateApplicationAsync(client, baseUrl, instanceAbbrev, slug, providerId, ct);
|
||||
await CreateApplicationAsync(client, baseUrl, instanceAbbrev, slug, providerId, instanceBaseUrl, ct);
|
||||
}
|
||||
|
||||
// ── 5. Ensure provider has a signing keypair (required for metadata) ──
|
||||
@@ -175,6 +175,62 @@ public class AuthentikService : IAuthentikService
|
||||
}).OrderBy(k => k.Name).ToList() ?? new();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<AuthentikGroupItem>> ListGroupsAsync(
|
||||
string? overrideUrl = null, string? overrideApiKey = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var (_, client) = await CreateAuthenticatedClientAsync(overrideUrl, overrideApiKey);
|
||||
|
||||
var groups = new List<AuthentikGroupItem>();
|
||||
var nextUrl = "/api/v3/core/groups/?page_size=200";
|
||||
|
||||
while (!string.IsNullOrEmpty(nextUrl))
|
||||
{
|
||||
var resp = await client.GetAsync(nextUrl, ct);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
|
||||
var body = await resp.Content.ReadAsStringAsync(ct);
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
var root = doc.RootElement;
|
||||
|
||||
if (root.TryGetProperty("results", out var results) && results.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
foreach (var g in results.EnumerateArray())
|
||||
{
|
||||
var pk = g.TryGetProperty("pk", out var pkProp) ? pkProp.GetString() ?? "" : "";
|
||||
var name = g.TryGetProperty("name", out var nProp) ? nProp.GetString() ?? "" : "";
|
||||
var memberCount = g.TryGetProperty("users_obj", out var usersObj) && usersObj.ValueKind == JsonValueKind.Array
|
||||
? usersObj.GetArrayLength()
|
||||
: (g.TryGetProperty("users", out var users) && users.ValueKind == JsonValueKind.Array
|
||||
? users.GetArrayLength()
|
||||
: 0);
|
||||
|
||||
// Skip Authentik built-in groups (authentik Admins, etc.)
|
||||
if (!string.IsNullOrEmpty(name) && !name.StartsWith("authentik ", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
groups.Add(new AuthentikGroupItem
|
||||
{
|
||||
Pk = pk,
|
||||
Name = name,
|
||||
MemberCount = memberCount,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle pagination
|
||||
nextUrl = root.TryGetProperty("pagination", out var pagination) &&
|
||||
pagination.TryGetProperty("next", out var nextProp) &&
|
||||
nextProp.ValueKind == JsonValueKind.Number
|
||||
? $"/api/v3/core/groups/?page_size=200&page={nextProp.GetInt32()}"
|
||||
: null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("[Authentik] Found {Count} group(s)", groups.Count);
|
||||
return groups.OrderBy(g => g.Name).ToList();
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// HTTP client setup
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@@ -640,7 +696,7 @@ public class AuthentikService : IAuthentikService
|
||||
private async Task CreateApplicationAsync(
|
||||
HttpClient client, string baseUrl,
|
||||
string abbrev, string slug, int providerId,
|
||||
CancellationToken ct)
|
||||
string instanceBaseUrl, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("[Authentik] Creating application '{Slug}' linked to provider {ProviderId}", slug, providerId);
|
||||
|
||||
@@ -649,6 +705,7 @@ public class AuthentikService : IAuthentikService
|
||||
["name"] = $"OTS Signs — {abbrev.ToUpperInvariant()}",
|
||||
["slug"] = slug,
|
||||
["provider"] = providerId,
|
||||
["meta_launch_url"] = instanceBaseUrl.TrimEnd('/'),
|
||||
};
|
||||
|
||||
var jsonBody = JsonSerializer.Serialize(payload);
|
||||
|
||||
Reference in New Issue
Block a user