feat: add student video and profile experience
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Text.Json;
|
||||
using Tiku.Application.Content;
|
||||
using Tiku.Application.Jobs;
|
||||
using Tiku.Application.Security;
|
||||
using Tiku.Application.Tenancy;
|
||||
@@ -65,7 +66,7 @@ internal sealed class BackgroundJobService(
|
||||
var result = await tenantExecutionScope.ExecuteAsync(
|
||||
job.TenantId,
|
||||
$"Background job {job.JobType}",
|
||||
(_, token) => ProcessCoreAsync(job, token),
|
||||
(provider, token) => ProcessCoreAsync(provider, job, token),
|
||||
cancellationToken);
|
||||
job.Status = BackgroundJobStatus.Succeeded;
|
||||
job.CompletedAt = DateTimeOffset.UtcNow;
|
||||
@@ -114,13 +115,16 @@ internal sealed class BackgroundJobService(
|
||||
return jobs.Select(ToItem).ToArray();
|
||||
}
|
||||
|
||||
private async Task<JsonElement> ProcessCoreAsync(BackgroundJob job, CancellationToken cancellationToken)
|
||||
private async Task<JsonElement> ProcessCoreAsync(
|
||||
IServiceProvider scopedProvider,
|
||||
BackgroundJob job,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return job.JobType switch
|
||||
{
|
||||
"content_export" => await ProcessContentExportAsync(job, cancellationToken),
|
||||
"content_import" => throw new NotSupportedException("content_import requires the module-specific importer before it can mutate content."),
|
||||
"content_import" => await ProcessContentImportAsync(scopedProvider, job, cancellationToken),
|
||||
"asset_security_scan" => throw new NotSupportedException("asset_security_scan requires a configured scanner provider before it can write scan results."),
|
||||
"statistics_aggregation" => await ProcessStatisticsAggregationAsync(job, cancellationToken),
|
||||
"commerce_reconciliation" => await ProcessCommerceReconciliationAsync(job, cancellationToken),
|
||||
@@ -129,6 +133,47 @@ internal sealed class BackgroundJobService(
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task<JsonElement> ProcessContentImportAsync(
|
||||
IServiceProvider scopedProvider,
|
||||
BackgroundJob job,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var directContentService = scopedProvider.GetRequiredService<IDirectContentService>();
|
||||
var createdBy = GetJsonGuid(job.Payload, "createdBy") ?? Guid.Empty;
|
||||
if (createdBy == Guid.Empty)
|
||||
{
|
||||
throw new InvalidOperationException("content_import job requires createdBy.");
|
||||
}
|
||||
|
||||
var command = new SimpleImportCommand(
|
||||
GetJsonString(job.Payload, "importType") ?? throw new InvalidOperationException("content_import job requires importType."),
|
||||
GetJsonString(job.Payload, "sourceFormat"),
|
||||
GetJsonString(job.Payload, "sourceName"),
|
||||
GetJsonGuid(job.Payload, "regionId"),
|
||||
GetJsonGuid(job.Payload, "entryId"),
|
||||
GetJsonGuid(job.Payload, "contentNodeId"),
|
||||
GetJsonGuid(job.Payload, "subjectId"),
|
||||
GetJsonGuid(job.Payload, "categoryId"),
|
||||
GetJsonGuid(job.Payload, "questionBankId"),
|
||||
GetJsonGuid(job.Payload, "collectionId"),
|
||||
GetJsonArray(job.Payload, "items"),
|
||||
false);
|
||||
var result = await directContentService.ExecuteImportAsync(
|
||||
new DirectContentActor(job.TenantId, createdBy),
|
||||
command,
|
||||
cancellationToken);
|
||||
return JsonSerializer.SerializeToElement(new
|
||||
{
|
||||
importJobId = result.Job.Id,
|
||||
result.Job.ImportType,
|
||||
result.Job.Status,
|
||||
result.Job.TotalCount,
|
||||
result.Job.InsertedCount,
|
||||
result.Job.UpdatedCount,
|
||||
result.Job.ErrorCount
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<JsonElement> ProcessContentExportAsync(
|
||||
BackgroundJob job,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -300,6 +345,31 @@ internal sealed class BackgroundJobService(
|
||||
: null;
|
||||
}
|
||||
|
||||
private static Guid? GetJsonGuid(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.ValueKind != JsonValueKind.Object ||
|
||||
!element.TryGetProperty(propertyName, out var property))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return property.ValueKind == JsonValueKind.String && Guid.TryParse(property.GetString(), out var value)
|
||||
? value
|
||||
: null;
|
||||
}
|
||||
|
||||
private static IReadOnlyCollection<JsonElement> GetJsonArray(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.ValueKind != JsonValueKind.Object ||
|
||||
!element.TryGetProperty(propertyName, out var property) ||
|
||||
property.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return property.EnumerateArray().Select(item => item.Clone()).ToArray();
|
||||
}
|
||||
|
||||
private static DateOnly? GetJsonDateOnly(JsonElement element, string propertyName)
|
||||
{
|
||||
var value = GetJsonString(element, propertyName);
|
||||
|
||||
Reference in New Issue
Block a user