@hed-hog/lms 0.0.361 → 0.0.365

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.
Files changed (434) hide show
  1. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts +66 -0
  2. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -1
  3. package/dist/bitcode-wallet/bitcode-wallet.service.js +91 -0
  4. package/dist/bitcode-wallet/bitcode-wallet.service.js.map +1 -1
  5. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts +8 -0
  6. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts.map +1 -0
  7. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js +40 -0
  8. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js.map +1 -0
  9. package/dist/class-group/class-group.controller.d.ts +16 -16
  10. package/dist/class-group/class-group.service.d.ts +12 -12
  11. package/dist/course/course-audio-transcription.service.d.ts +3 -2
  12. package/dist/course/course-audio-transcription.service.d.ts.map +1 -1
  13. package/dist/course/course-audio-transcription.service.js +49 -8
  14. package/dist/course/course-audio-transcription.service.js.map +1 -1
  15. package/dist/course/course-export-scorm12-worker.service.d.ts +21 -0
  16. package/dist/course/course-export-scorm12-worker.service.d.ts.map +1 -0
  17. package/dist/course/course-export-scorm12-worker.service.js +109 -0
  18. package/dist/course/course-export-scorm12-worker.service.js.map +1 -0
  19. package/dist/course/course-export-scorm12.service.d.ts +42 -0
  20. package/dist/course/course-export-scorm12.service.d.ts.map +1 -0
  21. package/dist/course/course-export-scorm12.service.js +628 -0
  22. package/dist/course/course-export-scorm12.service.js.map +1 -0
  23. package/dist/course/course-export.service.d.ts +84 -0
  24. package/dist/course/course-export.service.d.ts.map +1 -0
  25. package/dist/course/course-export.service.js +237 -0
  26. package/dist/course/course-export.service.js.map +1 -0
  27. package/dist/course/course-lesson.controller.d.ts +4 -0
  28. package/dist/course/course-lesson.controller.d.ts.map +1 -1
  29. package/dist/course/course-lesson.controller.js +10 -0
  30. package/dist/course/course-lesson.controller.js.map +1 -1
  31. package/dist/course/course-structure.controller.d.ts +24 -9
  32. package/dist/course/course-structure.controller.d.ts.map +1 -1
  33. package/dist/course/course-structure.controller.js +30 -3
  34. package/dist/course/course-structure.controller.js.map +1 -1
  35. package/dist/course/course-structure.service.d.ts +25 -3
  36. package/dist/course/course-structure.service.d.ts.map +1 -1
  37. package/dist/course/course-structure.service.js +234 -24
  38. package/dist/course/course-structure.service.js.map +1 -1
  39. package/dist/course/course-video-conversion.service.d.ts +8 -0
  40. package/dist/course/course-video-conversion.service.d.ts.map +1 -1
  41. package/dist/course/course-video-conversion.service.js +87 -51
  42. package/dist/course/course-video-conversion.service.js.map +1 -1
  43. package/dist/course/course-video-hls.service.d.ts +57 -0
  44. package/dist/course/course-video-hls.service.d.ts.map +1 -0
  45. package/dist/course/course-video-hls.service.js +767 -0
  46. package/dist/course/course-video-hls.service.js.map +1 -0
  47. package/dist/course/course.controller.d.ts +115 -11
  48. package/dist/course/course.controller.d.ts.map +1 -1
  49. package/dist/course/course.controller.js +66 -28
  50. package/dist/course/course.controller.js.map +1 -1
  51. package/dist/course/course.mcp-tools.js +1 -1
  52. package/dist/course/course.mcp-tools.js.map +1 -1
  53. package/dist/course/course.module.d.ts.map +1 -1
  54. package/dist/course/course.module.js +13 -0
  55. package/dist/course/course.module.js.map +1 -1
  56. package/dist/course/course.service.d.ts +112 -11
  57. package/dist/course/course.service.d.ts.map +1 -1
  58. package/dist/course/course.service.js +682 -72
  59. package/dist/course/course.service.js.map +1 -1
  60. package/dist/course/dto/cleanup-course-storage.dto.d.ts +6 -0
  61. package/dist/course/dto/cleanup-course-storage.dto.d.ts.map +1 -0
  62. package/dist/course/dto/cleanup-course-storage.dto.js +34 -0
  63. package/dist/course/dto/cleanup-course-storage.dto.js.map +1 -0
  64. package/dist/course/dto/cleanup-upload-history.dto.d.ts +9 -0
  65. package/dist/course/dto/cleanup-upload-history.dto.d.ts.map +1 -0
  66. package/dist/course/dto/cleanup-upload-history.dto.js +36 -0
  67. package/dist/course/dto/cleanup-upload-history.dto.js.map +1 -0
  68. package/dist/course/dto/create-course-bulk-job.dto.d.ts +5 -0
  69. package/dist/course/dto/create-course-bulk-job.dto.d.ts.map +1 -0
  70. package/dist/course/dto/create-course-bulk-job.dto.js +26 -0
  71. package/dist/course/dto/create-course-bulk-job.dto.js.map +1 -0
  72. package/dist/course/dto/create-course-export.dto.d.ts +14 -0
  73. package/dist/course/dto/create-course-export.dto.d.ts.map +1 -0
  74. package/dist/course/dto/create-course-export.dto.js +71 -0
  75. package/dist/course/dto/create-course-export.dto.js.map +1 -0
  76. package/dist/course/dto/create-course-structure-lesson.dto.d.ts +2 -2
  77. package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
  78. package/dist/course/dto/create-course-structure-lesson.dto.js +3 -2
  79. package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
  80. package/dist/course/lms-bulk-upload-automation.service.d.ts +54 -0
  81. package/dist/course/lms-bulk-upload-automation.service.d.ts.map +1 -0
  82. package/dist/course/lms-bulk-upload-automation.service.js +537 -0
  83. package/dist/course/lms-bulk-upload-automation.service.js.map +1 -0
  84. package/dist/course/lms-bulk-upload-infra.service.d.ts +32 -0
  85. package/dist/course/lms-bulk-upload-infra.service.d.ts.map +1 -0
  86. package/dist/course/lms-bulk-upload-infra.service.js +301 -0
  87. package/dist/course/lms-bulk-upload-infra.service.js.map +1 -0
  88. package/dist/course/lms-bulk-upload.constants.d.ts +4 -0
  89. package/dist/course/lms-bulk-upload.constants.d.ts.map +1 -0
  90. package/dist/course/lms-bulk-upload.constants.js +7 -0
  91. package/dist/course/lms-bulk-upload.constants.js.map +1 -0
  92. package/dist/course/lms-bulk-upload.controller.d.ts +144 -1
  93. package/dist/course/lms-bulk-upload.controller.d.ts.map +1 -1
  94. package/dist/course/lms-bulk-upload.controller.js +114 -4
  95. package/dist/course/lms-bulk-upload.controller.js.map +1 -1
  96. package/dist/course/lms-bulk-upload.service.d.ts +153 -3
  97. package/dist/course/lms-bulk-upload.service.d.ts.map +1 -1
  98. package/dist/course/lms-bulk-upload.service.js +659 -21
  99. package/dist/course/lms-bulk-upload.service.js.map +1 -1
  100. package/dist/course/lms-setting.controller.d.ts +6 -2
  101. package/dist/course/lms-setting.controller.d.ts.map +1 -1
  102. package/dist/course/lms-setting.controller.js +25 -8
  103. package/dist/course/lms-setting.controller.js.map +1 -1
  104. package/dist/course/scorm12-schemas.d.ts +4 -0
  105. package/dist/course/scorm12-schemas.d.ts.map +1 -0
  106. package/dist/course/scorm12-schemas.js +9 -0
  107. package/dist/course/scorm12-schemas.js.map +1 -0
  108. package/dist/enterprise/enterprise.controller.d.ts +20 -20
  109. package/dist/enterprise/enterprise.service.d.ts +20 -20
  110. package/dist/enterprise/training/training-admin.controller.d.ts +11 -11
  111. package/dist/enterprise/training/training-admin.service.d.ts +11 -11
  112. package/dist/enterprise/training/training-instructor.controller.d.ts +2 -2
  113. package/dist/enterprise/training/training-instructor.service.d.ts +2 -2
  114. package/dist/enterprise/training/training-student.controller.d.ts +1 -1
  115. package/dist/enterprise/training/training-student.service.d.ts +52 -1
  116. package/dist/enterprise/training/training-student.service.d.ts.map +1 -1
  117. package/dist/enterprise/training/training-student.service.js +217 -4
  118. package/dist/enterprise/training/training-student.service.js.map +1 -1
  119. package/dist/enterprise/training/training-viewer.controller.d.ts +2 -2
  120. package/dist/evaluation/evaluation.controller.d.ts +8 -8
  121. package/dist/evaluation/evaluation.service.d.ts +26 -8
  122. package/dist/evaluation/evaluation.service.d.ts.map +1 -1
  123. package/dist/evaluation/evaluation.service.js +125 -0
  124. package/dist/evaluation/evaluation.service.js.map +1 -1
  125. package/dist/exam/dto/create-standalone-question.dto.d.ts +12 -0
  126. package/dist/exam/dto/create-standalone-question.dto.d.ts.map +1 -0
  127. package/dist/exam/dto/create-standalone-question.dto.js +70 -0
  128. package/dist/exam/dto/create-standalone-question.dto.js.map +1 -0
  129. package/dist/exam/exam.module.d.ts.map +1 -1
  130. package/dist/exam/exam.module.js +2 -1
  131. package/dist/exam/exam.module.js.map +1 -1
  132. package/dist/exam/exam.service.d.ts +21 -0
  133. package/dist/exam/exam.service.d.ts.map +1 -1
  134. package/dist/exam/exam.service.js +80 -0
  135. package/dist/exam/exam.service.js.map +1 -1
  136. package/dist/exam/question.controller.d.ts +27 -0
  137. package/dist/exam/question.controller.d.ts.map +1 -0
  138. package/dist/exam/question.controller.js +53 -0
  139. package/dist/exam/question.controller.js.map +1 -0
  140. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts +6 -0
  141. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts.map +1 -0
  142. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js +34 -0
  143. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js.map +1 -0
  144. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts +28 -0
  145. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts.map +1 -0
  146. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js +123 -0
  147. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js.map +1 -0
  148. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts +4 -0
  149. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts.map +1 -0
  150. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js +22 -0
  151. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js.map +1 -0
  152. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts +10 -0
  153. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts.map +1 -0
  154. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js +52 -0
  155. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js.map +1 -0
  156. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts +15 -0
  157. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts.map +1 -0
  158. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js +86 -0
  159. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js.map +1 -0
  160. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts +30 -0
  161. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts.map +1 -0
  162. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js +440 -0
  163. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js.map +1 -0
  164. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts +87 -0
  165. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts.map +1 -0
  166. package/dist/lesson-xp-map/lesson-xp-map.controller.js +185 -0
  167. package/dist/lesson-xp-map/lesson-xp-map.controller.js.map +1 -0
  168. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts +3 -0
  169. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts.map +1 -0
  170. package/dist/lesson-xp-map/lesson-xp-map.module.js +34 -0
  171. package/dist/lesson-xp-map/lesson-xp-map.module.js.map +1 -0
  172. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts +84 -0
  173. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts.map +1 -0
  174. package/dist/lesson-xp-map/lesson-xp-map.service.js +353 -0
  175. package/dist/lesson-xp-map/lesson-xp-map.service.js.map +1 -0
  176. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts +10 -0
  177. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts.map +1 -0
  178. package/dist/lesson-xp-map/lesson-xp-segment.controller.js +63 -0
  179. package/dist/lesson-xp-map/lesson-xp-segment.controller.js.map +1 -0
  180. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts +27 -0
  181. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts.map +1 -0
  182. package/dist/lesson-xp-map/lesson-xp-segment.service.js +194 -0
  183. package/dist/lesson-xp-map/lesson-xp-segment.service.js.map +1 -0
  184. package/dist/libraries/lms/tsconfig.tsbuildinfo +1 -0
  185. package/dist/lms-commerce-access.subscriber.d.ts +11 -0
  186. package/dist/lms-commerce-access.subscriber.d.ts.map +1 -0
  187. package/dist/lms-commerce-access.subscriber.js +74 -0
  188. package/dist/lms-commerce-access.subscriber.js.map +1 -0
  189. package/dist/lms.module.d.ts.map +1 -1
  190. package/dist/lms.module.js +21 -5
  191. package/dist/lms.module.js.map +1 -1
  192. package/dist/platforma/dto/update-profile.dto.d.ts +17 -0
  193. package/dist/platforma/dto/update-profile.dto.d.ts.map +1 -0
  194. package/dist/platforma/dto/update-profile.dto.js +87 -0
  195. package/dist/platforma/dto/update-profile.dto.js.map +1 -0
  196. package/dist/platforma/platforma-video.service.d.ts +39 -0
  197. package/dist/platforma/platforma-video.service.d.ts.map +1 -0
  198. package/dist/platforma/platforma-video.service.js +301 -0
  199. package/dist/platforma/platforma-video.service.js.map +1 -0
  200. package/dist/platforma/platforma.controller.d.ts +182 -1
  201. package/dist/platforma/platforma.controller.d.ts.map +1 -1
  202. package/dist/platforma/platforma.controller.js +243 -2
  203. package/dist/platforma/platforma.controller.js.map +1 -1
  204. package/dist/platforma/platforma.service.d.ts +27 -0
  205. package/dist/platforma/platforma.service.d.ts.map +1 -0
  206. package/dist/platforma/platforma.service.js +274 -0
  207. package/dist/platforma/platforma.service.js.map +1 -0
  208. package/dist/student-xp/dto/grant-skill-card-xp.dto.d.ts +5 -0
  209. package/dist/student-xp/dto/grant-skill-card-xp.dto.d.ts.map +1 -0
  210. package/dist/student-xp/dto/grant-skill-card-xp.dto.js +26 -0
  211. package/dist/student-xp/dto/grant-skill-card-xp.dto.js.map +1 -0
  212. package/dist/student-xp/student-xp.controller.d.ts +56 -0
  213. package/dist/student-xp/student-xp.controller.d.ts.map +1 -0
  214. package/dist/student-xp/student-xp.controller.js +138 -0
  215. package/dist/student-xp/student-xp.controller.js.map +1 -0
  216. package/dist/student-xp/student-xp.module.d.ts +3 -0
  217. package/dist/student-xp/student-xp.module.d.ts.map +1 -0
  218. package/dist/student-xp/student-xp.module.js +25 -0
  219. package/dist/student-xp/student-xp.module.js.map +1 -0
  220. package/dist/student-xp/student-xp.service.d.ts +81 -0
  221. package/dist/student-xp/student-xp.service.d.ts.map +1 -0
  222. package/dist/student-xp/student-xp.service.js +247 -0
  223. package/dist/student-xp/student-xp.service.js.map +1 -0
  224. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts +12 -0
  225. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts.map +1 -0
  226. package/dist/xp-catalog/dto/create-xp-area.dto.js +63 -0
  227. package/dist/xp-catalog/dto/create-xp-area.dto.js.map +1 -0
  228. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts +11 -0
  229. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts.map +1 -0
  230. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js +57 -0
  231. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js.map +1 -0
  232. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts +11 -0
  233. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts.map +1 -0
  234. package/dist/xp-catalog/dto/create-xp-skill.dto.js +57 -0
  235. package/dist/xp-catalog/dto/create-xp-skill.dto.js.map +1 -0
  236. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts +12 -0
  237. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts.map +1 -0
  238. package/dist/xp-catalog/dto/update-xp-area.dto.js +66 -0
  239. package/dist/xp-catalog/dto/update-xp-area.dto.js.map +1 -0
  240. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts +11 -0
  241. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts.map +1 -0
  242. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js +60 -0
  243. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js.map +1 -0
  244. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts +11 -0
  245. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts.map +1 -0
  246. package/dist/xp-catalog/dto/update-xp-skill.dto.js +60 -0
  247. package/dist/xp-catalog/dto/update-xp-skill.dto.js.map +1 -0
  248. package/dist/xp-catalog/xp-area.controller.d.ts +25 -0
  249. package/dist/xp-catalog/xp-area.controller.d.ts.map +1 -0
  250. package/dist/xp-catalog/xp-area.controller.js +105 -0
  251. package/dist/xp-catalog/xp-area.controller.js.map +1 -0
  252. package/dist/xp-catalog/xp-area.service.d.ts +35 -0
  253. package/dist/xp-catalog/xp-area.service.d.ts.map +1 -0
  254. package/dist/xp-catalog/xp-area.service.js +168 -0
  255. package/dist/xp-catalog/xp-area.service.js.map +1 -0
  256. package/dist/xp-catalog/xp-catalog.module.d.ts +3 -0
  257. package/dist/xp-catalog/xp-catalog.module.d.ts.map +1 -0
  258. package/dist/xp-catalog/xp-catalog.module.js +29 -0
  259. package/dist/xp-catalog/xp-catalog.module.js.map +1 -0
  260. package/dist/xp-catalog/xp-learning-type.controller.d.ts +20 -0
  261. package/dist/xp-catalog/xp-learning-type.controller.d.ts.map +1 -0
  262. package/dist/xp-catalog/xp-learning-type.controller.js +96 -0
  263. package/dist/xp-catalog/xp-learning-type.controller.js.map +1 -0
  264. package/dist/xp-catalog/xp-learning-type.service.d.ts +30 -0
  265. package/dist/xp-catalog/xp-learning-type.service.d.ts.map +1 -0
  266. package/dist/xp-catalog/xp-learning-type.service.js +146 -0
  267. package/dist/xp-catalog/xp-learning-type.service.js.map +1 -0
  268. package/dist/xp-catalog/xp-skill.controller.d.ts +26 -0
  269. package/dist/xp-catalog/xp-skill.controller.d.ts.map +1 -0
  270. package/dist/xp-catalog/xp-skill.controller.js +113 -0
  271. package/dist/xp-catalog/xp-skill.controller.js.map +1 -0
  272. package/dist/xp-catalog/xp-skill.service.d.ts +37 -0
  273. package/dist/xp-catalog/xp-skill.service.d.ts.map +1 -0
  274. package/dist/xp-catalog/xp-skill.service.js +174 -0
  275. package/dist/xp-catalog/xp-skill.service.js.map +1 -0
  276. package/hedhog/data/evaluation_topic.yaml +17 -0
  277. package/hedhog/data/menu.yaml +91 -7
  278. package/hedhog/data/queue_definition.yaml +48 -0
  279. package/hedhog/data/route.yaml +511 -29
  280. package/hedhog/data/setting_group.yaml +20 -20
  281. package/hedhog/data/xp_area.yaml +164 -0
  282. package/hedhog/data/xp_learning_type.yaml +131 -0
  283. package/hedhog/data/xp_skill.yaml +1834 -0
  284. package/hedhog/frontend/app/achievements/page.tsx.ejs +108 -118
  285. package/hedhog/frontend/app/bitcodes/page.tsx.ejs +22 -34
  286. package/hedhog/frontend/app/bulk-upload-sessions/page.tsx.ejs +1749 -0
  287. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +21 -45
  288. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +40 -74
  289. package/hedhog/frontend/app/classes/page.tsx.ejs +56 -85
  290. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +3 -2
  291. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +48 -5
  292. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +73 -8
  293. package/hedhog/frontend/app/courses/[id]/structure/_components/course-export-sheet.tsx.ejs +420 -0
  294. package/hedhog/frontend/app/courses/[id]/structure/_components/course-exports-tab.tsx.ejs +308 -0
  295. package/hedhog/frontend/app/courses/[id]/structure/_components/course-operations-tab.tsx.ejs +19 -2
  296. package/hedhog/frontend/app/courses/[id]/structure/_components/course-overview-tab.tsx.ejs +1172 -0
  297. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +16 -0
  298. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +2 -0
  299. package/hedhog/frontend/app/courses/[id]/structure/_components/course-xp-overview-tab.tsx.ejs +623 -0
  300. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson-xp-tab.tsx.ejs +1458 -0
  301. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +87 -46
  302. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-panel.tsx.ejs +8 -3
  303. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +31 -8
  304. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-overlay.tsx.ejs +16 -9
  305. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +618 -480
  306. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +672 -737
  307. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +1 -2
  308. package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +3 -0
  309. package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +1 -0
  310. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +101 -85
  311. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +24 -10
  312. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +3 -0
  313. package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +1 -1
  314. package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +7 -1
  315. package/hedhog/frontend/app/courses/[id]/structure/_components/xp-premium-pills.tsx.ejs +44 -0
  316. package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +6 -10
  317. package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +49 -0
  318. package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +4 -3
  319. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-content-overview.ts.ejs +53 -0
  320. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-exports.ts.ejs +106 -0
  321. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +80 -1
  322. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-xp-overview.ts.ejs +76 -0
  323. package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-xp-map.ts.ejs +128 -0
  324. package/hedhog/frontend/app/courses/[id]/structure/_data/use-lms-settings-query.ts.ejs +0 -2
  325. package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +30 -0
  326. package/hedhog/frontend/app/courses/[id]/structure/_utils/xp-color-config.ts.ejs +115 -0
  327. package/hedhog/frontend/app/courses/_components/CourseDeleteDialog.tsx.ejs +223 -0
  328. package/hedhog/frontend/app/courses/_components/CourseRowActions.tsx.ejs +89 -0
  329. package/hedhog/frontend/app/courses/page.tsx.ejs +445 -230
  330. package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -63
  331. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +53 -77
  332. package/hedhog/frontend/app/exams/page.tsx.ejs +54 -90
  333. package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +23 -36
  334. package/hedhog/frontend/app/instructors/page.tsx.ejs +72 -81
  335. package/hedhog/frontend/app/paths/page.tsx.ejs +40 -68
  336. package/hedhog/frontend/app/training/page.tsx.ejs +40 -68
  337. package/hedhog/frontend/app/xp/areas/page.tsx.ejs +782 -0
  338. package/hedhog/frontend/app/xp/learning-types/page.tsx.ejs +690 -0
  339. package/hedhog/frontend/app/xp/skills/page.tsx.ejs +811 -0
  340. package/hedhog/frontend/messages/en.json +412 -31
  341. package/hedhog/frontend/messages/pt.json +412 -31
  342. package/hedhog/table/course_export.yaml +62 -0
  343. package/hedhog/table/lesson_xp_map.yaml +50 -0
  344. package/hedhog/table/lesson_xp_segment.yaml +40 -0
  345. package/hedhog/table/lesson_xp_segment_area.yaml +24 -0
  346. package/hedhog/table/lesson_xp_segment_learning_type.yaml +24 -0
  347. package/hedhog/table/lesson_xp_segment_skill.yaml +24 -0
  348. package/hedhog/table/lms_bulk_upload_item.yaml +44 -0
  349. package/hedhog/table/lms_bulk_upload_session.yaml +42 -0
  350. package/hedhog/table/student_area_xp.yaml +30 -0
  351. package/hedhog/table/student_learning_type_xp.yaml +30 -0
  352. package/hedhog/table/student_skill_xp.yaml +30 -0
  353. package/hedhog/table/student_xp_event.yaml +34 -0
  354. package/hedhog/table/xp_area.yaml +39 -0
  355. package/hedhog/table/xp_learning_type.yaml +34 -0
  356. package/hedhog/table/xp_skill.yaml +39 -0
  357. package/package.json +13 -8
  358. package/src/bitcode-wallet/bitcode-wallet.service.ts +152 -0
  359. package/src/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.ts +32 -0
  360. package/src/course/course-audio-transcription.service.ts +58 -21
  361. package/src/course/course-export-scorm12-worker.service.ts +124 -0
  362. package/src/course/course-export-scorm12.service.ts +668 -0
  363. package/src/course/course-export.service.ts +280 -0
  364. package/src/course/course-lesson.controller.ts +6 -1
  365. package/src/course/course-structure.controller.ts +23 -1
  366. package/src/course/course-structure.service.ts +273 -7
  367. package/src/course/course-video-conversion.service.ts +113 -75
  368. package/src/course/course-video-hls.service.ts +946 -0
  369. package/src/course/course.controller.ts +54 -21
  370. package/src/course/course.mcp-tools.ts +1 -1
  371. package/src/course/course.module.ts +13 -0
  372. package/src/course/course.service.ts +906 -76
  373. package/src/course/dto/cleanup-course-storage.dto.ts +23 -0
  374. package/src/course/dto/cleanup-upload-history.dto.ts +26 -0
  375. package/src/course/dto/create-course-bulk-job.dto.ts +10 -0
  376. package/src/course/dto/create-course-export.dto.ts +56 -0
  377. package/src/course/dto/create-course-structure-lesson.dto.ts +4 -3
  378. package/src/course/lms-bulk-upload-automation.service.ts +707 -0
  379. package/src/course/lms-bulk-upload-infra.service.ts +360 -0
  380. package/src/course/lms-bulk-upload.constants.ts +5 -0
  381. package/src/course/lms-bulk-upload.controller.ts +110 -4
  382. package/src/course/lms-bulk-upload.service.ts +1092 -204
  383. package/src/course/lms-setting.controller.ts +26 -8
  384. package/src/course/scorm12-schemas.ts +9 -0
  385. package/src/enterprise/training/training-student.service.ts +221 -2
  386. package/src/evaluation/evaluation.service.ts +123 -0
  387. package/src/exam/dto/create-standalone-question.dto.ts +66 -0
  388. package/src/exam/exam.module.ts +2 -1
  389. package/src/exam/exam.service.ts +86 -0
  390. package/src/exam/question.controller.ts +28 -0
  391. package/src/lesson-xp-map/dto/create-lesson-xp-map.dto.ts +17 -0
  392. package/src/lesson-xp-map/dto/create-lesson-xp-segment.dto.ts +102 -0
  393. package/src/lesson-xp-map/dto/review-lesson-xp-map.dto.ts +7 -0
  394. package/src/lesson-xp-map/dto/update-lesson-xp-map.dto.ts +36 -0
  395. package/src/lesson-xp-map/dto/update-lesson-xp-segment.dto.ts +78 -0
  396. package/src/lesson-xp-map/lesson-xp-ai-calculation.service.ts +570 -0
  397. package/src/lesson-xp-map/lesson-xp-map.controller.ts +116 -0
  398. package/src/lesson-xp-map/lesson-xp-map.module.ts +21 -0
  399. package/src/lesson-xp-map/lesson-xp-map.service.ts +442 -0
  400. package/src/lesson-xp-map/lesson-xp-segment.controller.ts +36 -0
  401. package/src/lesson-xp-map/lesson-xp-segment.service.ts +229 -0
  402. package/src/lms-commerce-access.subscriber.ts +88 -0
  403. package/src/lms.module.ts +21 -5
  404. package/src/platforma/dto/update-profile.dto.ts +59 -0
  405. package/src/platforma/platforma-video.service.ts +346 -0
  406. package/src/platforma/platforma.controller.ts +152 -3
  407. package/src/platforma/platforma.service.ts +268 -0
  408. package/src/student-xp/dto/grant-skill-card-xp.dto.ts +10 -0
  409. package/src/student-xp/student-xp.controller.ts +92 -0
  410. package/src/student-xp/student-xp.module.ts +12 -0
  411. package/src/student-xp/student-xp.service.ts +318 -0
  412. package/src/xp-catalog/dto/create-xp-area.dto.ts +40 -0
  413. package/src/xp-catalog/dto/create-xp-learning-type.dto.ts +35 -0
  414. package/src/xp-catalog/dto/create-xp-skill.dto.ts +35 -0
  415. package/src/xp-catalog/dto/update-xp-area.dto.ts +43 -0
  416. package/src/xp-catalog/dto/update-xp-learning-type.dto.ts +38 -0
  417. package/src/xp-catalog/dto/update-xp-skill.dto.ts +38 -0
  418. package/src/xp-catalog/xp-area.controller.ts +64 -0
  419. package/src/xp-catalog/xp-area.service.ts +196 -0
  420. package/src/xp-catalog/xp-catalog.module.ts +16 -0
  421. package/src/xp-catalog/xp-learning-type.controller.ts +59 -0
  422. package/src/xp-catalog/xp-learning-type.service.ts +170 -0
  423. package/src/xp-catalog/xp-skill.controller.ts +71 -0
  424. package/src/xp-catalog/xp-skill.service.ts +205 -0
  425. package/hedhog/data/video_resolution_profile.yaml +0 -7
  426. package/hedhog/frontend/app/video-resolution-profiles/page.tsx.ejs +0 -607
  427. package/hedhog/table/course_video_resolution_profile.yaml +0 -22
  428. package/hedhog/table/video_resolution_profile.yaml +0 -18
  429. package/src/video-resolution-profile/dto/create-video-resolution-profile.dto.ts +0 -16
  430. package/src/video-resolution-profile/dto/update-video-resolution-profile.dto.ts +0 -16
  431. package/src/video-resolution-profile/video-resolution-profile.controller.ts +0 -62
  432. package/src/video-resolution-profile/video-resolution-profile.mcp-tools.ts +0 -128
  433. package/src/video-resolution-profile/video-resolution-profile.module.ts +0 -13
  434. package/src/video-resolution-profile/video-resolution-profile.service.ts +0 -117
