Files
tiku-backend.net/Tiku.Infrastructure/Persistence/Configurations/ContentPlatformConfigurations.cs

159 lines
9.3 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Catalog;
using Tiku.Domain.Content;
using Tiku.Domain.Identity;
using Tiku.Domain.QuestionBanks;
using Tiku.Domain.Tenancy;
namespace Tiku.Infrastructure.Persistence.Configurations;
internal sealed class ContentAssetAccessEventConfiguration : IEntityTypeConfiguration<ContentAssetAccessEvent>
{
public void Configure(EntityTypeBuilder<ContentAssetAccessEvent> builder)
{
builder.ConfigureEntity("content_asset_access_events");
builder.HasAlternateKey(entity => new { entity.TenantId, entity.Id });
builder.Property(entity => entity.ActorRole).HasSnakeCaseEnum();
builder.Property(entity => entity.AccessType).HasSnakeCaseEnum();
builder.Property(entity => entity.Visibility).HasMaxLength(50);
builder.Property(entity => entity.AssetType).HasMaxLength(50);
builder.Property(entity => entity.StorageProvider).HasMaxLength(50);
builder.Property(entity => entity.Disposition).HasNullableSnakeCaseEnum();
builder.Property(entity => entity.SignatureMode).HasMaxLength(100);
builder.Property(entity => entity.Result).HasSnakeCaseEnum();
builder.Property(entity => entity.DenyCode).HasMaxLength(100);
builder.Property(entity => entity.IpAddress).HasMaxLength(100);
builder.Property(entity => entity.UserAgent).HasMaxLength(1024);
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()");
builder.HasIndex(entity => new { entity.TenantId, entity.AssetId, entity.CreatedAt });
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt })
.HasFilter("user_id is not null");
builder.HasIndex(entity => new { entity.TenantId, entity.AccessType, entity.Result, entity.CreatedAt });
builder.ToTable(table => table.HasCheckConstraint("ck_content_asset_access_events_expiry", "expires_in_seconds is null or expires_in_seconds > 0"));
builder.HasOne<Tenant>().WithMany().HasForeignKey(entity => entity.TenantId).OnDelete(DeleteBehavior.Cascade);
builder.HasOne<ContentAsset>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.AssetId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.SetNull);
}
}
internal sealed class ContentAssetSecurityScanEventConfiguration : IEntityTypeConfiguration<ContentAssetSecurityScanEvent>
{
public void Configure(EntityTypeBuilder<ContentAssetSecurityScanEvent> builder)
{
builder.ConfigureEntity("content_asset_security_scan_events");
builder.HasAlternateKey(entity => new { entity.TenantId, entity.Id });
builder.Property(entity => entity.Provider).HasMaxLength(100);
builder.Property(entity => entity.ScanStatus).HasSnakeCaseEnum();
builder.Property(entity => entity.RiskLevel).HasSnakeCaseEnum();
builder.Property(entity => entity.IssueCodes)
.HasColumnType("text[]")
.HasDefaultValueSql("'{}'::text[]");
builder.Property(entity => entity.Details).IsJson("{}");
builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()");
builder.HasIndex(entity => new { entity.TenantId, entity.AssetId, entity.CreatedAt });
builder.HasIndex(entity => new { entity.TenantId, entity.ScanStatus, entity.RiskLevel, entity.CreatedAt });
builder.HasOne<Tenant>().WithMany().HasForeignKey(entity => entity.TenantId).OnDelete(DeleteBehavior.Cascade);
builder.HasOne<ContentAsset>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.AssetId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class QuestionBankGrantConfiguration : IEntityTypeConfiguration<QuestionBankGrant>
{
public void Configure(EntityTypeBuilder<QuestionBankGrant> builder)
{
builder.ConfigureEntity("question_bank_grants");
builder.ConfigureTimestamps();
builder.Property(entity => entity.GrantScope).HasSnakeCaseEnum();
builder.Property(entity => entity.AllowedPlanCodes)
.HasColumnType("text[]")
.HasDefaultValueSql("'{}'::text[]");
builder.Property(entity => entity.AllowedTenantIds)
.HasColumnType("uuid[]")
.HasDefaultValueSql("'{}'::uuid[]");
builder.Property(entity => entity.AllowedRegionIds)
.HasColumnType("uuid[]")
.HasDefaultValueSql("'{}'::uuid[]");
builder.Property(entity => entity.AllowedSubjectIds)
.HasColumnType("uuid[]")
.HasDefaultValueSql("'{}'::uuid[]");
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.HasIndex(entity => new { entity.SourceQuestionBankId, entity.Status, entity.StartsAt, entity.ExpiresAt });
builder.HasIndex(entity => entity.AllowedTenantIds).HasMethod("gin");
builder.HasIndex(entity => entity.AllowedPlanCodes).HasMethod("gin");
builder.HasOne<QuestionBank>().WithMany()
.HasForeignKey(entity => entity.SourceQuestionBankId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.CreatedBy).OnDelete(DeleteBehavior.SetNull);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UpdatedBy).OnDelete(DeleteBehavior.SetNull);
}
}
internal sealed class TenantQuestionBankAdoptionConfiguration : IEntityTypeConfiguration<TenantQuestionBankAdoption>
{
public void Configure(EntityTypeBuilder<TenantQuestionBankAdoption> builder)
{
builder.ConfigureTenantEntity("tenant_question_bank_adoptions");
builder.ConfigureTimestamps();
builder.Property(entity => entity.AdoptionMode).HasSnakeCaseEnum();
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.SyncStatus).HasSnakeCaseEnum();
builder.Property(entity => entity.SourceSnapshot).IsJson("{}");
builder.Property(entity => entity.Metadata).IsJson("{}");
builder.HasIndex(entity => new { entity.TenantId, entity.SourceQuestionBankId }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.Status, entity.UpdatedAt });
builder.ToTable(table => table.HasCheckConstraint("ck_tenant_question_bank_adoptions_copied_count", "copied_question_count >= 0"));
builder.HasOne<QuestionBank>().WithMany()
.HasForeignKey(entity => entity.SourceQuestionBankId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne<QuestionBankGrant>().WithMany()
.HasForeignKey(entity => entity.GrantId)
.OnDelete(DeleteBehavior.SetNull);
builder.HasOne<QuestionBank>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.TargetQuestionBankId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<ContentEntry>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.TargetEntryId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<QuestionCollection>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.TargetCollectionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.CreatedBy).OnDelete(DeleteBehavior.SetNull);
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UpdatedBy).OnDelete(DeleteBehavior.SetNull);
}
}
internal sealed class AiRecommendationReportConfiguration : IEntityTypeConfiguration<AiRecommendationReport>
{
public void Configure(EntityTypeBuilder<AiRecommendationReport> builder)
{
builder.ConfigureTenantEntity("ai_recommendation_reports");
builder.ConfigureTimestamps();
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.Provider).HasMaxLength(100);
builder.Property(entity => entity.Model).HasMaxLength(100);
builder.Property(entity => entity.PromptVersion).HasMaxLength(100);
builder.Property(entity => entity.InputPayload).IsJson("{}");
builder.Property(entity => entity.ContextPayload).IsJson("{}");
builder.Property(entity => entity.ResultPayload).IsJson("{}");
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt });
builder.HasIndex(entity => new { entity.TenantId, entity.RegionId, entity.CreatedAt });
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
builder.HasOne<Region>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, entity.RegionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}