Gradebook: CRUD on gradebook certificates working - refs #2834

pull/4677/head
Borja Sánchez 2 years ago
parent 8044514fcf
commit f7a9704808
  1. 3
      assets/locales/ar.json
  2. 3
      assets/locales/ast_ES.json
  3. 3
      assets/locales/bg.json
  4. 3
      assets/locales/bn_BD.json
  5. 3
      assets/locales/bo_CN.json
  6. 3
      assets/locales/bs_BA.json
  7. 3
      assets/locales/ca_ES.json
  8. 3
      assets/locales/cs_CZ.json
  9. 3
      assets/locales/da.json
  10. 3
      assets/locales/de.json
  11. 3
      assets/locales/el.json
  12. 3
      assets/locales/en.json
  13. 3
      assets/locales/eo.json
  14. 3
      assets/locales/es.json
  15. 3
      assets/locales/eu_ES.json
  16. 3
      assets/locales/fa_AF.json
  17. 3
      assets/locales/fa_IR.json
  18. 3
      assets/locales/fi_FI.json
  19. 3
      assets/locales/fo_FO.json
  20. 3
      assets/locales/fr_FR.json
  21. 3
      assets/locales/fur.json
  22. 3
      assets/locales/gl.json
  23. 3
      assets/locales/he_IL.json
  24. 3
      assets/locales/hi.json
  25. 3
      assets/locales/hr_HR.json
  26. 3
      assets/locales/hu_HU.json
  27. 3
      assets/locales/id_ID.json
  28. 3
      assets/locales/it.json
  29. 3
      assets/locales/ja.json
  30. 3
      assets/locales/ka_GE.json
  31. 3
      assets/locales/ko_KR.json
  32. 3
      assets/locales/lt_LT.json
  33. 3
      assets/locales/lv_LV.json
  34. 3
      assets/locales/mk_MK.json
  35. 3
      assets/locales/ms_MY.json
  36. 3
      assets/locales/nl.json
  37. 3
      assets/locales/nn_NO.json
  38. 3
      assets/locales/oc.json
  39. 3
      assets/locales/pl_PL.json
  40. 3
      assets/locales/ps.json
  41. 3
      assets/locales/pt_PT.json
  42. 3
      assets/locales/quz_PE.json
  43. 3
      assets/locales/ro_RO.json
  44. 3
      assets/locales/ru_RU.json
  45. 3
      assets/locales/sk_SK.json
  46. 3
      assets/locales/sl_SI.json
  47. 3
      assets/locales/so_SO.json
  48. 3
      assets/locales/sr_RS.json
  49. 3
      assets/locales/sv_SE.json
  50. 3
      assets/locales/sw_KE.json
  51. 3
      assets/locales/th.json
  52. 3
      assets/locales/tl_PH.json
  53. 3
      assets/locales/tr.json
  54. 3
      assets/locales/uk_UA.json
  55. 3
      assets/locales/vi_VN.json
  56. 3
      assets/locales/xh_ZA.json
  57. 3
      assets/locales/yo_NG.json
  58. 3
      assets/locales/zh_CN.json
  59. 3
      assets/locales/zh_TW.json
  60. 12
      assets/vue/components/resource_links/ShowLinks.vue
  61. 4
      assets/vue/mixins/CreateMixin.js
  62. 68
      assets/vue/views/documents/CreateFile.vue
  63. 42
      assets/vue/views/documents/List.vue
  64. 21
      assets/vue/views/documents/Upload.vue
  65. 2
      public/certificates/index.php
  66. 2
      public/main/exercise/exercise.class.php
  67. 5
      public/main/gradebook/gradebook_edit_link.php
  68. 2
      public/main/gradebook/index.php
  69. 2
      public/main/gradebook/lib/GradebookUtils.php
  70. 11
      public/main/gradebook/lib/be/category.class.php
  71. 3
      public/main/gradebook/lib/be/exerciselink.class.php
  72. 8
      public/main/gradebook/lib/fe/gradebooktable.class.php
  73. 9
      public/main/inc/global.inc.php
  74. 258
      public/main/inc/lib/certificate.lib.php
  75. 2
      public/main/inc/lib/chamilo_session.class.php
  76. 1
      src/CoreBundle/Controller/Api/BaseResourceFileAction.php
  77. 40
      src/CoreBundle/Entity/GradebookCategory.php
  78. 7
      src/CoreBundle/Framework/Container.php
  79. 15
      src/CourseBundle/Entity/CDocument.php

@ -67,6 +67,9 @@
"Delete": "\u062d\u0630\u0641 \u0645\u0633\u0627\u0631 \u0627\u0644\u062a\u0651\u0639\u0644\u0645",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "\u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u062d\u062f\u062b",
"Add event": "\u0627\u0636\u0627\u0641\u0629 \u062d\u062f\u062b",
"Add": " \u0623\u0636\u0641",

@ -67,6 +67,9 @@
"Delete": "Esborrar l'itinerariu d'aprendizaxe",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Camudar eventu",
"Add event": "Amestar un eventu",
"Add": "Amestar",

@ -67,6 +67,9 @@
"Delete": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u044a\u0442\u0435\u043a\u0430\u0442\u0430 \u0437\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0431\u0438\u0442\u0438\u0435\u0442\u043e",
"Add event": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0441\u044a\u0431\u0438\u0442\u0438\u0435",
"Add": "\u0414\u043e\u0431\u0430\u0432\u0438",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "Eliminar l'itinerari formatiu",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Modificar esdeveniment",
"Add event": "Afegir una nova activitat a l'agenda",
"Add": "Afegeix",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Upravit ud\u00e1lost",
"Add event": "",
"Add": "P\u0159idat",

