@hed-hog/lms 0.0.351 → 0.0.354
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/course/course-audio-transcription.service.d.ts +29 -0
- package/dist/course/course-audio-transcription.service.d.ts.map +1 -0
- package/dist/course/course-audio-transcription.service.js +291 -0
- package/dist/course/course-audio-transcription.service.js.map +1 -0
- package/dist/course/course-lesson.controller.d.ts +10 -0
- package/dist/course/course-lesson.controller.d.ts.map +1 -0
- package/dist/course/course-lesson.controller.js +62 -0
- package/dist/course/course-lesson.controller.js.map +1 -0
- package/dist/course/course-structure.controller.d.ts +41 -15
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +50 -6
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +50 -15
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +238 -73
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course-video-conversion.service.d.ts +20 -2
- package/dist/course/course-video-conversion.service.d.ts.map +1 -1
- package/dist/course/course-video-conversion.service.js +730 -10
- package/dist/course/course-video-conversion.service.js.map +1 -1
- package/dist/course/course.controller.d.ts +24 -8
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.module.d.ts.map +1 -1
- package/dist/course/course.module.js +5 -3
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +24 -8
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +112 -176
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/create-course-lesson-frame.dto.d.ts +5 -0
- package/dist/course/dto/create-course-lesson-frame.dto.d.ts.map +1 -0
- package/dist/course/dto/create-course-lesson-frame.dto.js +30 -0
- package/dist/course/dto/create-course-lesson-frame.dto.js.map +1 -0
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts +4 -2
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.js +10 -3
- package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
- package/dist/course/dto/create-course.dto.d.ts +1 -1
- package/dist/course/dto/create-course.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course.dto.js +6 -6
- package/dist/course/dto/create-course.dto.js.map +1 -1
- package/dist/course/dto/update-course-lesson-frame.dto.d.ts +5 -0
- package/dist/course/dto/update-course-lesson-frame.dto.d.ts.map +1 -0
- package/dist/course/dto/update-course-lesson-frame.dto.js +32 -0
- package/dist/course/dto/update-course-lesson-frame.dto.js.map +1 -0
- package/dist/course/dto/update-course-resources.dto.d.ts +4 -2
- package/dist/course/dto/update-course-resources.dto.d.ts.map +1 -1
- package/dist/course/dto/update-course-resources.dto.js +10 -3
- package/dist/course/dto/update-course-resources.dto.js.map +1 -1
- package/dist/course/dto/update-transcription-segments.dto.d.ts +10 -0
- package/dist/course/dto/update-transcription-segments.dto.d.ts.map +1 -0
- package/dist/course/dto/update-transcription-segments.dto.js +38 -0
- package/dist/course/dto/update-transcription-segments.dto.js.map +1 -0
- package/dist/course/lms-setting.controller.d.ts +13 -0
- package/dist/course/lms-setting.controller.d.ts.map +1 -0
- package/dist/course/lms-setting.controller.js +53 -0
- package/dist/course/lms-setting.controller.js.map +1 -0
- package/dist/enterprise/training/training-admin.service.d.ts.map +1 -1
- package/dist/enterprise/training/training-admin.service.js +74 -33
- package/dist/enterprise/training/training-admin.service.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +6 -0
- package/dist/lms.module.js.map +1 -1
- package/hedhog/data/route.yaml +63 -0
- package/hedhog/data/setting_group.yaml +76 -0
- package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +10 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +7 -2
- package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +5 -2
- package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +7 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/_components/CourseMultiEntityPicker.tsx.ejs +95 -50
- package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +11 -36
- package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +19 -5
- package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +30 -10
- package/hedhog/frontend/app/courses/[id]/structure/_components/CourseInstructorsSummaryCard.tsx.ejs +95 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +29 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +42 -31
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +10 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +51 -9
- package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +25 -22
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +12 -9
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +315 -229
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +3220 -534
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +20 -15
- package/hedhog/frontend/app/courses/[id]/structure/_components/icon-action-tooltip.tsx.ejs +35 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +76 -67
- package/hedhog/frontend/app/courses/[id]/structure/_components/search-filter.tsx.ejs +13 -10
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +18 -16
- package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +6 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-context-menu.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +23 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-helpers.ts.ejs +48 -9
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-course.tsx.ejs +11 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +121 -15
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +69 -14
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +11 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +31 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +32 -6
- package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +57 -3
- package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +46 -6
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +14 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-audio-files.ts.ejs +23 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-lms-settings-query.ts.ejs +34 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +76 -0
- package/hedhog/frontend/messages/en.json +39 -3
- package/hedhog/frontend/messages/pt.json +39 -3
- package/hedhog/table/course.yaml +8 -0
- package/hedhog/table/course_lesson_file.yaml +12 -4
- package/hedhog/table/course_lesson_transcription_segment.yaml +22 -0
- package/hedhog/table/course_lesson_video_frame.yaml +25 -0
- package/package.json +9 -9
- package/src/course/course-audio-transcription.service.ts +393 -0
- package/src/course/course-lesson.controller.ts +28 -0
- package/src/course/course-structure.controller.ts +49 -3
- package/src/course/course-structure.service.ts +294 -32
- package/src/course/course-video-conversion.service.ts +972 -6
- package/src/course/course.module.ts +5 -3
- package/src/course/course.service.ts +87 -139
- package/src/course/dto/create-course-lesson-frame.dto.ts +14 -0
- package/src/course/dto/create-course-structure-lesson.dto.ts +19 -3
- package/src/course/dto/create-course.dto.ts +5 -5
- package/src/course/dto/update-course-lesson-frame.dto.ts +16 -0
- package/src/course/dto/update-course-resources.dto.ts +18 -3
- package/src/course/dto/update-transcription-segments.dto.ts +20 -0
- package/src/course/lms-setting.controller.ts +30 -0
- package/src/enterprise/training/training-admin.service.ts +77 -24
- package/src/index.ts +2 -0
- package/src/lms.module.ts +6 -0
- package/hedhog/table/course_instructor.yaml +0 -27
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
2
|
+
import { FileService } from '@hed-hog/core';
|
|
2
3
|
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
|
3
4
|
import { InstructorService } from '../instructor/instructor.service';
|
|
4
5
|
import { CourseOperationsIntegrationService } from './course-operations-integration.service';
|
|
6
|
+
import { CreateCourseLessonFrameDto } from './dto/create-course-lesson-frame.dto';
|
|
5
7
|
import { CreateCourseStructureLessonDto } from './dto/create-course-structure-lesson.dto';
|
|
6
8
|
import { CreateCourseStructureSessionDto } from './dto/create-course-structure-session.dto';
|
|
7
9
|
import { MoveLessonDto } from './dto/move-lesson.dto';
|
|
8
10
|
import { PasteLessonsDto } from './dto/paste-lessons.dto';
|
|
9
11
|
import { ReorderLessonsDto } from './dto/reorder-lessons.dto';
|
|
10
12
|
import { ReorderSessionsDto } from './dto/reorder-sessions.dto';
|
|
13
|
+
import { UpdateCourseLessonFrameDto } from './dto/update-course-lesson-frame.dto';
|
|
11
14
|
import { UpdateCourseResourcesDto } from './dto/update-course-resources.dto';
|
|
12
15
|
import { UpdateCourseStructureLessonDto } from './dto/update-course-structure-lesson.dto';
|
|
13
16
|
import { UpdateCourseStructureSessionDto } from './dto/update-course-structure-session.dto';
|
|
17
|
+
import { UpdateTranscriptionSegmentsDTO } from './dto/update-transcription-segments.dto';
|
|
14
18
|
|
|
15
19
|
type LessonUiType = 'video' | 'questao' | 'post' | 'exercicio';
|
|
16
20
|
type LessonDbType = 'video' | 'text' | 'quiz';
|
|
21
|
+
type LessonFileType =
|
|
22
|
+
| 'video_original'
|
|
23
|
+
| `video_profile:${number}`
|
|
24
|
+
| 'lesson_audio'
|
|
25
|
+
| 'student_download'
|
|
26
|
+
| 'supplementary_material';
|
|
17
27
|
|
|
18
28
|
@Injectable()
|
|
19
29
|
export class CourseStructureService {
|
|
20
30
|
constructor(
|
|
21
31
|
private readonly prisma: PrismaService,
|
|
32
|
+
private readonly fileService: FileService,
|
|
22
33
|
private readonly instructorService: InstructorService,
|
|
23
34
|
private readonly operationsIntegration: CourseOperationsIntegrationService,
|
|
24
35
|
) {}
|
|
@@ -38,6 +49,17 @@ export class CourseStructureService {
|
|
|
38
49
|
orderBy: { order: 'asc' },
|
|
39
50
|
include: {
|
|
40
51
|
course_lesson_file: true,
|
|
52
|
+
course_lesson_video_frame: {
|
|
53
|
+
orderBy: { id: 'asc' },
|
|
54
|
+
include: {
|
|
55
|
+
file: {
|
|
56
|
+
select: {
|
|
57
|
+
id: true,
|
|
58
|
+
filename: true,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
41
63
|
course_lesson_question: {
|
|
42
64
|
orderBy: { order: 'asc' },
|
|
43
65
|
},
|
|
@@ -118,8 +140,15 @@ export class CourseStructureService {
|
|
|
118
140
|
nome: fileLink.title,
|
|
119
141
|
fileId: fileLink.file_id,
|
|
120
142
|
tamanho: '',
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
type: this.readLessonFileType(fileLink),
|
|
144
|
+
is_public: this.readLessonFileVisibility(fileLink),
|
|
145
|
+
})),
|
|
146
|
+
frames: lesson.course_lesson_video_frame.map((frame) => ({
|
|
147
|
+
id: String(frame.id),
|
|
148
|
+
nome: frame.file?.filename ?? `frame-${frame.id}`,
|
|
149
|
+
fileId: frame.file_id ?? 0,
|
|
150
|
+
timeSeconds: frame.time_seconds ?? 0,
|
|
151
|
+
url: frame.file_id ? `/file/open/${frame.file_id}` : undefined,
|
|
123
152
|
})),
|
|
124
153
|
instrutores: lesson.course_lesson_instructor.map((item) => ({
|
|
125
154
|
id: String(item.instructor_id),
|
|
@@ -174,8 +203,8 @@ export class CourseStructureService {
|
|
|
174
203
|
id: row.id,
|
|
175
204
|
nome: row.title,
|
|
176
205
|
fileId: row.file_id,
|
|
177
|
-
|
|
178
|
-
|
|
206
|
+
type: 'student_download',
|
|
207
|
+
is_public: true,
|
|
179
208
|
}));
|
|
180
209
|
}
|
|
181
210
|
|
|
@@ -413,6 +442,145 @@ export class CourseStructureService {
|
|
|
413
442
|
return { success: true };
|
|
414
443
|
}
|
|
415
444
|
|
|
445
|
+
async deleteLessonFrame(
|
|
446
|
+
courseId: number,
|
|
447
|
+
sessionId: number,
|
|
448
|
+
lessonId: number,
|
|
449
|
+
frameId: number,
|
|
450
|
+
) {
|
|
451
|
+
const frame = await this.prisma.course_lesson_video_frame.findFirst({
|
|
452
|
+
where: {
|
|
453
|
+
id: frameId,
|
|
454
|
+
course_lesson_id: lessonId,
|
|
455
|
+
course_lesson: {
|
|
456
|
+
course_module_id: sessionId,
|
|
457
|
+
course_module: { course_id: courseId },
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
select: {
|
|
461
|
+
id: true,
|
|
462
|
+
file_id: true,
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
if (!frame) {
|
|
467
|
+
throw new NotFoundException('Lesson frame not found for this lesson');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
await this.prisma.course_lesson_video_frame.delete({ where: { id: frameId } });
|
|
471
|
+
|
|
472
|
+
if (frame.file_id) {
|
|
473
|
+
await this.fileService.delete('pt', { ids: [frame.file_id] }).catch(() => undefined);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return { success: true };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async createLessonFrame(
|
|
480
|
+
courseId: number,
|
|
481
|
+
sessionId: number,
|
|
482
|
+
lessonId: number,
|
|
483
|
+
dto: CreateCourseLessonFrameDto,
|
|
484
|
+
) {
|
|
485
|
+
const lesson = await this.prisma.course_lesson.findFirst({
|
|
486
|
+
where: {
|
|
487
|
+
id: lessonId,
|
|
488
|
+
course_module_id: sessionId,
|
|
489
|
+
course_module: { course_id: courseId },
|
|
490
|
+
},
|
|
491
|
+
select: { id: true },
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
if (!lesson) {
|
|
495
|
+
throw new NotFoundException('Lesson not found for this session');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
await this.fileService.get(dto.fileId);
|
|
499
|
+
|
|
500
|
+
const created = await this.prisma.course_lesson_video_frame.create({
|
|
501
|
+
data: {
|
|
502
|
+
course_lesson_id: lessonId,
|
|
503
|
+
file_id: dto.fileId,
|
|
504
|
+
time_seconds: dto.timeSeconds,
|
|
505
|
+
},
|
|
506
|
+
select: {
|
|
507
|
+
id: true,
|
|
508
|
+
file_id: true,
|
|
509
|
+
time_seconds: true,
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
return {
|
|
514
|
+
success: true,
|
|
515
|
+
id: created.id,
|
|
516
|
+
fileId: created.file_id,
|
|
517
|
+
timeSeconds: created.time_seconds,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async updateLessonFrame(
|
|
522
|
+
courseId: number,
|
|
523
|
+
sessionId: number,
|
|
524
|
+
lessonId: number,
|
|
525
|
+
frameId: number,
|
|
526
|
+
dto: UpdateCourseLessonFrameDto,
|
|
527
|
+
) {
|
|
528
|
+
const frame = await this.prisma.course_lesson_video_frame.findFirst({
|
|
529
|
+
where: {
|
|
530
|
+
id: frameId,
|
|
531
|
+
course_lesson_id: lessonId,
|
|
532
|
+
course_lesson: {
|
|
533
|
+
course_module_id: sessionId,
|
|
534
|
+
course_module: { course_id: courseId },
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
select: {
|
|
538
|
+
id: true,
|
|
539
|
+
file_id: true,
|
|
540
|
+
},
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
if (!frame) {
|
|
544
|
+
throw new NotFoundException('Lesson frame not found for this lesson');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (dto.timeSeconds === undefined && dto.fileId === undefined) {
|
|
548
|
+
throw new BadRequestException('No frame update fields provided');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (dto.fileId !== undefined) {
|
|
552
|
+
await this.fileService.get(dto.fileId);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const updated = await this.prisma.course_lesson_video_frame.update({
|
|
556
|
+
where: { id: frameId },
|
|
557
|
+
data: {
|
|
558
|
+
...(dto.timeSeconds !== undefined && { time_seconds: dto.timeSeconds }),
|
|
559
|
+
...(dto.fileId !== undefined && { file_id: dto.fileId }),
|
|
560
|
+
},
|
|
561
|
+
select: {
|
|
562
|
+
id: true,
|
|
563
|
+
file_id: true,
|
|
564
|
+
time_seconds: true,
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
if (
|
|
569
|
+
dto.fileId !== undefined &&
|
|
570
|
+
frame.file_id &&
|
|
571
|
+
frame.file_id !== dto.fileId
|
|
572
|
+
) {
|
|
573
|
+
await this.fileService.delete('pt', { ids: [frame.file_id] }).catch(() => undefined);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
success: true,
|
|
578
|
+
id: updated.id,
|
|
579
|
+
fileId: updated.file_id,
|
|
580
|
+
timeSeconds: updated.time_seconds,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
416
584
|
async reorderSessions(courseId: number, dto: ReorderSessionsDto) {
|
|
417
585
|
await this.ensureCourseExists(courseId);
|
|
418
586
|
|
|
@@ -608,13 +776,12 @@ export class CourseStructureService {
|
|
|
608
776
|
});
|
|
609
777
|
|
|
610
778
|
if (lesson.course_lesson_file.length > 0) {
|
|
611
|
-
await this.prisma.course_lesson_file.createMany({
|
|
779
|
+
await (this.prisma as any).course_lesson_file.createMany({
|
|
612
780
|
data: lesson.course_lesson_file.map((f) => ({
|
|
613
781
|
course_lesson_id: newLesson.id,
|
|
614
782
|
title: f.title,
|
|
615
783
|
file_id: f.file_id,
|
|
616
|
-
|
|
617
|
-
publico: (f as any).publico ?? true,
|
|
784
|
+
...this.buildLessonFilePersistence((f as any).type, (f as any).is_public),
|
|
618
785
|
})),
|
|
619
786
|
});
|
|
620
787
|
}
|
|
@@ -711,13 +878,12 @@ export class CourseStructureService {
|
|
|
711
878
|
});
|
|
712
879
|
|
|
713
880
|
if (sourceLesson.course_lesson_file.length > 0) {
|
|
714
|
-
await this.prisma.course_lesson_file.createMany({
|
|
881
|
+
await (this.prisma as any).course_lesson_file.createMany({
|
|
715
882
|
data: sourceLesson.course_lesson_file.map((f) => ({
|
|
716
883
|
course_lesson_id: newLesson.id,
|
|
717
884
|
title: f.title,
|
|
718
885
|
file_id: f.file_id,
|
|
719
|
-
|
|
720
|
-
publico: (f as any).publico ?? true,
|
|
886
|
+
...this.buildLessonFilePersistence((f as any).type, (f as any).is_public),
|
|
721
887
|
})),
|
|
722
888
|
});
|
|
723
889
|
}
|
|
@@ -801,13 +967,12 @@ export class CourseStructureService {
|
|
|
801
967
|
});
|
|
802
968
|
|
|
803
969
|
if (lesson.course_lesson_file.length > 0) {
|
|
804
|
-
await this.prisma.course_lesson_file.createMany({
|
|
970
|
+
await (this.prisma as any).course_lesson_file.createMany({
|
|
805
971
|
data: lesson.course_lesson_file.map((f) => ({
|
|
806
972
|
course_lesson_id: newLesson.id,
|
|
807
973
|
title: f.title,
|
|
808
974
|
file_id: f.file_id,
|
|
809
|
-
|
|
810
|
-
publico: (f as any).publico ?? true,
|
|
975
|
+
...this.buildLessonFilePersistence((f as any).type, (f as any).is_public),
|
|
811
976
|
})),
|
|
812
977
|
});
|
|
813
978
|
}
|
|
@@ -847,6 +1012,52 @@ export class CourseStructureService {
|
|
|
847
1012
|
return { lessons: result };
|
|
848
1013
|
}
|
|
849
1014
|
|
|
1015
|
+
async getTranscriptionSegments(lessonId: number) {
|
|
1016
|
+
return (this.prisma as any).course_lesson_transcription_segment.findMany({
|
|
1017
|
+
where: { course_lesson_id: lessonId },
|
|
1018
|
+
orderBy: { start_seconds: 'asc' },
|
|
1019
|
+
select: {
|
|
1020
|
+
id: true,
|
|
1021
|
+
start_seconds: true,
|
|
1022
|
+
end_seconds: true,
|
|
1023
|
+
text: true,
|
|
1024
|
+
},
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
async updateTranscriptionSegments(
|
|
1029
|
+
lessonId: number,
|
|
1030
|
+
dto: UpdateTranscriptionSegmentsDTO,
|
|
1031
|
+
) {
|
|
1032
|
+
return this.prisma.$transaction([
|
|
1033
|
+
(this.prisma as any).course_lesson_transcription_segment.deleteMany({
|
|
1034
|
+
where: { course_lesson_id: lessonId },
|
|
1035
|
+
}),
|
|
1036
|
+
(this.prisma as any).course_lesson_transcription_segment.createMany({
|
|
1037
|
+
data: (dto.segments ?? []).map((segment) => ({
|
|
1038
|
+
course_lesson_id: lessonId,
|
|
1039
|
+
start_seconds: segment.startSeconds,
|
|
1040
|
+
end_seconds: segment.endSeconds,
|
|
1041
|
+
text: segment.text,
|
|
1042
|
+
})),
|
|
1043
|
+
}),
|
|
1044
|
+
]);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
async getAudioFiles(lessonId: number) {
|
|
1048
|
+
return (this.prisma as any).course_lesson_file.findMany({
|
|
1049
|
+
where: {
|
|
1050
|
+
course_lesson_id: lessonId,
|
|
1051
|
+
type: 'lesson_audio',
|
|
1052
|
+
},
|
|
1053
|
+
include: {
|
|
1054
|
+
locale: true,
|
|
1055
|
+
file: true,
|
|
1056
|
+
},
|
|
1057
|
+
orderBy: { created_at: 'asc' },
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
|
|
850
1061
|
private async syncLessonRelations(
|
|
851
1062
|
lessonId: number,
|
|
852
1063
|
dto: Partial<
|
|
@@ -857,9 +1068,15 @@ export class CourseStructureService {
|
|
|
857
1068
|
>,
|
|
858
1069
|
client: any = this.prisma,
|
|
859
1070
|
) {
|
|
860
|
-
const
|
|
1071
|
+
const shouldSyncInstructors = Object.prototype.hasOwnProperty.call(
|
|
1072
|
+
dto,
|
|
1073
|
+
'instructorIds',
|
|
1074
|
+
);
|
|
1075
|
+
const instructorIds = shouldSyncInstructors
|
|
1076
|
+
? [...new Set(dto.instructorIds ?? [])]
|
|
1077
|
+
: [];
|
|
861
1078
|
|
|
862
|
-
if (instructorIds.length > 0) {
|
|
1079
|
+
if (shouldSyncInstructors && instructorIds.length > 0) {
|
|
863
1080
|
await this.instructorService.assertQualifiedInstructorIds(
|
|
864
1081
|
instructorIds,
|
|
865
1082
|
['course-lessons'],
|
|
@@ -867,18 +1084,20 @@ export class CourseStructureService {
|
|
|
867
1084
|
}
|
|
868
1085
|
|
|
869
1086
|
const syncWithClient = async (tx: any) => {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
if (instructorIds.length > 0) {
|
|
875
|
-
await tx.course_lesson_instructor.createMany({
|
|
876
|
-
data: instructorIds.map((instructorId, index) => ({
|
|
877
|
-
course_lesson_id: lessonId,
|
|
878
|
-
instructor_id: instructorId,
|
|
879
|
-
role: index === 0 ? 'lead' : 'assistant',
|
|
880
|
-
})),
|
|
1087
|
+
if (shouldSyncInstructors) {
|
|
1088
|
+
await tx.course_lesson_instructor.deleteMany({
|
|
1089
|
+
where: { course_lesson_id: lessonId },
|
|
881
1090
|
});
|
|
1091
|
+
|
|
1092
|
+
if (instructorIds.length > 0) {
|
|
1093
|
+
await tx.course_lesson_instructor.createMany({
|
|
1094
|
+
data: instructorIds.map((instructorId, index) => ({
|
|
1095
|
+
course_lesson_id: lessonId,
|
|
1096
|
+
instructor_id: instructorId,
|
|
1097
|
+
role: index === 0 ? 'lead' : 'assistant',
|
|
1098
|
+
})),
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
882
1101
|
}
|
|
883
1102
|
|
|
884
1103
|
await tx.course_lesson_file.deleteMany({
|
|
@@ -887,13 +1106,12 @@ export class CourseStructureService {
|
|
|
887
1106
|
|
|
888
1107
|
const recursos = dto.recursos ?? [];
|
|
889
1108
|
if (recursos.length > 0) {
|
|
890
|
-
await tx.course_lesson_file.createMany({
|
|
1109
|
+
await (tx as any).course_lesson_file.createMany({
|
|
891
1110
|
data: recursos.map((recurso) => ({
|
|
892
1111
|
course_lesson_id: lessonId,
|
|
893
1112
|
title: recurso.nome,
|
|
894
1113
|
file_id: recurso.fileId ?? null,
|
|
895
|
-
|
|
896
|
-
publico: recurso.publico ?? true,
|
|
1114
|
+
...this.buildLessonFilePersistence((recurso as any).type, (recurso as any).is_public),
|
|
897
1115
|
})),
|
|
898
1116
|
});
|
|
899
1117
|
}
|
|
@@ -993,8 +1211,8 @@ export class CourseStructureService {
|
|
|
993
1211
|
nome: fileLink.title,
|
|
994
1212
|
fileId: fileLink.file_id,
|
|
995
1213
|
tamanho: '',
|
|
996
|
-
|
|
997
|
-
|
|
1214
|
+
type: this.readLessonFileType(fileLink),
|
|
1215
|
+
is_public: this.readLessonFileVisibility(fileLink),
|
|
998
1216
|
})),
|
|
999
1217
|
instrutores: lesson.course_lesson_instructor.map((item) => ({
|
|
1000
1218
|
id: String(item.instructor_id),
|
|
@@ -1079,7 +1297,7 @@ export class CourseStructureService {
|
|
|
1079
1297
|
};
|
|
1080
1298
|
|
|
1081
1299
|
if (data.tipo === 'video') {
|
|
1082
|
-
payload.videoProvedor = data.videoProvedor ?? '
|
|
1300
|
+
payload.videoProvedor = data.videoProvedor ?? 'file_storage';
|
|
1083
1301
|
payload.videoUrl = data.videoUrl ?? '';
|
|
1084
1302
|
payload.duracaoAutomatica = data.duracaoAutomatica ?? false;
|
|
1085
1303
|
payload.transcricao = data.transcricao ?? '';
|
|
@@ -1109,6 +1327,50 @@ export class CourseStructureService {
|
|
|
1109
1327
|
}
|
|
1110
1328
|
}
|
|
1111
1329
|
|
|
1330
|
+
private normalizeLessonFileType(value?: string | null): LessonFileType {
|
|
1331
|
+
if (value === 'video_original') {
|
|
1332
|
+
return 'video_original';
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
if (value?.startsWith('video_profile:')) {
|
|
1336
|
+
const profileId = Number(value.replace('video_profile:', ''));
|
|
1337
|
+
if (Number.isInteger(profileId) && profileId > 0) {
|
|
1338
|
+
return `video_profile:${profileId}`;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
if (value === 'lesson_audio') {
|
|
1343
|
+
return 'lesson_audio';
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
if (value === 'student_download' || value === 'file' || value === 'download') {
|
|
1347
|
+
return 'student_download';
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
return 'supplementary_material';
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
private readLessonFileType(fileLink: any): LessonFileType {
|
|
1354
|
+
return this.normalizeLessonFileType(fileLink?.type);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
private readLessonFileVisibility(fileLink: any): boolean {
|
|
1358
|
+
return Boolean(fileLink?.is_public ?? true);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
private buildLessonFilePersistence(
|
|
1362
|
+
typeValue?: string | null,
|
|
1363
|
+
isPublicValue?: boolean,
|
|
1364
|
+
) {
|
|
1365
|
+
const normalizedType = this.normalizeLessonFileType(typeValue);
|
|
1366
|
+
const normalizedIsPublic = Boolean(isPublicValue ?? true);
|
|
1367
|
+
|
|
1368
|
+
return {
|
|
1369
|
+
type: normalizedType,
|
|
1370
|
+
is_public: normalizedIsPublic,
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1112
1374
|
private personName(person?: {
|
|
1113
1375
|
name?: string | null;
|
|
1114
1376
|
} | null) {
|