@hed-hog/lms 0.0.358 → 0.0.364
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/bitcode-wallet/bitcode-wallet.service.d.ts +65 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -1
- package/dist/bitcode-wallet/bitcode-wallet.service.js +72 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.js.map +1 -1
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts +8 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js +40 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js.map +1 -0
- package/dist/class-group/class-group.controller.d.ts +16 -16
- package/dist/class-group/class-group.service.d.ts +12 -12
- package/dist/course/course-audio-transcription.service.d.ts +3 -2
- package/dist/course/course-audio-transcription.service.d.ts.map +1 -1
- package/dist/course/course-audio-transcription.service.js +49 -8
- package/dist/course/course-audio-transcription.service.js.map +1 -1
- package/dist/course/course-lesson.controller.d.ts +4 -0
- package/dist/course/course-lesson.controller.d.ts.map +1 -1
- package/dist/course/course-lesson.controller.js +10 -0
- package/dist/course/course-lesson.controller.js.map +1 -1
- package/dist/course/course-structure.controller.d.ts +11 -4
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +14 -0
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +15 -1
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +139 -4
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course-video-conversion.service.d.ts +8 -0
- package/dist/course/course-video-conversion.service.d.ts.map +1 -1
- package/dist/course/course-video-conversion.service.js +87 -51
- package/dist/course/course-video-conversion.service.js.map +1 -1
- package/dist/course/course.controller.d.ts +73 -1
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.controller.js +27 -3
- package/dist/course/course.controller.js.map +1 -1
- package/dist/course/course.module.d.ts.map +1 -1
- package/dist/course/course.module.js +15 -3
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +108 -4
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +631 -30
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/cleanup-course-storage.dto.d.ts +6 -0
- package/dist/course/dto/cleanup-course-storage.dto.d.ts.map +1 -0
- package/dist/course/dto/cleanup-course-storage.dto.js +33 -0
- package/dist/course/dto/cleanup-course-storage.dto.js.map +1 -0
- package/dist/course/dto/cleanup-upload-history.dto.d.ts +9 -0
- package/dist/course/dto/cleanup-upload-history.dto.d.ts.map +1 -0
- package/dist/course/dto/cleanup-upload-history.dto.js +36 -0
- package/dist/course/dto/cleanup-upload-history.dto.js.map +1 -0
- package/dist/course/dto/create-course-bulk-job.dto.d.ts +4 -0
- package/dist/course/dto/create-course-bulk-job.dto.d.ts.map +1 -0
- package/dist/course/dto/create-course-bulk-job.dto.js +21 -0
- package/dist/course/dto/create-course-bulk-job.dto.js.map +1 -0
- package/dist/course/lms-bulk-upload-automation.service.d.ts +39 -0
- package/dist/course/lms-bulk-upload-automation.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload-automation.service.js +443 -0
- package/dist/course/lms-bulk-upload-automation.service.js.map +1 -0
- package/dist/course/lms-bulk-upload-infra.service.d.ts +31 -0
- package/dist/course/lms-bulk-upload-infra.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload-infra.service.js +277 -0
- package/dist/course/lms-bulk-upload-infra.service.js.map +1 -0
- package/dist/course/lms-bulk-upload.constants.d.ts +4 -0
- package/dist/course/lms-bulk-upload.constants.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.constants.js +7 -0
- package/dist/course/lms-bulk-upload.constants.js.map +1 -0
- package/dist/course/lms-bulk-upload.controller.d.ts +153 -0
- package/dist/course/lms-bulk-upload.controller.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.controller.js +129 -0
- package/dist/course/lms-bulk-upload.controller.js.map +1 -0
- package/dist/course/lms-bulk-upload.service.d.ts +181 -0
- package/dist/course/lms-bulk-upload.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.service.js +754 -0
- package/dist/course/lms-bulk-upload.service.js.map +1 -0
- package/dist/course/lms-setting.controller.d.ts +7 -1
- package/dist/course/lms-setting.controller.d.ts.map +1 -1
- package/dist/course/lms-setting.controller.js +26 -3
- package/dist/course/lms-setting.controller.js.map +1 -1
- package/dist/enterprise/enterprise.controller.d.ts +20 -20
- package/dist/enterprise/enterprise.service.d.ts +20 -20
- package/dist/enterprise/training/training-admin.controller.d.ts +11 -11
- package/dist/enterprise/training/training-admin.service.d.ts +11 -11
- package/dist/enterprise/training/training-instructor.controller.d.ts +2 -2
- package/dist/enterprise/training/training-instructor.service.d.ts +2 -2
- package/dist/enterprise/training/training-student.controller.d.ts +1 -1
- package/dist/enterprise/training/training-student.service.d.ts +1 -1
- package/dist/enterprise/training/training-viewer.controller.d.ts +2 -2
- package/dist/evaluation/evaluation.controller.d.ts +8 -8
- package/dist/evaluation/evaluation.service.d.ts +8 -8
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts +6 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js +34 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts +28 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js +123 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts +4 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js +22 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts +10 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js +52 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts +15 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js +86 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts +26 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js +304 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts +87 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.js +185 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.d.ts +3 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.js +34 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.d.ts +84 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.js +353 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts +10 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.js +63 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts +27 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.js +194 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.js.map +1 -0
- package/dist/libraries/lms/tsconfig.tsbuildinfo +1 -0
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +17 -2
- package/dist/lms.module.js.map +1 -1
- package/dist/platforma/dto/update-profile.dto.d.ts +17 -0
- package/dist/platforma/dto/update-profile.dto.d.ts.map +1 -0
- package/dist/platforma/dto/update-profile.dto.js +87 -0
- package/dist/platforma/dto/update-profile.dto.js.map +1 -0
- package/dist/platforma/platforma.controller.d.ts +94 -7
- package/dist/platforma/platforma.controller.d.ts.map +1 -1
- package/dist/platforma/platforma.controller.js +85 -2
- package/dist/platforma/platforma.controller.js.map +1 -1
- package/dist/platforma/platforma.service.d.ts +27 -0
- package/dist/platforma/platforma.service.d.ts.map +1 -0
- package/dist/platforma/platforma.service.js +274 -0
- package/dist/platforma/platforma.service.js.map +1 -0
- package/dist/student-xp/student-xp.controller.d.ts +41 -0
- package/dist/student-xp/student-xp.controller.d.ts.map +1 -0
- package/dist/student-xp/student-xp.controller.js +114 -0
- package/dist/student-xp/student-xp.controller.js.map +1 -0
- package/dist/student-xp/student-xp.module.d.ts +3 -0
- package/dist/student-xp/student-xp.module.d.ts.map +1 -0
- package/dist/student-xp/student-xp.module.js +25 -0
- package/dist/student-xp/student-xp.module.js.map +1 -0
- package/dist/student-xp/student-xp.service.d.ts +65 -0
- package/dist/student-xp/student-xp.service.d.ts.map +1 -0
- package/dist/student-xp/student-xp.service.js +197 -0
- package/dist/student-xp/student-xp.service.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.d.ts +12 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.js +63 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.js +57 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.js +57 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.d.ts +12 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.js +66 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.js +60 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.js +60 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.js.map +1 -0
- package/dist/xp-catalog/xp-area.controller.d.ts +25 -0
- package/dist/xp-catalog/xp-area.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-area.controller.js +105 -0
- package/dist/xp-catalog/xp-area.controller.js.map +1 -0
- package/dist/xp-catalog/xp-area.service.d.ts +35 -0
- package/dist/xp-catalog/xp-area.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-area.service.js +168 -0
- package/dist/xp-catalog/xp-area.service.js.map +1 -0
- package/dist/xp-catalog/xp-catalog.module.d.ts +3 -0
- package/dist/xp-catalog/xp-catalog.module.d.ts.map +1 -0
- package/dist/xp-catalog/xp-catalog.module.js +29 -0
- package/dist/xp-catalog/xp-catalog.module.js.map +1 -0
- package/dist/xp-catalog/xp-learning-type.controller.d.ts +20 -0
- package/dist/xp-catalog/xp-learning-type.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-learning-type.controller.js +96 -0
- package/dist/xp-catalog/xp-learning-type.controller.js.map +1 -0
- package/dist/xp-catalog/xp-learning-type.service.d.ts +30 -0
- package/dist/xp-catalog/xp-learning-type.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-learning-type.service.js +146 -0
- package/dist/xp-catalog/xp-learning-type.service.js.map +1 -0
- package/dist/xp-catalog/xp-skill.controller.d.ts +26 -0
- package/dist/xp-catalog/xp-skill.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-skill.controller.js +113 -0
- package/dist/xp-catalog/xp-skill.controller.js.map +1 -0
- package/dist/xp-catalog/xp-skill.service.d.ts +37 -0
- package/dist/xp-catalog/xp-skill.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-skill.service.js +174 -0
- package/dist/xp-catalog/xp-skill.service.js.map +1 -0
- package/hedhog/data/menu.yaml +101 -0
- package/hedhog/data/role.yaml +8 -0
- package/hedhog/data/route.yaml +547 -0
- package/hedhog/data/setting_group.yaml +33 -0
- package/hedhog/data/xp_area.yaml +164 -0
- package/hedhog/data/xp_learning_type.yaml +131 -0
- package/hedhog/data/xp_skill.yaml +1834 -0
- package/hedhog/frontend/app/achievements/page.tsx.ejs +108 -118
- package/hedhog/frontend/app/bitcodes/page.tsx.ejs +22 -34
- package/hedhog/frontend/app/bulk-upload-sessions/page.tsx.ejs +1453 -0
- package/hedhog/frontend/app/certificates/models/page.tsx.ejs +21 -45
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +40 -74
- package/hedhog/frontend/app/classes/page.tsx.ejs +56 -85
- package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +3 -2
- package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +48 -5
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +4 -4
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-operations-tab.tsx.ejs +19 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-overview-tab.tsx.ejs +1170 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +16 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +2 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-xp-overview-tab.tsx.ejs +623 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson-xp-tab.tsx.ejs +1458 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +55 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +442 -104
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +296 -49
- package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +101 -85
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +21 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +7 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/xp-premium-pills.tsx.ejs +44 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-content-overview.ts.ejs +54 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +52 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-xp-overview.ts.ejs +76 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-xp-map.ts.ejs +128 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +30 -0
- package/hedhog/frontend/app/courses/[id]/structure/_utils/xp-color-config.ts.ejs +115 -0
- package/hedhog/frontend/app/courses/_components/CourseDeleteDialog.tsx.ejs +223 -0
- package/hedhog/frontend/app/courses/_components/CourseRowActions.tsx.ejs +89 -0
- package/hedhog/frontend/app/courses/page.tsx.ejs +400 -230
- package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -63
- package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +53 -77
- package/hedhog/frontend/app/exams/page.tsx.ejs +54 -90
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +23 -36
- package/hedhog/frontend/app/instructors/page.tsx.ejs +72 -81
- package/hedhog/frontend/app/paths/page.tsx.ejs +40 -68
- package/hedhog/frontend/app/training/page.tsx.ejs +40 -68
- package/hedhog/frontend/app/xp/areas/page.tsx.ejs +782 -0
- package/hedhog/frontend/app/xp/learning-types/page.tsx.ejs +690 -0
- package/hedhog/frontend/app/xp/skills/page.tsx.ejs +811 -0
- package/hedhog/frontend/messages/en.json +386 -3
- package/hedhog/frontend/messages/pt.json +386 -3
- package/hedhog/table/lesson_xp_map.yaml +50 -0
- package/hedhog/table/lesson_xp_segment.yaml +40 -0
- package/hedhog/table/lesson_xp_segment_area.yaml +24 -0
- package/hedhog/table/lesson_xp_segment_learning_type.yaml +24 -0
- package/hedhog/table/lesson_xp_segment_skill.yaml +24 -0
- package/hedhog/table/lms_bulk_upload_item.yaml +44 -0
- package/hedhog/table/lms_bulk_upload_session.yaml +42 -0
- package/hedhog/table/student_area_xp.yaml +30 -0
- package/hedhog/table/student_learning_type_xp.yaml +30 -0
- package/hedhog/table/student_skill_xp.yaml +30 -0
- package/hedhog/table/student_xp_event.yaml +34 -0
- package/hedhog/table/xp_area.yaml +39 -0
- package/hedhog/table/xp_learning_type.yaml +34 -0
- package/hedhog/table/xp_skill.yaml +39 -0
- package/package.json +9 -8
- package/src/bitcode-wallet/bitcode-wallet.service.ts +113 -0
- package/src/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.ts +32 -0
- package/src/course/course-audio-transcription.service.ts +58 -21
- package/src/course/course-lesson.controller.ts +6 -1
- package/src/course/course-structure.controller.ts +10 -0
- package/src/course/course-structure.service.ts +174 -1
- package/src/course/course-video-conversion.service.ts +113 -75
- package/src/course/course.controller.ts +22 -3
- package/src/course/course.module.ts +15 -3
- package/src/course/course.service.ts +847 -30
- package/src/course/dto/cleanup-course-storage.dto.ts +22 -0
- package/src/course/dto/cleanup-upload-history.dto.ts +26 -0
- package/src/course/dto/create-course-bulk-job.dto.ts +6 -0
- package/src/course/lms-bulk-upload-automation.service.ts +560 -0
- package/src/course/lms-bulk-upload-infra.service.ts +327 -0
- package/src/course/lms-bulk-upload.constants.ts +5 -0
- package/src/course/lms-bulk-upload.controller.ts +103 -0
- package/src/course/lms-bulk-upload.service.ts +1029 -0
- package/src/course/lms-setting.controller.ts +28 -1
- package/src/lesson-xp-map/dto/create-lesson-xp-map.dto.ts +17 -0
- package/src/lesson-xp-map/dto/create-lesson-xp-segment.dto.ts +102 -0
- package/src/lesson-xp-map/dto/review-lesson-xp-map.dto.ts +7 -0
- package/src/lesson-xp-map/dto/update-lesson-xp-map.dto.ts +36 -0
- package/src/lesson-xp-map/dto/update-lesson-xp-segment.dto.ts +78 -0
- package/src/lesson-xp-map/lesson-xp-ai-calculation.service.ts +396 -0
- package/src/lesson-xp-map/lesson-xp-map.controller.ts +116 -0
- package/src/lesson-xp-map/lesson-xp-map.module.ts +21 -0
- package/src/lesson-xp-map/lesson-xp-map.service.ts +442 -0
- package/src/lesson-xp-map/lesson-xp-segment.controller.ts +36 -0
- package/src/lesson-xp-map/lesson-xp-segment.service.ts +229 -0
- package/src/lms.module.ts +17 -2
- package/src/platforma/dto/update-profile.dto.ts +59 -0
- package/src/platforma/platforma.controller.ts +57 -2
- package/src/platforma/platforma.service.ts +268 -0
- package/src/student-xp/student-xp.controller.ts +76 -0
- package/src/student-xp/student-xp.module.ts +12 -0
- package/src/student-xp/student-xp.service.ts +236 -0
- package/src/xp-catalog/dto/create-xp-area.dto.ts +40 -0
- package/src/xp-catalog/dto/create-xp-learning-type.dto.ts +35 -0
- package/src/xp-catalog/dto/create-xp-skill.dto.ts +35 -0
- package/src/xp-catalog/dto/update-xp-area.dto.ts +43 -0
- package/src/xp-catalog/dto/update-xp-learning-type.dto.ts +38 -0
- package/src/xp-catalog/dto/update-xp-skill.dto.ts +38 -0
- package/src/xp-catalog/xp-area.controller.ts +64 -0
- package/src/xp-catalog/xp-area.service.ts +196 -0
- package/src/xp-catalog/xp-catalog.module.ts +16 -0
- package/src/xp-catalog/xp-learning-type.controller.ts +59 -0
- package/src/xp-catalog/xp-learning-type.service.ts +170 -0
- package/src/xp-catalog/xp-skill.controller.ts +71 -0
- package/src/xp-catalog/xp-skill.service.ts +205 -0
|
@@ -22,18 +22,154 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
22
22
|
}
|
|
23
23
|
return t;
|
|
24
24
|
};
|
|
25
|
+
var CourseService_1;
|
|
25
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.CourseService = void 0;
|
|
27
|
+
exports.CourseService = exports.LMS_COURSE_STORAGE_CLEANUP_JOB = exports.LMS_COURSE_DELETE_JOB = void 0;
|
|
27
28
|
const api_prisma_1 = require("@hed-hog/api-prisma");
|
|
28
29
|
const core_1 = require("@hed-hog/core");
|
|
30
|
+
const queue_1 = require("@hed-hog/queue");
|
|
29
31
|
const common_1 = require("@nestjs/common");
|
|
30
32
|
const course_operations_integration_service_1 = require("./course-operations-integration.service");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
const cleanup_course_storage_dto_1 = require("./dto/cleanup-course-storage.dto");
|
|
34
|
+
exports.LMS_COURSE_DELETE_JOB = 'lms.course.delete';
|
|
35
|
+
exports.LMS_COURSE_STORAGE_CLEANUP_JOB = 'lms.course.storage.cleanup';
|
|
36
|
+
let CourseService = CourseService_1 = class CourseService {
|
|
37
|
+
constructor(prisma, fileService, integrationApi, queueJobService, queueRegistry, notificationService, operationsIntegration) {
|
|
33
38
|
this.prisma = prisma;
|
|
34
39
|
this.fileService = fileService;
|
|
35
40
|
this.integrationApi = integrationApi;
|
|
41
|
+
this.queueJobService = queueJobService;
|
|
42
|
+
this.queueRegistry = queueRegistry;
|
|
43
|
+
this.notificationService = notificationService;
|
|
36
44
|
this.operationsIntegration = operationsIntegration;
|
|
45
|
+
this.logger = new common_1.Logger(CourseService_1.name);
|
|
46
|
+
}
|
|
47
|
+
onModuleInit() {
|
|
48
|
+
this.queueRegistry.register(exports.LMS_COURSE_DELETE_JOB, this);
|
|
49
|
+
this.queueRegistry.register(exports.LMS_COURSE_STORAGE_CLEANUP_JOB, this);
|
|
50
|
+
this.logger.log(`Registered handler for "${exports.LMS_COURSE_DELETE_JOB}"`);
|
|
51
|
+
this.logger.log(`Registered handler for "${exports.LMS_COURSE_STORAGE_CLEANUP_JOB}"`);
|
|
52
|
+
}
|
|
53
|
+
async handle(job) {
|
|
54
|
+
if (job.type === exports.LMS_COURSE_STORAGE_CLEANUP_JOB) {
|
|
55
|
+
return this.handleStorageCleanupJob(job);
|
|
56
|
+
}
|
|
57
|
+
if (job.type === exports.LMS_COURSE_DELETE_JOB) {
|
|
58
|
+
return this.handleCourseDeleteJob(job);
|
|
59
|
+
}
|
|
60
|
+
throw new common_1.BadRequestException(`Unsupported job type: ${job.type}`);
|
|
61
|
+
}
|
|
62
|
+
async handleCourseDeleteJob(job) {
|
|
63
|
+
const { courseId, notificationId, notificationUserId } = job.payload;
|
|
64
|
+
if (!courseId) {
|
|
65
|
+
throw new common_1.BadRequestException('Missing courseId in job payload');
|
|
66
|
+
}
|
|
67
|
+
const notify = async (progress, body, success) => {
|
|
68
|
+
if (!notificationId || !notificationUserId)
|
|
69
|
+
return;
|
|
70
|
+
await this.notificationService
|
|
71
|
+
.updateProgress(notificationUserId, notificationId, Object.assign({ progress,
|
|
72
|
+
body }, (success !== undefined ? { success } : {})))
|
|
73
|
+
.catch(() => undefined);
|
|
74
|
+
};
|
|
75
|
+
try {
|
|
76
|
+
await notify(5, 'Preparando exclusão completa do curso...');
|
|
77
|
+
const course = await this.prisma.course.findUnique({
|
|
78
|
+
where: { id: courseId },
|
|
79
|
+
select: { id: true, status: true, title: true, slug: true },
|
|
80
|
+
});
|
|
81
|
+
if (!course) {
|
|
82
|
+
throw new common_1.NotFoundException('Course not found');
|
|
83
|
+
}
|
|
84
|
+
if (course.status !== 'archived') {
|
|
85
|
+
throw new common_1.BadRequestException('ONLY_ARCHIVED_COURSE_CAN_BE_DELETED');
|
|
86
|
+
}
|
|
87
|
+
const impact = await this.getCourseDeletionImpact(courseId);
|
|
88
|
+
await notify(20, `Removendo ${impact.deletionImpact.fileCount} arquivo(s) relacionados ao curso...`);
|
|
89
|
+
if (impact.deletionImpact.fileIds.length > 0) {
|
|
90
|
+
await this.fileService
|
|
91
|
+
.delete('pt', { ids: impact.deletionImpact.fileIds })
|
|
92
|
+
.catch(() => undefined);
|
|
93
|
+
}
|
|
94
|
+
await notify(75, 'Removendo registros do curso e dependências...');
|
|
95
|
+
await this.prisma.course.delete({ where: { id: courseId } });
|
|
96
|
+
await notify(90, 'Finalizando exclusão e publicando evento...');
|
|
97
|
+
await this.integrationApi
|
|
98
|
+
.publishEvent({
|
|
99
|
+
eventName: 'lms.course.deleted',
|
|
100
|
+
sourceModule: 'lms',
|
|
101
|
+
aggregateType: 'course',
|
|
102
|
+
aggregateId: String(courseId),
|
|
103
|
+
payload: { id: courseId },
|
|
104
|
+
})
|
|
105
|
+
.catch(() => null);
|
|
106
|
+
await notify(100, 'Curso e todos os arquivos relacionados foram excluídos.', true);
|
|
107
|
+
return { success: true, courseId };
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const message = error instanceof Error && error.message
|
|
111
|
+
? error.message
|
|
112
|
+
: 'Falha ao excluir o curso.';
|
|
113
|
+
await notify(100, message, false);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async handleStorageCleanupJob(job) {
|
|
118
|
+
const { courseId, category, notificationId, notificationUserId } = job.payload;
|
|
119
|
+
if (!courseId) {
|
|
120
|
+
throw new common_1.BadRequestException('Missing courseId in job payload');
|
|
121
|
+
}
|
|
122
|
+
if (!this.isSupportedStorageCleanupCategory(category)) {
|
|
123
|
+
throw new common_1.BadRequestException('Invalid storage category');
|
|
124
|
+
}
|
|
125
|
+
const notify = async (progress, body, success) => {
|
|
126
|
+
if (!notificationId || !notificationUserId)
|
|
127
|
+
return;
|
|
128
|
+
await this.notificationService
|
|
129
|
+
.updateProgress(notificationUserId, notificationId, Object.assign({ progress,
|
|
130
|
+
body }, (success !== undefined ? { success } : {})))
|
|
131
|
+
.catch(() => undefined);
|
|
132
|
+
};
|
|
133
|
+
try {
|
|
134
|
+
const categoryLabel = this.getStorageCategoryLabel(category);
|
|
135
|
+
await notify(5, `Preparando limpeza da categoria ${categoryLabel}...`);
|
|
136
|
+
const impact = await this.getCourseStorageCategoryImpact(courseId, category);
|
|
137
|
+
if (impact.fileCount === 0) {
|
|
138
|
+
await notify(100, `Nenhum arquivo encontrado em ${categoryLabel}.`, true);
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
status: 'empty',
|
|
142
|
+
courseId,
|
|
143
|
+
category,
|
|
144
|
+
cleanupImpact: impact,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
await notify(25, `Removendo vínculos da categoria ${categoryLabel} (${impact.fileCount} arquivo(s))...`);
|
|
148
|
+
await this.deleteCourseStorageCategoryLinks(courseId, category);
|
|
149
|
+
await notify(65, `Excluindo ${impact.fileCount} arquivo(s) da categoria ${categoryLabel}...`);
|
|
150
|
+
if (impact.fileIds.length > 0) {
|
|
151
|
+
await this.fileService.delete('pt', { ids: impact.fileIds }).catch(() => undefined);
|
|
152
|
+
}
|
|
153
|
+
await notify(100, `Categoria ${categoryLabel} limpa com sucesso (${this.formatBytes(impact.totalBytes)} liberados).`, true);
|
|
154
|
+
return {
|
|
155
|
+
success: true,
|
|
156
|
+
status: 'processed',
|
|
157
|
+
courseId,
|
|
158
|
+
category,
|
|
159
|
+
cleanupImpact: {
|
|
160
|
+
fileCount: impact.fileCount,
|
|
161
|
+
totalBytes: impact.totalBytes,
|
|
162
|
+
formattedSize: this.formatBytes(impact.totalBytes),
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const message = error instanceof Error && error.message
|
|
168
|
+
? error.message
|
|
169
|
+
: 'Falha ao limpar a categoria de armazenamento.';
|
|
170
|
+
await notify(100, message, false);
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
37
173
|
}
|
|
38
174
|
normalizeLevel(value) {
|
|
39
175
|
if (!value)
|
|
@@ -216,7 +352,7 @@ let CourseService = class CourseService {
|
|
|
216
352
|
};
|
|
217
353
|
}
|
|
218
354
|
async getById(id) {
|
|
219
|
-
var _a;
|
|
355
|
+
var _a, _b;
|
|
220
356
|
const [c, lessonInstructors] = await Promise.all([
|
|
221
357
|
this.prisma.course.findUnique({
|
|
222
358
|
where: { id },
|
|
@@ -243,7 +379,16 @@ let CourseService = class CourseService {
|
|
|
243
379
|
},
|
|
244
380
|
},
|
|
245
381
|
file: {
|
|
246
|
-
select: {
|
|
382
|
+
select: {
|
|
383
|
+
id: true,
|
|
384
|
+
filename: true,
|
|
385
|
+
size: true,
|
|
386
|
+
file_mimetype: {
|
|
387
|
+
select: {
|
|
388
|
+
name: true,
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
},
|
|
247
392
|
},
|
|
248
393
|
},
|
|
249
394
|
orderBy: [{ is_primary: 'desc' }, { order: 'asc' }],
|
|
@@ -334,13 +479,21 @@ let CourseService = class CourseService {
|
|
|
334
479
|
progress: average,
|
|
335
480
|
};
|
|
336
481
|
});
|
|
337
|
-
|
|
482
|
+
const mapped = this.mapCourse(c, {
|
|
338
483
|
lessonCount,
|
|
339
484
|
sessionCount,
|
|
340
485
|
certificatesIssued,
|
|
341
486
|
averageCompletion: (_a = avgProgress._avg.progress_percent) !== null && _a !== void 0 ? _a : 0,
|
|
342
487
|
progressByModule,
|
|
343
488
|
}, extrasById.get(id), projectLinksById.get(id), lessonInstructors);
|
|
489
|
+
const deletionImpact = await this.getCourseDeletionImpact(id);
|
|
490
|
+
return Object.assign(Object.assign({}, mapped), { deletionImpact: {
|
|
491
|
+
fileCount: deletionImpact.deletionImpact.fileCount,
|
|
492
|
+
totalBytes: deletionImpact.deletionImpact.totalBytes,
|
|
493
|
+
formattedSize: this.formatBytes(deletionImpact.deletionImpact.totalBytes),
|
|
494
|
+
countsBySource: deletionImpact.deletionImpact.countsBySource,
|
|
495
|
+
enrollmentCount: (_b = mapped.enrollmentCount) !== null && _b !== void 0 ? _b : 0,
|
|
496
|
+
} });
|
|
344
497
|
}
|
|
345
498
|
async create(dto) {
|
|
346
499
|
var _a, _b, _c, _d, _e;
|
|
@@ -548,10 +701,11 @@ let CourseService = class CourseService {
|
|
|
548
701
|
}).catch(() => null);
|
|
549
702
|
return updateResult;
|
|
550
703
|
}
|
|
551
|
-
async remove(id) {
|
|
704
|
+
async remove(id, userId) {
|
|
705
|
+
var _a;
|
|
552
706
|
const course = await this.prisma.course.findUnique({
|
|
553
707
|
where: { id },
|
|
554
|
-
select: { id: true, status: true },
|
|
708
|
+
select: { id: true, status: true, title: true, slug: true },
|
|
555
709
|
});
|
|
556
710
|
if (!course) {
|
|
557
711
|
throw new common_1.BadRequestException('Course not found');
|
|
@@ -559,62 +713,362 @@ let CourseService = class CourseService {
|
|
|
559
713
|
if (course.status !== 'archived') {
|
|
560
714
|
throw new common_1.BadRequestException('ONLY_ARCHIVED_COURSE_CAN_BE_DELETED');
|
|
561
715
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
await this.fileService.delete('pt', { ids: fileIds }).catch(() => undefined);
|
|
716
|
+
if (!userId) {
|
|
717
|
+
throw new common_1.BadRequestException('Authenticated user is required');
|
|
565
718
|
}
|
|
566
|
-
await this.
|
|
567
|
-
await this.
|
|
568
|
-
|
|
719
|
+
const impact = await this.getCourseDeletionImpact(id);
|
|
720
|
+
const notification = await this.notificationService.create({
|
|
721
|
+
user_id: userId,
|
|
722
|
+
title: `Excluindo curso "${(_a = course.title) !== null && _a !== void 0 ? _a : course.slug}"`,
|
|
723
|
+
body: `Preparando remoção de ${impact.deletionImpact.fileCount} arquivo(s) (${this.formatBytes(impact.deletionImpact.totalBytes)}).`,
|
|
724
|
+
type: 'progress',
|
|
725
|
+
progress: 1,
|
|
726
|
+
started_at: new Date().toISOString(),
|
|
727
|
+
auto_remove: false,
|
|
728
|
+
action_type: 'url',
|
|
729
|
+
action_url: '/lms/courses',
|
|
730
|
+
action_data: {
|
|
731
|
+
source: 'lms-course-delete',
|
|
732
|
+
courseId: id,
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
const job = await this.queueJobService.enqueue({
|
|
736
|
+
type: exports.LMS_COURSE_DELETE_JOB,
|
|
737
|
+
queueName: exports.LMS_COURSE_DELETE_JOB,
|
|
738
|
+
payload: {
|
|
739
|
+
courseId: id,
|
|
740
|
+
notificationId: notification.id,
|
|
741
|
+
notificationUserId: userId,
|
|
742
|
+
},
|
|
569
743
|
sourceModule: 'lms',
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
return {
|
|
744
|
+
sourceEntity: 'course',
|
|
745
|
+
sourceEntityId: String(id),
|
|
746
|
+
maxAttempts: 3,
|
|
747
|
+
}, userId);
|
|
748
|
+
return {
|
|
749
|
+
success: true,
|
|
750
|
+
status: 'queued',
|
|
751
|
+
queueJobId: job.id,
|
|
752
|
+
notificationId: notification.id,
|
|
753
|
+
deletionImpact: {
|
|
754
|
+
fileCount: impact.deletionImpact.fileCount,
|
|
755
|
+
totalBytes: impact.deletionImpact.totalBytes,
|
|
756
|
+
formattedSize: this.formatBytes(impact.deletionImpact.totalBytes),
|
|
757
|
+
},
|
|
758
|
+
};
|
|
575
759
|
}
|
|
576
|
-
async
|
|
760
|
+
async enqueueStorageCategoryCleanup(courseId, category, userId) {
|
|
761
|
+
if (!userId) {
|
|
762
|
+
throw new common_1.BadRequestException('Authenticated user is required');
|
|
763
|
+
}
|
|
764
|
+
if (!this.isSupportedStorageCleanupCategory(category)) {
|
|
765
|
+
throw new common_1.BadRequestException('Invalid storage category');
|
|
766
|
+
}
|
|
767
|
+
const course = await this.prisma.course.findUnique({
|
|
768
|
+
where: { id: courseId },
|
|
769
|
+
select: { id: true, title: true, slug: true },
|
|
770
|
+
});
|
|
771
|
+
if (!course) {
|
|
772
|
+
throw new common_1.NotFoundException('Course not found');
|
|
773
|
+
}
|
|
774
|
+
const categoryLabel = this.getStorageCategoryLabel(category);
|
|
775
|
+
const impact = await this.getCourseStorageCategoryImpact(courseId, category);
|
|
776
|
+
if (impact.fileCount === 0) {
|
|
777
|
+
return {
|
|
778
|
+
success: true,
|
|
779
|
+
status: 'empty',
|
|
780
|
+
cleanupImpact: {
|
|
781
|
+
fileCount: 0,
|
|
782
|
+
totalBytes: 0,
|
|
783
|
+
formattedSize: this.formatBytes(0),
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
const notification = await this.notificationService.create({
|
|
788
|
+
user_id: userId,
|
|
789
|
+
title: `Limpando armazenamento (${categoryLabel})`,
|
|
790
|
+
body: `Preparando remoção de ${impact.fileCount} arquivo(s) (${this.formatBytes(impact.totalBytes)}).`,
|
|
791
|
+
type: 'progress',
|
|
792
|
+
progress: 1,
|
|
793
|
+
started_at: new Date().toISOString(),
|
|
794
|
+
auto_remove: false,
|
|
795
|
+
action_type: 'url',
|
|
796
|
+
action_url: `/lms/courses/${courseId}`,
|
|
797
|
+
action_data: {
|
|
798
|
+
source: 'lms-course-storage-cleanup',
|
|
799
|
+
courseId,
|
|
800
|
+
category,
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
const job = await this.queueJobService.enqueue({
|
|
804
|
+
type: exports.LMS_COURSE_STORAGE_CLEANUP_JOB,
|
|
805
|
+
queueName: exports.LMS_COURSE_STORAGE_CLEANUP_JOB,
|
|
806
|
+
payload: {
|
|
807
|
+
courseId,
|
|
808
|
+
category,
|
|
809
|
+
notificationId: notification.id,
|
|
810
|
+
notificationUserId: userId,
|
|
811
|
+
},
|
|
812
|
+
sourceModule: 'lms',
|
|
813
|
+
sourceEntity: 'course',
|
|
814
|
+
sourceEntityId: String(courseId),
|
|
815
|
+
maxAttempts: 3,
|
|
816
|
+
}, userId);
|
|
817
|
+
return {
|
|
818
|
+
success: true,
|
|
819
|
+
status: 'queued',
|
|
820
|
+
queueJobId: job.id,
|
|
821
|
+
notificationId: notification.id,
|
|
822
|
+
category,
|
|
823
|
+
cleanupImpact: {
|
|
824
|
+
fileCount: impact.fileCount,
|
|
825
|
+
totalBytes: impact.totalBytes,
|
|
826
|
+
formattedSize: this.formatBytes(impact.totalBytes),
|
|
827
|
+
},
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
isSupportedStorageCleanupCategory(value) {
|
|
831
|
+
return (typeof value === 'string' &&
|
|
832
|
+
cleanup_course_storage_dto_1.COURSE_STORAGE_CLEANUP_CATEGORIES.includes(value));
|
|
833
|
+
}
|
|
834
|
+
getStorageCategoryLabel(category) {
|
|
835
|
+
const labels = {
|
|
836
|
+
video_original: 'Vídeos originais',
|
|
837
|
+
video_profile: 'Vídeos convertidos',
|
|
838
|
+
lesson_audio: 'Áudios',
|
|
839
|
+
extracted_image: 'Imagens extraídas',
|
|
840
|
+
student_download: 'Downloads do aluno',
|
|
841
|
+
supplementary_material: 'Materiais de apoio',
|
|
842
|
+
course_image: 'Imagens do curso',
|
|
843
|
+
course_file: 'Arquivos do curso',
|
|
844
|
+
other_lesson_file: 'Outros arquivos',
|
|
845
|
+
};
|
|
846
|
+
return labels[category];
|
|
847
|
+
}
|
|
848
|
+
async getCourseStorageCategoryImpact(courseId, category) {
|
|
849
|
+
var _a, _b;
|
|
850
|
+
const rows = await this.getCourseStorageRows(courseId);
|
|
851
|
+
const uniqueFiles = new Map();
|
|
852
|
+
for (const row of rows) {
|
|
853
|
+
const rowCategory = String(row.storage_category || 'other_lesson_file');
|
|
854
|
+
if (rowCategory !== category)
|
|
855
|
+
continue;
|
|
856
|
+
const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
|
|
857
|
+
if (fileId <= 0)
|
|
858
|
+
continue;
|
|
859
|
+
if (!uniqueFiles.has(fileId)) {
|
|
860
|
+
uniqueFiles.set(fileId, Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const fileIds = Array.from(uniqueFiles.keys());
|
|
864
|
+
const totalBytes = Array.from(uniqueFiles.values()).reduce((sum, size) => sum + size, 0);
|
|
865
|
+
return {
|
|
866
|
+
category,
|
|
867
|
+
fileIds,
|
|
868
|
+
fileCount: fileIds.length,
|
|
869
|
+
totalBytes,
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
async deleteCourseStorageCategoryLinks(courseId, category) {
|
|
873
|
+
if (category === 'course_image') {
|
|
874
|
+
await this.prisma.course_image.deleteMany({ where: { course_id: courseId } });
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (category === 'course_file') {
|
|
878
|
+
await this.prisma.course_file.deleteMany({ where: { course_id: courseId } });
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (category === 'extracted_image') {
|
|
882
|
+
await this.prisma.$executeRaw `
|
|
883
|
+
DELETE FROM course_lesson_video_frame clvf
|
|
884
|
+
USING course_lesson cl, course_module cm
|
|
885
|
+
WHERE clvf.course_lesson_id = cl.id
|
|
886
|
+
AND cl.course_module_id = cm.id
|
|
887
|
+
AND cm.course_id = ${courseId}
|
|
888
|
+
`;
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (category === 'video_profile') {
|
|
892
|
+
await this.prisma.$executeRaw `
|
|
893
|
+
DELETE FROM course_lesson_file clf
|
|
894
|
+
USING course_lesson cl, course_module cm
|
|
895
|
+
WHERE clf.course_lesson_id = cl.id
|
|
896
|
+
AND cl.course_module_id = cm.id
|
|
897
|
+
AND cm.course_id = ${courseId}
|
|
898
|
+
AND clf.type LIKE 'video_profile:%'
|
|
899
|
+
`;
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
if (category === 'other_lesson_file') {
|
|
903
|
+
await this.prisma.$executeRaw `
|
|
904
|
+
DELETE FROM course_lesson_file clf
|
|
905
|
+
USING course_lesson cl, course_module cm
|
|
906
|
+
WHERE clf.course_lesson_id = cl.id
|
|
907
|
+
AND cl.course_module_id = cm.id
|
|
908
|
+
AND cm.course_id = ${courseId}
|
|
909
|
+
AND (
|
|
910
|
+
clf.type IS NULL
|
|
911
|
+
OR (
|
|
912
|
+
clf.type <> 'video_original'
|
|
913
|
+
AND clf.type <> 'lesson_audio'
|
|
914
|
+
AND clf.type <> 'student_download'
|
|
915
|
+
AND clf.type <> 'supplementary_material'
|
|
916
|
+
AND clf.type NOT LIKE 'video_profile:%'
|
|
917
|
+
)
|
|
918
|
+
)
|
|
919
|
+
`;
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
await this.prisma.course_lesson_file.deleteMany({
|
|
923
|
+
where: {
|
|
924
|
+
course_lesson: { course_module: { course_id: courseId } },
|
|
925
|
+
type: category,
|
|
926
|
+
},
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
async getCourseStorageRows(courseId) {
|
|
930
|
+
return this.prisma.$queryRaw `
|
|
931
|
+
SELECT files.file_id, files.file_size, files.storage_category
|
|
932
|
+
FROM (
|
|
933
|
+
SELECT ci.file_id, f.size AS file_size, 'course_image' AS storage_category
|
|
934
|
+
FROM course_image ci
|
|
935
|
+
INNER JOIN file f ON f.id = ci.file_id
|
|
936
|
+
WHERE ci.course_id = ${courseId}
|
|
937
|
+
|
|
938
|
+
UNION ALL
|
|
939
|
+
|
|
940
|
+
SELECT cf.file_id, f.size AS file_size, 'course_file' AS storage_category
|
|
941
|
+
FROM course_file cf
|
|
942
|
+
INNER JOIN file f ON f.id = cf.file_id
|
|
943
|
+
WHERE cf.course_id = ${courseId}
|
|
944
|
+
|
|
945
|
+
UNION ALL
|
|
946
|
+
|
|
947
|
+
SELECT clf.file_id,
|
|
948
|
+
f.size AS file_size,
|
|
949
|
+
CASE
|
|
950
|
+
WHEN clf.type = 'video_original' THEN 'video_original'
|
|
951
|
+
WHEN clf.type LIKE 'video_profile:%' THEN 'video_profile'
|
|
952
|
+
WHEN clf.type = 'lesson_audio' THEN 'lesson_audio'
|
|
953
|
+
WHEN clf.type = 'student_download' THEN 'student_download'
|
|
954
|
+
WHEN clf.type = 'supplementary_material' THEN 'supplementary_material'
|
|
955
|
+
ELSE 'other_lesson_file'
|
|
956
|
+
END AS storage_category
|
|
957
|
+
FROM course_lesson_file clf
|
|
958
|
+
INNER JOIN file f ON f.id = clf.file_id
|
|
959
|
+
INNER JOIN course_lesson cl ON cl.id = clf.course_lesson_id
|
|
960
|
+
INNER JOIN course_module cm ON cm.id = cl.course_module_id
|
|
961
|
+
WHERE cm.course_id = ${courseId}
|
|
962
|
+
|
|
963
|
+
UNION ALL
|
|
964
|
+
|
|
965
|
+
SELECT clvf.file_id, f.size AS file_size, 'extracted_image' AS storage_category
|
|
966
|
+
FROM course_lesson_video_frame clvf
|
|
967
|
+
INNER JOIN file f ON f.id = clvf.file_id
|
|
968
|
+
INNER JOIN course_lesson cl ON cl.id = clvf.course_lesson_id
|
|
969
|
+
INNER JOIN course_module cm ON cm.id = cl.course_module_id
|
|
970
|
+
WHERE cm.course_id = ${courseId}
|
|
971
|
+
) AS files
|
|
972
|
+
WHERE files.file_id IS NOT NULL
|
|
973
|
+
`;
|
|
974
|
+
}
|
|
975
|
+
async getCourseDeletionImpact(courseId) {
|
|
577
976
|
const rows = await this.prisma.$queryRaw `
|
|
578
|
-
SELECT DISTINCT files.file_id
|
|
977
|
+
SELECT DISTINCT files.file_id, files.file_size, files.source_type
|
|
579
978
|
FROM (
|
|
580
|
-
SELECT ci.file_id
|
|
979
|
+
SELECT ci.file_id, f.size AS file_size, 'course_image' AS source_type
|
|
581
980
|
FROM course_image ci
|
|
981
|
+
INNER JOIN file f ON f.id = ci.file_id
|
|
582
982
|
WHERE ci.course_id = ${courseId}
|
|
583
983
|
|
|
584
984
|
UNION ALL
|
|
585
985
|
|
|
586
|
-
SELECT cf.file_id
|
|
986
|
+
SELECT cf.file_id, f.size AS file_size, 'course_file' AS source_type
|
|
587
987
|
FROM course_file cf
|
|
988
|
+
INNER JOIN file f ON f.id = cf.file_id
|
|
588
989
|
WHERE cf.course_id = ${courseId}
|
|
589
990
|
|
|
590
991
|
UNION ALL
|
|
591
992
|
|
|
592
|
-
SELECT clf.file_id
|
|
993
|
+
SELECT clf.file_id, f.size AS file_size, 'course_lesson_file' AS source_type
|
|
593
994
|
FROM course_lesson_file clf
|
|
995
|
+
INNER JOIN file f ON f.id = clf.file_id
|
|
594
996
|
INNER JOIN course_lesson cl ON cl.id = clf.course_lesson_id
|
|
595
997
|
INNER JOIN course_module cm ON cm.id = cl.course_module_id
|
|
596
998
|
WHERE cm.course_id = ${courseId}
|
|
597
999
|
|
|
598
1000
|
UNION ALL
|
|
599
1001
|
|
|
600
|
-
SELECT clvf.file_id
|
|
1002
|
+
SELECT clvf.file_id, f.size AS file_size, 'course_lesson_video_frame' AS source_type
|
|
601
1003
|
FROM course_lesson_video_frame clvf
|
|
1004
|
+
INNER JOIN file f ON f.id = clvf.file_id
|
|
602
1005
|
INNER JOIN course_lesson cl ON cl.id = clvf.course_lesson_id
|
|
603
1006
|
INNER JOIN course_module cm ON cm.id = cl.course_module_id
|
|
604
1007
|
WHERE cm.course_id = ${courseId}
|
|
605
1008
|
|
|
606
1009
|
UNION ALL
|
|
607
1010
|
|
|
608
|
-
SELECT cgm.file_id
|
|
1011
|
+
SELECT cgm.file_id, f.size AS file_size, 'course_class_group_material' AS source_type
|
|
609
1012
|
FROM course_class_group_material cgm
|
|
1013
|
+
INNER JOIN file f ON f.id = cgm.file_id
|
|
610
1014
|
INNER JOIN course_class_group ccg ON ccg.id = cgm.course_class_group_id
|
|
611
1015
|
WHERE ccg.course_id = ${courseId}
|
|
1016
|
+
|
|
1017
|
+
UNION ALL
|
|
1018
|
+
|
|
1019
|
+
SELECT cln.frame_file_id AS file_id, f.size AS file_size, 'course_lesson_note_frame' AS source_type
|
|
1020
|
+
FROM course_lesson_note cln
|
|
1021
|
+
INNER JOIN file f ON f.id = cln.frame_file_id
|
|
1022
|
+
INNER JOIN course_lesson cl ON cl.id = cln.course_lesson_id
|
|
1023
|
+
INNER JOIN course_module cm ON cm.id = cl.course_module_id
|
|
1024
|
+
WHERE cm.course_id = ${courseId}
|
|
612
1025
|
) AS files
|
|
613
1026
|
WHERE files.file_id IS NOT NULL
|
|
614
1027
|
`;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
1028
|
+
const uniqueRows = Array.from(rows.reduce((map, row) => {
|
|
1029
|
+
var _a, _b;
|
|
1030
|
+
const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
|
|
1031
|
+
if (fileId > 0 && !map.has(fileId)) {
|
|
1032
|
+
map.set(fileId, {
|
|
1033
|
+
fileId,
|
|
1034
|
+
size: Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0,
|
|
1035
|
+
sourceType: row.source_type,
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
return map;
|
|
1039
|
+
}, new Map()).values());
|
|
1040
|
+
const countsBySource = rows.reduce((acc, row) => {
|
|
1041
|
+
var _a;
|
|
1042
|
+
const key = String(row.source_type || 'unknown');
|
|
1043
|
+
acc[key] = ((_a = acc[key]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1044
|
+
return acc;
|
|
1045
|
+
}, {});
|
|
1046
|
+
return {
|
|
1047
|
+
deletionImpact: {
|
|
1048
|
+
fileIds: uniqueRows.map((row) => row.fileId),
|
|
1049
|
+
fileCount: uniqueRows.length,
|
|
1050
|
+
totalBytes: uniqueRows.reduce((sum, row) => sum + row.size, 0),
|
|
1051
|
+
countsBySource,
|
|
1052
|
+
},
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
formatBytes(bytes) {
|
|
1056
|
+
if (!Number.isFinite(bytes) || bytes <= 0) {
|
|
1057
|
+
return '0 B';
|
|
1058
|
+
}
|
|
1059
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
1060
|
+
let value = bytes;
|
|
1061
|
+
let unitIndex = 0;
|
|
1062
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
1063
|
+
value /= 1024;
|
|
1064
|
+
unitIndex += 1;
|
|
1065
|
+
}
|
|
1066
|
+
const digits = unitIndex === 0 ? 0 : value >= 10 ? 1 : 2;
|
|
1067
|
+
return `${value.toFixed(digits)} ${units[unitIndex]}`;
|
|
1068
|
+
}
|
|
1069
|
+
async getCourseRelatedFileIds(courseId) {
|
|
1070
|
+
const impact = await this.getCourseDeletionImpact(courseId);
|
|
1071
|
+
return impact.deletionImpact.fileIds.filter((id) => Number.isInteger(id) && id > 0);
|
|
618
1072
|
}
|
|
619
1073
|
mapCourse(c, metrics, extras, project, lessonInstructors) {
|
|
620
1074
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38;
|
|
@@ -925,14 +1379,161 @@ let CourseService = class CourseService {
|
|
|
925
1379
|
status: row.video_resolution_profile.status,
|
|
926
1380
|
})));
|
|
927
1381
|
}
|
|
1382
|
+
async getCourseContentOverview(courseId) {
|
|
1383
|
+
var _a, _b, _c;
|
|
1384
|
+
const [moduleCount, lessons, transcriptionRows, xpMapRows, extractedImageCount, resourceFileCount, storageRows,] = await Promise.all([
|
|
1385
|
+
this.prisma.course_module.count({ where: { course_id: courseId } }),
|
|
1386
|
+
this.prisma.course_lesson.findMany({
|
|
1387
|
+
where: { course_module: { course_id: courseId } },
|
|
1388
|
+
select: { id: true, type: true, content: true, published: true },
|
|
1389
|
+
}),
|
|
1390
|
+
this.prisma.course_lesson_transcription_segment.findMany({
|
|
1391
|
+
where: { course_lesson: { course_module: { course_id: courseId } } },
|
|
1392
|
+
select: { course_lesson_id: true },
|
|
1393
|
+
distinct: ['course_lesson_id'],
|
|
1394
|
+
}),
|
|
1395
|
+
this.prisma.lesson_xp_map.findMany({
|
|
1396
|
+
where: { course_lesson: { course_module: { course_id: courseId } } },
|
|
1397
|
+
select: { course_lesson_id: true },
|
|
1398
|
+
}),
|
|
1399
|
+
this.prisma.course_lesson_video_frame.count({
|
|
1400
|
+
where: { course_lesson: { course_module: { course_id: courseId } } },
|
|
1401
|
+
}),
|
|
1402
|
+
this.prisma.course_lesson_file.count({
|
|
1403
|
+
where: {
|
|
1404
|
+
course_lesson: { course_module: { course_id: courseId } },
|
|
1405
|
+
type: { in: ['student_download', 'supplementary_material'] },
|
|
1406
|
+
},
|
|
1407
|
+
}),
|
|
1408
|
+
this.getCourseStorageRows(courseId),
|
|
1409
|
+
]);
|
|
1410
|
+
const transcriptionLessonIds = new Set(transcriptionRows.map((r) => r.course_lesson_id));
|
|
1411
|
+
const xpLessonIds = new Set(xpMapRows.map((r) => r.course_lesson_id));
|
|
1412
|
+
const lessonsByType = { video: 0, questao: 0, post: 0, exercicio: 0 };
|
|
1413
|
+
let publishedLessonCount = 0;
|
|
1414
|
+
let videoWithTranscription = 0;
|
|
1415
|
+
let videoWithXp = 0;
|
|
1416
|
+
const categoryOrder = [
|
|
1417
|
+
'video_original',
|
|
1418
|
+
'video_profile',
|
|
1419
|
+
'lesson_audio',
|
|
1420
|
+
'extracted_image',
|
|
1421
|
+
'student_download',
|
|
1422
|
+
'supplementary_material',
|
|
1423
|
+
'course_image',
|
|
1424
|
+
'course_file',
|
|
1425
|
+
'other_lesson_file',
|
|
1426
|
+
];
|
|
1427
|
+
const uniqueStorageFiles = new Map();
|
|
1428
|
+
const uniqueStorageCategoryEntries = new Set();
|
|
1429
|
+
const storageCategoryMap = new Map();
|
|
1430
|
+
for (const row of storageRows) {
|
|
1431
|
+
const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
|
|
1432
|
+
if (fileId <= 0)
|
|
1433
|
+
continue;
|
|
1434
|
+
const size = Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0;
|
|
1435
|
+
const category = String(row.storage_category || 'other_lesson_file');
|
|
1436
|
+
if (!uniqueStorageFiles.has(fileId)) {
|
|
1437
|
+
uniqueStorageFiles.set(fileId, size);
|
|
1438
|
+
}
|
|
1439
|
+
const categoryEntryKey = `${category}:${fileId}`;
|
|
1440
|
+
if (uniqueStorageCategoryEntries.has(categoryEntryKey)) {
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
uniqueStorageCategoryEntries.add(categoryEntryKey);
|
|
1444
|
+
const current = (_c = storageCategoryMap.get(category)) !== null && _c !== void 0 ? _c : {
|
|
1445
|
+
key: category,
|
|
1446
|
+
fileCount: 0,
|
|
1447
|
+
totalBytes: 0,
|
|
1448
|
+
};
|
|
1449
|
+
current.fileCount += 1;
|
|
1450
|
+
current.totalBytes += size;
|
|
1451
|
+
storageCategoryMap.set(category, current);
|
|
1452
|
+
}
|
|
1453
|
+
const storageCategories = Array.from(storageCategoryMap.values()).sort((a, b) => {
|
|
1454
|
+
const orderA = categoryOrder.indexOf(a.key);
|
|
1455
|
+
const orderB = categoryOrder.indexOf(b.key);
|
|
1456
|
+
if (orderA !== -1 || orderB !== -1) {
|
|
1457
|
+
return (orderA === -1 ? Number.MAX_SAFE_INTEGER : orderA) -
|
|
1458
|
+
(orderB === -1 ? Number.MAX_SAFE_INTEGER : orderB);
|
|
1459
|
+
}
|
|
1460
|
+
return b.totalBytes - a.totalBytes;
|
|
1461
|
+
});
|
|
1462
|
+
for (const lesson of lessons) {
|
|
1463
|
+
if (lesson.published)
|
|
1464
|
+
publishedLessonCount++;
|
|
1465
|
+
let sourceType;
|
|
1466
|
+
try {
|
|
1467
|
+
const parsed = lesson.content
|
|
1468
|
+
? JSON.parse(lesson.content)
|
|
1469
|
+
: null;
|
|
1470
|
+
sourceType =
|
|
1471
|
+
typeof (parsed === null || parsed === void 0 ? void 0 : parsed.sourceType) === 'string'
|
|
1472
|
+
? parsed.sourceType
|
|
1473
|
+
: undefined;
|
|
1474
|
+
}
|
|
1475
|
+
catch (_d) {
|
|
1476
|
+
// ignore malformed content
|
|
1477
|
+
}
|
|
1478
|
+
let uiType;
|
|
1479
|
+
if (sourceType === 'video' ||
|
|
1480
|
+
sourceType === 'questao' ||
|
|
1481
|
+
sourceType === 'post' ||
|
|
1482
|
+
sourceType === 'exercicio') {
|
|
1483
|
+
uiType = sourceType;
|
|
1484
|
+
}
|
|
1485
|
+
else if (lesson.type === 'video') {
|
|
1486
|
+
uiType = 'video';
|
|
1487
|
+
}
|
|
1488
|
+
else if (lesson.type === 'quiz') {
|
|
1489
|
+
uiType = 'questao';
|
|
1490
|
+
}
|
|
1491
|
+
else {
|
|
1492
|
+
uiType = 'post';
|
|
1493
|
+
}
|
|
1494
|
+
lessonsByType[uiType]++;
|
|
1495
|
+
if (uiType === 'video') {
|
|
1496
|
+
if (transcriptionLessonIds.has(lesson.id))
|
|
1497
|
+
videoWithTranscription++;
|
|
1498
|
+
if (xpLessonIds.has(lesson.id))
|
|
1499
|
+
videoWithXp++;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
return {
|
|
1503
|
+
structure: {
|
|
1504
|
+
moduleCount,
|
|
1505
|
+
lessonCount: lessons.length,
|
|
1506
|
+
publishedLessonCount,
|
|
1507
|
+
lessonsByType,
|
|
1508
|
+
},
|
|
1509
|
+
videos: {
|
|
1510
|
+
lessonCount: lessonsByType.video,
|
|
1511
|
+
withTranscription: videoWithTranscription,
|
|
1512
|
+
withXp: videoWithXp,
|
|
1513
|
+
},
|
|
1514
|
+
media: { extractedImageCount },
|
|
1515
|
+
resources: { fileCount: resourceFileCount },
|
|
1516
|
+
storage: {
|
|
1517
|
+
totalBytes: Array.from(uniqueStorageFiles.values()).reduce((sum, size) => sum + size, 0),
|
|
1518
|
+
totalFileCount: uniqueStorageFiles.size,
|
|
1519
|
+
categories: storageCategories,
|
|
1520
|
+
},
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
928
1523
|
};
|
|
929
1524
|
exports.CourseService = CourseService;
|
|
930
|
-
exports.CourseService = CourseService = __decorate([
|
|
1525
|
+
exports.CourseService = CourseService = CourseService_1 = __decorate([
|
|
931
1526
|
(0, common_1.Injectable)(),
|
|
932
1527
|
__param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => core_1.IntegrationDeveloperApiService))),
|
|
1528
|
+
__param(3, (0, common_1.Inject)((0, common_1.forwardRef)(() => queue_1.QueueJobService))),
|
|
1529
|
+
__param(4, (0, common_1.Inject)((0, common_1.forwardRef)(() => queue_1.QueueHandlerRegistry))),
|
|
1530
|
+
__param(5, (0, common_1.Inject)((0, common_1.forwardRef)(() => core_1.NotificationService))),
|
|
933
1531
|
__metadata("design:paramtypes", [api_prisma_1.PrismaService,
|
|
934
1532
|
core_1.FileService,
|
|
935
1533
|
core_1.IntegrationDeveloperApiService,
|
|
1534
|
+
queue_1.QueueJobService,
|
|
1535
|
+
queue_1.QueueHandlerRegistry,
|
|
1536
|
+
core_1.NotificationService,
|
|
936
1537
|
course_operations_integration_service_1.CourseOperationsIntegrationService])
|
|
937
1538
|
], CourseService);
|
|
938
1539
|
//# sourceMappingURL=course.service.js.map
|