using System.Net; using System.Text.Json; using Tiku.Domain.Catalog; using Tiku.Domain.Common; using Tiku.Domain.Content; using Tiku.Domain.QuestionBanks; using Tiku.Domain.Tenancy; namespace Tiku.IntegrationTests.Api; public sealed class AssetEndpointTests { [Fact] public async Task Content_assets_return_public_active_assets_by_default() { var tenantId = Guid.NewGuid(); var regionId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new Region { Id = regionId, TenantId = tenantId, Name = "测试地区" }, new ContentAsset { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, Title = "公开讲义", FileName = "handbook.pdf", AssetType = ContentAssetType.Pdf, StorageProvider = AssetStorageProvider.AliyunOss, Bucket = "tiku-assets", ObjectKey = $"{tenantId:N}/handbook.pdf", MimeType = "application/pdf", Visibility = ContentVisibility.Public, Status = ContentStatus.Active, SortOrder = 2 }, new ContentAsset { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, Title = "会员讲义", Visibility = ContentVisibility.Members, Status = ContentStatus.Active, SortOrder = 1 }, new ContentAsset { Id = Guid.NewGuid(), TenantId = tenantId, RegionId = regionId, Title = "归档讲义", Visibility = ContentVisibility.Public, Status = ContentStatus.Archived }); using var client = factory.CreateClient(); using var response = await client.GetAsync( $"/api/public/catalog/content-assets?tenantCode=master®ionId={regionId}&assetType=pdf"); var items = await ReadItemsAsync(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var item = Assert.Single(items); Assert.Equal("公开讲义", item.GetProperty("title").GetString()); Assert.Equal("AliyunOss", item.GetProperty("storageProvider").GetString()); } [Fact] public async Task Content_assets_can_include_locked_catalog_items_when_requested() { var tenantId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new ContentAsset { Id = Guid.NewGuid(), TenantId = tenantId, Title = "会员讲义", Visibility = ContentVisibility.Members, Status = ContentStatus.Active }); using var client = factory.CreateClient(); using var response = await client.GetAsync("/api/public/catalog/content-assets?tenantCode=master&includeLocked=true"); var items = await ReadItemsAsync(response); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("会员讲义", Assert.Single(items).GetProperty("title").GetString()); } [Fact] public async Task Images_filter_private_items_until_include_locked() { var tenantId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new ImageAsset { Id = Guid.NewGuid(), TenantId = tenantId, Title = "公开图", Category = "banner", IsPublic = true }, new ImageAsset { Id = Guid.NewGuid(), TenantId = tenantId, Title = "内部图", Category = "banner", IsPublic = false }); using var client = factory.CreateClient(); using var publicResponse = await client.GetAsync("/api/public/catalog/images?tenantCode=master&category=banner"); using var lockedResponse = await client.GetAsync("/api/public/catalog/images?tenantCode=master&category=banner&includeLocked=true"); Assert.Equal(["公开图"], (await ReadItemsAsync(publicResponse)).Select(item => item.GetProperty("title").GetString()!).ToArray()); var lockedTitles = (await ReadItemsAsync(lockedResponse)) .Select(item => item.GetProperty("title").GetString()!) .ToArray(); Assert.Equal(2, lockedTitles.Length); Assert.Contains("内部图", lockedTitles); Assert.Contains("公开图", lockedTitles); } [Fact] public async Task App_assets_support_asset_key_lookup() { var tenantId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new AppAsset { Id = Guid.NewGuid(), TenantId = tenantId, AssetKey = "logo", FileName = "logo.png" }, new AppAsset { Id = Guid.NewGuid(), TenantId = tenantId, AssetKey = "icon", FileName = "icon.png" }); using var client = factory.CreateClient(); using var response = await client.GetAsync("/api/public/catalog/app-assets?tenantCode=master&assetKey=logo"); var item = Assert.Single(await ReadItemsAsync(response)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("logo", item.GetProperty("assetKey").GetString()); } [Fact] public async Task Question_videos_include_video_explanation_summary() { var tenantId = Guid.NewGuid(); var questionId = Guid.NewGuid(); var videoId = Guid.NewGuid(); await using var factory = new ApiTestFactory(); await factory.SeedAsync( Tenant(tenantId, "master"), new Question { Id = questionId, TenantId = tenantId, Type = "choice", Status = QuestionStatus.Published }, new VideoExplanation { Id = videoId, TenantId = tenantId, Title = "解题视频", IsActive = true, SortOrder = 1 }, new QuestionVideo { Id = Guid.NewGuid(), TenantId = tenantId, QuestionId = questionId, VideoId = videoId, VideoType = QuestionVideoType.Specific }); using var client = factory.CreateClient(); using var response = await client.GetAsync($"/api/public/catalog/question-videos?tenantCode=master&questionId={questionId}"); var item = Assert.Single(await ReadItemsAsync(response)); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(questionId, item.GetProperty("questionId").GetGuid()); Assert.Equal("解题视频", item.GetProperty("video").GetProperty("title").GetString()); } private static Tenant Tenant(Guid id, string slug) { return new Tenant { Id = id, Slug = slug, Name = slug, Status = TenantStatus.Active, Metadata = JsonDefaults.Object() }; } private static async Task ReadItemsAsync(HttpResponseMessage response) { var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); return body.RootElement .GetProperty("items") .EnumerateArray() .Select(item => item.Clone()) .ToArray(); } }