Files
tiku-backend.net/Tiku.Api/Controllers/CatalogController.cs

563 lines
25 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Tiku.Api.Contracts;
using Tiku.Api.Security;
using Tiku.Application.Assets;
using Tiku.Application.Catalog;
using Tiku.Application.Content;
using Tiku.Application.Learning;
using Tiku.Application.QuestionBanks;
using Tiku.Application.Security;
using Tiku.Application.StudyContent;
namespace Tiku.Api.Controllers;
[ApiController]
[Tags("学生端-认证目录")]
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
[Produces("application/json")]
[Route("api/student/catalog")]
public sealed class CatalogController(
ICatalogQueryService catalogQueryService,
IContentNavigationQueryService contentNavigationQueryService,
IQuestionBankQueryService questionBankQueryService,
IStudyContentQueryService studyContentQueryService,
IAssetQueryService assetQueryService,
ITenantContext currentTenant,
ILearningAccessService learningAccessService,
LearningActorResolver learningActorResolver) : ControllerBase
{
[HttpGet("regions")]
[EndpointSummary("查询可用地区")]
[ProducesResponseType<CatalogList<RegionCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<RegionCatalogItem>>> GetRegions(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetRegionsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("region-modules")]
[EndpointSummary("查询地区功能模块")]
[ProducesResponseType<CatalogList<RegionModuleCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<RegionModuleCatalogItem>>> GetRegionModules(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetRegionModulesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("module-nodes")]
[EndpointSummary("查询模块导航节点")]
[ProducesResponseType<CatalogList<ModuleNodeCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ModuleNodeCatalogItem>>> GetModuleNodes(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetModuleNodesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("schools")]
[EndpointSummary("查询院校目录")]
[ProducesResponseType<CatalogList<SchoolCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<SchoolCatalogItem>>> GetSchools(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetSchoolsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("majors")]
[EndpointSummary("查询专业目录")]
[ProducesResponseType<CatalogList<MajorCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<MajorCatalogItem>>> GetMajors(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetMajorsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("subjects")]
[EndpointSummary("查询科目目录")]
[ProducesResponseType<CatalogList<SubjectCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<SubjectCatalogItem>>> GetSubjects(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetSubjectsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("categories")]
[HttpGet("question-categories")]
[EndpointSummary("查询题目分类")]
[ProducesResponseType<CatalogList<CategoryCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<CategoryCatalogItem>>> GetCategories(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetCategoriesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("content-entries")]
[EndpointSummary("查询内容入口")]
[ProducesResponseType<CatalogList<ContentEntryCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ContentEntryCatalogItem>>> GetContentEntries(
[FromQuery] ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await contentNavigationQueryService.GetContentEntriesAsync(
await ToAuthorizedFilterAsync(query, cancellationToken),
cancellationToken));
}
[HttpGet("content-nodes")]
[EndpointSummary("查询内容导航节点")]
[ProducesResponseType<CatalogList<ContentNodeCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ContentNodeCatalogItem>>> GetContentNodes(
[FromQuery] ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await contentNavigationQueryService.GetContentNodesAsync(
await ToAuthorizedFilterAsync(query, cancellationToken),
cancellationToken));
}
[HttpGet("question-collections")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询可用题集")]
[ProducesResponseType<CatalogList<QuestionCollectionCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<QuestionCollectionCatalogItem>>> GetQuestionCollections(
[FromQuery] ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await contentNavigationQueryService.GetQuestionCollectionsAsync(
await ToAuthorizedFilterAsync(query, cancellationToken),
cancellationToken));
}
[HttpGet("question-collections/questions")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询题集内题目")]
[ProducesResponseType<CatalogList<CollectionQuestionCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<CollectionQuestionCatalogItem>>> GetCollectionQuestions(
[FromQuery] ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await contentNavigationQueryService.GetCollectionQuestionsAsync(
await ToAuthorizedFilterAsync(query, cancellationToken),
cancellationToken));
}
[HttpGet("practice-blueprints")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询练习蓝图")]
[ProducesResponseType<CatalogList<PracticeBlueprintCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<PracticeBlueprintCatalogItem>>> GetPracticeBlueprints(
[FromQuery] ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await contentNavigationQueryService.GetPracticeBlueprintsAsync(
await ToAuthorizedFilterAsync(query, cancellationToken),
cancellationToken));
}
[HttpGet("question-banks")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询题库列表")]
[ProducesResponseType<CatalogList<QuestionBankCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<QuestionBankCatalogItem>>> GetQuestionBanks(
[FromQuery] QuestionBankQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await questionBankQueryService.GetQuestionBanksAsync(
await ToAuthorizedFilterAsync(query, null, cancellationToken),
cancellationToken));
}
[HttpGet("questions")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询已发布题目")]
[EndpointDescription("支持按题库、科目、分类、模块节点、内容入口、内容节点、题集或题目 ID 列表筛选。")]
[ProducesResponseType<CatalogList<QuestionCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<QuestionCatalogItem>>> GetQuestions(
[FromQuery] QuestionBankQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await questionBankQueryService.GetQuestionsAsync(
await ToAuthorizedFilterAsync(query, null, cancellationToken),
cancellationToken));
}
[HttpGet("questions/{questionId:guid}")]
[RequireSaasFeature(SaasFeatureCatalog.Practice)]
[EndpointSummary("查询题目详情")]
[ProducesResponseType<QuestionCatalogItem>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<QuestionCatalogItem>> GetQuestion(
Guid questionId,
[FromQuery] QuestionBankQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await questionBankQueryService.GetQuestionAsync(
await ToAuthorizedFilterAsync(query, questionId, cancellationToken),
cancellationToken));
}
[HttpGet("vocabulary-units")]
[RequireSaasFeature(SaasFeatureCatalog.Vocabulary)]
[EndpointSummary("查询词汇单元")]
[ProducesResponseType<CatalogList<VocabularyUnitCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<VocabularyUnitCatalogItem>>> GetVocabularyUnits(
[FromQuery] StudyContentQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await studyContentQueryService.GetVocabularyUnitsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("vocabulary-words")]
[RequireSaasFeature(SaasFeatureCatalog.Vocabulary)]
[EndpointSummary("查询词汇单词")]
[ProducesResponseType<CatalogList<VocabularyWordCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<VocabularyWordCatalogItem>>> GetVocabularyWords(
[FromQuery] StudyContentQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await studyContentQueryService.GetVocabularyWordsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("handbook-subjects")]
[RequireSaasFeature(SaasFeatureCatalog.Handbook)]
[EndpointSummary("查询知识手册科目")]
[ProducesResponseType<CatalogList<HandbookSubjectCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<HandbookSubjectCatalogItem>>> GetHandbookSubjects(
[FromQuery] StudyContentQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await studyContentQueryService.GetHandbookSubjectsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("handbook-chapters")]
[RequireSaasFeature(SaasFeatureCatalog.Handbook)]
[EndpointSummary("查询知识手册章节")]
[ProducesResponseType<CatalogList<HandbookChapterCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<HandbookChapterCatalogItem>>> GetHandbookChapters(
[FromQuery] StudyContentQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await studyContentQueryService.GetHandbookChaptersAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("handbook-entries")]
[RequireSaasFeature(SaasFeatureCatalog.Handbook)]
[EndpointSummary("查询知识手册条目")]
[ProducesResponseType<CatalogList<HandbookEntryCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<HandbookEntryCatalogItem>>> GetHandbookEntries(
[FromQuery] StudyContentQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await studyContentQueryService.GetHandbookEntriesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("content-assets")]
[EndpointSummary("查询内容资源")]
[ProducesResponseType<CatalogList<ContentAssetCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ContentAssetCatalogItem>>> GetContentAssets(
[FromQuery] AssetQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await assetQueryService.GetContentAssetsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("images")]
[EndpointSummary("查询图片资源")]
[ProducesResponseType<CatalogList<ImageAssetCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ImageAssetCatalogItem>>> GetImages(
[FromQuery] AssetQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await assetQueryService.GetImagesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("app-assets")]
[EndpointSummary("查询应用资源")]
[ProducesResponseType<CatalogList<AppAssetCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<AppAssetCatalogItem>>> GetAppAssets(
[FromQuery] AssetQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await assetQueryService.GetAppAssetsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("video-explanations")]
[RequireSaasFeature(SaasFeatureCatalog.Video)]
[EndpointSummary("查询视频讲解")]
[ProducesResponseType<CatalogList<VideoExplanationCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<VideoExplanationCatalogItem>>> GetVideoExplanations(
[FromQuery] AssetQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await assetQueryService.GetVideoExplanationsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("question-videos")]
[RequireSaasFeature(SaasFeatureCatalog.Video)]
[EndpointSummary("查询题目关联视频")]
[ProducesResponseType<CatalogList<QuestionVideoCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<QuestionVideoCatalogItem>>> GetQuestionVideos(
[FromQuery] AssetQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await assetQueryService.GetQuestionVideosAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("banners")]
[RequireSaasFeature(SaasFeatureCatalog.SiteContent)]
[EndpointSummary("查询首页横幅")]
[ProducesResponseType<CatalogList<BannerCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<BannerCatalogItem>>> GetBanners(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetBannersAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("faqs")]
[RequireSaasFeature(SaasFeatureCatalog.SiteContent)]
[EndpointSummary("查询常见问题")]
[ProducesResponseType<CatalogList<FaqCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<FaqCatalogItem>>> GetFaqs(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetFaqsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("announcements")]
[RequireSaasFeature(SaasFeatureCatalog.SiteContent)]
[EndpointSummary("查询公告")]
[ProducesResponseType<CatalogList<AnnouncementCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<AnnouncementCatalogItem>>> GetAnnouncements(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetAnnouncementsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("exam-dates")]
[RequireSaasFeature(SaasFeatureCatalog.SiteContent)]
[EndpointSummary("查询考试日期")]
[ProducesResponseType<CatalogList<ExamDateCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ExamDateCatalogItem>>> GetExamDates(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetExamDatesAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("products")]
[RequireSaasFeature(SaasFeatureCatalog.StudentStore)]
[EndpointSummary("查询可购买产品")]
[ProducesResponseType<CatalogList<ProductCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<ProductCatalogItem>>> GetProducts(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetProductsAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
[HttpGet("svip-plans")]
[RequireSaasFeature(SaasFeatureCatalog.StudentStore)]
[EndpointSummary("查询 SVIP 套餐")]
[ProducesResponseType<CatalogList<SvipPlanCatalogItem>>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
public async Task<ActionResult<CatalogList<SvipPlanCatalogItem>>> GetSvipPlans(
[FromQuery] CatalogQueryDto query,
CancellationToken cancellationToken)
{
return Ok(await catalogQueryService.GetSvipPlansAsync(
query.ToFilter(await ResolveTenantIdAsync(query, cancellationToken)),
cancellationToken));
}
private async Task<Guid> ResolveTenantIdAsync(
CatalogQueryDto query,
CancellationToken cancellationToken)
{
var actor = learningActorResolver.Resolve();
var snapshot = await learningAccessService.GetSnapshotAsync(actor, cancellationToken);
query.RegionId = ResolveAuthorizedRegion(query.RegionId, snapshot);
query.AllowedRegionIds = snapshot.LicensedRegionIds.ToArray();
return currentTenant.TenantId ?? throw new TenantNotFoundException();
}
private async Task<ContentNavigationFilter> ToAuthorizedFilterAsync(
ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
var actor = learningActorResolver.Resolve();
var snapshot = await learningAccessService.GetSnapshotAsync(actor, cancellationToken);
return query.ToFilter(actor.TenantId) with
{
RegionId = ResolveAuthorizedRegion(query.RegionId, snapshot),
AllowedContentSliceIds = snapshot.ContentSliceIds.ToArray(),
AllowedRegionIds = snapshot.LicensedRegionIds.ToArray()
};
}
private async Task<QuestionBankFilter> ToAuthorizedFilterAsync(
QuestionBankQueryDto query,
Guid? questionId,
CancellationToken cancellationToken)
{
var actor = learningActorResolver.Resolve();
var snapshot = await learningAccessService.GetSnapshotAsync(actor, cancellationToken);
return query.ToFilter(actor.TenantId, questionId) with
{
RegionId = ResolveAuthorizedRegion(query.RegionId, snapshot),
AllowedContentSliceIds = snapshot.ContentSliceIds.ToArray()
};
}
private static Guid? ResolveAuthorizedRegion(Guid? requestedRegionId, LearningAccessSnapshot snapshot)
{
if (requestedRegionId.HasValue &&
requestedRegionId != snapshot.TargetRegionId &&
!snapshot.LicensedRegionIds.Contains(requestedRegionId.Value))
throw new LearningAccessException(
"catalog_region_not_entitled",
"The requested catalog region is outside the current learning grant.");
return requestedRegionId ?? snapshot.TargetRegionId ??
(snapshot.LicensedRegionIds.Count == 1 ? snapshot.LicensedRegionIds.Single() : null);
}
private Task<Guid> ResolveTenantIdAsync(
ContentNavigationQueryDto query,
CancellationToken cancellationToken)
{
return ResolveTenantIdAsync(
new CatalogQueryDto
{
TenantCode = query.TenantCode
},
cancellationToken);
}
private Task<Guid> ResolveTenantIdAsync(
QuestionBankQueryDto query,
CancellationToken cancellationToken)
{
return ResolveTenantIdAsync(
new CatalogQueryDto
{
TenantCode = query.TenantCode
},
cancellationToken);
}
private async Task<Guid> ResolveTenantIdAsync(
StudyContentQueryDto query,
CancellationToken cancellationToken)
{
var actor = learningActorResolver.Resolve();
var snapshot = await learningAccessService.GetSnapshotAsync(actor, cancellationToken);
query.RegionId = ResolveAuthorizedRegion(query.RegionId, snapshot);
query.AllowedRegionIds = snapshot.LicensedRegionIds.ToArray();
return currentTenant.TenantId ?? throw new TenantNotFoundException();
}
private async Task<Guid> ResolveTenantIdAsync(
AssetQueryDto query,
CancellationToken cancellationToken)
{
var actor = learningActorResolver.Resolve();
var snapshot = await learningAccessService.GetSnapshotAsync(actor, cancellationToken);
query.RegionId = ResolveAuthorizedRegion(query.RegionId, snapshot);
query.AllowedRegionIds = snapshot.LicensedRegionIds.ToArray();
return currentTenant.TenantId ?? throw new TenantNotFoundException();
}
}
public sealed class TenantNotFoundException : Exception
{
public TenantNotFoundException()
: base("Tenant was not found.")
{
}
}