@hed-hog/lms 0.0.350 → 0.0.353
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/certificate/certificate.controller.d.ts +2 -2
- package/dist/certificate/certificate.controller.d.ts.map +1 -1
- package/dist/certificate/certificate.controller.js +8 -6
- package/dist/certificate/certificate.controller.js.map +1 -1
- package/dist/certificate/certificate.service.d.ts +5 -2
- package/dist/certificate/certificate.service.d.ts.map +1 -1
- package/dist/certificate/certificate.service.js +70 -6
- package/dist/certificate/certificate.service.js.map +1 -1
- package/dist/course/course-structure.controller.d.ts +24 -10
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +23 -2
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +16 -8
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +61 -30
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course-video-conversion.service.d.ts +37 -0
- package/dist/course/course-video-conversion.service.d.ts.map +1 -0
- package/dist/course/course-video-conversion.service.js +308 -0
- package/dist/course/course-video-conversion.service.js.map +1 -0
- package/dist/course/course.controller.d.ts +17 -0
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.controller.js +23 -0
- 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 -2
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +15 -0
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +103 -49
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts +5 -1
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.js +16 -2
- package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
- package/dist/course/dto/create-course.dto.d.ts +1 -0
- package/dist/course/dto/create-course.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course.dto.js +9 -0
- package/dist/course/dto/create-course.dto.js.map +1 -1
- package/dist/enterprise/enterprise.controller.d.ts +3 -3
- package/dist/enterprise/enterprise.controller.d.ts.map +1 -1
- package/dist/enterprise/enterprise.controller.js +0 -1
- package/dist/enterprise/enterprise.controller.js.map +1 -1
- package/dist/enterprise/enterprise.service.d.ts +3 -3
- package/dist/evaluation/evaluation.service.d.ts.map +1 -1
- package/dist/evaluation/evaluation.service.js +9 -2
- package/dist/evaluation/evaluation.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +3 -0
- package/dist/lms.module.js.map +1 -1
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.d.ts +6 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.d.ts.map +1 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.js +33 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.js.map +1 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.d.ts +6 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.d.ts.map +1 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.js +33 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.d.ts +38 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.js +89 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.d.ts +26 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.js +160 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.d.ts +3 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.js +26 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.d.ts +45 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.js +117 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.js.map +1 -0
- package/hedhog/data/menu.yaml +17 -0
- package/hedhog/data/route.yaml +133 -0
- package/hedhog/data/video_resolution_profile.yaml +7 -0
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +269 -324
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +124 -70
- package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +7 -4
- package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/_lib/editor/templateSerializer.ts.ejs +34 -4
- package/hedhog/frontend/app/_lib/editor/types.ts.ejs +28 -3
- package/hedhog/frontend/app/achievements/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/bitcodes/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +7 -3
- package/hedhog/frontend/app/certificates/models/CanvasStage.tsx.ejs +29 -8
- package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +14 -0
- package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +194 -9
- package/hedhog/frontend/app/certificates/models/page.tsx.ejs +15 -5
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +9 -5
- package/hedhog/frontend/app/classes/page.tsx.ejs +73 -47
- package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +19 -9
- package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +24 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +28 -16
- package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +11 -6
- package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +7 -4
- package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +24 -87
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +892 -411
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +1004 -293
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +11 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +62 -52
- package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +2 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +19 -6
- package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +86 -1
- package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/page.tsx.ejs +112 -89
- package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-detail-sheet.tsx.ejs +8 -4
- package/hedhog/frontend/app/enterprise/_components/enterprise-person-edit-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +10 -4
- package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/evaluations/_components/evaluation-topic-form-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +23 -9
- package/hedhog/frontend/app/exams/page.tsx.ejs +14 -6
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/instructors/_components/instructor-form-sheet.tsx.ejs +190 -17
- package/hedhog/frontend/app/layout.tsx.ejs +5 -1
- package/hedhog/frontend/app/paths/page.tsx.ejs +13 -5
- package/hedhog/frontend/app/reports/evaluations/page.tsx.ejs +10 -10
- package/hedhog/frontend/app/training/page.tsx.ejs +13 -5
- package/hedhog/frontend/app/video-resolution-profiles/page.tsx.ejs +607 -0
- package/hedhog/frontend/messages/en.json +250 -9
- package/hedhog/frontend/messages/pt.json +250 -9
- package/hedhog/table/course.yaml +4 -0
- package/hedhog/table/course_lesson_file.yaml +8 -0
- package/hedhog/table/course_video_resolution_profile.yaml +22 -0
- package/hedhog/table/video_resolution_profile.yaml +18 -0
- package/package.json +9 -8
- package/src/certificate/certificate.controller.ts +19 -14
- package/src/certificate/certificate.service.ts +106 -11
- package/src/course/course-structure.controller.ts +24 -2
- package/src/course/course-structure.service.ts +21 -4
- package/src/course/course-video-conversion.service.ts +415 -0
- package/src/course/course.controller.ts +18 -0
- package/src/course/course.module.ts +15 -2
- package/src/course/course.service.ts +72 -2
- package/src/course/dto/create-course-structure-lesson.dto.ts +13 -2
- package/src/course/dto/create-course.dto.ts +8 -0
- package/src/enterprise/enterprise.controller.ts +0 -1
- package/src/evaluation/evaluation.service.ts +9 -2
- package/src/index.ts +1 -0
- package/src/lms.module.ts +3 -0
- package/src/video-resolution-profile/dto/create-video-resolution-profile.dto.ts +16 -0
- package/src/video-resolution-profile/dto/update-video-resolution-profile.dto.ts +16 -0
- package/src/video-resolution-profile/video-resolution-profile.controller.ts +62 -0
- package/src/video-resolution-profile/video-resolution-profile.mcp-tools.ts +128 -0
- package/src/video-resolution-profile/video-resolution-profile.module.ts +13 -0
- package/src/video-resolution-profile/video-resolution-profile.service.ts +117 -0
|
@@ -242,13 +242,19 @@
|
|
|
242
242
|
"certification": "Certificação",
|
|
243
243
|
"flags": "Flags"
|
|
244
244
|
},
|
|
245
|
+
"sectionDescriptions": {
|
|
246
|
+
"basicInfo": "Os identificadores e a comunicação principal do curso ficam aqui.",
|
|
247
|
+
"relations": "Agrupe os vínculos que ajudam a encontrar, operar e ensinar este curso.",
|
|
248
|
+
"certification": "Escolha o modelo usado na emissão e deixe o impacto desse vínculo explícito."
|
|
249
|
+
},
|
|
245
250
|
"title": "Dados do Curso",
|
|
246
251
|
"description": "Edite as informações do curso abaixo. Os campos com * são obrigatórios.",
|
|
247
252
|
"fields": {
|
|
248
253
|
"code": {
|
|
249
|
-
"label": "Código
|
|
250
|
-
"placeholder": "Ex:
|
|
251
|
-
"description": "
|
|
254
|
+
"label": "Código de Edição",
|
|
255
|
+
"placeholder": "Ex: REACT2024",
|
|
256
|
+
"description": "Somente letras maiúsculas e números, sem espaços (mínimo 2)",
|
|
257
|
+
"sectionTitle": "Código de Edição"
|
|
252
258
|
},
|
|
253
259
|
"internalName": {
|
|
254
260
|
"label": "Nome Interno *",
|
|
@@ -291,9 +297,18 @@
|
|
|
291
297
|
"selectPlaceholder": "Selecione uma categoria",
|
|
292
298
|
"searchPlaceholder": "Digite para buscar categoria...",
|
|
293
299
|
"noResults": "Nenhuma categoria encontrada",
|
|
300
|
+
"emptyHint": "Nenhuma categoria vinculada ainda.",
|
|
294
301
|
"selectedCount": "categoria(s) selecionada(s)",
|
|
295
302
|
"removeAction": "Remover categoria",
|
|
296
|
-
"createAction": "Criar categoria"
|
|
303
|
+
"createAction": "Criar categoria",
|
|
304
|
+
"createTitle": "Criar categoria",
|
|
305
|
+
"createDescription": "Cadastre uma categoria rapidamente sem sair da edição do curso.",
|
|
306
|
+
"createFields": {
|
|
307
|
+
"name": {
|
|
308
|
+
"label": "Nome da categoria",
|
|
309
|
+
"placeholder": "Ex: Desenvolvimento Web"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
297
312
|
},
|
|
298
313
|
"instructors": {
|
|
299
314
|
"label": "Instrutores",
|
|
@@ -302,7 +317,16 @@
|
|
|
302
317
|
"selectPlaceholder": "Selecione um instrutor",
|
|
303
318
|
"searchPlaceholder": "Digite para buscar instrutor...",
|
|
304
319
|
"noResults": "Nenhum instrutor encontrado",
|
|
305
|
-
"
|
|
320
|
+
"emptyHint": "Nenhum instrutor vinculado ainda.",
|
|
321
|
+
"removeAction": "Remover instrutor",
|
|
322
|
+
"createAction": "Cadastrar instrutor"
|
|
323
|
+
},
|
|
324
|
+
"operationsProject": {
|
|
325
|
+
"label": "Projeto vinculado",
|
|
326
|
+
"placeholder": "Selecione um projeto do Operations",
|
|
327
|
+
"searchPlaceholder": "Buscar projeto...",
|
|
328
|
+
"entityLabel": "projeto",
|
|
329
|
+
"noResults": "Nenhum projeto encontrado"
|
|
306
330
|
},
|
|
307
331
|
"prerequisites": {
|
|
308
332
|
"label": "Pré-requisitos",
|
|
@@ -328,7 +352,21 @@
|
|
|
328
352
|
"certificateModel": {
|
|
329
353
|
"label": "Modelo de Certificado",
|
|
330
354
|
"description": "Selecione um único modelo para emissão do certificado",
|
|
331
|
-
"placeholder": "Selecione um modelo"
|
|
355
|
+
"placeholder": "Selecione um modelo",
|
|
356
|
+
"entityLabel": "modelo de certificado",
|
|
357
|
+
"createAction": "Criar modelo",
|
|
358
|
+
"createTitle": "Criar modelo de certificado",
|
|
359
|
+
"createDescription": "Crie um modelo base e já o vincule ao curso sem sair desta página.",
|
|
360
|
+
"createFields": {
|
|
361
|
+
"name": {
|
|
362
|
+
"label": "Nome do modelo",
|
|
363
|
+
"placeholder": "Ex: Certificado institucional"
|
|
364
|
+
},
|
|
365
|
+
"description": {
|
|
366
|
+
"label": "Descrição",
|
|
367
|
+
"placeholder": "Resumo interno para identificar o template"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
332
370
|
}
|
|
333
371
|
},
|
|
334
372
|
"media": {
|
|
@@ -389,7 +427,76 @@
|
|
|
389
427
|
"media": "Mídia",
|
|
390
428
|
"resources": "Recursos",
|
|
391
429
|
"extra": "Extra",
|
|
392
|
-
"publish": "Publicação"
|
|
430
|
+
"publish": "Publicação",
|
|
431
|
+
"videoProfiles": "Vídeos"
|
|
432
|
+
},
|
|
433
|
+
"structureTab": {
|
|
434
|
+
"summary": {
|
|
435
|
+
"title": "Resumo do conteúdo",
|
|
436
|
+
"stats": {
|
|
437
|
+
"sessions": "Sessões",
|
|
438
|
+
"lessons": "Aulas",
|
|
439
|
+
"duration": "Duração",
|
|
440
|
+
"published": "Publicadas"
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
"mainInfo": {
|
|
444
|
+
"title": "Dados principais",
|
|
445
|
+
"fields": {
|
|
446
|
+
"title": "Título",
|
|
447
|
+
"internalName": "Nome Interno",
|
|
448
|
+
"slug": "Slug"
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
"description": {
|
|
452
|
+
"title": "Descrição"
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
"resources": {
|
|
456
|
+
"title": "Recursos para download do curso",
|
|
457
|
+
"dropzoneAriaLabel": "Soltar arquivo ou clicar para selecionar",
|
|
458
|
+
"uploading": "Enviando arquivos...",
|
|
459
|
+
"saving": "Salvando recursos...",
|
|
460
|
+
"idle": "Arraste arquivos para adicionar",
|
|
461
|
+
"helper": "Clique para selecionar arquivos",
|
|
462
|
+
"empty": "Nenhum recurso de curso cadastrado ainda.",
|
|
463
|
+
"attachedFile": "Arquivo anexado",
|
|
464
|
+
"downloadAria": "Baixar {name}",
|
|
465
|
+
"removeAria": "Remover {name}"
|
|
466
|
+
},
|
|
467
|
+
"videoProfiles": {
|
|
468
|
+
"title": "Perfis de Resolução de Vídeo",
|
|
469
|
+
"placeholder": "Selecionar perfil de vídeo...",
|
|
470
|
+
"createTitle": "Novo perfil de vídeo",
|
|
471
|
+
"createFields": {
|
|
472
|
+
"name": {
|
|
473
|
+
"label": "Nome",
|
|
474
|
+
"placeholder": "Ex: 1080p Full HD"
|
|
475
|
+
},
|
|
476
|
+
"ffmpegParams": {
|
|
477
|
+
"label": "Parâmetros FFmpeg",
|
|
478
|
+
"placeholder": "-vf \"scale=1920:1080\" -c:v libx264 ..."
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
"createError": "Não foi possível criar o perfil.",
|
|
482
|
+
"empty": "Nenhum perfil de resolução adicionado.",
|
|
483
|
+
"fallbackName": "Perfil #{id}",
|
|
484
|
+
"editAria": "Editar perfil",
|
|
485
|
+
"removeAria": "Remover perfil",
|
|
486
|
+
"sheet": {
|
|
487
|
+
"title": "Editar perfil de vídeo",
|
|
488
|
+
"description": "Atualize o nome e os parâmetros FFmpeg deste perfil de resolução.",
|
|
489
|
+
"actions": {
|
|
490
|
+
"cancel": "Cancelar",
|
|
491
|
+
"save": "Salvar",
|
|
492
|
+
"saving": "Salvando..."
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
"footer": {
|
|
497
|
+
"cancel": "Cancelar",
|
|
498
|
+
"newSession": "Nova sessão",
|
|
499
|
+
"save": "Salvar"
|
|
393
500
|
},
|
|
394
501
|
"publishChecklist": {
|
|
395
502
|
"title": "Checklist de publicação",
|
|
@@ -441,7 +548,8 @@
|
|
|
441
548
|
"statusRequired": "Selecione um status",
|
|
442
549
|
"offeringTypeRequired": "Selecione o formato do curso",
|
|
443
550
|
"categoryRequired": "Selecione pelo menos uma categoria",
|
|
444
|
-
"colorInvalid": "Informe uma cor hexadecimal válida (ex: #107f46)"
|
|
551
|
+
"colorInvalid": "Informe uma cor hexadecimal válida (ex: #107f46)",
|
|
552
|
+
"editionCodeFormat": "Somente letras maiúsculas e números, sem espaços (mínimo 2)"
|
|
445
553
|
}
|
|
446
554
|
},
|
|
447
555
|
"CoursesPage": {
|
|
@@ -616,6 +724,10 @@
|
|
|
616
724
|
"replace": "Substituir logo",
|
|
617
725
|
"remove": "Remover",
|
|
618
726
|
"description": "Imagem opcional para identificar o curso"
|
|
727
|
+
},
|
|
728
|
+
"code": {
|
|
729
|
+
"label": "Código de Edição",
|
|
730
|
+
"placeholder": "Ex: REACT2024"
|
|
619
731
|
}
|
|
620
732
|
},
|
|
621
733
|
"flags": {
|
|
@@ -649,7 +761,8 @@
|
|
|
649
761
|
"levelRequired": "Selecione um nível",
|
|
650
762
|
"statusRequired": "Selecione um status",
|
|
651
763
|
"categoriesRequired": "Selecione pelo menos uma categoria",
|
|
652
|
-
"colorInvalid": "Informe uma cor HEX válida"
|
|
764
|
+
"colorInvalid": "Informe uma cor HEX válida",
|
|
765
|
+
"editionCodePattern": "Somente letras maiúsculas e números, mínimo 2 caracteres"
|
|
653
766
|
}
|
|
654
767
|
},
|
|
655
768
|
"deleteDialog": {
|
|
@@ -936,6 +1049,7 @@
|
|
|
936
1049
|
"update": "Atualizar",
|
|
937
1050
|
"save": "Salvar aula",
|
|
938
1051
|
"tabData": "Dados",
|
|
1052
|
+
"tabVideos": "Vídeos",
|
|
939
1053
|
"tabTranscription": "Transcrição",
|
|
940
1054
|
"tabResources": "Recursos",
|
|
941
1055
|
"videoProvider": "Provedor de vídeo",
|
|
@@ -959,6 +1073,70 @@
|
|
|
959
1073
|
"videoResolutionPlaceholder": "Ex.: 1080p",
|
|
960
1074
|
"uploadVideoForResolution": "Enviar vídeo para esta resolução",
|
|
961
1075
|
"noResolutionVideosYet": "Nenhum vídeo por resolução enviado ainda.",
|
|
1076
|
+
"loadingVideoProfiles": "Carregando perfis de vídeo do curso...",
|
|
1077
|
+
"videoProfilesLoadError": "Não foi possível carregar os perfis de vídeo do curso.",
|
|
1078
|
+
"retryLoadVideoProfiles": "Tentar carregar novamente",
|
|
1079
|
+
"noVideoProfilesConfigured": "Configure os perfis de vídeo na aba Vídeos do curso antes de anexar vídeos File Storage.",
|
|
1080
|
+
"originalVideoTitle": "Vídeo original em alta resolução",
|
|
1081
|
+
"originalVideoHint": "Envie um original para gerar automaticamente os vídeos dos perfis do curso.",
|
|
1082
|
+
"originalVideoPurpose": "Este arquivo original é usado apenas para gerar as versões de vídeo do curso.",
|
|
1083
|
+
"fileStorageVideoHint": "Use o vídeo original abaixo para gerar automaticamente as versões por perfil do curso.",
|
|
1084
|
+
"uploadOriginalForConversion": "Enviar original para conversão",
|
|
1085
|
+
"videoUploadBlockedWhileProcessing": "O upload de original fica bloqueado enquanto a conversão atual estiver em andamento.",
|
|
1086
|
+
"videoUploadMaxSizeError": "O vídeo excede o limite de {size}.",
|
|
1087
|
+
"videoConversionQueued": "Conversão de vídeo enviada para a fila #{id}.",
|
|
1088
|
+
"videoConversionFailed": "Não foi possível enviar o vídeo para conversão.",
|
|
1089
|
+
"videoConversionJob": "Conversão na fila #{id}",
|
|
1090
|
+
"videoJobFeedbackTitle": "Acompanhamento da conversão",
|
|
1091
|
+
"videoJobLoading": "Carregando andamento da conversão...",
|
|
1092
|
+
"videoJobPendingLoad": "Preparando acompanhamento do job de conversão...",
|
|
1093
|
+
"videoJobLoadError": "Não foi possível carregar o andamento da conversão.",
|
|
1094
|
+
"retryLoadVideoJob": "Tentar novamente",
|
|
1095
|
+
"videoJobIdLabel": "Job",
|
|
1096
|
+
"videoJobAttemptsLabel": "Tentativas",
|
|
1097
|
+
"videoJobAttemptsValue": "{current} de {total}",
|
|
1098
|
+
"videoJobCreatedAt": "Enviado em",
|
|
1099
|
+
"videoJobStartedAt": "Iniciado em",
|
|
1100
|
+
"videoJobFinishedAt": "Finalizado em",
|
|
1101
|
+
"videoJobLatestAttempt": "Última tentativa",
|
|
1102
|
+
"videoJobAttemptValue": "Tentativa {count}",
|
|
1103
|
+
"videoJobLastError": "Último erro",
|
|
1104
|
+
"videoJobRecentEvents": "Eventos recentes",
|
|
1105
|
+
"videoJobNoEvents": "Nenhum evento registrado ainda.",
|
|
1106
|
+
"videoProfilesLockedWhileProcessing": "Os vídeos por perfil ficam bloqueados enquanto a conversão do original está ativa.",
|
|
1107
|
+
"videoJobStatuses": {
|
|
1108
|
+
"pending": "Na fila",
|
|
1109
|
+
"scheduled": "Agendado",
|
|
1110
|
+
"processing": "Processando",
|
|
1111
|
+
"completed": "Concluído",
|
|
1112
|
+
"failed": "Falhou",
|
|
1113
|
+
"retrying": "Tentando novamente",
|
|
1114
|
+
"canceled": "Cancelado",
|
|
1115
|
+
"dead_letter": "Falha definitiva"
|
|
1116
|
+
},
|
|
1117
|
+
"videoAttemptStatuses": {
|
|
1118
|
+
"processing": "Em execução",
|
|
1119
|
+
"completed": "Concluída",
|
|
1120
|
+
"failed": "Falhou",
|
|
1121
|
+
"canceled": "Cancelada"
|
|
1122
|
+
},
|
|
1123
|
+
"videoJobEvents": {
|
|
1124
|
+
"created": "Criado",
|
|
1125
|
+
"scheduled": "Agendado",
|
|
1126
|
+
"locked": "Reservado para worker",
|
|
1127
|
+
"started": "Iniciado",
|
|
1128
|
+
"completed": "Concluído",
|
|
1129
|
+
"failed": "Falhou",
|
|
1130
|
+
"retry_scheduled": "Nova tentativa agendada",
|
|
1131
|
+
"canceled": "Cancelado",
|
|
1132
|
+
"moved_to_dead_letter": "Movido para falha definitiva",
|
|
1133
|
+
"requeued": "Reenfileirado",
|
|
1134
|
+
"unlocked": "Liberado"
|
|
1135
|
+
},
|
|
1136
|
+
"videoProfileMissing": "Nenhum vídeo enviado para este perfil.",
|
|
1137
|
+
"playVideoAria": "Reproduzir vídeo {name}",
|
|
1138
|
+
"videoPreviewTitle": "Pré-visualização do vídeo: {name}",
|
|
1139
|
+
"replaceVideo": "Substituir",
|
|
962
1140
|
"openVideoAria": "Abrir vídeo {name}",
|
|
963
1141
|
"downloadVideoAria": "Baixar vídeo {name}",
|
|
964
1142
|
"removeVideoAria": "Remover vídeo {name}",
|
|
@@ -3866,6 +4044,8 @@
|
|
|
3866
4044
|
}
|
|
3867
4045
|
},
|
|
3868
4046
|
"evaluations": {
|
|
4047
|
+
"emptyTitle": "Avaliações — funcionalidade em breve",
|
|
4048
|
+
"emptyDescription": "Em breve você poderá visualizar as avaliações recebidas pelos alunos.",
|
|
3869
4049
|
"comingSoonTitle": "Avaliações — funcionalidade em breve",
|
|
3870
4050
|
"comingSoonDescription": "Em breve você poderá visualizar as avaliações recebidas pelos alunos."
|
|
3871
4051
|
},
|
|
@@ -4418,5 +4598,66 @@
|
|
|
4418
4598
|
"deleteError": "Erro ao excluir itens"
|
|
4419
4599
|
}
|
|
4420
4600
|
}
|
|
4601
|
+
},
|
|
4602
|
+
"VideoResolutionProfilesPage": {
|
|
4603
|
+
"title": "Perfis de Vídeo",
|
|
4604
|
+
"description": "Gerencie perfis de codificação FFmpeg para transcodificação de vídeos.",
|
|
4605
|
+
"breadcrumbs": {
|
|
4606
|
+
"home": "Início",
|
|
4607
|
+
"lms": "LMS",
|
|
4608
|
+
"current": "Perfis de Vídeo"
|
|
4609
|
+
},
|
|
4610
|
+
"table": {
|
|
4611
|
+
"name": "Nome",
|
|
4612
|
+
"ffmpegParams": "Parâmetros FFmpeg",
|
|
4613
|
+
"status": "Status"
|
|
4614
|
+
},
|
|
4615
|
+
"form": {
|
|
4616
|
+
"name": "Nome",
|
|
4617
|
+
"namePlaceholder": "Ex: 1080p Full HD",
|
|
4618
|
+
"ffmpegParams": "Parâmetros FFmpeg",
|
|
4619
|
+
"ffmpegParamsPlaceholder": "-vf \"scale=1920:1080\" -c:v libx264 ...",
|
|
4620
|
+
"status": "Status",
|
|
4621
|
+
"statusPlaceholder": "Selecione o status",
|
|
4622
|
+
"validation": {
|
|
4623
|
+
"required": "Este campo é obrigatório.",
|
|
4624
|
+
"max100": "Máximo de 100 caracteres."
|
|
4625
|
+
}
|
|
4626
|
+
},
|
|
4627
|
+
"sheet": {
|
|
4628
|
+
"createTitle": "Novo Perfil de Vídeo",
|
|
4629
|
+
"editTitle": "Editar Perfil de Vídeo"
|
|
4630
|
+
},
|
|
4631
|
+
"status": {
|
|
4632
|
+
"active": "Ativo",
|
|
4633
|
+
"inactive": "Inativo"
|
|
4634
|
+
},
|
|
4635
|
+
"actions": {
|
|
4636
|
+
"create": "Novo Perfil",
|
|
4637
|
+
"edit": "Editar",
|
|
4638
|
+
"delete": "Excluir",
|
|
4639
|
+
"save": "Salvar",
|
|
4640
|
+
"saving": "Salvando...",
|
|
4641
|
+
"cancel": "Cancelar",
|
|
4642
|
+
"deleting": "Excluindo..."
|
|
4643
|
+
},
|
|
4644
|
+
"filters": {
|
|
4645
|
+
"searchPlaceholder": "Buscar perfis..."
|
|
4646
|
+
},
|
|
4647
|
+
"empty": {
|
|
4648
|
+
"title": "Nenhum perfil de vídeo",
|
|
4649
|
+
"description": "Crie o primeiro perfil de resolução de vídeo para iniciar a transcodificação."
|
|
4650
|
+
},
|
|
4651
|
+
"messages": {
|
|
4652
|
+
"createSuccess": "Perfil criado com sucesso.",
|
|
4653
|
+
"updateSuccess": "Perfil atualizado com sucesso.",
|
|
4654
|
+
"deleteSuccess": "Perfil excluído com sucesso.",
|
|
4655
|
+
"saveError": "Erro ao salvar o perfil.",
|
|
4656
|
+
"deleteError": "Erro ao excluir o perfil."
|
|
4657
|
+
},
|
|
4658
|
+
"deleteDialog": {
|
|
4659
|
+
"title": "Excluir perfil",
|
|
4660
|
+
"description": "Tem certeza que deseja excluir o perfil \"{name}\"? Esta ação não pode ser desfeita."
|
|
4661
|
+
}
|
|
4421
4662
|
}
|
|
4422
4663
|
}
|
package/hedhog/table/course.yaml
CHANGED
|
@@ -16,8 +16,16 @@ columns:
|
|
|
16
16
|
- name: title
|
|
17
17
|
type: varchar
|
|
18
18
|
length: 255
|
|
19
|
+
- name: tipo
|
|
20
|
+
type: varchar
|
|
21
|
+
length: 80
|
|
22
|
+
isNullable: true
|
|
23
|
+
- name: publico
|
|
24
|
+
type: boolean
|
|
25
|
+
default: true
|
|
19
26
|
- type: created_at
|
|
20
27
|
- type: updated_at
|
|
21
28
|
|
|
22
29
|
indices:
|
|
23
30
|
- columns: [course_lesson_id]
|
|
31
|
+
- columns: [course_lesson_id, tipo]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: course_id
|
|
4
|
+
type: fk
|
|
5
|
+
references:
|
|
6
|
+
table: course
|
|
7
|
+
column: id
|
|
8
|
+
onDelete: CASCADE
|
|
9
|
+
- name: video_resolution_profile_id
|
|
10
|
+
type: fk
|
|
11
|
+
references:
|
|
12
|
+
table: video_resolution_profile
|
|
13
|
+
column: id
|
|
14
|
+
onDelete: CASCADE
|
|
15
|
+
- type: created_at
|
|
16
|
+
- type: updated_at
|
|
17
|
+
|
|
18
|
+
indices:
|
|
19
|
+
- columns: [course_id, video_resolution_profile_id]
|
|
20
|
+
isUnique: true
|
|
21
|
+
- columns: [course_id]
|
|
22
|
+
- columns: [video_resolution_profile_id]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- name: name
|
|
4
|
+
type: varchar
|
|
5
|
+
length: 100
|
|
6
|
+
- name: ffmpeg_params
|
|
7
|
+
type: text
|
|
8
|
+
- name: status
|
|
9
|
+
type: enum
|
|
10
|
+
values: [active, inactive]
|
|
11
|
+
default: active
|
|
12
|
+
- type: created_at
|
|
13
|
+
- type: updated_at
|
|
14
|
+
|
|
15
|
+
indices:
|
|
16
|
+
- columns: [name]
|
|
17
|
+
isUnique: true
|
|
18
|
+
- columns: [status]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/lms",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.353",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/api-locale": "0.0.14",
|
|
13
12
|
"@hed-hog/api-prisma": "0.0.6",
|
|
14
|
-
"@hed-hog/api-
|
|
13
|
+
"@hed-hog/api-locale": "0.0.14",
|
|
15
14
|
"@hed-hog/api-types": "0.0.1",
|
|
16
|
-
"@hed-hog/api": "0.0.
|
|
17
|
-
"@hed-hog/
|
|
18
|
-
"@hed-hog/
|
|
19
|
-
"@hed-hog/finance": "0.0.
|
|
20
|
-
"@hed-hog/
|
|
15
|
+
"@hed-hog/api-pagination": "0.0.7",
|
|
16
|
+
"@hed-hog/category": "0.0.353",
|
|
17
|
+
"@hed-hog/crm": "0.0.353",
|
|
18
|
+
"@hed-hog/finance": "0.0.353",
|
|
19
|
+
"@hed-hog/core": "0.0.353",
|
|
20
|
+
"@hed-hog/queue": "0.0.353",
|
|
21
|
+
"@hed-hog/api": "0.0.8"
|
|
21
22
|
},
|
|
22
23
|
"exports": {
|
|
23
24
|
".": {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { Role } from '@hed-hog/api';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
Body,
|
|
4
|
+
Controller,
|
|
5
|
+
Delete,
|
|
6
|
+
Get,
|
|
7
|
+
Headers,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
Query,
|
|
13
|
+
UploadedFile,
|
|
14
|
+
UseInterceptors,
|
|
14
15
|
} from '@nestjs/common';
|
|
15
16
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
16
17
|
import { LmsCertificateService } from './certificate.service';
|
|
@@ -52,8 +53,9 @@ export class LmsCertificateController {
|
|
|
52
53
|
updateTemplate(
|
|
53
54
|
@Param('id', ParseIntPipe) id: number,
|
|
54
55
|
@Body() dto: UpdateCertificateTemplateDto,
|
|
56
|
+
@Headers('accept-language') locale?: string,
|
|
55
57
|
) {
|
|
56
|
-
return this.certificateService.updateTemplate(id, dto);
|
|
58
|
+
return this.certificateService.updateTemplate(id, dto, locale);
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
@Post('templates/background-image')
|
|
@@ -63,8 +65,11 @@ export class LmsCertificateController {
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
@Delete('templates/:id')
|
|
66
|
-
deleteTemplate(
|
|
67
|
-
|
|
68
|
+
deleteTemplate(
|
|
69
|
+
@Param('id', ParseIntPipe) id: number,
|
|
70
|
+
@Headers('accept-language') locale?: string,
|
|
71
|
+
) {
|
|
72
|
+
return this.certificateService.deleteTemplate(id, locale);
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
@Get('issued')
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
2
2
|
import { FileService, IntegrationDeveloperApiService } from '@hed-hog/core';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
BadRequestException,
|
|
5
|
+
Inject,
|
|
6
|
+
Injectable,
|
|
7
|
+
NotFoundException,
|
|
8
|
+
forwardRef,
|
|
9
9
|
} from '@nestjs/common';
|
|
10
10
|
import { CreateCertificateTemplateDto } from './dto/create-certificate-template.dto';
|
|
11
11
|
import { UpdateCertificateTemplateDto } from './dto/update-certificate-template.dto';
|
|
@@ -27,6 +27,13 @@ type ListCertificateTemplatesParams = {
|
|
|
27
27
|
status?: string;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
type TemplateLike = {
|
|
31
|
+
objects?: Array<{
|
|
32
|
+
type?: string;
|
|
33
|
+
image?: { file_id?: number | null };
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
|
|
30
37
|
@Injectable()
|
|
31
38
|
export class LmsCertificateService {
|
|
32
39
|
constructor(
|
|
@@ -134,16 +141,33 @@ export class LmsCertificateService {
|
|
|
134
141
|
return this.mapTemplate(template);
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
async updateTemplate(
|
|
138
|
-
|
|
144
|
+
async updateTemplate(
|
|
145
|
+
id: number,
|
|
146
|
+
dto: UpdateCertificateTemplateDto,
|
|
147
|
+
locale?: string,
|
|
148
|
+
) {
|
|
149
|
+
const existingTemplate = await this.ensureTemplateExists(id);
|
|
139
150
|
|
|
140
151
|
const payload = this.prepareTemplatePayload(dto, true);
|
|
141
152
|
|
|
153
|
+
const previousFileIds = this.extractTemplateImageFileIds(
|
|
154
|
+
existingTemplate.template_content,
|
|
155
|
+
);
|
|
156
|
+
const nextFileIds =
|
|
157
|
+
payload.template_content !== undefined
|
|
158
|
+
? this.extractTemplateImageFileIds(payload.template_content)
|
|
159
|
+
: previousFileIds;
|
|
160
|
+
const removedFileIds = previousFileIds.filter(
|
|
161
|
+
(fileId) => !nextFileIds.includes(fileId),
|
|
162
|
+
);
|
|
163
|
+
|
|
142
164
|
const template = await this.prisma.certificate_template.update({
|
|
143
165
|
where: { id },
|
|
144
166
|
data: payload,
|
|
145
167
|
});
|
|
146
168
|
|
|
169
|
+
await this.deleteFilesIfExist(removedFileIds, locale);
|
|
170
|
+
|
|
147
171
|
await this.integrationApi.publishEvent({
|
|
148
172
|
eventName: 'lms.certificate_template.updated',
|
|
149
173
|
sourceModule: 'lms',
|
|
@@ -155,8 +179,11 @@ export class LmsCertificateService {
|
|
|
155
179
|
return this.mapTemplate(template);
|
|
156
180
|
}
|
|
157
181
|
|
|
158
|
-
async deleteTemplate(id: number) {
|
|
159
|
-
await this.ensureTemplateExists(id);
|
|
182
|
+
async deleteTemplate(id: number, locale?: string) {
|
|
183
|
+
const existingTemplate = await this.ensureTemplateExists(id);
|
|
184
|
+
const fileIdsToDelete = this.extractTemplateImageFileIds(
|
|
185
|
+
existingTemplate.template_content,
|
|
186
|
+
);
|
|
160
187
|
|
|
161
188
|
try {
|
|
162
189
|
await this.prisma.certificate_template.delete({
|
|
@@ -166,6 +193,8 @@ export class LmsCertificateService {
|
|
|
166
193
|
throw new BadRequestException('Certificate template cannot be removed');
|
|
167
194
|
}
|
|
168
195
|
|
|
196
|
+
await this.deleteFilesIfExist(fileIdsToDelete, locale);
|
|
197
|
+
|
|
169
198
|
await this.integrationApi.publishEvent({
|
|
170
199
|
eventName: 'lms.certificate_template.deleted',
|
|
171
200
|
sourceModule: 'lms',
|
|
@@ -462,14 +491,80 @@ export class LmsCertificateService {
|
|
|
462
491
|
return normalized.slice(0, 255);
|
|
463
492
|
}
|
|
464
493
|
|
|
494
|
+
private extractTemplateImageFileIds(templateContent: string): number[] {
|
|
495
|
+
try {
|
|
496
|
+
const parsed = JSON.parse(templateContent) as TemplateLike;
|
|
497
|
+
if (!Array.isArray(parsed?.objects)) {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const unique = new Set<number>();
|
|
502
|
+
for (const obj of parsed.objects) {
|
|
503
|
+
if (!obj || obj.type !== 'image') {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const fileId = obj.image?.file_id;
|
|
508
|
+
if (
|
|
509
|
+
typeof fileId === 'number' &&
|
|
510
|
+
Number.isInteger(fileId) &&
|
|
511
|
+
fileId > 0
|
|
512
|
+
) {
|
|
513
|
+
unique.add(fileId);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return [...unique];
|
|
518
|
+
} catch {
|
|
519
|
+
return [];
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private normalizeLocale(locale?: string) {
|
|
524
|
+
const value = String(locale || '').trim();
|
|
525
|
+
if (!value) {
|
|
526
|
+
return 'en';
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return value.split(',')[0]?.trim() || 'en';
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
private async deleteFilesIfExist(fileIds: number[], locale?: string) {
|
|
533
|
+
if (!Array.isArray(fileIds) || fileIds.length === 0) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const existingFiles = await this.prisma.file.findMany({
|
|
538
|
+
where: {
|
|
539
|
+
id: { in: fileIds },
|
|
540
|
+
},
|
|
541
|
+
select: { id: true },
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const existingIds = existingFiles.map((file) => file.id);
|
|
545
|
+
if (existingIds.length === 0) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
await this.fileService.delete(this.normalizeLocale(locale), {
|
|
550
|
+
ids: existingIds,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
465
554
|
private async ensureTemplateExists(id: number) {
|
|
466
|
-
const
|
|
555
|
+
const template = await this.prisma.certificate_template.findUnique({
|
|
467
556
|
where: { id },
|
|
557
|
+
select: {
|
|
558
|
+
id: true,
|
|
559
|
+
template_content: true,
|
|
560
|
+
},
|
|
468
561
|
});
|
|
469
562
|
|
|
470
|
-
if (!
|
|
563
|
+
if (!template) {
|
|
471
564
|
throw new NotFoundException('Certificate template not found');
|
|
472
565
|
}
|
|
566
|
+
|
|
567
|
+
return template;
|
|
473
568
|
}
|
|
474
569
|
|
|
475
570
|
private async ensureCertificateExists(id: number) {
|