forked from gongxuegit/tiku-backend.net
feat: modularize external providers
This commit is contained in:
@@ -2,6 +2,8 @@ using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Tiku.Application.Catalog;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Application.Notifications;
|
||||
using Tiku.Application.Tenancy;
|
||||
using Tiku.Application.TenantAdmin;
|
||||
using Tiku.Domain.Catalog;
|
||||
using Tiku.Domain.Common;
|
||||
@@ -13,7 +15,10 @@ using Tiku.Infrastructure.Persistence;
|
||||
|
||||
namespace Tiku.Infrastructure.TenantAdmin;
|
||||
|
||||
public sealed class TenantAdminDirectService(TikuDbContext dbContext) : ITenantAdminDirectService
|
||||
public sealed class TenantAdminDirectService(
|
||||
TikuDbContext dbContext,
|
||||
ITenantExternalProviderConfigService providerConfigService,
|
||||
INotificationProvider notificationProvider) : ITenantAdminDirectService
|
||||
{
|
||||
private static readonly TenantAdminPermissionCatalogItem[] PermissionCatalog =
|
||||
[
|
||||
@@ -1099,42 +1104,39 @@ public sealed class TenantAdminDirectService(TikuDbContext dbContext) : ITenantA
|
||||
return new ContentManagementResult<TenantDomainItem>(ToDomainItem(item));
|
||||
}
|
||||
|
||||
public async Task<CatalogList<TenantAuthProviderItem>> GetAuthProvidersAsync(
|
||||
public async Task<CatalogList<TenantIdentityProviderItem>> GetAuthProvidersAsync(
|
||||
TenantAdminActor actor,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var items = await dbContext.TenantAuthProviders.AsNoTracking()
|
||||
.Where(item => item.TenantId == actor.TenantId)
|
||||
.OrderBy(item => item.CreatedAt)
|
||||
.Select(item => ToAuthProviderItem(item))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
return new CatalogList<TenantAuthProviderItem>(items);
|
||||
var items = await providerConfigService.GetProvidersAsync(
|
||||
actor.TenantId,
|
||||
TenantExternalProviderCapability.Identity,
|
||||
cancellationToken: cancellationToken);
|
||||
return new CatalogList<TenantIdentityProviderItem>(items.Select(ToAuthProviderItem).ToArray());
|
||||
}
|
||||
|
||||
public async Task<ContentManagementResult<TenantAuthProviderItem>> UpsertAuthProviderAsync(
|
||||
public async Task<ContentManagementResult<TenantIdentityProviderItem>> UpsertAuthProviderAsync(
|
||||
TenantAdminActor actor,
|
||||
UpsertTenantAuthProviderCommand command,
|
||||
UpsertTenantIdentityProviderCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(command.Provider);
|
||||
AssertNoSecrets(command.ConfigPublic, "config_public");
|
||||
var provider = command.Provider.Trim().ToLowerInvariant();
|
||||
var item = await dbContext.TenantAuthProviders.FirstOrDefaultAsync(
|
||||
authProvider => authProvider.TenantId == actor.TenantId && authProvider.Provider == provider,
|
||||
var item = await providerConfigService.UpsertProviderAsync(
|
||||
actor.TenantId,
|
||||
new UpsertTenantExternalProviderCommand(
|
||||
TenantExternalProviderCapability.Identity,
|
||||
command.Provider,
|
||||
ParseEnum(command.Status, TenantExternalProviderStatus.Disabled, "invalid_auth_provider_status"),
|
||||
command.DisplayName,
|
||||
command.SecretRef,
|
||||
command.Priority,
|
||||
command.ConfigPublic,
|
||||
JsonObjectOrDefault(default)),
|
||||
cancellationToken);
|
||||
var isNew = item is null;
|
||||
item ??= new TenantAuthProvider { TenantId = actor.TenantId, Provider = provider };
|
||||
item.Status = ParseEnum(command.Status, TenantAuthProviderStatus.Disabled, "invalid_auth_provider_status");
|
||||
item.DisplayName = Normalize(command.DisplayName);
|
||||
item.ConfigPublic = JsonObjectOrDefault(command.ConfigPublic);
|
||||
if (isNew)
|
||||
{
|
||||
dbContext.TenantAuthProviders.Add(item);
|
||||
}
|
||||
|
||||
await AddAuditAsync(actor, "tenant.auth_provider.upserted", "tenant_auth_providers", item.Id, cancellationToken);
|
||||
await AddAuditAsync(actor, "tenant.auth_provider.upserted", "tenant_external_providers", item.Id, cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return new ContentManagementResult<TenantAuthProviderItem>(ToAuthProviderItem(item));
|
||||
return new ContentManagementResult<TenantIdentityProviderItem>(ToAuthProviderItem(item));
|
||||
}
|
||||
|
||||
public async Task<CatalogList<TenantAdminBadgeItem>> GetBadgesAsync(
|
||||
@@ -1273,33 +1275,22 @@ public sealed class TenantAdminDirectService(TikuDbContext dbContext) : ITenantA
|
||||
}
|
||||
|
||||
var dedupeKey = $"badge:{grant.Id:N}";
|
||||
var notification = await dbContext.UserNotifications.FirstOrDefaultAsync(
|
||||
item =>
|
||||
item.TenantId == actor.TenantId &&
|
||||
item.UserId == command.UserId &&
|
||||
item.NotificationType == "badge_granted" &&
|
||||
item.DedupeKey == dedupeKey,
|
||||
await notificationProvider.UpsertInAppAsync(
|
||||
new InAppNotificationRequest(
|
||||
actor.TenantId,
|
||||
command.UserId,
|
||||
"badge_granted",
|
||||
NotificationSeverity.Success,
|
||||
$"获得勋章:{badge.Name}",
|
||||
Normalize(command.Note) ?? "管理员为你发放了一枚新的学习勋章。",
|
||||
actor.UserId,
|
||||
"查看勋章",
|
||||
"/profile?tab=badges",
|
||||
"user_badges",
|
||||
grant.Id,
|
||||
dedupeKey,
|
||||
JsonSerializer.SerializeToElement(new { badgeId = badge.Id, badgeName = badge.Name })),
|
||||
cancellationToken);
|
||||
notification ??= new UserNotification
|
||||
{
|
||||
TenantId = actor.TenantId,
|
||||
UserId = command.UserId,
|
||||
NotificationType = "badge_granted",
|
||||
DedupeKey = dedupeKey,
|
||||
CreatedBy = actor.UserId
|
||||
};
|
||||
notification.Severity = NotificationSeverity.Success;
|
||||
notification.Title = $"获得勋章:{badge.Name}";
|
||||
notification.Message = Normalize(command.Note) ?? "管理员为你发放了一枚新的学习勋章。";
|
||||
notification.ActionLabel = "查看勋章";
|
||||
notification.ActionPath = "/profile?tab=badges";
|
||||
notification.SourceType = "user_badges";
|
||||
notification.SourceId = grant.Id;
|
||||
notification.Metadata = JsonSerializer.SerializeToElement(new { badgeId = badge.Id, badgeName = badge.Name });
|
||||
if (dbContext.Entry(notification).State == EntityState.Detached)
|
||||
{
|
||||
dbContext.UserNotifications.Add(notification);
|
||||
}
|
||||
|
||||
await AddAuditAsync(actor, "tenant.badge.granted", "user_badges", grant.Id, cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
@@ -1346,35 +1337,22 @@ public sealed class TenantAdminDirectService(TikuDbContext dbContext) : ITenantA
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(command.Message);
|
||||
await AssertTenantMemberAsync(actor.TenantId, command.UserId, cancellationToken);
|
||||
|
||||
var item = !string.IsNullOrWhiteSpace(command.DedupeKey)
|
||||
? await dbContext.UserNotifications.FirstOrDefaultAsync(notification =>
|
||||
notification.TenantId == actor.TenantId &&
|
||||
notification.UserId == command.UserId &&
|
||||
notification.NotificationType == command.NotificationType &&
|
||||
notification.DedupeKey == command.DedupeKey,
|
||||
cancellationToken)
|
||||
: null;
|
||||
var isNew = item is null;
|
||||
item ??= new UserNotification
|
||||
{
|
||||
TenantId = actor.TenantId,
|
||||
UserId = command.UserId,
|
||||
CreatedBy = actor.UserId
|
||||
};
|
||||
item.NotificationType = command.NotificationType.Trim();
|
||||
item.Severity = ParseEnum(command.Severity, NotificationSeverity.Info, "invalid_notification_severity");
|
||||
item.Title = command.Title.Trim();
|
||||
item.Message = command.Message.Trim();
|
||||
item.ActionLabel = Normalize(command.ActionLabel);
|
||||
item.ActionPath = Normalize(command.ActionPath);
|
||||
item.SourceType = Normalize(command.SourceType);
|
||||
item.SourceId = command.SourceId;
|
||||
item.DedupeKey = Normalize(command.DedupeKey);
|
||||
item.Metadata = JsonObjectOrDefault(command.Metadata);
|
||||
if (isNew)
|
||||
{
|
||||
dbContext.UserNotifications.Add(item);
|
||||
}
|
||||
var item = await notificationProvider.UpsertInAppAsync(
|
||||
new InAppNotificationRequest(
|
||||
actor.TenantId,
|
||||
command.UserId,
|
||||
command.NotificationType,
|
||||
ParseEnum(command.Severity, NotificationSeverity.Info, "invalid_notification_severity"),
|
||||
command.Title,
|
||||
command.Message,
|
||||
actor.UserId,
|
||||
command.ActionLabel,
|
||||
command.ActionPath,
|
||||
command.SourceType,
|
||||
command.SourceId,
|
||||
command.DedupeKey,
|
||||
JsonObjectOrDefault(command.Metadata)),
|
||||
cancellationToken);
|
||||
|
||||
await AddAuditAsync(actor, "tenant.notification.upserted", "user_notifications", item.Id, cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
@@ -1941,13 +1919,15 @@ public sealed class TenantAdminDirectService(TikuDbContext dbContext) : ITenantA
|
||||
item.UpdatedAt);
|
||||
}
|
||||
|
||||
private static TenantAuthProviderItem ToAuthProviderItem(TenantAuthProvider item)
|
||||
private static TenantIdentityProviderItem ToAuthProviderItem(TenantExternalProviderItem item)
|
||||
{
|
||||
return new TenantAuthProviderItem(
|
||||
return new TenantIdentityProviderItem(
|
||||
item.Id,
|
||||
item.Provider,
|
||||
item.Status,
|
||||
item.DisplayName,
|
||||
item.SecretRef,
|
||||
item.Priority,
|
||||
item.ConfigPublic,
|
||||
item.CreatedAt,
|
||||
item.UpdatedAt);
|
||||
|
||||
Reference in New Issue
Block a user