@sync-in/server 1.3.9 → 1.5.0

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 (294) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +5 -3
  3. package/environment/environment.dist.yaml +2 -0
  4. package/package.json +6 -6
  5. package/server/app.bootstrap.js +9 -0
  6. package/server/app.bootstrap.js.map +1 -1
  7. package/server/app.service.spec.js +44 -19
  8. package/server/app.service.spec.js.map +1 -1
  9. package/server/applications/comments/comments.controller.spec.js +103 -4
  10. package/server/applications/comments/comments.controller.spec.js.map +1 -1
  11. package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
  12. package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
  13. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
  14. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
  15. package/server/applications/files/constants/files.js +0 -23
  16. package/server/applications/files/constants/files.js.map +1 -1
  17. package/server/applications/files/constants/only-office.js +8 -0
  18. package/server/applications/files/constants/only-office.js.map +1 -1
  19. package/server/applications/files/constants/routes.js +6 -1
  20. package/server/applications/files/constants/routes.js.map +1 -1
  21. package/server/applications/files/files-only-office.controller.js +11 -0
  22. package/server/applications/files/files-only-office.controller.js.map +1 -1
  23. package/server/applications/files/files-only-office.controller.spec.js +97 -3
  24. package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
  25. package/server/applications/files/files-tasks.controller.spec.js +91 -1
  26. package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
  27. package/server/applications/files/files.config.js +5 -0
  28. package/server/applications/files/files.config.js.map +1 -1
  29. package/server/applications/files/files.controller.spec.js +268 -46
  30. package/server/applications/files/files.controller.spec.js.map +1 -1
  31. package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
  32. package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
  33. package/server/applications/files/guards/files-only-office.strategy.js +0 -1
  34. package/server/applications/files/guards/files-only-office.strategy.js.map +1 -1
  35. package/server/applications/files/services/files-only-office-manager.service.js +5 -0
  36. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  37. package/server/applications/links/links.controller.spec.js +91 -58
  38. package/server/applications/links/links.controller.spec.js.map +1 -1
  39. package/server/applications/links/services/links-manager.service.js +4 -6
  40. package/server/applications/links/services/links-manager.service.js.map +1 -1
  41. package/server/applications/links/services/links-manager.service.spec.js +378 -14
  42. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  43. package/server/applications/links/services/links-queries.service.js +1 -1
  44. package/server/applications/links/services/links-queries.service.js.map +1 -1
  45. package/server/applications/notifications/notifications.controller.spec.js +56 -1
  46. package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
  47. package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
  48. package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
  49. package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
  50. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  51. package/server/applications/spaces/guards/space.guard.spec.js +153 -18
  52. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  53. package/server/applications/spaces/services/spaces-browser.service.js +7 -7
  54. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  55. package/server/applications/spaces/services/spaces-manager.service.js +17 -17
  56. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  57. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
  58. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
  59. package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
  60. package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
  61. package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
  62. package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
  63. package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
  64. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  65. package/server/applications/sync/utils/routes.js +1 -1
  66. package/server/applications/sync/utils/routes.js.map +1 -1
  67. package/server/applications/users/guards/permissions.guard.js +4 -4
  68. package/server/applications/users/guards/permissions.guard.js.map +1 -1
  69. package/server/applications/users/guards/permissions.guard.spec.js +6 -6
  70. package/server/applications/users/guards/permissions.guard.spec.js.map +1 -1
  71. package/server/applications/users/guards/roles.guard.js +1 -1
  72. package/server/applications/users/guards/roles.guard.js.map +1 -1
  73. package/server/applications/users/models/user.model.js +1 -1
  74. package/server/applications/users/models/user.model.js.map +1 -1
  75. package/server/applications/users/services/admin-users-manager.service.js +22 -24
  76. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  77. package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
  78. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  79. package/server/applications/users/services/users-manager.service.js +1 -1
  80. package/server/applications/users/services/users-manager.service.js.map +1 -1
  81. package/server/applications/users/services/users-manager.service.spec.js +938 -49
  82. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  83. package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
  84. package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
  85. package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
  86. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
  87. package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
  88. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  89. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
  90. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
  91. package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
  92. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  93. package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
  94. package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
  95. package/server/applications/webdav/webdav.controller.js +2 -2
  96. package/server/applications/webdav/webdav.controller.js.map +1 -1
  97. package/server/authentication/guards/auth-basic.guard.js.map +1 -1
  98. package/server/authentication/guards/auth-basic.guard.spec.js +38 -2
  99. package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
  100. package/server/authentication/guards/auth-basic.strategy.js +0 -1
  101. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  102. package/server/authentication/guards/auth-digest.guard.js +1 -2
  103. package/server/authentication/guards/auth-digest.guard.js.map +1 -1
  104. package/server/authentication/guards/auth-local.guard.js.map +1 -1
  105. package/server/authentication/guards/auth-local.guard.spec.js +7 -5
  106. package/server/authentication/guards/auth-local.guard.spec.js.map +1 -1
  107. package/server/authentication/guards/auth-local.strategy.js +0 -1
  108. package/server/authentication/guards/auth-local.strategy.js.map +1 -1
  109. package/server/authentication/guards/auth-token-access.guard.spec.js +30 -0
  110. package/server/authentication/guards/auth-token-access.guard.spec.js.map +1 -1
  111. package/server/authentication/guards/auth-token-access.strategy.js +0 -1
  112. package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
  113. package/server/authentication/guards/auth-token-refresh.strategy.js +0 -1
  114. package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
  115. package/server/authentication/services/auth-methods/auth-method-database.service.js +1 -1
  116. package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
  117. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +8 -6
  118. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
  119. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +2 -2
  120. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  121. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +500 -5
  122. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  123. package/server/configuration/config.loader.js +0 -3
  124. package/server/configuration/config.loader.js.map +1 -1
  125. package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
  126. package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
  127. package/server/infrastructure/context/services/context-manager.service.spec.js +98 -0
  128. package/server/infrastructure/context/services/context-manager.service.spec.js.map +1 -0
  129. package/server/infrastructure/database/constants.js +0 -1
  130. package/server/infrastructure/database/constants.js.map +1 -1
  131. package/server/infrastructure/database/scripts/seed/usersgroups.js +3 -3
  132. package/server/infrastructure/database/scripts/seed/usersgroups.js.map +1 -1
  133. package/server/infrastructure/mailer/mailer.service.js +20 -19
  134. package/server/infrastructure/mailer/mailer.service.js.map +1 -1
  135. package/server/infrastructure/mailer/mailer.service.spec.js +176 -0
  136. package/server/infrastructure/mailer/mailer.service.spec.js.map +1 -0
  137. package/static/3rdpartylicenses.txt +26 -26
  138. package/static/assets/pdfjs/build/pdf.mjs +1177 -255
  139. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  140. package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
  141. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  142. package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
  143. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  144. package/static/assets/pdfjs/version +1 -1
  145. package/static/assets/pdfjs/web/debugger.css +31 -0
  146. package/static/assets/pdfjs/web/debugger.mjs +144 -2
  147. package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
  148. package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
  149. package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
  150. package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
  151. package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
  152. package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
  153. package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
  154. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
  155. package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
  156. package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
  157. package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
  158. package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
  159. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
  160. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
  161. package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
  162. package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
  163. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
  164. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
  165. package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
  166. package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
  167. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
  168. package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
  169. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
  170. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
  171. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
  172. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
  173. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
  174. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
  175. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
  176. package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
  177. package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
  178. package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
  179. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
  180. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
  181. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
  182. package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
  183. package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
  184. package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
  185. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
  186. package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
  187. package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
  188. package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
  189. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
  190. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
  191. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
  192. package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
  193. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
  194. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
  195. package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
  196. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
  197. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
  198. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
  199. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
  200. package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
  201. package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
  202. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
  203. package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
  204. package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
  205. package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
  206. package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
  207. package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
  208. package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
  209. package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
  210. package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
  211. package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
  212. package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
  213. package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
  214. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
  215. package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
  216. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
  217. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
  218. package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
  219. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
  220. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
  221. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
  222. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
  223. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
  224. package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
  225. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
  226. package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
  227. package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
  228. package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
  229. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
  230. package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
  231. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
  232. package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
  233. package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
  234. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
  235. package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
  236. package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
  237. package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
  238. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
  239. package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
  240. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
  241. package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
  242. package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
  243. package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
  244. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
  245. package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
  246. package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
  247. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
  248. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
  249. package/static/assets/pdfjs/web/viewer.css +649 -120
  250. package/static/assets/pdfjs/web/viewer.html +19 -0
  251. package/static/assets/pdfjs/web/viewer.mjs +489 -38
  252. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  253. package/static/chunk-22EANI6R.js +1 -0
  254. package/static/{chunk-KFM544CA.js → chunk-2UWN7IQF.js} +1 -1
  255. package/static/{chunk-N3T57OCA.js → chunk-2VSPDSJS.js} +1 -1
  256. package/static/{chunk-HUWQHCUX.js → chunk-34UZ7SYI.js} +1 -1
  257. package/static/{chunk-MWFRZBJD.js → chunk-45UQJGGY.js} +1 -1
  258. package/static/{chunk-LYTD6AJE.js → chunk-5TEXH3LJ.js} +1 -1
  259. package/static/{chunk-4KESSWTF.js → chunk-66FMKVJX.js} +1 -1
  260. package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
  261. package/static/chunk-CK4BY2NX.js +27 -0
  262. package/static/{chunk-QTW62OKJ.js → chunk-CSBDAY77.js} +1 -1
  263. package/static/{chunk-XUZSYWRF.js → chunk-CXXPLBDZ.js} +1 -1
  264. package/static/{chunk-ZTXJC5IC.js → chunk-EILQG525.js} +1 -1
  265. package/static/{chunk-FJFNDK67.js → chunk-ENWABUR4.js} +1 -1
  266. package/static/{chunk-WL65GYD5.js → chunk-FR4AOLYL.js} +4 -4
  267. package/static/chunk-HW2H3ISM.js +559 -0
  268. package/static/{chunk-BW5PQAKK.js → chunk-HYMDGBZL.js} +1 -1
  269. package/static/{chunk-WLPYIJFI.js → chunk-IML5UYQG.js} +1 -1
  270. package/static/{chunk-Z5X7LVMZ.js → chunk-IPSMJHMQ.js} +1 -1
  271. package/static/{chunk-3S4WNZ2T.js → chunk-JVCWYSNP.js} +1 -1
  272. package/static/{chunk-CLSVDV7J.js → chunk-KGPCIUD2.js} +1 -1
  273. package/static/{chunk-O4AQBQBF.js → chunk-KQZJSEM3.js} +1 -1
  274. package/static/{chunk-MK7WZG3F.js → chunk-NPEMJJIU.js} +1 -1
  275. package/static/{chunk-4TEHM3AS.js → chunk-OEFBC4GG.js} +1 -1
  276. package/static/{chunk-O67RFAWU.js → chunk-P734A3XZ.js} +1 -1
  277. package/static/{chunk-SRLMFJ7C.js → chunk-RASR4CK6.js} +1 -1
  278. package/static/{chunk-S5WXHO6D.js → chunk-RFMOUC22.js} +1 -1
  279. package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
  280. package/static/{chunk-3FX6ISDY.js → chunk-SBOQGGZX.js} +1 -1
  281. package/static/{chunk-NV2MEIWP.js → chunk-SJAFPXQV.js} +1 -1
  282. package/static/{chunk-PYSFXLMV.js → chunk-XTYGMF2V.js} +1 -1
  283. package/static/{chunk-ZFKCGL6X.js → chunk-YCWMV2YR.js} +1 -1
  284. package/static/{chunk-LB7B5RIV.js → chunk-YGD22MWQ.js} +1 -1
  285. package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
  286. package/static/{chunk-SKDQM65G.js → chunk-ZVY37DKS.js} +1 -1
  287. package/static/index.html +2 -2
  288. package/static/main-N5CZRHAO.js +7 -0
  289. package/static/styles-FYUSO6OJ.css +1 -0
  290. package/static/chunk-AY2GOSJ2.js +0 -24
  291. package/static/chunk-RSNLYAN6.js +0 -560
  292. package/static/chunk-ZZ3LHYOY.js +0 -1
  293. package/static/main-RREKR34B.js +0 -10
  294. package/static/styles-3DONJ2Z4.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/configuration/config.loader.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport deepmerge from 'deepmerge'\nimport * as yaml from 'js-yaml'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport {\n DEFAULT_LOG_FILE_PATH,\n ENVIRONMENT_DIST_FILE_NAME,\n ENVIRONMENT_DIST_PATH,\n ENVIRONMENT_FILE_NAME,\n ENVIRONMENT_PATH,\n ENVIRONMENT_PREFIX\n} from './config.constants'\nimport type { Configuration } from './config.validation'\n\nexport function configLoader(): any {\n let config: Partial<Configuration> = loadEnvFile(ENVIRONMENT_PATH, ENVIRONMENT_FILE_NAME)\n\n if (hasEnvConfig()) {\n // If any environment vars are found, parse the config model and apply those settings\n const envConfig = getEnvOverrides(loadEnvFile(ENVIRONMENT_DIST_PATH, ENVIRONMENT_DIST_FILE_NAME, true))\n config = deepmerge(config, envConfig)\n }\n\n if (Object.keys(config).length === 0) {\n throw new Error(`Missing configuration: \"${ENVIRONMENT_FILE_NAME}\" not found, or no variables beginning with \"${ENVIRONMENT_PREFIX}\" are set.`)\n }\n\n if (config.logger?.stdout === false) {\n // ensure log directory exists\n const logFilePath = config.logger.filePath || DEFAULT_LOG_FILE_PATH\n const dirLogPath = path.dirname(logFilePath)\n if (!fs.existsSync(dirLogPath)) {\n fs.mkdirSync(dirLogPath, { recursive: true })\n }\n console.log(`Logging to file → ${logFilePath}`)\n }\n\n return config\n}\n\nfunction buildPathsUp(basePath: string, fileName: string, levels = 4): string[] {\n // Generates candidate file paths, optionally walking up from __dirname to a given depth.\n return Array.from({ length: levels + 1 }, (_, i) => path.resolve(basePath, ...Array(i).fill('..'), fileName))\n}\n\nfunction loadEnvFile(envPath: string, envFileName: string, throwIfMissing = false): any {\n const candidates = [envPath, envFileName, ...buildPathsUp(__dirname, envPath), ...buildPathsUp(__dirname, envFileName)]\n for (const envFilePath of candidates) {\n if (fs.existsSync(envFilePath) && fs.lstatSync(envFilePath).isFile()) {\n if (envFileName === ENVIRONMENT_FILE_NAME) {\n console.log(`Load configuration → ${envFilePath}`)\n }\n return yaml.load(fs.readFileSync(envFilePath, 'utf8'))\n }\n }\n if (throwIfMissing) {\n throw new Error(`${envFileName} not found`)\n }\n return {}\n}\n\nfunction hasEnvConfig(): boolean {\n return Object.keys(process.env).some((key) => key.startsWith(ENVIRONMENT_PREFIX))\n}\n\n/**\n * Parse a raw env-string into boolean, number or leave as string.\n */\nfunction parseEnvValue(value: string): any {\n // remove first and last quote if exists\n value = value.replace(/^\"(.*)\"$/, '$1')\n if (value === 'true') return true\n if (value === 'false') return false\n if (!isNaN(Number(value))) return Number(value)\n return value\n}\n\n/**\n * Assigns a nested property into obj, creating sub-objects as needed.\n */\nfunction setObjectPropertyFromString(obj: any, property: string, value: any): void {\n const segments = property.split('.')\n let cursor = obj\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (!(seg in cursor) || typeof cursor[seg] !== 'object') {\n cursor[seg] = {}\n }\n cursor = cursor[seg]\n }\n cursor[segments[segments.length - 1]] = value\n}\n\n/**\n * Returns a new object containing only the env-var overrides\n * that match existing keys in `config`, nested and cased properly.\n */\nfunction getEnvOverrides(config: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [envKey, rawValue] of Object.entries(process.env)) {\n if (!envKey.startsWith(ENVIRONMENT_PREFIX) || rawValue === undefined) {\n continue\n }\n\n // [\"APPLICATIONS\",\"FILES\",\"DATAPATH\"] etc.\n const segments = envKey.slice(ENVIRONMENT_PREFIX.length).split('_')\n const secretFromFile = segments[segments.length - 1] === 'FILE'\n if (secretFromFile) {\n // remove FILE attribute\n segments.pop()\n }\n\n // Walk through config to validate path & capture real key names\n let cursorConfig: any = config\n const realSegments: string[] = []\n let pathExists = true\n\n for (const seg of segments) {\n if (cursorConfig == null || typeof cursorConfig !== 'object') {\n pathExists = false\n break\n }\n // Find the actual key (preserving camelCase) whose uppercase matches seg\n const match = Object.keys(cursorConfig).find((k) => k.toUpperCase() === seg)\n if (!match) {\n pathExists = false\n break\n }\n realSegments.push(match)\n cursorConfig = cursorConfig[match]\n }\n\n if (!pathExists) {\n console.warn(`Ignoring unknown environment variable: \"${envKey}\".`)\n continue\n }\n\n // Build the nested override in `result`\n const path = realSegments.join('.')\n if (secretFromFile) {\n try {\n setObjectPropertyFromString(result, path, fs.readFileSync(rawValue, 'utf-8').trim())\n } catch (e) {\n console.error(`Unable to store secret from file ${rawValue} : ${e}`)\n }\n } else {\n setObjectPropertyFromString(result, path, parseEnvValue(rawValue))\n }\n }\n\n return result\n}\n"],"names":["configLoader","config","loadEnvFile","ENVIRONMENT_PATH","ENVIRONMENT_FILE_NAME","hasEnvConfig","envConfig","getEnvOverrides","ENVIRONMENT_DIST_PATH","ENVIRONMENT_DIST_FILE_NAME","deepmerge","Object","keys","length","Error","ENVIRONMENT_PREFIX","logger","stdout","logFilePath","filePath","DEFAULT_LOG_FILE_PATH","dirLogPath","path","dirname","fs","existsSync","mkdirSync","recursive","console","log","buildPathsUp","basePath","fileName","levels","Array","from","_","i","resolve","fill","envPath","envFileName","throwIfMissing","candidates","__dirname","envFilePath","lstatSync","isFile","yaml","load","readFileSync","process","env","some","key","startsWith","parseEnvValue","value","replace","isNaN","Number","setObjectPropertyFromString","obj","property","segments","split","cursor","seg","result","envKey","rawValue","entries","undefined","slice","secretFromFile","pop","cursorConfig","realSegments","pathExists","match","find","k","toUpperCase","push","warn","join","trim","e","error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../backend/src/configuration/config.loader.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport deepmerge from 'deepmerge'\nimport * as yaml from 'js-yaml'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport {\n DEFAULT_LOG_FILE_PATH,\n ENVIRONMENT_DIST_FILE_NAME,\n ENVIRONMENT_DIST_PATH,\n ENVIRONMENT_FILE_NAME,\n ENVIRONMENT_PATH,\n ENVIRONMENT_PREFIX\n} from './config.constants'\nimport type { Configuration } from './config.validation'\n\nexport function configLoader(): any {\n let config: Partial<Configuration> = loadEnvFile(ENVIRONMENT_PATH, ENVIRONMENT_FILE_NAME)\n\n if (hasEnvConfig()) {\n // If any environment vars are found, parse the config model and apply those settings\n const envConfig = getEnvOverrides(loadEnvFile(ENVIRONMENT_DIST_PATH, ENVIRONMENT_DIST_FILE_NAME, true))\n config = deepmerge(config, envConfig)\n }\n\n if (Object.keys(config).length === 0) {\n throw new Error(`Missing configuration: \"${ENVIRONMENT_FILE_NAME}\" not found, or no variables beginning with \"${ENVIRONMENT_PREFIX}\" are set.`)\n }\n\n if (config.logger?.stdout === false) {\n // ensure log directory exists\n const logFilePath = config.logger.filePath || DEFAULT_LOG_FILE_PATH\n const dirLogPath = path.dirname(logFilePath)\n if (!fs.existsSync(dirLogPath)) {\n fs.mkdirSync(dirLogPath, { recursive: true })\n }\n console.log(`Logging to file → ${logFilePath}`)\n }\n\n return config\n}\n\nfunction buildPathsUp(basePath: string, fileName: string, levels = 4): string[] {\n // Generates candidate file paths, optionally walking up from __dirname to a given depth.\n return Array.from({ length: levels + 1 }, (_, i) => path.resolve(basePath, ...Array(i).fill('..'), fileName))\n}\n\nfunction loadEnvFile(envPath: string, envFileName: string, throwIfMissing = false): any {\n const candidates = [envPath, envFileName, ...buildPathsUp(__dirname, envPath), ...buildPathsUp(__dirname, envFileName)]\n for (const envFilePath of candidates) {\n if (fs.existsSync(envFilePath) && fs.lstatSync(envFilePath).isFile()) {\n return yaml.load(fs.readFileSync(envFilePath, 'utf8'))\n }\n }\n if (throwIfMissing) {\n throw new Error(`${envFileName} not found`)\n }\n return {}\n}\n\nfunction hasEnvConfig(): boolean {\n return Object.keys(process.env).some((key) => key.startsWith(ENVIRONMENT_PREFIX))\n}\n\n/**\n * Parse a raw env-string into boolean, number or leave as string.\n */\nfunction parseEnvValue(value: string): any {\n // remove first and last quote if exists\n value = value.replace(/^\"(.*)\"$/, '$1')\n if (value === 'true') return true\n if (value === 'false') return false\n if (!isNaN(Number(value))) return Number(value)\n return value\n}\n\n/**\n * Assigns a nested property into obj, creating sub-objects as needed.\n */\nfunction setObjectPropertyFromString(obj: any, property: string, value: any): void {\n const segments = property.split('.')\n let cursor = obj\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (!(seg in cursor) || typeof cursor[seg] !== 'object') {\n cursor[seg] = {}\n }\n cursor = cursor[seg]\n }\n cursor[segments[segments.length - 1]] = value\n}\n\n/**\n * Returns a new object containing only the env-var overrides\n * that match existing keys in `config`, nested and cased properly.\n */\nfunction getEnvOverrides(config: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const [envKey, rawValue] of Object.entries(process.env)) {\n if (!envKey.startsWith(ENVIRONMENT_PREFIX) || rawValue === undefined) {\n continue\n }\n\n // [\"APPLICATIONS\",\"FILES\",\"DATAPATH\"] etc.\n const segments = envKey.slice(ENVIRONMENT_PREFIX.length).split('_')\n const secretFromFile = segments[segments.length - 1] === 'FILE'\n if (secretFromFile) {\n // remove FILE attribute\n segments.pop()\n }\n\n // Walk through config to validate path & capture real key names\n let cursorConfig: any = config\n const realSegments: string[] = []\n let pathExists = true\n\n for (const seg of segments) {\n if (cursorConfig == null || typeof cursorConfig !== 'object') {\n pathExists = false\n break\n }\n // Find the actual key (preserving camelCase) whose uppercase matches seg\n const match = Object.keys(cursorConfig).find((k) => k.toUpperCase() === seg)\n if (!match) {\n pathExists = false\n break\n }\n realSegments.push(match)\n cursorConfig = cursorConfig[match]\n }\n\n if (!pathExists) {\n console.warn(`Ignoring unknown environment variable: \"${envKey}\".`)\n continue\n }\n\n // Build the nested override in `result`\n const path = realSegments.join('.')\n if (secretFromFile) {\n try {\n setObjectPropertyFromString(result, path, fs.readFileSync(rawValue, 'utf-8').trim())\n } catch (e) {\n console.error(`Unable to store secret from file ${rawValue} : ${e}`)\n }\n } else {\n setObjectPropertyFromString(result, path, parseEnvValue(rawValue))\n }\n }\n\n return result\n}\n"],"names":["configLoader","config","loadEnvFile","ENVIRONMENT_PATH","ENVIRONMENT_FILE_NAME","hasEnvConfig","envConfig","getEnvOverrides","ENVIRONMENT_DIST_PATH","ENVIRONMENT_DIST_FILE_NAME","deepmerge","Object","keys","length","Error","ENVIRONMENT_PREFIX","logger","stdout","logFilePath","filePath","DEFAULT_LOG_FILE_PATH","dirLogPath","path","dirname","fs","existsSync","mkdirSync","recursive","console","log","buildPathsUp","basePath","fileName","levels","Array","from","_","i","resolve","fill","envPath","envFileName","throwIfMissing","candidates","__dirname","envFilePath","lstatSync","isFile","yaml","load","readFileSync","process","env","some","key","startsWith","parseEnvValue","value","replace","isNaN","Number","setObjectPropertyFromString","obj","property","segments","split","cursor","seg","result","envKey","rawValue","entries","undefined","slice","secretFromFile","pop","cursorConfig","realSegments","pathExists","match","find","k","toUpperCase","push","warn","join","trim","e","error"],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ const _testing = require("@nestjs/testing");
10
+ const _rxjs = require("rxjs");
11
+ const _contextinterceptor = require("./context.interceptor");
12
+ const _contextmanagerservice = require("../services/context-manager.service");
13
+ // Helper to create a minimal ExecutionContext with Fastify-like request
14
+ function createHttpExecutionContext(request) {
15
+ return {
16
+ switchToHttp: ()=>({
17
+ getRequest: ()=>request,
18
+ getResponse: ()=>({}),
19
+ getNext: ()=>({})
20
+ }),
21
+ getType: ()=>'http',
22
+ getClass: ()=>({}),
23
+ getHandler: ()=>({}),
24
+ switchToRpc: ()=>({}),
25
+ switchToWs: ()=>({}),
26
+ getArgByIndex: ()=>({}),
27
+ getArgs: ()=>[]
28
+ };
29
+ }
30
+ describe('ContextInterceptor', ()=>{
31
+ let interceptor;
32
+ let contextManager;
33
+ beforeEach(async ()=>{
34
+ contextManager = {
35
+ // By default, run will execute the provided callback and return its result
36
+ run: jest.fn((_ctx, cb)=>cb())
37
+ };
38
+ const module = await _testing.Test.createTestingModule({
39
+ providers: [
40
+ _contextinterceptor.ContextInterceptor,
41
+ {
42
+ provide: _contextmanagerservice.ContextManager,
43
+ useValue: contextManager
44
+ }
45
+ ]
46
+ }).compile();
47
+ interceptor = module.get(_contextinterceptor.ContextInterceptor);
48
+ });
49
+ it('should pass headerOriginUrl from Origin header to ContextManager.run and forward next.handle()', (done)=>{
50
+ const origin = 'https://example.com';
51
+ const request = {
52
+ headers: {
53
+ origin,
54
+ host: 'ignored-host'
55
+ },
56
+ protocol: 'http'
57
+ };
58
+ const context = createHttpExecutionContext(request);
59
+ const next = {
60
+ handle: jest.fn(()=>(0, _rxjs.of)('ok'))
61
+ };
62
+ const result$ = interceptor.intercept(context, next);
63
+ expect(contextManager.run).toHaveBeenCalledTimes(1);
64
+ const [ctxArg, cbArg] = contextManager.run.mock.calls[0];
65
+ expect(ctxArg).toEqual({
66
+ headerOriginUrl: origin
67
+ });
68
+ expect(typeof cbArg).toBe('function');
69
+ // next.handle is invoked synchronously by ContextManager.run; assert in subscription to keep flow consistent
70
+ result$.subscribe({
71
+ next: (val)=>{
72
+ expect(next.handle).toHaveBeenCalledTimes(1);
73
+ expect(val).toBe('ok');
74
+ done();
75
+ },
76
+ error: done
77
+ });
78
+ });
79
+ it('should build headerOriginUrl from protocol and host when Origin header is missing', (done)=>{
80
+ const request = {
81
+ headers: {
82
+ host: 'my-host.local:3000'
83
+ },
84
+ protocol: 'http'
85
+ };
86
+ const context = createHttpExecutionContext(request);
87
+ const next = {
88
+ handle: jest.fn(()=>(0, _rxjs.of)({
89
+ status: 'passed'
90
+ }))
91
+ };
92
+ const result$ = interceptor.intercept(context, next);
93
+ expect(contextManager.run).toHaveBeenCalledTimes(1);
94
+ const [ctxArg, cbArg] = contextManager.run.mock.calls[0];
95
+ expect(ctxArg).toEqual({
96
+ headerOriginUrl: 'http://my-host.local:3000'
97
+ });
98
+ expect(typeof cbArg).toBe('function');
99
+ result$.subscribe({
100
+ next: (val)=>{
101
+ expect(next.handle).toHaveBeenCalledTimes(1);
102
+ expect(val).toEqual({
103
+ status: 'passed'
104
+ });
105
+ done();
106
+ },
107
+ error: done
108
+ });
109
+ });
110
+ it('should return the observable produced by next.handle() within ContextManager.run callback', (done)=>{
111
+ // Ensure run executes the callback and returns its result
112
+ contextManager.run.mockImplementation((_ctx, cb)=>cb());
113
+ const request = {
114
+ headers: {
115
+ origin: 'https://origin.test'
116
+ },
117
+ protocol: 'https'
118
+ };
119
+ const context = createHttpExecutionContext(request);
120
+ const next = {
121
+ handle: jest.fn(()=>(0, _rxjs.of)(123))
122
+ };
123
+ const result$ = interceptor.intercept(context, next);
124
+ result$.subscribe({
125
+ next: (val)=>{
126
+ expect(val).toBe(123);
127
+ expect(next.handle).toHaveBeenCalledTimes(1);
128
+ done();
129
+ },
130
+ error: done
131
+ });
132
+ });
133
+ });
134
+
135
+ //# sourceMappingURL=context.interceptor.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/infrastructure/context/interceptors/context.interceptor.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { CallHandler, ExecutionContext } from '@nestjs/common'\nimport { of } from 'rxjs'\nimport { ContextInterceptor } from './context.interceptor'\nimport { ContextManager } from '../services/context-manager.service'\n\n// Helper to create a minimal ExecutionContext with Fastify-like request\nfunction createHttpExecutionContext(request: any): ExecutionContext {\n return {\n switchToHttp: () => ({\n getRequest: () => request,\n getResponse: () => ({}) as any,\n getNext: () => ({}) as any\n }),\n getType: () => 'http' as any,\n getClass: () => ({}) as any,\n getHandler: () => ({}) as any,\n switchToRpc: () => ({}) as any,\n switchToWs: () => ({}) as any,\n getArgByIndex: () => ({}) as any,\n getArgs: () => [] as any\n } as ExecutionContext\n}\n\ndescribe('ContextInterceptor', () => {\n let interceptor: ContextInterceptor\n let contextManager: { run: jest.Mock }\n\n beforeEach(async () => {\n contextManager = {\n // By default, run will execute the provided callback and return its result\n run: jest.fn((_ctx: any, cb: () => any) => cb())\n }\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n ContextInterceptor,\n {\n provide: ContextManager,\n useValue: contextManager\n }\n ]\n }).compile()\n\n interceptor = module.get(ContextInterceptor)\n })\n\n it('should pass headerOriginUrl from Origin header to ContextManager.run and forward next.handle()', (done) => {\n const origin = 'https://example.com'\n const request = {\n headers: { origin, host: 'ignored-host' },\n protocol: 'http'\n }\n\n const context = createHttpExecutionContext(request)\n const next: CallHandler = { handle: jest.fn(() => of('ok')) }\n\n const result$ = interceptor.intercept(context, next)\n\n expect(contextManager.run).toHaveBeenCalledTimes(1)\n const [ctxArg, cbArg] = contextManager.run.mock.calls[0]\n expect(ctxArg).toEqual({ headerOriginUrl: origin })\n expect(typeof cbArg).toBe('function')\n // next.handle is invoked synchronously by ContextManager.run; assert in subscription to keep flow consistent\n result$.subscribe({\n next: (val) => {\n expect(next.handle).toHaveBeenCalledTimes(1)\n expect(val).toBe('ok')\n done()\n },\n error: done\n })\n })\n\n it('should build headerOriginUrl from protocol and host when Origin header is missing', (done) => {\n const request = {\n headers: { host: 'my-host.local:3000' },\n protocol: 'http'\n }\n\n const context = createHttpExecutionContext(request)\n const next: CallHandler = { handle: jest.fn(() => of({ status: 'passed' })) }\n\n const result$ = interceptor.intercept(context, next)\n\n expect(contextManager.run).toHaveBeenCalledTimes(1)\n const [ctxArg, cbArg] = contextManager.run.mock.calls[0]\n expect(ctxArg).toEqual({ headerOriginUrl: 'http://my-host.local:3000' })\n expect(typeof cbArg).toBe('function')\n\n result$.subscribe({\n next: (val) => {\n expect(next.handle).toHaveBeenCalledTimes(1)\n expect(val).toEqual({ status: 'passed' })\n done()\n },\n error: done\n })\n })\n\n it('should return the observable produced by next.handle() within ContextManager.run callback', (done) => {\n // Ensure run executes the callback and returns its result\n contextManager.run.mockImplementation((_ctx: any, cb: () => any) => cb())\n\n const request = {\n headers: { origin: 'https://origin.test' },\n protocol: 'https'\n }\n\n const context = createHttpExecutionContext(request)\n const next: CallHandler = { handle: jest.fn(() => of(123)) }\n\n const result$ = interceptor.intercept(context, next)\n\n result$.subscribe({\n next: (val) => {\n expect(val).toBe(123)\n expect(next.handle).toHaveBeenCalledTimes(1)\n done()\n },\n error: done\n })\n })\n})\n"],"names":["createHttpExecutionContext","request","switchToHttp","getRequest","getResponse","getNext","getType","getClass","getHandler","switchToRpc","switchToWs","getArgByIndex","getArgs","describe","interceptor","contextManager","beforeEach","run","jest","fn","_ctx","cb","module","Test","createTestingModule","providers","ContextInterceptor","provide","ContextManager","useValue","compile","get","it","done","origin","headers","host","protocol","context","next","handle","of","result$","intercept","expect","toHaveBeenCalledTimes","ctxArg","cbArg","mock","calls","toEqual","headerOriginUrl","toBe","subscribe","val","error","status","mockImplementation"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;sBAEjB;oCACgB;uCACJ;AAE/B,wEAAwE;AACxE,SAASA,2BAA2BC,OAAY;IAC9C,OAAO;QACLC,cAAc,IAAO,CAAA;gBACnBC,YAAY,IAAMF;gBAClBG,aAAa,IAAO,CAAA,CAAC,CAAA;gBACrBC,SAAS,IAAO,CAAA,CAAC,CAAA;YACnB,CAAA;QACAC,SAAS,IAAM;QACfC,UAAU,IAAO,CAAA,CAAC,CAAA;QAClBC,YAAY,IAAO,CAAA,CAAC,CAAA;QACpBC,aAAa,IAAO,CAAA,CAAC,CAAA;QACrBC,YAAY,IAAO,CAAA,CAAC,CAAA;QACpBC,eAAe,IAAO,CAAA,CAAC,CAAA;QACvBC,SAAS,IAAM,EAAE;IACnB;AACF;AAEAC,SAAS,sBAAsB;IAC7B,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACTD,iBAAiB;YACf,2EAA2E;YAC3EE,KAAKC,KAAKC,EAAE,CAAC,CAACC,MAAWC,KAAkBA;QAC7C;QAEA,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTC,sCAAkB;gBAClB;oBACEC,SAASC,qCAAc;oBACvBC,UAAUd;gBACZ;aACD;QACH,GAAGe,OAAO;QAEVhB,cAAcQ,OAAOS,GAAG,CAACL,sCAAkB;IAC7C;IAEAM,GAAG,kGAAkG,CAACC;QACpG,MAAMC,SAAS;QACf,MAAMjC,UAAU;YACdkC,SAAS;gBAAED;gBAAQE,MAAM;YAAe;YACxCC,UAAU;QACZ;QAEA,MAAMC,UAAUtC,2BAA2BC;QAC3C,MAAMsC,OAAoB;YAAEC,QAAQtB,KAAKC,EAAE,CAAC,IAAMsB,IAAAA,QAAE,EAAC;QAAO;QAE5D,MAAMC,UAAU5B,YAAY6B,SAAS,CAACL,SAASC;QAE/CK,OAAO7B,eAAeE,GAAG,EAAE4B,qBAAqB,CAAC;QACjD,MAAM,CAACC,QAAQC,MAAM,GAAGhC,eAAeE,GAAG,CAAC+B,IAAI,CAACC,KAAK,CAAC,EAAE;QACxDL,OAAOE,QAAQI,OAAO,CAAC;YAAEC,iBAAiBjB;QAAO;QACjDU,OAAO,OAAOG,OAAOK,IAAI,CAAC;QAC1B,6GAA6G;QAC7GV,QAAQW,SAAS,CAAC;YAChBd,MAAM,CAACe;gBACLV,OAAOL,KAAKC,MAAM,EAAEK,qBAAqB,CAAC;gBAC1CD,OAAOU,KAAKF,IAAI,CAAC;gBACjBnB;YACF;YACAsB,OAAOtB;QACT;IACF;IAEAD,GAAG,qFAAqF,CAACC;QACvF,MAAMhC,UAAU;YACdkC,SAAS;gBAAEC,MAAM;YAAqB;YACtCC,UAAU;QACZ;QAEA,MAAMC,UAAUtC,2BAA2BC;QAC3C,MAAMsC,OAAoB;YAAEC,QAAQtB,KAAKC,EAAE,CAAC,IAAMsB,IAAAA,QAAE,EAAC;oBAAEe,QAAQ;gBAAS;QAAI;QAE5E,MAAMd,UAAU5B,YAAY6B,SAAS,CAACL,SAASC;QAE/CK,OAAO7B,eAAeE,GAAG,EAAE4B,qBAAqB,CAAC;QACjD,MAAM,CAACC,QAAQC,MAAM,GAAGhC,eAAeE,GAAG,CAAC+B,IAAI,CAACC,KAAK,CAAC,EAAE;QACxDL,OAAOE,QAAQI,OAAO,CAAC;YAAEC,iBAAiB;QAA4B;QACtEP,OAAO,OAAOG,OAAOK,IAAI,CAAC;QAE1BV,QAAQW,SAAS,CAAC;YAChBd,MAAM,CAACe;gBACLV,OAAOL,KAAKC,MAAM,EAAEK,qBAAqB,CAAC;gBAC1CD,OAAOU,KAAKJ,OAAO,CAAC;oBAAEM,QAAQ;gBAAS;gBACvCvB;YACF;YACAsB,OAAOtB;QACT;IACF;IAEAD,GAAG,6FAA6F,CAACC;QAC/F,0DAA0D;QAC1DlB,eAAeE,GAAG,CAACwC,kBAAkB,CAAC,CAACrC,MAAWC,KAAkBA;QAEpE,MAAMpB,UAAU;YACdkC,SAAS;gBAAED,QAAQ;YAAsB;YACzCG,UAAU;QACZ;QAEA,MAAMC,UAAUtC,2BAA2BC;QAC3C,MAAMsC,OAAoB;YAAEC,QAAQtB,KAAKC,EAAE,CAAC,IAAMsB,IAAAA,QAAE,EAAC;QAAM;QAE3D,MAAMC,UAAU5B,YAAY6B,SAAS,CAACL,SAASC;QAE/CG,QAAQW,SAAS,CAAC;YAChBd,MAAM,CAACe;gBACLV,OAAOU,KAAKF,IAAI,CAAC;gBACjBR,OAAOL,KAAKC,MAAM,EAAEK,qBAAqB,CAAC;gBAC1CZ;YACF;YACAsB,OAAOtB;QACT;IACF;AACF"}
@@ -0,0 +1,98 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ const _testing = require("@nestjs/testing");
10
+ const _contextmanagerservice = require("./context-manager.service");
11
+ describe(_contextmanagerservice.ContextManager.name, ()=>{
12
+ let contextManager;
13
+ beforeAll(async ()=>{
14
+ const module = await _testing.Test.createTestingModule({
15
+ providers: [
16
+ _contextmanagerservice.ContextManager
17
+ ]
18
+ }).compile();
19
+ contextManager = module.get(_contextmanagerservice.ContextManager);
20
+ });
21
+ it('should be defined', ()=>{
22
+ expect(contextManager).toBeDefined();
23
+ });
24
+ // Test helpers to reduce repetition and keep strong typing in one place
25
+ const getKey = (key)=>contextManager.get(key);
26
+ const runWithContext = (ctx, fn)=>contextManager.run(ctx, fn);
27
+ describe('Context access', ()=>{
28
+ it('get() should return undefined when no context is active', ()=>{
29
+ // Using a fake key ensures we don’t rely on a specific ContextStore shape
30
+ expect(getKey('')).toBeUndefined();
31
+ });
32
+ it('run() should expose context within the callback and surface return value', ()=>{
33
+ const ctx = {
34
+ userId: 'u1',
35
+ requestId: 'r1'
36
+ };
37
+ const value = runWithContext(ctx, ()=>{
38
+ expect(getKey('userId')).toBe('u1');
39
+ expect(getKey('requestId')).toBe('r1');
40
+ return 123;
41
+ });
42
+ expect(value).toBe(123);
43
+ });
44
+ });
45
+ describe('Context lifecycle', ()=>{
46
+ it('should restore to no context after run() completes', ()=>{
47
+ const ctx = {
48
+ userId: 'u2'
49
+ };
50
+ runWithContext(ctx, ()=>{
51
+ expect(getKey('userId')).toBe('u2');
52
+ });
53
+ expect(getKey('userId')).toBeUndefined();
54
+ });
55
+ it('should support nested contexts and restore the previous one after inner run()', ()=>{
56
+ const outer = {
57
+ userId: 'outer'
58
+ };
59
+ const inner = {
60
+ userId: 'inner'
61
+ };
62
+ runWithContext(outer, ()=>{
63
+ expect(getKey('userId')).toBe('outer');
64
+ runWithContext(inner, ()=>{
65
+ expect(getKey('userId')).toBe('inner');
66
+ });
67
+ // After inner completes, outer should be visible again
68
+ expect(getKey('userId')).toBe('outer');
69
+ });
70
+ // After outer completing, no context should be active
71
+ expect(getKey('userId')).toBeUndefined();
72
+ });
73
+ });
74
+ describe('Async propagation', ()=>{
75
+ it('should propagate context across microtasks (Promise)', async ()=>{
76
+ const ctx = {
77
+ userId: 'async-user'
78
+ };
79
+ await runWithContext(ctx, async ()=>{
80
+ await Promise.resolve();
81
+ expect(getKey('userId')).toBe('async-user');
82
+ });
83
+ });
84
+ it('should propagate context across timers (setTimeout)', async ()=>{
85
+ const ctx = {
86
+ requestId: 'req-timer'
87
+ };
88
+ await runWithContext(ctx, async ()=>{
89
+ await new Promise((resolve)=>setTimeout(()=>{
90
+ expect(getKey('requestId')).toBe('req-timer');
91
+ resolve();
92
+ }, 0));
93
+ });
94
+ });
95
+ });
96
+ });
97
+
98
+ //# sourceMappingURL=context-manager.service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/infrastructure/context/services/context-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { ContextManager } from './context-manager.service'\nimport type { ContextStore } from '../interfaces/context-store.interface'\n\ndescribe(ContextManager.name, () => {\n let contextManager: ContextManager\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [ContextManager]\n }).compile()\n\n contextManager = module.get<ContextManager>(ContextManager)\n })\n\n it('should be defined', () => {\n expect(contextManager).toBeDefined()\n })\n\n // Test helpers to reduce repetition and keep strong typing in one place\n const getKey = <K extends keyof ContextStore>(key: K): ContextStore[K] => contextManager.get(key) as ContextStore[K]\n\n const runWithContext = <T>(ctx: Partial<ContextStore>, fn: () => T): T => contextManager.run(ctx as ContextStore, fn) as unknown as T\n\n describe('Context access', () => {\n it('get() should return undefined when no context is active', () => {\n // Using a fake key ensures we don’t rely on a specific ContextStore shape\n expect(getKey('' as keyof ContextStore)).toBeUndefined()\n })\n\n it('run() should expose context within the callback and surface return value', () => {\n const ctx = { userId: 'u1', requestId: 'r1' } as Partial<ContextStore>\n\n const value = runWithContext<number>(ctx, () => {\n expect(getKey('userId' as keyof ContextStore)).toBe('u1')\n expect(getKey('requestId' as keyof ContextStore)).toBe('r1')\n return 123\n })\n\n expect(value).toBe(123)\n })\n })\n\n describe('Context lifecycle', () => {\n it('should restore to no context after run() completes', () => {\n const ctx = { userId: 'u2' } as Partial<ContextStore>\n\n runWithContext<void>(ctx, () => {\n expect(getKey('userId' as keyof ContextStore)).toBe('u2')\n })\n\n expect(getKey('userId' as keyof ContextStore)).toBeUndefined()\n })\n\n it('should support nested contexts and restore the previous one after inner run()', () => {\n const outer = { userId: 'outer' } as Partial<ContextStore>\n const inner = { userId: 'inner' } as Partial<ContextStore>\n\n runWithContext<void>(outer, () => {\n expect(getKey('userId' as keyof ContextStore)).toBe('outer')\n\n runWithContext<void>(inner, () => {\n expect(getKey('userId' as keyof ContextStore)).toBe('inner')\n })\n\n // After inner completes, outer should be visible again\n expect(getKey('userId' as keyof ContextStore)).toBe('outer')\n })\n\n // After outer completing, no context should be active\n expect(getKey('userId' as keyof ContextStore)).toBeUndefined()\n })\n })\n\n describe('Async propagation', () => {\n it('should propagate context across microtasks (Promise)', async () => {\n const ctx = { userId: 'async-user' } as Partial<ContextStore>\n\n await runWithContext<Promise<void>>(ctx, async () => {\n await Promise.resolve()\n expect(getKey('userId' as keyof ContextStore)).toBe('async-user')\n })\n })\n\n it('should propagate context across timers (setTimeout)', async () => {\n const ctx = { requestId: 'req-timer' } as Partial<ContextStore>\n\n await runWithContext<Promise<void>>(ctx, async () => {\n await new Promise<void>((resolve) =>\n setTimeout(() => {\n expect(getKey('requestId' as keyof ContextStore)).toBe('req-timer')\n resolve()\n }, 0)\n )\n })\n })\n })\n})\n"],"names":["describe","ContextManager","name","contextManager","beforeAll","module","Test","createTestingModule","providers","compile","get","it","expect","toBeDefined","getKey","key","runWithContext","ctx","fn","run","toBeUndefined","userId","requestId","value","toBe","outer","inner","Promise","resolve","setTimeout"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;uCACL;AAG/BA,SAASC,qCAAc,CAACC,IAAI,EAAE;IAC5B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBAACP,qCAAc;aAAC;QAC7B,GAAGQ,OAAO;QAEVN,iBAAiBE,OAAOK,GAAG,CAAiBT,qCAAc;IAC5D;IAEAU,GAAG,qBAAqB;QACtBC,OAAOT,gBAAgBU,WAAW;IACpC;IAEA,wEAAwE;IACxE,MAAMC,SAAS,CAA+BC,MAA4BZ,eAAeO,GAAG,CAACK;IAE7F,MAAMC,iBAAiB,CAAIC,KAA4BC,KAAmBf,eAAegB,GAAG,CAACF,KAAqBC;IAElHlB,SAAS,kBAAkB;QACzBW,GAAG,2DAA2D;YAC5D,0EAA0E;YAC1EC,OAAOE,OAAO,KAA2BM,aAAa;QACxD;QAEAT,GAAG,4EAA4E;YAC7E,MAAMM,MAAM;gBAAEI,QAAQ;gBAAMC,WAAW;YAAK;YAE5C,MAAMC,QAAQP,eAAuBC,KAAK;gBACxCL,OAAOE,OAAO,WAAiCU,IAAI,CAAC;gBACpDZ,OAAOE,OAAO,cAAoCU,IAAI,CAAC;gBACvD,OAAO;YACT;YAEAZ,OAAOW,OAAOC,IAAI,CAAC;QACrB;IACF;IAEAxB,SAAS,qBAAqB;QAC5BW,GAAG,sDAAsD;YACvD,MAAMM,MAAM;gBAAEI,QAAQ;YAAK;YAE3BL,eAAqBC,KAAK;gBACxBL,OAAOE,OAAO,WAAiCU,IAAI,CAAC;YACtD;YAEAZ,OAAOE,OAAO,WAAiCM,aAAa;QAC9D;QAEAT,GAAG,iFAAiF;YAClF,MAAMc,QAAQ;gBAAEJ,QAAQ;YAAQ;YAChC,MAAMK,QAAQ;gBAAEL,QAAQ;YAAQ;YAEhCL,eAAqBS,OAAO;gBAC1Bb,OAAOE,OAAO,WAAiCU,IAAI,CAAC;gBAEpDR,eAAqBU,OAAO;oBAC1Bd,OAAOE,OAAO,WAAiCU,IAAI,CAAC;gBACtD;gBAEA,uDAAuD;gBACvDZ,OAAOE,OAAO,WAAiCU,IAAI,CAAC;YACtD;YAEA,sDAAsD;YACtDZ,OAAOE,OAAO,WAAiCM,aAAa;QAC9D;IACF;IAEApB,SAAS,qBAAqB;QAC5BW,GAAG,wDAAwD;YACzD,MAAMM,MAAM;gBAAEI,QAAQ;YAAa;YAEnC,MAAML,eAA8BC,KAAK;gBACvC,MAAMU,QAAQC,OAAO;gBACrBhB,OAAOE,OAAO,WAAiCU,IAAI,CAAC;YACtD;QACF;QAEAb,GAAG,uDAAuD;YACxD,MAAMM,MAAM;gBAAEK,WAAW;YAAY;YAErC,MAAMN,eAA8BC,KAAK;gBACvC,MAAM,IAAIU,QAAc,CAACC,UACvBC,WAAW;wBACTjB,OAAOE,OAAO,cAAoCU,IAAI,CAAC;wBACvDI;oBACF,GAAG;YAEP;QACF;IACF;AACF"}
@@ -45,7 +45,6 @@ function getSchemaPath() {
45
45
  for (const ext of extensions){
46
46
  const filePath = _nodepath.default.join(__dirname, `schema.${ext}`);
47
47
  if (_nodefs.default.existsSync(filePath)) {
48
- console.log('USE SCHEMA PATH', filePath);
49
48
  return filePath;
50
49
  }
51
50
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/infrastructure/database/constants.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport path from 'node:path'\nimport fs from 'node:fs'\n\nexport const DB_CHARSET = 'utf8mb4'\nexport const DB_TOKEN_PROVIDER = 'DB'\nexport const MIGRATIONS_PATH = path.relative(process.cwd(), path.join(__dirname, '../../../migrations'))\n\nexport function getSchemaPath(): string {\n // Look for schema.ts (dev) or schema.js (production), throw if none is found\n const extensions = ['js', 'ts']\n\n for (const ext of extensions) {\n const filePath = path.join(__dirname, `schema.${ext}`)\n if (fs.existsSync(filePath)) {\n console.log('USE SCHEMA PATH', filePath)\n return filePath\n }\n }\n\n throw new Error('No schema.ts or schema.js file found !')\n}\n"],"names":["DB_CHARSET","DB_TOKEN_PROVIDER","MIGRATIONS_PATH","getSchemaPath","path","relative","process","cwd","join","__dirname","extensions","ext","filePath","fs","existsSync","console","log","Error"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAKYA;eAAAA;;QACAC;eAAAA;;QACAC;eAAAA;;QAEGC;eAAAA;;;iEAPC;+DACF;;;;;;AAER,MAAMH,aAAa;AACnB,MAAMC,oBAAoB;AAC1B,MAAMC,kBAAkBE,iBAAI,CAACC,QAAQ,CAACC,QAAQC,GAAG,IAAIH,iBAAI,CAACI,IAAI,CAACC,WAAW;AAE1E,SAASN;IACd,6EAA6E;IAC7E,MAAMO,aAAa;QAAC;QAAM;KAAK;IAE/B,KAAK,MAAMC,OAAOD,WAAY;QAC5B,MAAME,WAAWR,iBAAI,CAACI,IAAI,CAACC,WAAW,CAAC,OAAO,EAAEE,KAAK;QACrD,IAAIE,eAAE,CAACC,UAAU,CAACF,WAAW;YAC3BG,QAAQC,GAAG,CAAC,mBAAmBJ;YAC/B,OAAOA;QACT;IACF;IAEA,MAAM,IAAIK,MAAM;AAClB"}
1
+ {"version":3,"sources":["../../../../backend/src/infrastructure/database/constants.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport path from 'node:path'\nimport fs from 'node:fs'\n\nexport const DB_CHARSET = 'utf8mb4'\nexport const DB_TOKEN_PROVIDER = 'DB'\nexport const MIGRATIONS_PATH = path.relative(process.cwd(), path.join(__dirname, '../../../migrations'))\n\nexport function getSchemaPath(): string {\n // Look for schema.ts (dev) or schema.js (production), throw if none is found\n const extensions = ['js', 'ts']\n\n for (const ext of extensions) {\n const filePath = path.join(__dirname, `schema.${ext}`)\n if (fs.existsSync(filePath)) {\n return filePath\n }\n }\n\n throw new Error('No schema.ts or schema.js file found !')\n}\n"],"names":["DB_CHARSET","DB_TOKEN_PROVIDER","MIGRATIONS_PATH","getSchemaPath","path","relative","process","cwd","join","__dirname","extensions","ext","filePath","fs","existsSync","Error"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAKYA;eAAAA;;QACAC;eAAAA;;QACAC;eAAAA;;QAEGC;eAAAA;;;iEAPC;+DACF;;;;;;AAER,MAAMH,aAAa;AACnB,MAAMC,oBAAoB;AAC1B,MAAMC,kBAAkBE,iBAAI,CAACC,QAAQ,CAACC,QAAQC,GAAG,IAAIH,iBAAI,CAACI,IAAI,CAACC,WAAW;AAE1E,SAASN;IACd,6EAA6E;IAC7E,MAAMO,aAAa;QAAC;QAAM;KAAK;IAE/B,KAAK,MAAMC,OAAOD,WAAY;QAC5B,MAAME,WAAWR,iBAAI,CAACI,IAAI,CAACC,WAAW,CAAC,OAAO,EAAEE,KAAK;QACrD,IAAIE,eAAE,CAACC,UAAU,CAACF,WAAW;YAC3B,OAAOA;QACT;IACF;IAEA,MAAM,IAAIG,MAAM;AAClB"}
@@ -37,10 +37,10 @@ const usersAndGroups = async ()=>{
37
37
  ];
38
38
  const newGroups = [];
39
39
  for(let i = 0; i < 10; i++){
40
- let login = _faker.faker.internet.userName();
40
+ let login = _faker.faker.person.firstName();
41
41
  let email = _faker.faker.internet.email();
42
42
  while(alreadyUsed.includes(login) || alreadyUsed.includes(email)){
43
- login = _faker.faker.internet.userName();
43
+ login = _faker.faker.person.firstName();
44
44
  email = _faker.faker.internet.email();
45
45
  }
46
46
  alreadyUsed.push(login, email);
@@ -83,7 +83,7 @@ const usersAndGroups = async ()=>{
83
83
  }));
84
84
  const usersGroupsInfo = (await db.insert(_usersgroupsschema.usersGroups).values(newUsersGroups))[0];
85
85
  console.log('users & groups: ', usersGroupsInfo.info);
86
- await db.$client.end();
86
+ db.$client.end();
87
87
  };
88
88
  if (require.main === module) {
89
89
  usersAndGroups().then(()=>console.log('Seed done'));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../backend/src/infrastructure/database/scripts/seed/usersgroups.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { faker } from '@faker-js/faker'\nimport { ResultSetHeader } from 'mysql2/promise'\nimport { USER_PERMISSION, USER_ROLE } from '../../../../applications/users/constants/user'\nimport { Group } from '../../../../applications/users/schemas/group.interface'\nimport { groups } from '../../../../applications/users/schemas/groups.schema'\nimport { User } from '../../../../applications/users/schemas/user.interface'\nimport { usersGroups } from '../../../../applications/users/schemas/users-groups.schema'\nimport { users } from '../../../../applications/users/schemas/users.schema'\nimport { hashPassword } from '../../../../common/functions'\nimport { getDB } from '../db'\n\nconst alreadyUsed = ['sync-in', 'support@sync-in.com']\n\nexport const usersAndGroups = async () => {\n const newUsers: Partial<User>[] = [\n {\n login: 'sync-in',\n email: 'support@sync-in.com',\n firstName: 'Sync-in',\n lastName: 'Admin',\n role: USER_ROLE.ADMINISTRATOR,\n password: await hashPassword('password'),\n permissions: Object.values(USER_PERMISSION).join(',')\n }\n ]\n const newGroups: Partial<Group>[] = []\n\n for (let i = 0; i < 10; i++) {\n let login = faker.internet.userName()\n let email = faker.internet.email()\n while (alreadyUsed.includes(login) || alreadyUsed.includes(email)) {\n login = faker.internet.userName()\n email = faker.internet.email()\n }\n alreadyUsed.push(login, email)\n newUsers.push({\n login: login,\n email: email,\n firstName: faker.person.firstName(),\n lastName: faker.person.lastName(),\n password: await hashPassword('password'),\n permissions: faker.helpers.arrayElements(Object.values(USER_PERMISSION)).join(',')\n })\n }\n\n for (let i = 0; i < 5; i++) {\n let name = faker.commerce.department()\n while (alreadyUsed.includes(name)) {\n name = faker.commerce.department()\n }\n alreadyUsed.push(name)\n newGroups.push({\n name: name,\n description: faker.company.buzzPhrase(),\n type: 0\n })\n }\n\n const db = await getDB()\n\n console.log('Seed start')\n const usersInfo: ResultSetHeader = (await db.insert(users).values(newUsers as any))[0]\n console.log('users: ', usersInfo.info)\n const groupsInfo: ResultSetHeader = (await db.insert(groups).values(newGroups as any))[0]\n console.log('groups: ', groupsInfo.info)\n\n const usersId = (await db.select({ id: users.id }).from(users)).map((r) => r.id)\n const groupsId = (await db.select({ id: groups.id }).from(groups)).map((r) => r.id)\n const newUsersGroups = usersId.map((uid) => ({ userId: uid, groupId: groupsId[Math.floor(Math.random() * groupsId.length)] }))\n const usersGroupsInfo: ResultSetHeader = (await db.insert(usersGroups).values(newUsersGroups))[0]\n console.log('users & groups: ', usersGroupsInfo.info)\n\n await db.$client.end()\n}\n\nif (require.main === module) {\n usersAndGroups().then(() => console.log('Seed done'))\n}\n"],"names":["usersAndGroups","alreadyUsed","newUsers","login","email","firstName","lastName","role","USER_ROLE","ADMINISTRATOR","password","hashPassword","permissions","Object","values","USER_PERMISSION","join","newGroups","i","faker","internet","userName","includes","push","person","helpers","arrayElements","name","commerce","department","description","company","buzzPhrase","type","db","getDB","console","log","usersInfo","insert","users","info","groupsInfo","groups","usersId","select","id","from","map","r","groupsId","newUsersGroups","uid","userId","groupId","Math","floor","random","length","usersGroupsInfo","usersGroups","$client","end","require","main","module","then"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../backend/src/infrastructure/database/scripts/seed/usersgroups.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { faker } from '@faker-js/faker'\nimport { ResultSetHeader } from 'mysql2/promise'\nimport { USER_PERMISSION, USER_ROLE } from '../../../../applications/users/constants/user'\nimport { Group } from '../../../../applications/users/schemas/group.interface'\nimport { groups } from '../../../../applications/users/schemas/groups.schema'\nimport { User } from '../../../../applications/users/schemas/user.interface'\nimport { usersGroups } from '../../../../applications/users/schemas/users-groups.schema'\nimport { users } from '../../../../applications/users/schemas/users.schema'\nimport { hashPassword } from '../../../../common/functions'\nimport { getDB } from '../db'\n\nconst alreadyUsed = ['sync-in', 'support@sync-in.com']\n\nexport const usersAndGroups = async () => {\n const newUsers: Partial<User>[] = [\n {\n login: 'sync-in',\n email: 'support@sync-in.com',\n firstName: 'Sync-in',\n lastName: 'Admin',\n role: USER_ROLE.ADMINISTRATOR,\n password: await hashPassword('password'),\n permissions: Object.values(USER_PERMISSION).join(',')\n }\n ]\n const newGroups: Partial<Group>[] = []\n\n for (let i = 0; i < 10; i++) {\n let login = faker.person.firstName()\n let email = faker.internet.email()\n while (alreadyUsed.includes(login) || alreadyUsed.includes(email)) {\n login = faker.person.firstName()\n email = faker.internet.email()\n }\n alreadyUsed.push(login, email)\n newUsers.push({\n login: login,\n email: email,\n firstName: faker.person.firstName(),\n lastName: faker.person.lastName(),\n password: await hashPassword('password'),\n permissions: faker.helpers.arrayElements(Object.values(USER_PERMISSION)).join(',')\n })\n }\n\n for (let i = 0; i < 5; i++) {\n let name = faker.commerce.department()\n while (alreadyUsed.includes(name)) {\n name = faker.commerce.department()\n }\n alreadyUsed.push(name)\n newGroups.push({\n name: name,\n description: faker.company.buzzPhrase(),\n type: 0\n })\n }\n\n const db = await getDB()\n\n console.log('Seed start')\n const usersInfo: ResultSetHeader = (await db.insert(users).values(newUsers as any))[0]\n console.log('users: ', usersInfo.info)\n const groupsInfo: ResultSetHeader = (await db.insert(groups).values(newGroups as any))[0]\n console.log('groups: ', groupsInfo.info)\n\n const usersId = (await db.select({ id: users.id }).from(users)).map((r) => r.id)\n const groupsId = (await db.select({ id: groups.id }).from(groups)).map((r) => r.id)\n const newUsersGroups = usersId.map((uid) => ({ userId: uid, groupId: groupsId[Math.floor(Math.random() * groupsId.length)] }))\n const usersGroupsInfo: ResultSetHeader = (await db.insert(usersGroups).values(newUsersGroups))[0]\n console.log('users & groups: ', usersGroupsInfo.info)\n\n db.$client.end()\n}\n\nif (require.main === module) {\n usersAndGroups().then(() => console.log('Seed done'))\n}\n"],"names":["usersAndGroups","alreadyUsed","newUsers","login","email","firstName","lastName","role","USER_ROLE","ADMINISTRATOR","password","hashPassword","permissions","Object","values","USER_PERMISSION","join","newGroups","i","faker","person","internet","includes","push","helpers","arrayElements","name","commerce","department","description","company","buzzPhrase","type","db","getDB","console","log","usersInfo","insert","users","info","groupsInfo","groups","usersId","select","id","from","map","r","groupsId","newUsersGroups","uid","userId","groupId","Math","floor","random","length","usersGroupsInfo","usersGroups","$client","end","require","main","module","then"],"mappings":"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"}
@@ -59,26 +59,27 @@ let Mailer = class Mailer {
59
59
  this.available = false;
60
60
  this.logger.setContext(Mailer.name.toUpperCase());
61
61
  this.configuration = this.configService.get('mail');
62
- if (this.configuration) {
63
- this.logger.logger.level = this.configuration.debug ? 'debug' : 'info';
64
- if (this.configuration.secure && (this.configuration.port === 587 || this.configuration.port === 25)) {
65
- this.logger.warn(`Secure transport has been disabled due to use of port : ${this.configuration.port}`);
66
- this.configuration.secure = false;
67
- }
68
- this.transporter = _nodemailer.default.createTransport({
69
- host: this.configuration.host,
70
- port: this.configuration.port,
71
- auth: this.configuration.auth,
72
- secure: this.configuration.secure,
73
- logger: this.configuration.logger ? this.logger : false
74
- }, {
75
- from: this.configuration.sender,
76
- tls: {
77
- rejectUnauthorized: false
78
- }
79
- });
80
- this.verify().catch((e)=>this.logger.error(e));
62
+ if (!this.configuration) {
63
+ return;
81
64
  }
65
+ this.logger.logger.level = this.configuration.debug ? 'debug' : 'info';
66
+ if (this.configuration.secure && (this.configuration.port === 587 || this.configuration.port === 25)) {
67
+ this.logger.warn(`Secure transport has been disabled due to use of port : ${this.configuration.port}`);
68
+ this.configuration.secure = false;
69
+ }
70
+ this.transporter = _nodemailer.default.createTransport({
71
+ host: this.configuration.host,
72
+ port: this.configuration.port,
73
+ auth: this.configuration.auth,
74
+ secure: this.configuration.secure,
75
+ logger: this.configuration.logger ? this.logger : false
76
+ }, {
77
+ from: this.configuration.sender,
78
+ tls: {
79
+ rejectUnauthorized: false
80
+ }
81
+ });
82
+ this.verify().catch(this.logger.error);
82
83
  }
83
84
  };
84
85
  Mailer = _ts_decorate([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/infrastructure/mailer/mailer.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable } from '@nestjs/common'\nimport { ConfigService } from '@nestjs/config'\nimport { PinoLogger } from 'nestjs-pino'\nimport nodemailer from 'nodemailer'\nimport { MailDefaultsTransport, MailProps, MailTransport } from './interfaces/mail.interface'\nimport { MailerConfig } from './mailer.config'\n\n@Injectable()\nexport class Mailer {\n private readonly transporter: nodemailer.Transporter\n private readonly configuration: MailerConfig\n public available: boolean = false\n\n constructor(\n private configService: ConfigService,\n private readonly logger: PinoLogger\n ) {\n this.logger.setContext(Mailer.name.toUpperCase())\n this.configuration = this.configService.get<MailerConfig>('mail')\n if (this.configuration) {\n this.logger.logger.level = this.configuration.debug ? 'debug' : 'info'\n if (this.configuration.secure && (this.configuration.port === 587 || this.configuration.port === 25)) {\n this.logger.warn(`Secure transport has been disabled due to use of port : ${this.configuration.port}`)\n this.configuration.secure = false\n }\n this.transporter = nodemailer.createTransport(\n {\n host: this.configuration.host,\n port: this.configuration.port,\n auth: this.configuration.auth,\n secure: this.configuration.secure,\n logger: this.configuration.logger ? (this.logger as any) : false\n } satisfies MailTransport,\n { from: this.configuration.sender, tls: { rejectUnauthorized: false } } satisfies MailDefaultsTransport\n )\n this.verify().catch((e: Error) => this.logger.error(e))\n }\n }\n\n async sendMails(mails: MailProps[]) {\n if (!this.available) {\n return\n }\n for (const m of mails) {\n this.transporter\n .sendMail(m)\n .then(() => {\n this.logger.info(`Mail sent to '${m.to}' with subject '${m.subject}'`)\n })\n .catch((e) => {\n this.logger.error(`Mail was not sent to '${m.to}' with subject '${m.subject}' : ${e}`)\n })\n }\n }\n\n private async verify(): Promise<void> {\n try {\n await this.transporter.verify()\n this.logger.info(`Using Mail Server at ${this.configuration.host}:${this.configuration.port} (secure: ${this.configuration.secure})`)\n this.available = true\n } catch (e) {\n this.logger.error(\n `Unable to use Mail Server at ${this.configuration.host}:${this.configuration.port} (secure: ${this.configuration.secure}) : ${e}`\n )\n this.available = false\n }\n }\n}\n"],"names":["Mailer","sendMails","mails","available","m","transporter","sendMail","then","logger","info","to","subject","catch","e","error","verify","configuration","host","port","secure","configService","setContext","name","toUpperCase","get","level","debug","warn","nodemailer","createTransport","auth","from","sender","tls","rejectUnauthorized"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/infrastructure/mailer/mailer.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable } from '@nestjs/common'\nimport { ConfigService } from '@nestjs/config'\nimport { PinoLogger } from 'nestjs-pino'\nimport nodemailer from 'nodemailer'\nimport type { Logger as NodeMailLogger } from 'nodemailer/lib/shared'\nimport { MailDefaultsTransport, MailProps, MailTransport } from './interfaces/mail.interface'\nimport { MailerConfig } from './mailer.config'\n\n@Injectable()\nexport class Mailer {\n public available: boolean = false\n private readonly transporter: nodemailer.Transporter\n private readonly configuration: MailerConfig\n\n constructor(\n private configService: ConfigService,\n private readonly logger: PinoLogger\n ) {\n this.logger.setContext(Mailer.name.toUpperCase())\n this.configuration = this.configService.get<MailerConfig>('mail')\n if (!this.configuration) {\n return\n }\n this.logger.logger.level = this.configuration.debug ? 'debug' : 'info'\n if (this.configuration.secure && (this.configuration.port === 587 || this.configuration.port === 25)) {\n this.logger.warn(`Secure transport has been disabled due to use of port : ${this.configuration.port}`)\n this.configuration.secure = false\n }\n this.transporter = nodemailer.createTransport(\n {\n host: this.configuration.host,\n port: this.configuration.port,\n auth: this.configuration.auth,\n secure: this.configuration.secure,\n logger: this.configuration.logger ? (this.logger as NodeMailLogger & any) : false\n } satisfies MailTransport,\n { from: this.configuration.sender, tls: { rejectUnauthorized: false } } satisfies MailDefaultsTransport\n )\n this.verify().catch(this.logger.error)\n }\n\n async sendMails(mails: MailProps[]) {\n if (!this.available) {\n return\n }\n for (const m of mails) {\n this.transporter\n .sendMail(m)\n .then(() => {\n this.logger.info(`Mail sent to '${m.to}' with subject '${m.subject}'`)\n })\n .catch((e) => {\n this.logger.error(`Mail was not sent to '${m.to}' with subject '${m.subject}' : ${e}`)\n })\n }\n }\n\n private async verify(): Promise<void> {\n try {\n await this.transporter.verify()\n this.logger.info(`Using Mail Server at ${this.configuration.host}:${this.configuration.port} (secure: ${this.configuration.secure})`)\n this.available = true\n } catch (e) {\n this.logger.error(\n `Unable to use Mail Server at ${this.configuration.host}:${this.configuration.port} (secure: ${this.configuration.secure}) : ${e}`\n )\n this.available = false\n }\n }\n}\n"],"names":["Mailer","sendMails","mails","available","m","transporter","sendMail","then","logger","info","to","subject","catch","e","error","verify","configuration","host","port","secure","configService","setContext","name","toUpperCase","get","level","debug","warn","nodemailer","createTransport","auth","from","sender","tls","rejectUnauthorized"],"mappings":"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"}