forked from xiongyuxing/tiku-backend.net
feat: add student video and profile experience
This commit is contained in:
@@ -107,6 +107,27 @@ public sealed class ProfileController(
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("check-in")]
|
||||
[EndpointSummary("每日签到")]
|
||||
[ProducesResponseType<CheckInResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CheckInResult>> CheckIn(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await profileService.CheckInAsync(ResolveActor(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("score-events")]
|
||||
[EndpointSummary("查询积分流水")]
|
||||
[ProducesResponseType<ProfileScoreEventList>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ProfileScoreEventList>> ScoreEvents(
|
||||
[FromQuery] ProfileQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await profileService.GetScoreEventsAsync(
|
||||
ResolveActor(),
|
||||
new ProfileScoreEventQuery(query.Limit, query.SourceType, query.From, query.To),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("feedbacks")]
|
||||
[EndpointSummary("提交意见反馈")]
|
||||
[ProducesResponseType<FeedbackItem>(StatusCodes.Status200OK)]
|
||||
|
||||
48
Tiku.Api/Controllers/QuestionVideosController.cs
Normal file
48
Tiku.Api/Controllers/QuestionVideosController.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Assets;
|
||||
using Tiku.Application.Catalog;
|
||||
using Tiku.Application.Security;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/questions/videos")]
|
||||
public sealed class QuestionVideosController(
|
||||
IVideoPlaybackService videoPlaybackService,
|
||||
ICurrentUser currentUser,
|
||||
ITenantContext currentTenant) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[EndpointSummary("查询单道题目的解析视频")]
|
||||
[ProducesResponseType<CatalogList<QuestionVideoCatalogItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<QuestionVideoCatalogItem>>> List(
|
||||
[FromQuery] QuestionVideoQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await videoPlaybackService.GetQuestionVideosAsync(ResolveActor(), query.ToQuery(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("batch")]
|
||||
[EndpointSummary("批量查询题目解析视频")]
|
||||
[ProducesResponseType<CatalogList<QuestionVideoCatalogItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<QuestionVideoCatalogItem>>> Batch(
|
||||
QuestionVideoQueryDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await videoPlaybackService.GetQuestionVideosAsync(ResolveActor(), request.ToQuery(), cancellationToken));
|
||||
}
|
||||
|
||||
private VideoPlaybackActor ResolveActor()
|
||||
{
|
||||
if (currentTenant.TenantId is null || currentUser.UserId is null)
|
||||
{
|
||||
throw new VideoPlaybackException("Current video actor was not resolved.", "video_access_denied");
|
||||
}
|
||||
|
||||
return new VideoPlaybackActor(currentTenant.TenantId.Value, currentUser.UserId.Value);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Assets;
|
||||
using Tiku.Application.Catalog;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Application.Jobs;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Domain.Catalog;
|
||||
using Tiku.Domain.Content;
|
||||
@@ -16,6 +17,7 @@ namespace Tiku.Api.Controllers;
|
||||
[Route("api/tenant-content")]
|
||||
public sealed class TenantContentDirectController(
|
||||
IDirectContentService directContentService,
|
||||
IBackgroundJobService backgroundJobService,
|
||||
ICurrentUser currentUser,
|
||||
ITenantContext currentTenant) : ControllerBase
|
||||
{
|
||||
@@ -318,14 +320,53 @@ public sealed class TenantContentDirectController(
|
||||
|
||||
[HttpPost("imports/{importType}")]
|
||||
[Authorize(Policy = TikuPolicies.TenantContentManageAllScope)]
|
||||
[EndpointSummary("执行同步内容导入")]
|
||||
[EndpointSummary("执行或排队内容导入")]
|
||||
[ProducesResponseType<SimpleImportResult>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<SimpleImportResult>> ExecuteImport(
|
||||
[ProducesResponseType<BackgroundJobItem>(StatusCodes.Status202Accepted)]
|
||||
public async Task<ActionResult<object>> ExecuteImport(
|
||||
string importType,
|
||||
DirectImportDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.ExecuteImportAsync(ResolveActor(), request.ToCommand(importType, dryRun: false), cancellationToken));
|
||||
var actor = ResolveActor();
|
||||
var command = request.ToCommand(importType, dryRun: false);
|
||||
if (request.Async == true || command.Items.Count > 100)
|
||||
{
|
||||
var job = await backgroundJobService.EnqueueAsync(
|
||||
new CreateBackgroundJobCommand(
|
||||
actor.TenantId,
|
||||
"content_import",
|
||||
System.Text.Json.JsonSerializer.SerializeToElement(new
|
||||
{
|
||||
createdBy = actor.UserId,
|
||||
importType = command.ImportType,
|
||||
sourceFormat = command.SourceFormat,
|
||||
sourceName = command.SourceName,
|
||||
regionId = command.RegionId,
|
||||
entryId = command.EntryId,
|
||||
contentNodeId = command.ContentNodeId,
|
||||
subjectId = command.SubjectId,
|
||||
categoryId = command.CategoryId,
|
||||
questionBankId = command.QuestionBankId,
|
||||
collectionId = command.CollectionId,
|
||||
items = command.Items
|
||||
})),
|
||||
cancellationToken);
|
||||
return Accepted(job);
|
||||
}
|
||||
|
||||
return Ok(await directContentService.ExecuteImportAsync(actor, command, cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("imports/detail")]
|
||||
[Authorize(Policy = TikuPolicies.TenantContentManageAllScope)]
|
||||
[EndpointSummary("查询内容导入任务详情")]
|
||||
[ProducesResponseType<ContentImportJobDetail>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ContentImportJobDetail>> GetImportDetail(
|
||||
[FromQuery] DirectImportJobDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await directContentService.GetImportJobAsync(ResolveActor(), query.JobId, cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("imports/issues")]
|
||||
|
||||
58
Tiku.Api/Controllers/VideosController.cs
Normal file
58
Tiku.Api/Controllers/VideosController.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Assets;
|
||||
using Tiku.Application.Catalog;
|
||||
using Tiku.Application.Security;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/videos")]
|
||||
public sealed class VideosController(
|
||||
IVideoPlaybackService videoPlaybackService,
|
||||
ICurrentUser currentUser,
|
||||
ITenantContext currentTenant) : ControllerBase
|
||||
{
|
||||
[HttpGet("search")]
|
||||
[EndpointSummary("搜索通用解析视频")]
|
||||
[ProducesResponseType<CatalogList<VideoExplanationCatalogItem>>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<CatalogList<VideoExplanationCatalogItem>>> Search(
|
||||
[FromQuery] VideoSearchQueryDto query,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await videoPlaybackService.SearchAsync(ResolveActor(), query.ToQuery(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("play")]
|
||||
[EndpointSummary("申请视频播放信息")]
|
||||
[ProducesResponseType<VideoPlaybackItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<VideoPlaybackItem>> Play(
|
||||
VideoPlayDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await videoPlaybackService.PlayAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("progress")]
|
||||
[EndpointSummary("上报视频播放进度")]
|
||||
[ProducesResponseType<VideoProgressItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<VideoProgressItem>> Progress(
|
||||
VideoProgressDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await videoPlaybackService.ReportProgressAsync(ResolveActor(), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
private VideoPlaybackActor ResolveActor()
|
||||
{
|
||||
if (currentTenant.TenantId is null || currentUser.UserId is null)
|
||||
{
|
||||
throw new VideoPlaybackException("Current video actor was not resolved.", "video_access_denied");
|
||||
}
|
||||
|
||||
return new VideoPlaybackActor(currentTenant.TenantId.Value, currentUser.UserId.Value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user