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.Learning; using Tiku.Domain.Operations; using Tiku.Domain.Tenancy; using Tiku.Infrastructure.Security; using Tiku.Infrastructure.Tenancy; namespace Tiku.Infrastructure.TenantAdmin; internal sealed class TenantDomainProviderService(TenantAdminServiceDependencies dependencies) : TenantAdminServiceBase(dependencies), ITenantDomainProviderService { public async Task> GetDomainsAsync( TenantAdminActor actor, CancellationToken cancellationToken = default) { await RequireAllDataScopeAsync(actor, cancellationToken); var items = await tenancyPersistence.TenantDomains.AsNoTracking() .Where(item => item.TenantId == actor.TenantId) .OrderByDescending(item => item.IsPrimary) .ThenBy(item => item.CreatedAt) .Select(item => ToDomainItem(item)) .ToArrayAsync(cancellationToken); return new CatalogList(items); } public async Task> CreateDomainAsync( TenantAdminActor actor, CreateTenantDomainCommand command, CancellationToken cancellationToken = default) { await RequireAllDataScopeAsync(actor, cancellationToken); TenantDomain generated; try { generated = TenantDomainProvisioning.CreatePrimary(actor.TenantId, command.Host); } catch (ArgumentException exception) { throw new TenantAdminDirectException(exception.Message, "invalid_domain_host"); } var host = generated.Host; if (command.IsPrimary) { var primaryDomains = await tenancyPersistence.TenantDomains .Where(item => item.TenantId == actor.TenantId && item.IsPrimary) .ToArrayAsync(cancellationToken); foreach (var domain in primaryDomains) domain.IsPrimary = false; } var item = new TenantDomain { TenantId = actor.TenantId, Host = host, DomainType = ParseEnum(command.DomainType, TenantDomainType.Custom, "invalid_domain_type"), Status = TenantDomainStatus.Pending, IsPrimary = command.IsPrimary, VerificationToken = generated.VerificationToken }; tenancyPersistence.TenantDomains.Add(item); await AddAuditAsync(actor, "tenant.domain.created", "tenant_domains", item.Id, cancellationToken); await unitOfWork.SaveChangesAsync(cancellationToken); return new ContentManagementResult(ToDomainItem(item)); } public async Task> GetAuthProvidersAsync( TenantAdminActor actor, CancellationToken cancellationToken = default) { await RequireAllDataScopeAsync(actor, cancellationToken); var items = await providerConfigService.GetProvidersAsync( actor.TenantId, TenantExternalProviderCapability.Identity, cancellationToken: cancellationToken); return new CatalogList(items.Select(ToAuthProviderItem).ToArray()); } public async Task> UpsertAuthProviderAsync( TenantAdminActor actor, UpsertTenantIdentityProviderCommand command, CancellationToken cancellationToken = default) { await RequireAllDataScopeAsync(actor, cancellationToken); ArgumentException.ThrowIfNullOrWhiteSpace(command.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); await AddAuditAsync(actor, "tenant.auth_provider.upserted", "tenant_external_providers", item.Id, cancellationToken); await unitOfWork.SaveChangesAsync(cancellationToken); return new ContentManagementResult(ToAuthProviderItem(item)); } }