@ -67,6 +67,9 @@
"Delete": "slet l\u00e6ringssti",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Tilf\u00f8j ny kalenderaftale",
"Add": "Tilf\u00f8j",

@ -67,6 +67,9 @@
"Delete": "Lernpfad l\u00f6schen",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Eintrag \u00e4ndern",
"Add event": "Neuen Eintrag hinzuf\u00fcgen",
"Add": "hinzuf\u00fcgen",

@ -67,6 +67,9 @@
"Delete": "\u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03bc\u03bf\u03bd\u03bf\u03c0\u03b1\u03c4\u03b9\u03bf\u03cd \u03b3\u03bd\u03ce\u03c3\u03b7\u03c2",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b3\u03b5\u03b3\u03bf\u03bd\u03cc\u03c4\u03bf\u03c2",
"Add event": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03b3\u03b5\u03b3\u03bf\u03bd\u03cc\u03c4\u03bf\u03c2",
"Add": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7",

@ -67,6 +67,9 @@
"Delete": "Delete",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edit event",
"Add event": "Add event",
"Add": "Add",

@ -67,6 +67,9 @@
"Delete": "Forigi lernpadon",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Aldoni Novan Agenderon",
"Add": "Aldoni",

@ -67,6 +67,9 @@
"Delete": "Eliminar la lecci\u00f3n",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Curso: {course}",
"Session: {session}": "Sessión: {session}",
"Status: {status}": "Estado: {status}",
"Edit event": "Modificar evento",
"Add event": "A\u00f1adir un nuevo evento",
"Add": "A\u00f1adir",

@ -67,6 +67,9 @@
"Delete": "Kendu ikastaroa",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Editatu gertaera",
"Add event": "Gehitu gertaera",
"Add": "Gehitu",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "\u062d\u0630\u0641 \u062e\u0637 \u0633\u06cc\u0631 \u0622\u0645\u0648\u0632\u0634\u06cc",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0648\u06cc\u062f\u0627\u062f",
"Add event": "\u0627\u0641\u0632\u0648\u062f\u0646 \u0631\u0648\u06cc\u062f\u0627\u062f",
"Add": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646",

@ -67,6 +67,9 @@
"Delete": "poista oppimispolku",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Muokkaa tapahtumaa",
"Add event": "Lis\u00e4\u00e4 uusi merkint\u00e4",
"Add": "Lis\u00e4\u00e4",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Skriva \u00ed kalendaran",
"Add": "Goym",

@ -67,6 +67,9 @@
"Delete": "Supprimer",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Modifier l'\u00e9v\u00e8nement",
"Add event": "Ajouter un \u00e9v\u00e9nement",
"Add": "Ajouter",

@ -67,6 +67,9 @@
"Delete": "Delete",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edit event",
"Add event": "Add event",
"Add": "Add",

@ -67,6 +67,9 @@
"Delete": "Delete",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edit event",
"Add event": "Add event",
"Add": "Add",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "izbri\u0161i put u\u010denja",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Uredi element",
"Add event": "Dodaj novi element u raspored",
"Add": "Dodaj",

@ -67,6 +67,9 @@
"Delete": "Tan\u00f6sv\u00e9ny elt\u00e1vol\u00edt\u00e1sa",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Esem\u00e9ny szerkeszt\u00e9se",
"Add event": "\u00daj napt\u00e1r-bejegyz\u00e9s hozz\u00e1ad\u00e1sa",
"Add": "Hozz\u00e1ad",

@ -67,6 +67,9 @@
"Delete": "Hapus learning path",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Tambah Item Baru Agenda",
"Add": "Tambah",

@ -67,6 +67,9 @@
"Delete": "Elimina il modulo didattico",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Modifica evento",
"Add event": "Aggiungi evento",
"Add": "Aggiungi",

@ -67,6 +67,9 @@
"Delete": "\u30b3\u30fc\u30b9\u3092\u524a\u9664",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\u30a4\u30d9\u30f3\u30c8\u3092\u8ffd\u52a0",
"Add": "\u8ffd\u52a0",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "learnpath \uc0ad\uc81c",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\uc0c8\ub85c\uc6b4 \uc77c\uc815 \ucd94\uac00",
"Add": "\ucd94\uac00",

@ -67,6 +67,9 @@
"Delete": "i\u0161trinti",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Prid\u0117ti nauj\u0105 darbotvark\u0117s \u012fra\u0161\u0105",
"Add": "\u012era\u0161yti",

@ -67,6 +67,9 @@
"Delete": "Izdz\u0113st m\u0101c\u012bbu t\u0113mu",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Redi\u0123\u0113t notikumu",
"Add event": "Ierakst\u012bt jaunu notikumu pl\u0101not\u0101j\u0101",
"Add": "Pievienot",

@ -67,6 +67,9 @@
"Delete": "\u0438\u0437\u0431\u0440\u0438\u0448\u0438 \u043f\u0430\u0442\u0435\u043a\u0430_\u043d\u0430_\u0443\u0447\u0435\u045a\u0435\u0442\u043e",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\u0414\u043e\u0434\u0430\u0458 \u043d\u043e\u0432 \u0435\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u043e \u0440\u0430\u0441\u043f\u043e\u0440\u0435\u0434\u043e\u0442",
"Add": "\u0414\u043e\u0434\u0430\u0458",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "Tambah",

@ -67,6 +67,9 @@
"Delete": "Leerpad verwijderen",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Evenement wijzigen",
"Add event": "Nieuw agenda-item",
"Add": "Toevoegen",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Legg til ny oppf\u00f8ring i kalender",
"Add": "Legg til",