@@ -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
- let CourseService = class CourseService {
32
- constructor(prisma, fileService, integrationApi, operationsIntegration) {
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)
@@ -189,16 +325,17 @@ let CourseService = class CourseService {
189
325
  this.prisma.course.count({ where }),
190
326
  ]);
191
327
  const courseIds = courses.map((course) => course.id);
192
- const [extrasById, projectLinksById] = await Promise.all([
328
+ const [extrasById, projectLinksById, coursesWithRunningJobs] = await Promise.all([
193
329
  this.getCourseExtras(courseIds),
194
330
  this.operationsIntegration.getCourseProjectLinks(courseIds),
331
+ this.getCoursesWithRunningJobs(courseIds),
195
332
  ]);
196
333
  return {
197
334
  total,
198
335
  page,
199
336
  pageSize,
200
337
  lastPage: Math.max(1, Math.ceil(total / pageSize)),
201
- data: courses.map((c) => this.mapCourse(c, undefined, extrasById.get(c.id), projectLinksById.get(c.id))),
338
+ data: courses.map((c) => this.mapCourse(c, undefined, extrasById.get(c.id), projectLinksById.get(c.id), undefined, coursesWithRunningJobs.has(c.id))),
202
339
  };
203
340
  }
204
341
  async stats() {
@@ -216,7 +353,7 @@ let CourseService = class CourseService {
216
353
  };
217
354
  }
218
355
  async getById(id) {
219
- var _a;
356
+ var _a, _b;
220
357
  const [c, lessonInstructors] = await Promise.all([
221
358
  this.prisma.course.findUnique({
222
359
  where: { id },
@@ -243,7 +380,16 @@ let CourseService = class CourseService {
243
380
  },
244
381
  },
245
382
  file: {
246
- select: { id: true, filename: true },
383
+ select: {
384
+ id: true,
385
+ filename: true,
386
+ size: true,
387
+ file_mimetype: {
388
+ select: {
389
+ name: true,
390
+ },
391
+ },
392
+ },
247
393
  },
248
394
  },
249
395
  orderBy: [{ is_primary: 'desc' }, { order: 'asc' }],
@@ -334,13 +480,21 @@ let CourseService = class CourseService {
334
480
  progress: average,
335
481
  };
336
482
  });
337
- return this.mapCourse(c, {
483
+ const mapped = this.mapCourse(c, {
338
484
  lessonCount,
339
485
  sessionCount,
340
486
  certificatesIssued,
341
487
  averageCompletion: (_a = avgProgress._avg.progress_percent) !== null && _a !== void 0 ? _a : 0,
342
488
  progressByModule,
343
489
  }, extrasById.get(id), projectLinksById.get(id), lessonInstructors);
490
+ const deletionImpact = await this.getCourseDeletionImpact(id);
491
+ return Object.assign(Object.assign({}, mapped), { deletionImpact: {
492
+ fileCount: deletionImpact.deletionImpact.fileCount,
493
+ totalBytes: deletionImpact.deletionImpact.totalBytes,
494
+ formattedSize: this.formatBytes(deletionImpact.deletionImpact.totalBytes),
495
+ countsBySource: deletionImpact.deletionImpact.countsBySource,
496
+ enrollmentCount: (_b = mapped.enrollmentCount) !== null && _b !== void 0 ? _b : 0,
497
+ } });
344
498
  }
345
499
  async create(dto) {
346
500
  var _a, _b, _c, _d, _e;
@@ -548,10 +702,11 @@ let CourseService = class CourseService {
548
702
  }).catch(() => null);
549
703
  return updateResult;
550
704
  }
551
- async remove(id) {
705
+ async remove(id, userId) {
706
+ var _a;
552
707
  const course = await this.prisma.course.findUnique({
553
708
  where: { id },
554
- select: { id: true, status: true },
709
+ select: { id: true, status: true, title: true, slug: true },
555
710
  });
556
711
  if (!course) {
557
712
  throw new common_1.BadRequestException('Course not found');
@@ -559,64 +714,394 @@ let CourseService = class CourseService {
559
714
  if (course.status !== 'archived') {
560
715
  throw new common_1.BadRequestException('ONLY_ARCHIVED_COURSE_CAN_BE_DELETED');
561
716
  }
562
- const fileIds = await this.getCourseRelatedFileIds(id);
563
- if (fileIds.length > 0) {
564
- await this.fileService.delete('pt', { ids: fileIds }).catch(() => undefined);
717
+ if (!userId) {
718
+ throw new common_1.BadRequestException('Authenticated user is required');
565
719
  }
566
- await this.prisma.course.delete({ where: { id } });
567
- await this.integrationApi.publishEvent({
568
- eventName: 'lms.course.deleted',
720
+ const impact = await this.getCourseDeletionImpact(id);
721
+ const notification = await this.notificationService.create({
722
+ user_id: userId,
723
+ title: `Excluindo curso "${(_a = course.title) !== null && _a !== void 0 ? _a : course.slug}"`,
724
+ body: `Preparando remoção de ${impact.deletionImpact.fileCount} arquivo(s) (${this.formatBytes(impact.deletionImpact.totalBytes)}).`,
725
+ type: 'progress',
726
+ progress: 1,
727
+ started_at: new Date().toISOString(),
728
+ auto_remove: false,
729
+ action_type: 'url',
730
+ action_url: '/lms/courses',
731
+ action_data: {
732
+ source: 'lms-course-delete',
733
+ courseId: id,
734
+ },
735
+ });
736
+ const job = await this.queueJobService.enqueue({
737
+ type: exports.LMS_COURSE_DELETE_JOB,
738
+ queueName: exports.LMS_COURSE_DELETE_JOB,
739
+ payload: {
740
+ courseId: id,
741
+ notificationId: notification.id,
742
+ notificationUserId: userId,
743
+ },
569
744
  sourceModule: 'lms',
570
- aggregateType: 'course',
571
- aggregateId: String(id),
572
- payload: { id },
573
- }).catch(() => null);
574
- return { success: true };
745
+ sourceEntity: 'course',
746
+ sourceEntityId: String(id),
747
+ maxAttempts: 3,
748
+ }, userId);
749
+ return {
750
+ success: true,
751
+ status: 'queued',
752
+ queueJobId: job.id,
753
+ notificationId: notification.id,
754
+ deletionImpact: {
755
+ fileCount: impact.deletionImpact.fileCount,
756
+ totalBytes: impact.deletionImpact.totalBytes,
757
+ formattedSize: this.formatBytes(impact.deletionImpact.totalBytes),
758
+ },
759
+ };
575
760
  }
576
- async getCourseRelatedFileIds(courseId) {
761
+ async enqueueStorageCategoryCleanup(courseId, category, userId) {
762
+ if (!userId) {
763
+ throw new common_1.BadRequestException('Authenticated user is required');
764
+ }
765
+ if (!this.isSupportedStorageCleanupCategory(category)) {
766
+ throw new common_1.BadRequestException('Invalid storage category');
767
+ }
768
+ const course = await this.prisma.course.findUnique({
769
+ where: { id: courseId },
770
+ select: { id: true, title: true, slug: true },
771
+ });
772
+ if (!course) {
773
+ throw new common_1.NotFoundException('Course not found');
774
+ }
775
+ const categoryLabel = this.getStorageCategoryLabel(category);
776
+ const impact = await this.getCourseStorageCategoryImpact(courseId, category);
777
+ if (impact.fileCount === 0) {
778
+ return {
779
+ success: true,
780
+ status: 'empty',
781
+ cleanupImpact: {
782
+ fileCount: 0,
783
+ totalBytes: 0,
784
+ formattedSize: this.formatBytes(0),
785
+ },
786
+ };
787
+ }
788
+ const notification = await this.notificationService.create({
789
+ user_id: userId,
790
+ title: `Limpando armazenamento (${categoryLabel})`,
791
+ body: `Preparando remoção de ${impact.fileCount} arquivo(s) (${this.formatBytes(impact.totalBytes)}).`,
792
+ type: 'progress',
793
+ progress: 1,
794
+ started_at: new Date().toISOString(),
795
+ auto_remove: false,
796
+ action_type: 'url',
797
+ action_url: `/lms/courses/${courseId}`,
798
+ action_data: {
799
+ source: 'lms-course-storage-cleanup',
800
+ courseId,
801
+ category,
802
+ },
803
+ });
804
+ const job = await this.queueJobService.enqueue({
805
+ type: exports.LMS_COURSE_STORAGE_CLEANUP_JOB,
806
+ queueName: exports.LMS_COURSE_STORAGE_CLEANUP_JOB,
807
+ payload: {
808
+ courseId,
809
+ category,
810
+ notificationId: notification.id,
811
+ notificationUserId: userId,
812
+ },
813
+ sourceModule: 'lms',
814
+ sourceEntity: 'course',
815
+ sourceEntityId: String(courseId),
816
+ maxAttempts: 3,
817
+ }, userId);
818
+ return {
819
+ success: true,
820
+ status: 'queued',
821
+ queueJobId: job.id,
822
+ notificationId: notification.id,
823
+ category,
824
+ cleanupImpact: {
825
+ fileCount: impact.fileCount,
826
+ totalBytes: impact.totalBytes,
827
+ formattedSize: this.formatBytes(impact.totalBytes),
828
+ },
829
+ };
830
+ }
831
+ isSupportedStorageCleanupCategory(value) {
832
+ return (typeof value === 'string' &&
833
+ cleanup_course_storage_dto_1.COURSE_STORAGE_CLEANUP_CATEGORIES.includes(value));
834
+ }
835
+ getStorageCategoryLabel(category) {
836
+ const labels = {
837
+ video_original: 'Vídeos originais',
838
+ video_profile: 'Vídeos convertidos',
839
+ lesson_audio: 'Áudios',
840
+ extracted_image: 'Imagens extraídas',
841
+ student_download: 'Downloads do aluno',
842
+ supplementary_material: 'Materiais de apoio',
843
+ course_image: 'Imagens do curso',
844
+ course_file: 'Arquivos do curso',
845
+ other_lesson_file: 'Outros arquivos',
846
+ course_export: 'Arquivos de exportação',
847
+ };
848
+ return labels[category];
849
+ }
850
+ async getCourseStorageCategoryImpact(courseId, category) {
851
+ var _a, _b;
852
+ const rows = await this.getCourseStorageRows(courseId);
853
+ const uniqueFiles = new Map();
854
+ for (const row of rows) {
855
+ const rowCategory = String(row.storage_category || 'other_lesson_file');
856
+ if (rowCategory !== category)
857
+ continue;
858
+ const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
859
+ if (fileId <= 0)
860
+ continue;
861
+ if (!uniqueFiles.has(fileId)) {
862
+ uniqueFiles.set(fileId, Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0);
863
+ }
864
+ }
865
+ const fileIds = Array.from(uniqueFiles.keys());
866
+ const totalBytes = Array.from(uniqueFiles.values()).reduce((sum, size) => sum + size, 0);
867
+ return {
868
+ category,
869
+ fileIds,
870
+ fileCount: fileIds.length,
871
+ totalBytes,
872
+ };
873
+ }
874
+ async deleteCourseStorageCategoryLinks(courseId, category) {
875
+ if (category === 'course_image') {
876
+ await this.prisma.course_image.deleteMany({ where: { course_id: courseId } });
877
+ return;
878
+ }
879
+ if (category === 'course_file') {
880
+ await this.prisma.course_file.deleteMany({ where: { course_id: courseId } });
881
+ return;
882
+ }
883
+ if (category === 'extracted_image') {
884
+ await this.prisma.$executeRaw `
885
+ DELETE FROM course_lesson_video_frame clvf
886
+ USING course_lesson cl, course_module cm
887
+ WHERE clvf.course_lesson_id = cl.id
888
+ AND cl.course_module_id = cm.id
889
+ AND cm.course_id = ${courseId}
890
+ `;
891
+ return;
892
+ }
893
+ if (category === 'video_profile') {
894
+ await this.prisma.$executeRaw `
895
+ DELETE FROM course_lesson_file clf
896
+ USING course_lesson cl, course_module cm
897
+ WHERE clf.course_lesson_id = cl.id
898
+ AND cl.course_module_id = cm.id
899
+ AND cm.course_id = ${courseId}
900
+ AND clf.type LIKE 'video_profile:%'
901
+ `;
902
+ return;
903
+ }
904
+ if (category === 'other_lesson_file') {
905
+ await this.prisma.$executeRaw `
906
+ DELETE FROM course_lesson_file clf
907
+ USING course_lesson cl, course_module cm
908
+ WHERE clf.course_lesson_id = cl.id
909
+ AND cl.course_module_id = cm.id
910
+ AND cm.course_id = ${courseId}
911
+ AND (
912
+ clf.type IS NULL
913
+ OR (
914
+ clf.type <> 'video_original'
915
+ AND clf.type <> 'lesson_audio'
916
+ AND clf.type <> 'student_download'
917
+ AND clf.type <> 'supplementary_material'
918
+ AND clf.type NOT LIKE 'video_profile:%'
919
+ )
920
+ )
921
+ `;
922
+ return;
923
+ }
924
+ if (category === 'course_export') {
925
+ const exports = await this.prisma.course_export.findMany({
926
+ where: {
927
+ course_id: courseId,
928
+ file_id: { not: null },
929
+ status: { in: ['completed', 'failed'] },
930
+ },
931
+ select: { id: true, file_id: true },
932
+ });
933
+ const fileIds = exports
934
+ .map((e) => e.file_id)
935
+ .filter((id) => id != null);
936
+ await this.prisma.course_export.deleteMany({
937
+ where: { id: { in: exports.map((e) => e.id) } },
938
+ });
939
+ if (fileIds.length > 0) {
940
+ await this.fileService.delete('pt', { ids: fileIds }).catch(() => undefined);
941
+ }
942
+ return;
943
+ }
944
+ await this.prisma.course_lesson_file.deleteMany({
945
+ where: {
946
+ course_lesson: { course_module: { course_id: courseId } },
947
+ type: category,
948
+ },
949
+ });
950
+ }
951
+ async getCourseStorageRows(courseId) {
952
+ return this.prisma.$queryRaw `
953
+ SELECT files.file_id, files.file_size, files.storage_category
954
+ FROM (
955
+ SELECT ci.file_id, f.size AS file_size, 'course_image' AS storage_category
956
+ FROM course_image ci
957
+ INNER JOIN file f ON f.id = ci.file_id
958
+ WHERE ci.course_id = ${courseId}
959
+
960
+ UNION ALL
961
+
962
+ SELECT cf.file_id, f.size AS file_size, 'course_file' AS storage_category
963
+ FROM course_file cf
964
+ INNER JOIN file f ON f.id = cf.file_id
965
+ WHERE cf.course_id = ${courseId}
966
+
967
+ UNION ALL
968
+
969
+ SELECT clf.file_id,
970
+ f.size AS file_size,
971
+ CASE
972
+ WHEN clf.type = 'video_original' THEN 'video_original'
973
+ WHEN clf.type LIKE 'video_profile:%' THEN 'video_profile'
974
+ WHEN clf.type = 'lesson_audio' THEN 'lesson_audio'
975
+ WHEN clf.type = 'student_download' THEN 'student_download'
976
+ WHEN clf.type = 'supplementary_material' THEN 'supplementary_material'
977
+ ELSE 'other_lesson_file'
978
+ END AS storage_category
979
+ FROM course_lesson_file clf
980
+ INNER JOIN file f ON f.id = clf.file_id
981
+ INNER JOIN course_lesson cl ON cl.id = clf.course_lesson_id
982
+ INNER JOIN course_module cm ON cm.id = cl.course_module_id
983
+ WHERE cm.course_id = ${courseId}
984
+
985
+ UNION ALL
986
+
987
+ SELECT clvf.file_id, f.size AS file_size, 'extracted_image' AS storage_category
988
+ FROM course_lesson_video_frame clvf
989
+ INNER JOIN file f ON f.id = clvf.file_id
990
+ INNER JOIN course_lesson cl ON cl.id = clvf.course_lesson_id
991
+ INNER JOIN course_module cm ON cm.id = cl.course_module_id
992
+ WHERE cm.course_id = ${courseId}
993
+
994
+ UNION ALL
995
+
996
+ SELECT ce.file_id, f.size AS file_size, 'course_export' AS storage_category
997
+ FROM course_export ce
998
+ INNER JOIN file f ON f.id = ce.file_id
999
+ WHERE ce.course_id = ${courseId}
1000
+ AND ce.status = 'completed'
1001
+ AND ce.file_id IS NOT NULL
1002
+ ) AS files
1003
+ WHERE files.file_id IS NOT NULL
1004
+ `;
1005
+ }
1006
+ async getCourseDeletionImpact(courseId) {
577
1007
  const rows = await this.prisma.$queryRaw `
578
- SELECT DISTINCT files.file_id
1008
+ SELECT DISTINCT files.file_id, files.file_size, files.source_type
579
1009
  FROM (
580
- SELECT ci.file_id
1010
+ SELECT ci.file_id, f.size AS file_size, 'course_image' AS source_type
581
1011
  FROM course_image ci
1012
+ INNER JOIN file f ON f.id = ci.file_id
582
1013
  WHERE ci.course_id = ${courseId}
583
1014
 
584
1015
  UNION ALL
585
1016
 
586
- SELECT cf.file_id
1017
+ SELECT cf.file_id, f.size AS file_size, 'course_file' AS source_type
587
1018
  FROM course_file cf
1019
+ INNER JOIN file f ON f.id = cf.file_id
588
1020
  WHERE cf.course_id = ${courseId}
589
1021
 
590
1022
  UNION ALL
591
1023
 
592
- SELECT clf.file_id
1024
+ SELECT clf.file_id, f.size AS file_size, 'course_lesson_file' AS source_type
593
1025
  FROM course_lesson_file clf
1026
+ INNER JOIN file f ON f.id = clf.file_id
594
1027
  INNER JOIN course_lesson cl ON cl.id = clf.course_lesson_id
595
1028
  INNER JOIN course_module cm ON cm.id = cl.course_module_id
596
1029
  WHERE cm.course_id = ${courseId}
597
1030
 
598
1031
  UNION ALL
599
1032
 
600
- SELECT clvf.file_id
1033
+ SELECT clvf.file_id, f.size AS file_size, 'course_lesson_video_frame' AS source_type
601
1034
  FROM course_lesson_video_frame clvf
1035
+ INNER JOIN file f ON f.id = clvf.file_id
602
1036
  INNER JOIN course_lesson cl ON cl.id = clvf.course_lesson_id
603
1037
  INNER JOIN course_module cm ON cm.id = cl.course_module_id
604
1038
  WHERE cm.course_id = ${courseId}
605
1039
 
606
1040
  UNION ALL
607
1041
 
608
- SELECT cgm.file_id
1042
+ SELECT cgm.file_id, f.size AS file_size, 'course_class_group_material' AS source_type
609
1043
  FROM course_class_group_material cgm
1044
+ INNER JOIN file f ON f.id = cgm.file_id
610
1045
  INNER JOIN course_class_group ccg ON ccg.id = cgm.course_class_group_id
611
1046
  WHERE ccg.course_id = ${courseId}
1047
+
1048
+ UNION ALL
1049
+
1050
+ SELECT cln.frame_file_id AS file_id, f.size AS file_size, 'course_lesson_note_frame' AS source_type
1051
+ FROM course_lesson_note cln
1052
+ INNER JOIN file f ON f.id = cln.frame_file_id
1053
+ INNER JOIN course_lesson cl ON cl.id = cln.course_lesson_id
1054
+ INNER JOIN course_module cm ON cm.id = cl.course_module_id
1055
+ WHERE cm.course_id = ${courseId}
612
1056
  ) AS files
613
1057
  WHERE files.file_id IS NOT NULL
614
1058
  `;
615
- return rows
616
- .map((row) => Number(row.file_id))
617
- .filter((id) => Number.isInteger(id) && id > 0);
1059
+ const uniqueRows = Array.from(rows.reduce((map, row) => {
1060
+ var _a, _b;
1061
+ const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
1062
+ if (fileId > 0 && !map.has(fileId)) {
1063
+ map.set(fileId, {
1064
+ fileId,
1065
+ size: Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0,
1066
+ sourceType: row.source_type,
1067
+ });
1068
+ }
1069
+ return map;
1070
+ }, new Map()).values());
1071
+ const countsBySource = rows.reduce((acc, row) => {
1072
+ var _a;
1073
+ const key = String(row.source_type || 'unknown');
1074
+ acc[key] = ((_a = acc[key]) !== null && _a !== void 0 ? _a : 0) + 1;
1075
+ return acc;
1076
+ }, {});
1077
+ return {
1078
+ deletionImpact: {
1079
+ fileIds: uniqueRows.map((row) => row.fileId),
1080
+ fileCount: uniqueRows.length,
1081
+ totalBytes: uniqueRows.reduce((sum, row) => sum + row.size, 0),
1082
+ countsBySource,
1083
+ },
1084
+ };
618
1085
  }
619
- mapCourse(c, metrics, extras, project, lessonInstructors) {
1086
+ formatBytes(bytes) {
1087
+ if (!Number.isFinite(bytes) || bytes <= 0) {
1088
+ return '0 B';
1089
+ }
1090
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
1091
+ let value = bytes;
1092
+ let unitIndex = 0;
1093
+ while (value >= 1024 && unitIndex < units.length - 1) {
1094
+ value /= 1024;
1095
+ unitIndex += 1;
1096
+ }
1097
+ const digits = unitIndex === 0 ? 0 : value >= 10 ? 1 : 2;
1098
+ return `${value.toFixed(digits)} ${units[unitIndex]}`;
1099
+ }
1100
+ async getCourseRelatedFileIds(courseId) {
1101
+ const impact = await this.getCourseDeletionImpact(courseId);
1102
+ return impact.deletionImpact.fileIds.filter((id) => Number.isInteger(id) && id > 0);
1103
+ }
1104
+ mapCourse(c, metrics, extras, project, lessonInstructors, hasRunningJobs = false) {
620
1105
  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;
621
1106
  const resolvedName = (_b = (_a = extras === null || extras === void 0 ? void 0 : extras.name) !== null && _a !== void 0 ? _a : c.name) !== null && _b !== void 0 ? _b : null;
622
1107
  const resolvedTitle = (_c = this.normalizeOptionalText(c.title)) !== null && _c !== void 0 ? _c : c.slug;
@@ -684,6 +1169,7 @@ let CourseService = class CourseService {
684
1169
  certificateModel: (_37 = (_36 = c.certificate_template) === null || _36 === void 0 ? void 0 : _36.slug) !== null && _37 !== void 0 ? _37 : (c.certificate_template_id
685
1170
  ? String(c.certificate_template_id)
686
1171
  : null),
1172
+ hasRunningJobs,
687
1173
  progressByModule: (_38 = metrics === null || metrics === void 0 ? void 0 : metrics.progressByModule) !== null && _38 !== void 0 ? _38 : [],
688
1174
  instructors: Array.from(new Map((lessonInstructors !== null && lessonInstructors !== void 0 ? lessonInstructors : []).map((item) => [item.instructor_id, item])).values()).map((item) => {
689
1175
  var _a, _b, _c, _d, _e, _f;
@@ -739,6 +1225,21 @@ let CourseService = class CourseService {
739
1225
  }
740
1226
  return extrasById;
741
1227
  }
1228
+ async getCoursesWithRunningJobs(courseIds) {
1229
+ if (courseIds.length === 0)
1230
+ return new Set();
1231
+ const rows = (await this.prisma.$queryRawUnsafe(`
1232
+ SELECT DISTINCT cm.course_id
1233
+ FROM queue_job qj
1234
+ INNER JOIN course_lesson cl ON cl.id = CAST(qj.source_entity_id AS INTEGER)
1235
+ INNER JOIN course_module cm ON cm.id = cl.course_module_id
1236
+ WHERE qj.source_entity = 'course_lesson'
1237
+ AND qj.source_module = 'lms'
1238
+ AND qj.status IN ('pending', 'scheduled', 'processing', 'retrying')
1239
+ AND cm.course_id IN (${courseIds.join(',')})
1240
+ `));
1241
+ return new Set(rows.map((r) => Number(r.course_id)));
1242
+ }
742
1243
  async persistCourseExtras(id, data) {
743
1244
  const setClauses = [];
744
1245
  const values = [];
@@ -759,7 +1260,8 @@ let CourseService = class CourseService {
759
1260
  pushSetClause('is_listed', data.isListed);
760
1261
  }
761
1262
  if (data.offeringType !== undefined) {
762
- pushSetClause('offering_type', data.offeringType);
1263
+ values.push(data.offeringType);
1264
+ setClauses.push(`offering_type = $${values.length}::course_offering_type_8af4d2739d_enum`);
763
1265
  }
764
1266
  if (setClauses.length === 0) {
765
1267
  return;
@@ -772,8 +1274,8 @@ let CourseService = class CourseService {
772
1274
  WHERE id = $${values.length}
773
1275
  `, ...values);
774
1276
  }
775
- catch (_a) {
776
- // Some environments may still be behind the current course schema.
1277
+ catch (err) {
1278
+ console.error('[persistCourseExtras] failed:', err);
777
1279
  }
778
1280
  }
779
1281
  async syncCourseImages(courseId, data) {
@@ -886,53 +1388,161 @@ let CourseService = class CourseService {
886
1388
  select: { id: true },
887
1389
  });
888
1390
  }
889
- async getCourseVideoProfiles(courseId) {
890
- const rows = await this.prisma.course_video_resolution_profile.findMany({
891
- where: { course_id: courseId },
892
- include: { video_resolution_profile: true },
893
- orderBy: { video_resolution_profile: { name: 'asc' } },
894
- });
895
- return rows.map((row) => ({
896
- id: row.video_resolution_profile.id,
897
- name: row.video_resolution_profile.name,
898
- ffmpeg_params: row.video_resolution_profile.ffmpeg_params,
899
- status: row.video_resolution_profile.status,
900
- }));
901
- }
902
- async syncCourseVideoProfiles(courseId, profileIds) {
903
- const linkClient = this.prisma.course_video_resolution_profile;
904
- await this.prisma.$transaction(async (tx) => {
905
- await tx.course_video_resolution_profile.deleteMany({
906
- where: { course_id: courseId },
907
- });
908
- if (profileIds.length > 0) {
909
- await tx.course_video_resolution_profile.createMany({
910
- data: profileIds.map((id) => ({
911
- course_id: courseId,
912
- video_resolution_profile_id: id,
913
- })),
914
- });
1391
+ async getCourseContentOverview(courseId) {
1392
+ var _a, _b, _c;
1393
+ const [moduleCount, lessons, transcriptionRows, xpMapRows, extractedImageCount, resourceFileCount, storageRows,] = await Promise.all([
1394
+ this.prisma.course_module.count({ where: { course_id: courseId } }),
1395
+ this.prisma.course_lesson.findMany({
1396
+ where: { course_module: { course_id: courseId } },
1397
+ select: { id: true, type: true, content: true, published: true },
1398
+ }),
1399
+ this.prisma.course_lesson_transcription_segment.findMany({
1400
+ where: { course_lesson: { course_module: { course_id: courseId } } },
1401
+ select: { course_lesson_id: true },
1402
+ distinct: ['course_lesson_id'],
1403
+ }),
1404
+ this.prisma.lesson_xp_map.findMany({
1405
+ where: { course_lesson: { course_module: { course_id: courseId } } },
1406
+ select: { course_lesson_id: true },
1407
+ }),
1408
+ this.prisma.course_lesson_video_frame.count({
1409
+ where: { course_lesson: { course_module: { course_id: courseId } } },
1410
+ }),
1411
+ this.prisma.course_lesson_file.count({
1412
+ where: {
1413
+ course_lesson: { course_module: { course_id: courseId } },
1414
+ type: { in: ['student_download', 'supplementary_material'] },
1415
+ },
1416
+ }),
1417
+ this.getCourseStorageRows(courseId),
1418
+ ]);
1419
+ const transcriptionLessonIds = new Set(transcriptionRows.map((r) => r.course_lesson_id));
1420
+ const xpLessonIds = new Set(xpMapRows.map((r) => r.course_lesson_id));
1421
+ const lessonsByType = { video: 0, questao: 0, post: 0 };
1422
+ let publishedLessonCount = 0;
1423
+ let videoWithTranscription = 0;
1424
+ let videoWithXp = 0;
1425
+ const categoryOrder = [
1426
+ 'video_original',
1427
+ 'video_profile',
1428
+ 'lesson_audio',
1429
+ 'extracted_image',
1430
+ 'student_download',
1431
+ 'supplementary_material',
1432
+ 'course_image',
1433
+ 'course_file',
1434
+ 'other_lesson_file',
1435
+ 'course_export',
1436
+ ];
1437
+ const uniqueStorageFiles = new Map();
1438
+ const uniqueStorageCategoryEntries = new Set();
1439
+ const storageCategoryMap = new Map();
1440
+ for (const row of storageRows) {
1441
+ const fileId = Number((_a = row.file_id) !== null && _a !== void 0 ? _a : 0);
1442
+ if (fileId <= 0)
1443
+ continue;
1444
+ const size = Number((_b = row.file_size) !== null && _b !== void 0 ? _b : 0) || 0;
1445
+ const category = String(row.storage_category || 'other_lesson_file');
1446
+ if (!uniqueStorageFiles.has(fileId)) {
1447
+ uniqueStorageFiles.set(fileId, size);
1448
+ }
1449
+ const categoryEntryKey = `${category}:${fileId}`;
1450
+ if (uniqueStorageCategoryEntries.has(categoryEntryKey)) {
1451
+ continue;
915
1452
  }
1453
+ uniqueStorageCategoryEntries.add(categoryEntryKey);
1454
+ const current = (_c = storageCategoryMap.get(category)) !== null && _c !== void 0 ? _c : {
1455
+ key: category,
1456
+ fileCount: 0,
1457
+ totalBytes: 0,
1458
+ };
1459
+ current.fileCount += 1;
1460
+ current.totalBytes += size;
1461
+ storageCategoryMap.set(category, current);
1462
+ }
1463
+ const storageCategories = Array.from(storageCategoryMap.values()).sort((a, b) => {
1464
+ const orderA = categoryOrder.indexOf(a.key);
1465
+ const orderB = categoryOrder.indexOf(b.key);
1466
+ if (orderA !== -1 || orderB !== -1) {
1467
+ return (orderA === -1 ? Number.MAX_SAFE_INTEGER : orderA) -
1468
+ (orderB === -1 ? Number.MAX_SAFE_INTEGER : orderB);
1469
+ }
1470
+ return b.totalBytes - a.totalBytes;
916
1471
  });
917
- return linkClient.findMany({
918
- where: { course_id: courseId },
919
- include: { video_resolution_profile: true },
920
- orderBy: { video_resolution_profile: { name: 'asc' } },
921
- }).then((rows) => rows.map((row) => ({
922
- id: row.video_resolution_profile.id,
923
- name: row.video_resolution_profile.name,
924
- ffmpeg_params: row.video_resolution_profile.ffmpeg_params,
925
- status: row.video_resolution_profile.status,
926
- })));
1472
+ for (const lesson of lessons) {
1473
+ if (lesson.published)
1474
+ publishedLessonCount++;
1475
+ let sourceType;
1476
+ try {
1477
+ const parsed = lesson.content
1478
+ ? JSON.parse(lesson.content)
1479
+ : null;
1480
+ sourceType =
1481
+ typeof (parsed === null || parsed === void 0 ? void 0 : parsed.sourceType) === 'string'
1482
+ ? parsed.sourceType
1483
+ : undefined;
1484
+ }
1485
+ catch (_d) {
1486
+ // ignore malformed content
1487
+ }
1488
+ let uiType;
1489
+ if (sourceType === 'video' ||
1490
+ sourceType === 'questao' ||
1491
+ sourceType === 'post') {
1492
+ uiType = sourceType;
1493
+ }
1494
+ else if (lesson.type === 'video') {
1495
+ uiType = 'video';
1496
+ }
1497
+ else if (lesson.type === 'quiz') {
1498
+ uiType = 'questao';
1499
+ }
1500
+ else {
1501
+ uiType = 'post';
1502
+ }
1503
+ lessonsByType[uiType]++;
1504
+ if (uiType === 'video') {
1505
+ if (transcriptionLessonIds.has(lesson.id))
1506
+ videoWithTranscription++;
1507
+ if (xpLessonIds.has(lesson.id))
1508
+ videoWithXp++;
1509
+ }
1510
+ }
1511
+ return {
1512
+ structure: {
1513
+ moduleCount,
1514
+ lessonCount: lessons.length,
1515
+ publishedLessonCount,
1516
+ lessonsByType,
1517
+ },
1518
+ videos: {
1519
+ lessonCount: lessonsByType.video,
1520
+ withTranscription: videoWithTranscription,
1521
+ withXp: videoWithXp,
1522
+ },
1523
+ media: { extractedImageCount },
1524
+ resources: { fileCount: resourceFileCount },
1525
+ storage: {
1526
+ totalBytes: Array.from(uniqueStorageFiles.values()).reduce((sum, size) => sum + size, 0),
1527
+ totalFileCount: uniqueStorageFiles.size,
1528
+ categories: storageCategories,
1529
+ },
1530
+ };
927
1531
  }
928
1532
  };
929
1533
  exports.CourseService = CourseService;
930
- exports.CourseService = CourseService = __decorate([
1534
+ exports.CourseService = CourseService = CourseService_1 = __decorate([
931
1535
  (0, common_1.Injectable)(),
932
1536
  __param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => core_1.IntegrationDeveloperApiService))),
1537
+ __param(3, (0, common_1.Inject)((0, common_1.forwardRef)(() => queue_1.QueueJobService))),
1538
+ __param(4, (0, common_1.Inject)((0, common_1.forwardRef)(() => queue_1.QueueHandlerRegistry))),
1539
+ __param(5, (0, common_1.Inject)((0, common_1.forwardRef)(() => core_1.NotificationService))),
933
1540
  __metadata("design:paramtypes", [api_prisma_1.PrismaService,
934
1541
  core_1.FileService,
935
1542
  core_1.IntegrationDeveloperApiService,
1543
+ queue_1.QueueJobService,
1544
+ queue_1.QueueHandlerRegistry,
1545
+ core_1.NotificationService,
936
1546
  course_operations_integration_service_1.CourseOperationsIntegrationService])
937
1547
  ], CourseService);
938
1548
  //# sourceMappingURL=course.service.js.map