forked from gongxuegit/tiku-backend.net
feat: migrate direct tenant content and learning endpoints
This commit is contained in:
@@ -112,6 +112,83 @@ public sealed class AssetUploadConfirmDto
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UpsertAssetDto
|
||||
{
|
||||
public Guid? AssetId { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? AssetKey { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Category { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
public string? CdnUrl { get; set; }
|
||||
public bool? IsPublic { get; set; }
|
||||
public string? AssetType { get; set; }
|
||||
public string? Visibility { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? Provider { get; set; }
|
||||
public string? Bucket { get; set; }
|
||||
public string? ObjectKey { get; set; }
|
||||
public string? MimeType { get; set; }
|
||||
public long? FileSizeBytes { get; set; }
|
||||
public string? ChecksumSha256 { get; set; }
|
||||
public string? PreviewUrl { get; set; }
|
||||
public string? PreviewObjectKey { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertAssetCommand ToCommand()
|
||||
{
|
||||
return new UpsertAssetCommand(
|
||||
AssetId,
|
||||
RegionId,
|
||||
SubjectId,
|
||||
CategoryId,
|
||||
ContentNodeId,
|
||||
LegacyId,
|
||||
AssetKey,
|
||||
Title,
|
||||
Category,
|
||||
Description,
|
||||
FileName,
|
||||
CdnUrl,
|
||||
IsPublic,
|
||||
AssetType,
|
||||
Visibility,
|
||||
Status,
|
||||
Provider,
|
||||
Bucket,
|
||||
ObjectKey,
|
||||
MimeType,
|
||||
FileSizeBytes,
|
||||
ChecksumSha256,
|
||||
PreviewUrl,
|
||||
PreviewObjectKey,
|
||||
Order,
|
||||
AccessRules,
|
||||
Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssetAccessSignDto
|
||||
{
|
||||
[Required]
|
||||
public Guid AssetId { get; set; }
|
||||
|
||||
[Range(60, 3600)]
|
||||
public int? ExpiresInSeconds { get; set; }
|
||||
|
||||
public AssetAccessSignCommand ToCommand()
|
||||
{
|
||||
return new AssetAccessSignCommand(AssetId, ExpiresInSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssetManagementQueryDto
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
@@ -156,6 +233,20 @@ public sealed class AssetManagementQueryDto
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssetEventQueryDto
|
||||
{
|
||||
public Guid? AssetId { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
[Range(1, 500)]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
public AssetEventFilter ToFilter()
|
||||
{
|
||||
return new AssetEventFilter(AssetId, UserId, Limit);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ImportJobQueryDto
|
||||
{
|
||||
[StringLength(50)]
|
||||
|
||||
449
Tiku.Api/Contracts/DirectContentDtos.cs
Normal file
449
Tiku.Api/Contracts/DirectContentDtos.cs
Normal file
@@ -0,0 +1,449 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Api.Contracts;
|
||||
|
||||
public sealed class DirectContentQueryDto
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public Guid? ParentId { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? ChapterId { get; set; }
|
||||
public Guid? UnitId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public Guid? MajorId { get; set; }
|
||||
public Guid? QuestionId { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string? Status { get; set; }
|
||||
|
||||
[StringLength(200)]
|
||||
public string? Keyword { get; set; }
|
||||
|
||||
[Range(1900, 3000)]
|
||||
public int? Year { get; set; }
|
||||
|
||||
[Range(1, 1000)]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
public AdminLimitFilter ToFilter()
|
||||
{
|
||||
return new AdminLimitFilter(
|
||||
RegionId,
|
||||
EntryId,
|
||||
ContentNodeId,
|
||||
ParentId,
|
||||
SubjectId,
|
||||
ChapterId,
|
||||
UnitId,
|
||||
SchoolId,
|
||||
MajorId,
|
||||
QuestionId,
|
||||
Status,
|
||||
Keyword,
|
||||
Year,
|
||||
Limit);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectQuestionWriteDto
|
||||
{
|
||||
public Guid? QuestionId { get; set; }
|
||||
public Guid? QuestionBankId { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public Guid? NodeId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public Guid? PrimaryCollectionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public string? TypeLabel { get; set; }
|
||||
|
||||
[Range(1, 5)]
|
||||
public int? Difficulty { get; set; }
|
||||
|
||||
public JsonElement Tags { get; set; } = JsonDefaults.Array();
|
||||
public string? Content { get; set; }
|
||||
public JsonElement Options { get; set; } = JsonDefaults.Array();
|
||||
public int? CorrectOptionIndex { get; set; }
|
||||
public JsonElement CorrectOptionIndices { get; set; } = JsonDefaults.Array();
|
||||
public string? AnswerText { get; set; }
|
||||
public string? Explanation { get; set; }
|
||||
public JsonElement SubQuestions { get; set; } = JsonDefaults.Array();
|
||||
public string? CodeLang { get; set; }
|
||||
public string? CodeTemplate { get; set; }
|
||||
public string? MediaUrl { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public JsonElement ExamMarkers { get; set; } = JsonDefaults.Object();
|
||||
public string? SourceHash { get; set; }
|
||||
public bool? CreateVersion { get; set; }
|
||||
|
||||
public QuestionWriteCommand ToCommand(bool createVersionDefault)
|
||||
{
|
||||
return new QuestionWriteCommand(
|
||||
QuestionId,
|
||||
QuestionBankId,
|
||||
SubjectId,
|
||||
CategoryId,
|
||||
NodeId,
|
||||
EntryId,
|
||||
ContentNodeId,
|
||||
PrimaryCollectionId,
|
||||
LegacyId,
|
||||
Type,
|
||||
TypeLabel,
|
||||
Difficulty,
|
||||
Tags,
|
||||
Content,
|
||||
Options,
|
||||
CorrectOptionIndex,
|
||||
CorrectOptionIndices,
|
||||
AnswerText,
|
||||
Explanation,
|
||||
SubQuestions,
|
||||
CodeLang,
|
||||
CodeTemplate,
|
||||
MediaUrl,
|
||||
Status,
|
||||
ExamMarkers,
|
||||
SourceHash,
|
||||
CreateVersion ?? createVersionDefault);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectVocabularyUnitDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? WordCount { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public VocabularyUnitCommand ToCommand()
|
||||
{
|
||||
return new VocabularyUnitCommand(Id, RegionId, EntryId, ContentNodeId, LegacyId, Name, Description, WordCount, Order, IsActive, Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectVocabularyWordDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? UnitId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Word { get; set; }
|
||||
public string? Phonetic { get; set; }
|
||||
public string? Meaning { get; set; }
|
||||
public string? Example { get; set; }
|
||||
public string? ExampleTranslation { get; set; }
|
||||
public int? Difficulty { get; set; }
|
||||
public JsonElement Tags { get; set; } = JsonDefaults.Array();
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public VocabularyWordCommand ToCommand()
|
||||
{
|
||||
return new VocabularyWordCommand(
|
||||
Id,
|
||||
UnitId,
|
||||
EntryId,
|
||||
ContentNodeId,
|
||||
LegacyId,
|
||||
Word,
|
||||
Phonetic,
|
||||
Meaning,
|
||||
Example,
|
||||
ExampleTranslation,
|
||||
Difficulty,
|
||||
Tags,
|
||||
Order,
|
||||
IsActive,
|
||||
Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectHandbookSubjectDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public Guid? MajorId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public string? Color { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public HandbookSubjectCommand ToCommand()
|
||||
{
|
||||
return new HandbookSubjectCommand(
|
||||
Id,
|
||||
RegionId,
|
||||
SchoolId,
|
||||
MajorId,
|
||||
EntryId,
|
||||
ContentNodeId,
|
||||
LegacyId,
|
||||
Name,
|
||||
Type,
|
||||
Icon,
|
||||
Color,
|
||||
Description,
|
||||
Order,
|
||||
IsActive,
|
||||
Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectHandbookChapterDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public HandbookChapterCommand ToCommand()
|
||||
{
|
||||
return new HandbookChapterCommand(Id, SubjectId, EntryId, ContentNodeId, LegacyId, Name, Description, Order, IsActive, Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectHandbookEntryDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? ChapterId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Title { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public JsonElement Tags { get; set; } = JsonDefaults.Array();
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public HandbookEntryCommand ToCommand()
|
||||
{
|
||||
return new HandbookEntryCommand(Id, ChapterId, EntryId, ContentNodeId, LegacyId, Title, Summary, Content, Tags, Order, IsActive, Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectSchoolDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? ProfessionalExamDate { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public SchoolCommand ToCommand()
|
||||
{
|
||||
return new SchoolCommand(Id, RegionId, LegacyId, Name, ProfessionalExamDate, Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectMajorDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? StudyTips { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
|
||||
public MajorCommand ToCommand()
|
||||
{
|
||||
return new MajorCommand(Id, RegionId, SchoolId, LegacyId, Name, Description, StudyTips, Order, IsActive);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectVideoDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public required string Title { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? VideoUrl { get; set; }
|
||||
public string? ThumbnailUrl { get; set; }
|
||||
public int? DurationSeconds { get; set; }
|
||||
public JsonElement KnowledgeTags { get; set; } = JsonDefaults.Array();
|
||||
public bool? IsGeneral { get; set; }
|
||||
public int? Difficulty { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public VideoExplanationCommand ToCommand()
|
||||
{
|
||||
return new VideoExplanationCommand(
|
||||
Id,
|
||||
SubjectId,
|
||||
LegacyId,
|
||||
Title,
|
||||
Description,
|
||||
VideoUrl,
|
||||
ThumbnailUrl,
|
||||
DurationSeconds,
|
||||
KnowledgeTags,
|
||||
IsGeneral,
|
||||
Difficulty,
|
||||
Order,
|
||||
IsActive,
|
||||
Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectQuestionVideoDto
|
||||
{
|
||||
public Guid QuestionId { get; set; }
|
||||
public Guid VideoId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? VideoType { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public QuestionVideoCommand ToCommand()
|
||||
{
|
||||
return new QuestionVideoCommand(QuestionId, VideoId, LegacyId, VideoType, Order, Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectOperationContentDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Subtitle { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public string? Question { get; set; }
|
||||
public string? Answer { get; set; }
|
||||
public string? Link { get; set; }
|
||||
public string? ButtonText { get; set; }
|
||||
public string? ButtonLink { get; set; }
|
||||
public string? BackgroundColor { get; set; }
|
||||
public string? BorderColor { get; set; }
|
||||
public string? ExamName { get; set; }
|
||||
public DateTimeOffset? ExamAt { get; set; }
|
||||
public string? ExamType { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? Order { get; set; }
|
||||
public bool? IsActive { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public OperationContentCommand ToCommand()
|
||||
{
|
||||
return new OperationContentCommand(
|
||||
Id,
|
||||
RegionId,
|
||||
SchoolId,
|
||||
LegacyId,
|
||||
Title,
|
||||
Subtitle,
|
||||
Content,
|
||||
Question,
|
||||
Answer,
|
||||
Link,
|
||||
ButtonText,
|
||||
ButtonLink,
|
||||
BackgroundColor,
|
||||
BorderColor,
|
||||
ExamName,
|
||||
ExamAt,
|
||||
ExamType,
|
||||
Description,
|
||||
Order,
|
||||
IsActive,
|
||||
Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectImportDto
|
||||
{
|
||||
public string? SourceFormat { get; set; }
|
||||
public string? SourceName { get; set; }
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? EntryId { get; set; }
|
||||
public Guid? ContentNodeId { get; set; }
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid? CategoryId { get; set; }
|
||||
public Guid? QuestionBankId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Items { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Units { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Words { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Subjects { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Entries { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Fields { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Schools { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Majors { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Records { get; set; }
|
||||
public IReadOnlyCollection<JsonElement>? Videos { get; set; }
|
||||
|
||||
public SimpleImportCommand ToCommand(string importType, bool dryRun)
|
||||
{
|
||||
return new SimpleImportCommand(
|
||||
importType,
|
||||
SourceFormat,
|
||||
SourceName,
|
||||
RegionId,
|
||||
EntryId,
|
||||
ContentNodeId,
|
||||
SubjectId,
|
||||
CategoryId,
|
||||
QuestionBankId,
|
||||
CollectionId,
|
||||
ResolveItems(importType),
|
||||
dryRun);
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<JsonElement> ResolveItems(string importType)
|
||||
{
|
||||
return importType.ToLowerInvariant() switch
|
||||
{
|
||||
"questions" => Items ?? [],
|
||||
"vocabulary" => Words ?? Units ?? Items ?? [],
|
||||
"handbook" => Entries ?? Subjects ?? Items ?? [],
|
||||
"scoreline" => Records ?? Schools ?? Majors ?? Fields ?? Items ?? [],
|
||||
"videos" => Videos ?? Items ?? [],
|
||||
_ => Items ?? []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DirectImportJobDto
|
||||
{
|
||||
public Guid JobId { get; set; }
|
||||
}
|
||||
@@ -184,3 +184,19 @@ public sealed class FavoriteWordDto
|
||||
return new FavoriteWordCommand(WordId, Favorite, Note);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WordReviewDto
|
||||
{
|
||||
[Required]
|
||||
public Guid WordId { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
public string? Result { get; set; }
|
||||
|
||||
public DateTimeOffset? NextReviewAt { get; set; }
|
||||
|
||||
public WordReviewCommand ToCommand()
|
||||
{
|
||||
return new WordReviewCommand(WordId, Result, NextReviewAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,34 @@ public sealed class LearningController(
|
||||
ICurrentUser currentUser,
|
||||
ICurrentTenant currentTenant) : ControllerBase
|
||||
{
|
||||
[HttpGet("stats")]
|
||||
[EndpointSummary("查询学习统计")]
|
||||
[ProducesResponseType<LearningStatsItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<LearningStatsItem>> GetStats(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetStatsAsync(ResolveActor(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("trend")]
|
||||
[EndpointSummary("查询学习趋势")]
|
||||
[ProducesResponseType<LearningList<LearningTrendItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<LearningList<LearningTrendItem>>> GetTrend(
|
||||
[FromQuery] LearningLimitQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetTrendAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("leaderboard")]
|
||||
[EndpointSummary("查询学习排行榜")]
|
||||
[ProducesResponseType<LearningLeaderboardResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<LearningLeaderboardResult>> GetLeaderboard(
|
||||
[FromQuery] LearningLimitQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetLeaderboardAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("practice-sessions")]
|
||||
[EndpointSummary("创建练习会话")]
|
||||
[ProducesResponseType<PracticeSessionItem>(StatusCodes.Status200OK)]
|
||||
@@ -153,6 +181,19 @@ public sealed class LearningController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("wrong-questions/review-plan")]
|
||||
[EndpointSummary("生成错题复习计划")]
|
||||
[ProducesResponseType<WrongQuestionReviewPlan>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<WrongQuestionReviewPlan>> GetWrongQuestionReviewPlan(
|
||||
[FromQuery] LearningLimitQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetWrongQuestionReviewPlanAsync(
|
||||
ResolveActor(),
|
||||
query.ToFilter(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("wrong-questions/resolve")]
|
||||
[EndpointSummary("将错题标记为已解决")]
|
||||
[ProducesResponseType<LearningActionResult>(StatusCodes.Status200OK)]
|
||||
@@ -180,6 +221,19 @@ public sealed class LearningController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("vocabulary/review-plan")]
|
||||
[EndpointSummary("生成单词复习计划")]
|
||||
[ProducesResponseType<WordReviewPlan>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<WordReviewPlan>> GetWordReviewPlan(
|
||||
[FromQuery] LearningLimitQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetWordReviewPlanAsync(
|
||||
ResolveActor(),
|
||||
query.ToFilter(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("vocabulary/progress")]
|
||||
[EndpointSummary("更新单词学习进度")]
|
||||
[ProducesResponseType<WordProgressItem>(StatusCodes.Status200OK)]
|
||||
@@ -194,6 +248,33 @@ public sealed class LearningController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("vocabulary/review")]
|
||||
[EndpointSummary("提交单词复习结果")]
|
||||
[ProducesResponseType<WordProgressItem>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<WordProgressItem>> ReviewWord(
|
||||
WordReviewDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.ReviewWordAsync(
|
||||
ResolveActor(),
|
||||
request.ToCommand(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("vocabulary/stats")]
|
||||
[EndpointSummary("查询单词学习统计")]
|
||||
[ProducesResponseType<WordStatsItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<WordStatsItem>> GetWordStats(
|
||||
[FromQuery] LearningLimitQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await learningActivityService.GetWordStatsAsync(
|
||||
ResolveActor(),
|
||||
query.ToFilter(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("vocabulary/favorites")]
|
||||
[EndpointSummary("查询收藏单词")]
|
||||
[ProducesResponseType<LearningList<FavoriteWordItem>>(StatusCodes.Status200OK)]
|
||||
|
||||
@@ -166,6 +166,45 @@ public sealed class TenantContentController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("assets/access-events")]
|
||||
[EndpointSummary("查询资产访问审计事件")]
|
||||
[ProducesResponseType<CatalogList<ContentAssetAccessEventItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<ContentAssetAccessEventItem>>> GetAssetAccessEvents(
|
||||
[FromQuery] AssetEventQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await assetManagementService.GetAccessEventsAsync(
|
||||
ResolveActor(),
|
||||
query.ToFilter(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("assets/security-scan-events")]
|
||||
[EndpointSummary("查询资产安全扫描事件")]
|
||||
[ProducesResponseType<CatalogList<ContentAssetSecurityScanEventItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<ContentAssetSecurityScanEventItem>>> GetAssetSecurityScanEvents(
|
||||
[FromQuery] AssetEventQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await assetManagementService.GetSecurityScanEventsAsync(
|
||||
ResolveActor(),
|
||||
query.ToFilter(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("assets")]
|
||||
[EndpointSummary("新增或更新内容资产")]
|
||||
[ProducesResponseType<ContentManagementResult<ContentAssetManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<ContentAssetManagementItem>>> UpsertAsset(
|
||||
UpsertAssetDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await assetManagementService.UpsertAssetAsync(
|
||||
ResolveActor(),
|
||||
request.ToCommand(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("assets/uploads/sign")]
|
||||
[EndpointSummary("创建资产上传签名")]
|
||||
[ProducesResponseType<AssetUploadSignResult>(StatusCodes.Status200OK)]
|
||||
@@ -196,6 +235,32 @@ public sealed class TenantContentController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("assets/sign-download")]
|
||||
[EndpointSummary("签发管理侧资产下载地址")]
|
||||
[ProducesResponseType<AssetManagementSignedAccessResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<AssetManagementSignedAccessResult>> SignAssetDownload(
|
||||
AssetAccessSignDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await assetManagementService.SignDownloadAsync(
|
||||
ResolveActor(),
|
||||
request.ToCommand(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("assets/sign-preview")]
|
||||
[EndpointSummary("签发管理侧资产预览地址")]
|
||||
[ProducesResponseType<AssetManagementSignedAccessResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<AssetManagementSignedAccessResult>> SignAssetPreview(
|
||||
AssetAccessSignDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await assetManagementService.SignPreviewAsync(
|
||||
ResolveActor(),
|
||||
request.ToCommand(),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("import-jobs")]
|
||||
[EndpointSummary("查询内容导入任务")]
|
||||
[ProducesResponseType<CatalogList<ContentImportJobItem>>(StatusCodes.Status200OK)]
|
||||
|
||||
315
Tiku.Api/Controllers/TenantContentDirectController.cs
Normal file
315
Tiku.Api/Controllers/TenantContentDirectController.cs
Normal file
@@ -0,0 +1,315 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Assets;
|
||||
using Tiku.Application.Catalog;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Domain.Catalog;
|
||||
using Tiku.Domain.Content;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize(Policy = TikuPolicies.TenantAdmin)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant-content")]
|
||||
public sealed class TenantContentDirectController(
|
||||
IDirectContentService directContentService,
|
||||
ICurrentUser currentUser,
|
||||
ICurrentTenant currentTenant) : ControllerBase
|
||||
{
|
||||
[HttpPost("questions")]
|
||||
[EndpointSummary("创建题目及首个版本")]
|
||||
[ProducesResponseType<ContentManagementResult<QuestionManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<QuestionManagementItem>>> CreateQuestion(
|
||||
DirectQuestionWriteDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.CreateQuestionAsync(ResolveActor(), request.ToCommand(createVersionDefault: true), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPatch("questions")]
|
||||
[EndpointSummary("更新题目并可选择创建新版本")]
|
||||
[ProducesResponseType<ContentManagementResult<QuestionManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<QuestionManagementItem>>> UpdateQuestion(
|
||||
DirectQuestionWriteDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpdateQuestionAsync(ResolveActor(), request.ToCommand(createVersionDefault: false), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("vocabulary-units")]
|
||||
[EndpointSummary("查询管理侧词汇单元")]
|
||||
[ProducesResponseType<CatalogList<VocabularyUnit>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<VocabularyUnit>>> GetVocabularyUnits(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetVocabularyUnitsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("vocabulary-units")]
|
||||
[EndpointSummary("新增或更新词汇单元")]
|
||||
[ProducesResponseType<ContentManagementResult<VocabularyUnit>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<VocabularyUnit>>> UpsertVocabularyUnit(
|
||||
DirectVocabularyUnitDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertVocabularyUnitAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("vocabulary-words")]
|
||||
[EndpointSummary("查询管理侧词汇")]
|
||||
[ProducesResponseType<CatalogList<VocabularyWord>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<VocabularyWord>>> GetVocabularyWords(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetVocabularyWordsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("vocabulary-words")]
|
||||
[EndpointSummary("新增或更新词汇")]
|
||||
[ProducesResponseType<ContentManagementResult<VocabularyWord>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<VocabularyWord>>> UpsertVocabularyWord(
|
||||
DirectVocabularyWordDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertVocabularyWordAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("handbook-subjects")]
|
||||
[EndpointSummary("查询管理侧知识手册科目")]
|
||||
[ProducesResponseType<CatalogList<HandbookSubject>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<HandbookSubject>>> GetHandbookSubjects(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetHandbookSubjectsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("handbook-subjects")]
|
||||
[EndpointSummary("新增或更新知识手册科目")]
|
||||
[ProducesResponseType<ContentManagementResult<HandbookSubject>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<HandbookSubject>>> UpsertHandbookSubject(
|
||||
DirectHandbookSubjectDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertHandbookSubjectAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("handbook-chapters")]
|
||||
[EndpointSummary("查询管理侧知识手册章节")]
|
||||
[ProducesResponseType<CatalogList<HandbookChapter>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<HandbookChapter>>> GetHandbookChapters(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetHandbookChaptersAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("handbook-chapters")]
|
||||
[EndpointSummary("新增或更新知识手册章节")]
|
||||
[ProducesResponseType<ContentManagementResult<HandbookChapter>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<HandbookChapter>>> UpsertHandbookChapter(
|
||||
DirectHandbookChapterDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertHandbookChapterAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("handbook-entries")]
|
||||
[EndpointSummary("查询管理侧知识手册条目")]
|
||||
[ProducesResponseType<CatalogList<HandbookEntry>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<HandbookEntry>>> GetHandbookEntries(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetHandbookEntriesAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("handbook-entries")]
|
||||
[EndpointSummary("新增或更新知识手册条目")]
|
||||
[ProducesResponseType<ContentManagementResult<HandbookEntry>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<HandbookEntry>>> UpsertHandbookEntry(
|
||||
DirectHandbookEntryDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertHandbookEntryAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("scoreline/schools")]
|
||||
[EndpointSummary("查询管理侧分数线院校")]
|
||||
[ProducesResponseType<CatalogList<School>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<School>>> GetSchools(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetSchoolsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("scoreline/schools")]
|
||||
[EndpointSummary("新增或更新分数线院校")]
|
||||
[ProducesResponseType<ContentManagementResult<School>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<School>>> UpsertSchool(
|
||||
DirectSchoolDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertSchoolAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("scoreline/majors")]
|
||||
[EndpointSummary("查询管理侧分数线专业")]
|
||||
[ProducesResponseType<CatalogList<Major>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<Major>>> GetMajors(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetMajorsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("scoreline/majors")]
|
||||
[EndpointSummary("新增或更新分数线专业")]
|
||||
[ProducesResponseType<ContentManagementResult<Major>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<Major>>> UpsertMajor(
|
||||
DirectMajorDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertMajorAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("scoreline/years")]
|
||||
[EndpointSummary("查询分数线年份")]
|
||||
[ProducesResponseType<CatalogList<int>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<int>>> GetScorelineYears(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetScorelineYearsAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("scoreline/trend")]
|
||||
[EndpointSummary("查询分数线趋势摘要")]
|
||||
[ProducesResponseType<CatalogList<ScorelineTrendItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<ScorelineTrendItem>>> GetScorelineTrend(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetScorelineTrendAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("videos")]
|
||||
[EndpointSummary("查询租户视频解析")]
|
||||
[ProducesResponseType<CatalogList<VideoManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<VideoManagementItem>>> GetVideos(
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetVideosAsync(ResolveActor(), query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("videos")]
|
||||
[EndpointSummary("新增或更新视频解析")]
|
||||
[ProducesResponseType<ContentManagementResult<VideoManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<VideoManagementItem>>> UpsertVideo(
|
||||
DirectVideoDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertVideoAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("question-videos")]
|
||||
[EndpointSummary("绑定题目与解析视频")]
|
||||
[ProducesResponseType<ContentManagementResult<QuestionVideoManagementItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<QuestionVideoManagementItem>>> BindQuestionVideo(
|
||||
DirectQuestionVideoDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.BindQuestionVideoAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("operations/{kind}")]
|
||||
[EndpointSummary("查询运营内容")]
|
||||
[ProducesResponseType<CatalogList<OperationContentItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<OperationContentItem>>> GetOperationContent(
|
||||
string kind,
|
||||
[FromQuery] DirectContentQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetOperationContentAsync(ResolveActor(), kind, query.ToFilter(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("operations/{kind}")]
|
||||
[EndpointSummary("新增或更新运营内容")]
|
||||
[ProducesResponseType<ContentManagementResult<OperationContentItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentManagementResult<OperationContentItem>>> UpsertOperationContent(
|
||||
string kind,
|
||||
DirectOperationContentDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.UpsertOperationContentAsync(ResolveActor(), kind, request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("imports/preview/{importType}")]
|
||||
[EndpointSummary("预览内容导入数据")]
|
||||
[ProducesResponseType<SimpleImportResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<SimpleImportResult>> PreviewImport(
|
||||
string importType,
|
||||
DirectImportDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.PreviewImportAsync(ResolveActor(), request.ToCommand(importType, dryRun: true), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("imports/{importType}")]
|
||||
[EndpointSummary("执行同步内容导入")]
|
||||
[ProducesResponseType<SimpleImportResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<SimpleImportResult>> ExecuteImport(
|
||||
string importType,
|
||||
DirectImportDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.ExecuteImportAsync(ResolveActor(), request.ToCommand(importType, dryRun: false), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("imports/issues")]
|
||||
[EndpointSummary("查询内容导入问题明细")]
|
||||
[ProducesResponseType<CatalogList<ContentImportIssueModel>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<ContentImportIssueModel>>> GetImportIssues(
|
||||
[FromQuery] DirectImportJobDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetImportIssuesAsync(ResolveActor(), query.JobId, cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("imports/post-check")]
|
||||
[EndpointSummary("执行内容导入后完整性检查")]
|
||||
[ProducesResponseType<ImportPostCheckResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ImportPostCheckResult>> RunImportPostCheck(
|
||||
DirectImportJobDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.RunImportPostCheckAsync(ResolveActor(), request.JobId, cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("imports/post-check")]
|
||||
[EndpointSummary("查询内容导入后检查状态")]
|
||||
[ProducesResponseType<ImportPostCheckResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ImportPostCheckResult>> GetImportPostCheck(
|
||||
[FromQuery] DirectImportJobDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetImportPostCheckAsync(ResolveActor(), query.JobId, cancellationToken));
|
||||
}
|
||||
|
||||
private DirectContentActor ResolveActor()
|
||||
{
|
||||
if (currentTenant.TenantId is null || currentUser.UserId is null)
|
||||
{
|
||||
throw new ContentManagementException("Tenant content actor was not resolved.", "tenant_content_access_denied");
|
||||
}
|
||||
|
||||
return new DirectContentActor(currentTenant.TenantId.Value, currentUser.UserId.Value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user