@ -67,6 +67,9 @@
"Delete": "Delete",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edit event",
"Add event": "Add event",
"Add": "Add",

@ -67,6 +67,9 @@
"Delete": "Usu\u0144 \u015bcie\u017ck\u0119 nauki",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edytuj zdarzenie",
"Add event": "Dodaj nowy element agendy",
"Add": "Dodaj",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "Eliminar curso",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Editar evento",
"Add event": "Adicionar um evento",
"Add": "Adicionar",

@ -67,6 +67,9 @@
"Delete": "Delete",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Edit event",
"Add event": "Add event",
"Add": "Add",

@ -67,6 +67,9 @@
"Delete": "sterge calea de invatare",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Modificati evenimentul",
"Add event": "Adauga item nou",
"Add": "Adauga",

@ -67,6 +67,9 @@
"Delete": "\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0443\u0447\u0435\u0431\u043d\u044b\u0439 \u043f\u043b\u0430\u043d",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0437\u0430\u043d\u044f\u0442\u0438\u0435 \u0432 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435",
"Add": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c",

@ -67,6 +67,9 @@
"Delete": "Zmaza\u0165 osnovu",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Editova\u0165 udalos\u0165",
"Add event": "Prida\u0165 nov\u00fa polo\u017eku agendy",
"Add": "Prida\u0165",

@ -67,6 +67,9 @@
"Delete": "Odstrani u\u010dno pot",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Uredi dogodek",
"Add event": "Dodaj nov dogodek",
"Add": "Dodaj",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "obri\u0161i putanju u\u010denja",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Uredi dogadjaj",
"Add event": "Dodaj novu stavku u Agendu",
"Add": "Dodavanje",

@ -67,6 +67,9 @@
"Delete": "Ta bort inl\u00e4rningsv\u00e4g",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "L\u00e4gg till kalenderpost",
"Add": "L\u00e4gg till",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "\u0e25\u0e1a\u0e41\u0e1c\u0e19\u0e01\u0e32\u0e23\u0e40\u0e23\u0e35\u0e22\u0e19",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e01\u0e32\u0e23\u0e43\u0e2b\u0e21\u0e48",
"Add": "\u0e40\u0e1e\u0e34\u0e48\u0e21",

@ -67,6 +67,9 @@
"Delete": "Tanggalin ang kurso",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "Magdagdag ng event",
"Add": "Magdagdag",

@ -67,6 +67,9 @@
"Delete": "kurs sil",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "Etkinli\u011fi d\u00fczenle",
"Add event": "Yeni bir etkinlik ekle",
"Add": "Ekle",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "\u0414\u043e\u0434\u0430\u0442\u0438",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "Th\u00eam",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "",
"Add": "",

@ -67,6 +67,9 @@
"Delete": "\u5220\u9664",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "\u4fee\u6539\u4e8b\u4ef6",
"Add event": "\u6dfb\u52a0\u65b0\u65e5\u7a0b",
"Add": "\u6dfb\u52a0",

@ -67,6 +67,9 @@
"Delete": "\u522a\u9664",
"{resource} created": "{resource} created",
"{resource} deleted": "{resource} deleted",
"Course: {course}": "Course: {course}",
"Session: {session}": "Session: {session}",
"Status: {status}": "Status: {status}",
"Edit event": "",
"Add event": "\u65b0\u589e\u65e5\u7a0b\u9805\u76ee",
"Add": "\u6dfb\u52a0",

@ -9,7 +9,7 @@
:class="{ 'text-right text-body-2': editStatus }"
>
<span class="mdi mdi-book" />
{{ t('Course: {0}', [ link.course.resourceNode.title ]) }}
{{ t('Course: {course}', { 'course': link.course.resourceNode.title }) }}
</div>
<div
@ -17,7 +17,7 @@
:class="{ 'text-right text-body-2': editStatus }"
>
<span class="mdi mdi-book-open" />
{{ t('Session: {0}', [ link.session.name ]) }}
{{ t('Session: {session}', {'session': link.session.name }) }}
</div>
<div
@ -44,11 +44,9 @@
{{ link.user.username }}
</div>
<div
v-if="showStatus"
v-t="{ path: 'Status: {0}', args: [link.visibilityName] }"
/>
<div v-if="showStatus">
{{ t('Status: {status}', {'status': link.visibilityName }) }}
</div>
<div
v-if="editStatus"
>

@ -9,9 +9,9 @@ export default {
formatDateTime,
onCreated(item) {
if (item['resourceNode']) {
this.showMessage(this.$i18n.t('{resource} created', {'resource': item['resourceNode'].title}));
this.showMessage(this.$t('{resource} created', {'resource': item['resourceNode'].title}));
} else {
this.showMessage(this.$i18n.t('{resource} created', {'resource': item.title}));
this.showMessage(this.$t('{resource} created', {'resource': item.title}));
}
let folderParams = this.$route.query;

@ -1,15 +1,21 @@
<template>
<Toolbar
:handle-submit="onSendFormData"
:handle-reset="resetForm"
/>
<DocumentsForm
ref="createForm"
:values="item"
:errors="violations"
/>
<Loading :visible="isLoading" />
<Panel
v-if="$route.query.cert === '1'"
:header="$t('Create your certificate copy-pasting the following tags. They will be replaced in the document by their student-specific value:')"
>
<div v-html="finalTags" />
</Panel>
<DocumentsForm
ref="createForm"
:values="item"
:errors="violations"
/>
<Toolbar
:handle-submit="onSendFormData"
:handle-reset="resetForm"
/>
<Loading :visible="isLoading" />
</template>
<script>
@ -20,6 +26,7 @@ import Loading from '../../components/Loading.vue';
import Toolbar from '../../components/Toolbar.vue';
import CreateMixin from '../../mixins/CreateMixin';
import {RESOURCE_LINK_PUBLISHED} from "../../components/resource_links/visibility";
import Panel from 'primevue/panel';
const servicePrefix = 'Documents';
@ -34,18 +41,22 @@ export default {
components: {
Loading,
Toolbar,
DocumentsForm
DocumentsForm,
Panel
},
mixins: [CreateMixin],
data() {
const filetype = this.$route.query.cert === '1' ? 'certificate' : 'file';
const finalTags = this.getCertificateTags();
return {
item: {
newDocument: true, // Used in FormNewDocument.vue to show the editor
filetype: 'file',
filetype: filetype,
parentResourceNodeId: null,
resourceLinkList: null,
contentFile: null
},
finalTags,
};
},
computed: {
@ -60,7 +71,40 @@ export default {
visibility: RESOURCE_LINK_PUBLISHED,
}]);
},
methods: {
getCertificateTags(){
let finalTags = "";
let tags = [
'((user_firstname))',
'((user_lastname))',
'((user_username))',
'((gradebook_institution))',
'((gradebook_sitename))',
'((teacher_firstname))',
'((teacher_lastname))',
'((official_code))',
'((date_certificate))',
'((date_certificate_no_time))',
'((course_code))',
'((course_title))',
'((gradebook_grade))',
'((certificate_link))',
'((certificate_link_html))',
'((certificate_barcode))',
'((external_style))',
'((time_in_course))',
'((time_in_course_in_all_sessions))',
'((start_date_and_end_date))',
'((course_objectives))',
];
for (const tag of tags){
finalTags += "<p class=\"m-0\">"+tag+"</p>"
}
return finalTags;
},
...mapActions('documents', ['createWithFormData', 'reset'])
}
};

@ -123,6 +123,13 @@
@click="btnChangeVisibilityOnClick(slotProps.data)"
/>
<Button
v-if="isAuthenticated && isCurrentTeacher && $route.query.cert === '1'"
:icon="null === slotProps.data.gradebookCategory ? 'mdi mdi-file-plus' : 'mdi mdi-file-plus-outline'"
class="p-button-icon-only p-button-plain p-button-outlined p-button-sm"
@click="btnChangeAttachedCertificateOnClick(slotProps.data)"
/>
<Button
v-if="isAuthenticated && isCurrentTeacher"
class="p-button-icon-only p-button-plain p-button-outlined p-button-sm"
@ -253,12 +260,13 @@ import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import Toolbar from 'primevue/toolbar'
import Dialog from 'primevue/dialog'
import { computed, onMounted, ref, watch } from 'vue'
import {computed, onMounted, ref, watch} from 'vue'
import { useCidReq } from '../../composables/cidReq'
import { useDatatableList } from '../../composables/datatableList'
import { useRelativeDatetime } from '../../composables/formatDate'
import axios from 'axios'
import { useToast } from 'primevue/usetoast';
import {ENTRYPOINT} from "../../config/entrypoint";
const store = useStore()
const route = useRoute()
@ -472,6 +480,38 @@ function btnChangeVisibilityOnClick (item) {
;
}
function btnChangeAttachedCertificateOnClick (item) {
const folderParams = route.query;
folderParams.id = item['@id'];
if (null === item.gradebookCategory) {
axios
.get(ENTRYPOINT + 'gradebook_categories?course=' + cid)
.then(response => {
if (200 === response.status){
item.gradebookCategory = updateAttachedCertificate(response.data['hydra:member'][0]['id'], folderParams.id);
}
})
;
} else {
item.gradebookCategory = updateAttachedCertificate(item.gradebookCategory['id'], folderParams.id);
}
}
function updateAttachedCertificate(gradebookCertificateId, documentId){
axios
.patch(ENTRYPOINT + 'gradebook_categories/' + gradebookCertificateId,
{"document": documentId},
{headers: {'Content-Type': 'application/merge-patch+json'}}
)
.then(response => {
return response.data;
})
;
}
function btnEditOnClick (item) {
const folderParams = route.query;

@ -56,6 +56,7 @@ export default {
const parentResourceNodeId = ref(null);
const resourceLinkList = ref(null);
const route = useRoute();
const filetype = route.query.cert === '1' ? 'certificate' : 'file';
parentResourceNodeId.value = Number(route.params.node);
resourceLinkList.value = JSON.stringify([{
@ -67,7 +68,6 @@ export default {
let uppy = ref();
uppy.value = new Uppy()
.use(Webcam)
.use(ImageEditor, {
cropperOptions: {
viewMode: 1,
@ -97,11 +97,16 @@ export default {
;
uppy.value.setMeta({
filetype: 'file',
filetype: filetype,
parentResourceNodeId: parentResourceNodeId.value,
resourceLinkList: resourceLinkList.value,
});
if (filetype === 'certificate') {
uppy.value.opts.restrictions.allowedFileTypes = ['.html']
} else {
uppy.value.use(Webcam)
}
return {
createForm,
uppy
@ -131,12 +136,12 @@ export default {
methods: {
async processFiles(files) {
return new Promise((resolve) => {
for (let i = 0; i < files.length; i++) {
files[i].title = files[i].name;
files[i].parentResourceNodeId = this.parentResourceNodeId;
files[i].resourceLinkList = this.resourceLinkList;
files[i].uploadFile = files[i];
this.createFile(files[i]);
for (const element of files) {
element.title = element.name;
element.parentResourceNodeId = this.parentResourceNodeId;
element.resourceLinkList = this.resourceLinkList;
element.uploadFile = element;
this.createFile(element);
}
resolve(files);

@ -9,7 +9,7 @@ require_once '../main/inc/global.inc.php';
$action = isset($_GET['action']) ? $_GET['action'] : null;
$userId = isset($_GET['user_id']) ? $_GET['user_id'] : 0;
$certificate = new Certificate($_GET['id'], $userId);
$certificate = new Certificate($_GET['id'], $userId, false, false);
CustomCertificatePlugin::redirectCheck($certificate, $_GET['id'], $userId);

@ -9740,7 +9740,7 @@ class Exercise
$sessionId = (int) $sessionId;
foreach ($this->lpList as $lp) {
if ((int) $lp['session_id'] == $sessionId) {
if (isset($lp['session_id']) && (int) $lp['session_id'] == $sessionId) {
return $lp;
}
}

@ -77,7 +77,6 @@ if ($form->validate()) {
$sql = 'UPDATE '.$tbl_forum_thread.' SET
thread_weight = '.api_float_val($final_weight).'
WHERE
c_id = '.$course_id.' AND
iid = (
SELECT ref_id FROM '.$tbl_grade_links.'
WHERE id='.intval($_GET['editlink']).' AND type = 5
@ -89,15 +88,13 @@ if ($form->validate()) {
->createQuery('
UPDATE ChamiloCourseBundle:CStudentPublication w
SET w.weight = :final_weight
WHERE w.cId = :course
AND w.iid = (
WHERE w.iid = (
SELECT l.refId FROM ChamiloCoreBundle:GradebookLink l
WHERE l.id = :link AND l.type = :type
)
')
->execute([
'final_weight' => $final_weight,
'course' => $course_id,
'link' => intval($_GET['editlink']),
'type' => LINK_STUDENTPUBLICATION,
]);

@ -458,7 +458,7 @@ if (isset($_GET['deletelink'])) {
thread_qualify_max = 0,
thread_weight = 0,
thread_title_qualify = ""
WHERE c_id = '.$course_id.' AND iid = (
WHERE iid = (
SELECT ref_id FROM '.$tbl_grade_links.'
WHERE id='.$get_delete_link.' AND type = '.LINK_FORUM_THREAD.'
)';

@ -818,7 +818,7 @@ class GradebookUtils
// Generate document HTML
$content_html = DocumentManager::replace_user_info_into_html(
$user_id,
api_get_course_info($course_code),
api_get_course_info_by_id($course_code),
$sessionId,
$is_preview
);

@ -2054,10 +2054,7 @@ class Category implements GradebookItem
$user_id = (int) $user_id;
$categoryId = $category->getId();
$sessionId = $category->getSession() ? $category->getSession()->getId() : 0;
$courseCode = $category->getCourse()->getId();
$courseInfo = api_get_course_info($courseCode);
$courseId = $courseInfo['real_id'];
$courseId = $category->getCourse()->getId();
$userFinishedCourse = self::userFinishedCourse($user_id, $category, true);
if (!$userFinishedCourse) {
return false;
@ -2116,10 +2113,14 @@ class Category implements GradebookItem
$html = [];
if (!empty($my_certificate)) {
$pathToCertificate = $category->getDocument()->getResourceNode()->getResourceFile()->getFile()->getPathname();
$certificate_obj = new Certificate(
$my_certificate['id'],
0,
$sendNotification
$sendNotification,
true,
$pathToCertificate
);
$fileWasGenerated = $certificate_obj->isHtmlFileGenerated();

@ -230,7 +230,7 @@ class ExerciseLink extends AbstractLink
$lpList[] = $lpData['lp_id'];
}
} else {
if ((int) $lpData['session_id'] == $sessionId) {
if (in_array('session_id', $lpData) && (int) $lpData['session_id'] == $sessionId) {
$lpList[] = $lpData['lp_id'];
}
}
@ -567,7 +567,6 @@ class ExerciseLink extends AbstractLink
// Try with iid
$sql = 'SELECT * FROM '.$table.'
WHERE
c_id = '.$this->course_id.' AND
iid = '.$exerciseId;
$result = Database::query($sql);
$rows = Database::num_rows($result);

@ -481,12 +481,14 @@ class GradebookTable extends SortableTable
$totalResult = [];
if (isset($data['result_score'])) {
$totalResult = [
$data['result_score'][0],
$data['result_score'][1],
$data['result_score'][0] ?? 0,
$data['result_score'][1] ?? 0,
];
}
if (empty($model)) {
$data['best_score'][0] = $data['best_score'][0] ?? 0;
$data['best_score'][1] = $data['best_score'][1] ?? 0;
$totalBest = [
$scoredisplay->format_score($totalBest[0] + $data['best_score'][0]),
$scoredisplay->format_score($totalBest[1] + $data['best_score'][1]),
@ -538,7 +540,7 @@ class GradebookTable extends SortableTable
$this->dataForGraph['my_result'][] = floatval($totalResultAverageValue);
$this->dataForGraph['average'][] = floatval($totalAverageValue);
$this->dataForGraph['my_result_no_float'][] = $data['result_score'][0];
$this->dataForGraph['my_result_no_float'][] = $data['result_score'][0] ?? 0;
if (empty($model)) {
// Ranking

@ -60,17 +60,18 @@ $context = Container::getRouter()->getContext();
$pos = strpos($currentBaseUrl, 'main');
$posPlugin = strpos($currentBaseUrl, 'plugin');
$posCertificate = strpos($currentBaseUrl, 'certificate');
if (false === $pos && false === $posPlugin) {
if (false === $pos && false === $posPlugin && false === $posCertificate) {
echo 'Cannot load current URL';
exit;
}
if (false !== $pos) {
$newBaseUrl = substr($currentBaseUrl, 0, $pos - 1);
}
if (false !== $posPlugin) {
}elseif (false !== $posPlugin) {
$newBaseUrl = substr($currentBaseUrl, 0, $posPlugin - 1);
} elseif (false !== $posCertificate) {
$newBaseUrl = substr($currentBaseUrl, 0, $posPlugin - 1);
}

@ -2,6 +2,7 @@
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\GradebookCategory;
use Chamilo\CoreBundle\Framework\Container;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
@ -47,6 +48,7 @@ class Certificate extends Model
* @param int $userId
* @param bool $sendNotification send message to student
* @param bool $updateCertificateData
* @param string $pathToCertificate
*
* If no ID given, take user_id and try to generate one
*/
@ -54,7 +56,8 @@ class Certificate extends Model
$certificate_id = 0,
$userId = 0,
$sendNotification = false,
$updateCertificateData = true
$updateCertificateData = true,
$pathToCertificate = ''
) {
$this->table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE);
$this->user_id = !empty($userId) ? $userId : api_get_user_id();
@ -70,12 +73,14 @@ class Certificate extends Model
if ($this->user_id) {
// To force certification generation
if ($this->force_certificate_generation) {
$this->generate([], $sendNotification);
$this->generate(['certificate_path' => ''], $sendNotification);
}
if (isset($this->certificate_data) && $this->certificate_data) {
if (empty($this->certificate_data['path_certificate'])) {
$this->generate([], $sendNotification);
}
if (
isset($this->certificate_data)
&& $this->certificate_data
&& empty($this->certificate_data['path_certificate'])
) {
$this->generate(['certificate_path' => $pathToCertificate], $sendNotification);
}
}
@ -85,14 +90,24 @@ class Certificate extends Model
isset($this->certificate_data['path_certificate'])
) {
$pathinfo = pathinfo($this->certificate_data['path_certificate']);
$this->html_file = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
$this->html_file = $this->certificate_data['path_certificate'];
$this->qr_file = $this->certification_user_path.$pathinfo['filename'].'_qr.png';
} else {
if (api_get_configuration_value('allow_general_certificate')) {
$container = Container::getResourceNodeRepository();
$filesystem = $container->getFileSystem();
// General certificate
$name = md5($this->user_id).'.html';
$my_path_certificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
$name = hash('sha256', $this->user_id.$this->certificate_data['cat_id']);
$arrayName = str_split(substr($name, 0, 3));
$my_path_certificate = $arrayName[0].
DIRECTORY_SEPARATOR.
$arrayName[1].
DIRECTORY_SEPARATOR.
$arrayName[2].
DIRECTORY_SEPARATOR;
$this->certification_user_path = $my_path_certificate;
$path_certificate = $my_path_certificate.$name.'.html';
// Getting QR filename
$file_info = pathinfo($path_certificate);
@ -113,10 +128,10 @@ class Certificate extends Model
api_get_system_encoding()
);
$this->html_file = $my_path_certificate;
$result = @file_put_contents($my_path_certificate, $my_new_content_html);
$this->html_file = $path_certificate;
$filesystem->write($path_certificate, $my_new_content_html);
if ($result) {
if ($filesystem->fileExists($path_certificate)) {
// Updating the path
self::updateUserCertificateInfo(
0,
@ -184,24 +199,31 @@ class Certificate extends Model
) {
return false;
}
$result = false;
$params['hide_print_button'] = isset($params['hide_print_button']) ? true : false;
$pathToOriginalCertificate = $params['certificate_path'] ?? '';
$categoryId = 0;
$my_category = [];
if (isset($this->certificate_data) && isset($this->certificate_data['cat_id'])) {
if (isset($this->certificate_data['cat_id'])) {
$categoryId = $this->certificate_data['cat_id'];
$my_category = Category::load($categoryId);
$repo = Container::getGradeBookCategoryRepository();
$gradebookCategory = $repo->find($categoryId);
}
$container = Container::getResourceNodeRepository();
$filesystem = $container->getFileSystem();
if (isset($my_category[0]) && !empty($categoryId) &&
if (!empty($categoryId) &&
$my_category[0]->is_certificate_available($this->user_id)
) {
/** @var Category $category */
$category = $my_category[0];
/** @var GradebookCategory $category */
$category = $gradebookCategory;
$courseInfo = api_get_course_info($category->get_course_code());
$courseInfo = api_get_course_info($category->getCourse()->getCode());
$courseId = $courseInfo['real_id'];
$sessionId = $category->get_session_id();
$sessionId = $category->getSession() ? $category->getSession()->getId() : 0;
$skill = new SkillModel();
$skill->addSkillToUser(
@ -211,103 +233,117 @@ class Certificate extends Model
$sessionId
);
if (is_dir($this->certification_user_path)) {
if (!empty($this->certificate_data)) {
$new_content_html = GradebookUtils::get_user_certificate_content(
$this->user_id,
$category->get_course_code(),
$category->get_session_id(),
false,
$params['hide_print_button']
);
if ($category->get_id() == $categoryId) {
$name = $this->certificate_data['path_certificate'];
$myPathCertificate = $this->certification_user_path.basename($name);
if (file_exists($myPathCertificate) &&
!empty($name) &&
!is_dir($myPathCertificate) &&
false == $this->force_certificate_generation
) {
// Seems that the file was already generated
return true;
} else {
// Creating new name
$name = md5($this->user_id.$this->certificate_data['cat_id']).'.html';
$myPathCertificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
// Getting QR filename
$file_info = pathinfo($path_certificate);
$qr_code_filename = $this->certification_user_path.$file_info['filename'].'_qr.png';
$newContent = str_replace(
'((certificate_barcode))',
Display::img(
$this->certification_web_user_path.$file_info['filename'].'_qr.png',
'QR'
),
$new_content_html['content']
);
if ($filesystem->fileExists($pathToOriginalCertificate) && !empty($this->certificate_data)) {
$new_content_html = GradebookUtils::get_user_certificate_content(
$this->user_id,
$category->getCourse()->getId(),
$category->getSession() ? $category->getSession()->getId() : 0,
false,
$params['hide_print_button']
);
$newContent = api_convert_encoding(
$newContent,
'UTF-8',
api_get_system_encoding()
);
if ($category->getId() == $categoryId) {
$myPathCertificate = $this->certificate_data['path_certificate'] ?? '';
$result = @file_put_contents($myPathCertificate, $newContent);
if ($result) {
// Updating the path
$this->updateUserCertificateInfo(
$this->certificate_data['cat_id'],
$this->user_id,
$path_certificate
);
$this->certificate_data['path_certificate'] = $path_certificate;
if ($filesystem->fileExists($myPathCertificate) &&
!$this->force_certificate_generation
) {
// Seems that the file was already generated
return true;
} else {
// Creating new name
$name = hash('sha256', $this->user_id.$categoryId);
$arrayName = str_split(substr($name, 0, 3));
$myPathCertificate =
$arrayName[0]
.DIRECTORY_SEPARATOR
.$arrayName[1].DIRECTORY_SEPARATOR
.$arrayName[2].DIRECTORY_SEPARATOR;
$this->certification_user_path = $myPathCertificate;
$path_certificate = $myPathCertificate.$name.'.html';
// Getting QR filename
$file_info = pathinfo($pathToOriginalCertificate);
$qr_code_filename = $this->certification_user_path.$name.'_qr.png';
$newContent = str_replace(
'((certificate_barcode))',
Display::img(
$this->certification_web_user_path.$file_info['filename'].'_qr.png',
'QR'
),
$new_content_html['content']
);
if ($this->isHtmlFileGenerated()) {
if (!empty($file_info)) {
$text = $this->parseCertificateVariables(
$new_content_html['variables']
);
$this->generateQRImage(
$text,
$qr_code_filename
$newContent = api_convert_encoding(
$newContent,
'UTF-8',
api_get_system_encoding()
);
$filesystem->write($path_certificate, $newContent);
if ($filesystem->fileExists($path_certificate)) {
$result = true;
// Updating the path
$this->updateUserCertificateInfo(
$this->certificate_data['cat_id'],
$this->user_id,
$path_certificate
);
$this->certificate_data['path_certificate'] = $path_certificate;
if ($this->isHtmlFileGenerated()) {
if (!empty($file_info)) {
$text = $this->parseCertificateVariables(
$new_content_html['variables']
);
/* $this->generateQRImage(
$text,
$qr_code_filename
);*/
if ($sendNotification) {
$subject = get_lang('Certificate notification');
$message = nl2br(get_lang('((user_first_name)),'));
$score = $this->certificate_data['score_certificate'];
self::sendNotification(
$subject,
$message,
api_get_user_info($this->user_id),
$courseInfo,
[
'score_certificate' => $score,
]
);
if ($sendNotification) {
$subject = get_lang('Certificate notification');
$message = nl2br(get_lang('((user_first_name)),'));
$score = $this->certificate_data['score_certificate'];
self::sendNotification(
$subject,
$message,
api_get_user_info($this->user_id),
$courseInfo,
[
'score_certificate' => $score,
]
);
}
}
}
}
return $result;
}
return $result;
}
}
}
} else {
// General certificate
$name = md5($this->user_id).'.html';
$my_path_certificate = $this->certification_user_path.$name;
$path_certificate = '/'.$name;
$name = hash('sha256', $this->user_id.$categoryId);
$arrayName = str_split(substr($name, 0, 3));
$myPathCertificate =
$arrayName[0]
.DIRECTORY_SEPARATOR
.$arrayName[1].DIRECTORY_SEPARATOR
.$arrayName[2].DIRECTORY_SEPARATOR;
$this->certification_user_path = $myPathCertificate;
$path_certificate = $myPathCertificate.$name.'.html';
// Getting QR filename
$file_info = pathinfo($path_certificate);
$file_info = pathinfo($pathToOriginalCertificate);
$content = $this->generateCustomCertificate();
$my_new_content_html = str_replace(
@ -325,9 +361,10 @@ class Certificate extends Model
api_get_system_encoding()
);
$result = @file_put_contents($my_path_certificate, $my_new_content_html);
$filesystem->write($path_certificate, $my_new_content_html);
if ($result) {
if ($filesystem->fileExists($path_certificate)) {
$result = true;
// Updating the path
self::updateUserCertificateInfo(
0,
@ -601,9 +638,9 @@ class Certificate extends Model
return false;
}
$userCertificate = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
if (!file_exists($userCertificate)) {
$container = Container::getResourceNodeRepository();
$filesystem = $container->getFileSystem();
if (!$filesystem->fileExists($this->certificate_data['path_certificate'])) {
return false;
}
@ -615,11 +652,12 @@ class Certificate extends Model
*/
public function show()
{
$user_certificate = $this->certification_user_path.basename($this->certificate_data['path_certificate']);
if (file_exists($user_certificate)) {
$container = Container::getResourceNodeRepository();
$filesystem = $container->getFileSystem();
if ($filesystem->fileExists($this->certificate_data['path_certificate'])) {
// Needed in order to browsers don't add custom CSS
$certificateContent = '<!DOCTYPE html>';
$certificateContent .= (string) file_get_contents($user_certificate);
$certificateContent .= $filesystem->read($this->certificate_data['path_certificate']);
// Remove media=screen to be available when printing a document
$certificateContent = str_replace(

@ -59,7 +59,7 @@ class ChamiloSession implements \ArrayAccess
$session = Container::getSession();
$result = null;
if (isset($session) && $session) {
if (isset($session) && $session && $variable) {
$result = $session->get($variable);
}

@ -220,6 +220,7 @@ class BaseResourceFileAction
$resource->setParentResourceNode($parentResourceNodeId);
switch ($fileType) {
case 'certificate':
case 'file':
$content = '';
if ($request->request->has('contentFile')) {

@ -6,11 +6,17 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use Chamilo\CoreBundle\Traits\CourseTrait;
use Chamilo\CoreBundle\Traits\UserTrait;
use Chamilo\CourseBundle\Entity\CDocument;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
@ -19,6 +25,21 @@ use Symfony\Component\Validator\Constraints as Assert;
* }))
* @ORM\Entity
*/
#[ApiResource(
attributes: [
'security' => "is_granted('ROLE_USER')",
],
denormalizationContext: [
'groups' => ['gradebookCategory:write'],
],
normalizationContext: [
'groups' => ['gradebookCategory:read'],
],
)]
#[ApiFilter(SearchFilter::class, properties: [
'course' => 'exact',
])]
class GradebookCategory
{
use UserTrait;
@ -29,6 +50,7 @@ class GradebookCategory
* @ORM\Id
* @ORM\GeneratedValue
*/
#[Groups(['document:read', 'gradebookCategory:read'])]
protected ?int $id = null;
/**
@ -52,6 +74,7 @@ class GradebookCategory
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="gradebookCategories")
* @ORM\JoinColumn(name="c_id", referencedColumnName="id", onDelete="CASCADE")
*/
#[Groups(['gradebookCategory:read'])]
protected Course $course;
/**
@ -125,9 +148,12 @@ class GradebookCategory
protected ?int $certifMinScore = null;
/**
* @ORM\Column(name="document_id", type="integer", nullable=true)
* @ORM\OneToOne(targetEntity="Chamilo\CourseBundle\Entity\CDocument", inversedBy="gradebookCategory")
* @ORM\JoinColumn(name="document_id", referencedColumnName="iid", nullable=false, onDelete="cascade")
*/
protected ?int $documentId = null;
#[ApiSubresource]
#[Groups(['gradebookCategory:read', 'gradebookCategory:write'])]
protected ?CDocument $document = null;
/**
* @ORM\Column(name="locked", type="integer", nullable=false)
@ -275,9 +301,9 @@ class GradebookCategory
*
* @return GradebookCategory
*/
public function setDocumentId(int $documentId)
public function setDocument($document)
{
$this->documentId = $documentId;
$this->document = $document;
return $this;
}
@ -285,11 +311,11 @@ class GradebookCategory
/**
* Get documentId.
*
* @return int
* @return CDocument|null
*/
public function getDocumentId()
public function getDocument()
{
return $this->documentId;
return $this->document;
}
public function setLocked(int $locked): self

@ -26,6 +26,8 @@ use Chamilo\CoreBundle\Repository\Node\TicketMessageAttachmentRepository;
use Chamilo\CoreBundle\Repository\Node\UsergroupRepository;
use Chamilo\CoreBundle\Repository\Node\UserRepository;
use Chamilo\CoreBundle\Repository\PromotionRepository;
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
use Chamilo\CoreBundle\Repository\ResourceRepository;
use Chamilo\CoreBundle\Repository\SequenceRepository;
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
use Chamilo\CoreBundle\Repository\SessionRepository;
@ -275,6 +277,11 @@ class Container
return self::$container->get(AssetRepository::class);
}
public static function getResourceNodeRepository(): ResourceNodeRepository
{
return self::$container->get(ResourceNodeRepository::class);
}
public static function getAttendanceRepository(): CAttendanceRepository
{
return self::$container->get(CAttendanceRepository::class);

@ -16,6 +16,7 @@ use Chamilo\CoreBundle\Controller\Api\CreateDocumentFileAction;
use Chamilo\CoreBundle\Controller\Api\UpdateDocumentFileAction;
use Chamilo\CoreBundle\Controller\Api\UpdateVisibilityDocument;
use Chamilo\CoreBundle\Entity\AbstractResource;
use Chamilo\CoreBundle\Entity\GradebookCategory;
use Chamilo\CoreBundle\Entity\ResourceInterface;
use Chamilo\CoreBundle\Entity\ResourceShowCourseResourcesInSessionInterface;
use Doctrine\ORM\Mapping as ORM;
@ -210,6 +211,15 @@ class CDocument extends AbstractResource implements ResourceInterface, ResourceS
*/
protected bool $template;
/**
* @ORM\OneToOne(targetEntity="Chamilo\CoreBundle\Entity\GradebookCategory",
* mappedBy="document",
* cascade={"persist", "remove"},
* orphanRemoval=true)
*/
#[Groups(['document:read'])]
protected GradebookCategory|null $gradebookCategory = null;
public function __construct()
{
$this->comment = '';
@ -305,4 +315,9 @@ class CDocument extends AbstractResource implements ResourceInterface, ResourceS
{
return $this->setTitle($name);
}
public function getGradebookCategory(): GradebookCategory|null
{
return $this->gradebookCategory;
}
}

Loading…
Cancel
Save