@sync-in/server 1.5.2 → 1.6.1

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 (355) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +2 -1
  3. package/environment/environment.dist.min.yaml +1 -0
  4. package/environment/environment.dist.yaml +88 -30
  5. package/migrations/0002_sleepy_korath.sql +1 -0
  6. package/migrations/meta/0002_snapshot.json +2424 -0
  7. package/migrations/meta/_journal.json +7 -0
  8. package/package.json +14 -12
  9. package/server/app.bootstrap.js +1 -1
  10. package/server/app.bootstrap.js.map +1 -1
  11. package/server/applications/files/services/files-manager.service.js +1 -2
  12. package/server/applications/files/services/files-manager.service.js.map +1 -1
  13. package/server/applications/files/services/files-only-office-manager.service.js +5 -6
  14. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  15. package/server/applications/files/utils/files.js +6 -4
  16. package/server/applications/files/utils/files.js.map +1 -1
  17. package/server/applications/links/links.controller.js +2 -2
  18. package/server/applications/links/links.controller.js.map +1 -1
  19. package/server/applications/links/services/links-manager.service.js +2 -1
  20. package/server/applications/links/services/links-manager.service.js.map +1 -1
  21. package/server/applications/links/services/links-manager.service.spec.js +6 -3
  22. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  23. package/server/applications/notifications/constants/notifications.js +9 -0
  24. package/server/applications/notifications/constants/notifications.js.map +1 -1
  25. package/server/applications/notifications/i18n/fr.js +10 -1
  26. package/server/applications/notifications/i18n/fr.js.map +1 -1
  27. package/server/applications/notifications/interfaces/notification-properties.interface.js.map +1 -1
  28. package/server/applications/notifications/mails/models.js +41 -3
  29. package/server/applications/notifications/mails/models.js.map +1 -1
  30. package/server/applications/notifications/mails/templates.js +1 -1
  31. package/server/applications/notifications/mails/templates.js.map +1 -1
  32. package/server/applications/notifications/schemas/notifications.schema.js +2 -1
  33. package/server/applications/notifications/schemas/notifications.schema.js.map +1 -1
  34. package/server/applications/notifications/services/notifications-manager.service.js +16 -13
  35. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  36. package/server/applications/notifications/services/notifications-manager.service.spec.js +9 -8
  37. package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
  38. package/server/applications/notifications/services/notifications-queries.service.js +1 -1
  39. package/server/applications/notifications/services/notifications-queries.service.js.map +1 -1
  40. package/server/applications/shares/services/shares-manager.service.js +3 -2
  41. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  42. package/server/applications/sync/constants/auth.js +2 -2
  43. package/server/applications/sync/constants/auth.js.map +1 -1
  44. package/server/applications/sync/dtos/sync-client-registration.dto.js +5 -0
  45. package/server/applications/sync/dtos/sync-client-registration.dto.js.map +1 -1
  46. package/server/applications/sync/dtos/sync-operations.dto.js +1 -2
  47. package/server/applications/sync/dtos/sync-operations.dto.js.map +1 -1
  48. package/server/applications/sync/schemas/sync-clients.schema.js +2 -1
  49. package/server/applications/sync/schemas/sync-clients.schema.js.map +1 -1
  50. package/server/applications/sync/schemas/sync-paths.schema.js +2 -1
  51. package/server/applications/sync/schemas/sync-paths.schema.js.map +1 -1
  52. package/server/applications/sync/services/sync-clients-manager.service.js +28 -20
  53. package/server/applications/sync/services/sync-clients-manager.service.js.map +1 -1
  54. package/server/applications/sync/services/sync-clients-manager.service.spec.js +24 -18
  55. package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
  56. package/server/applications/sync/services/sync-queries.service.js +5 -5
  57. package/server/applications/sync/services/sync-queries.service.js.map +1 -1
  58. package/server/applications/users/admin-users.controller.js +48 -37
  59. package/server/applications/users/admin-users.controller.js.map +1 -1
  60. package/server/applications/users/admin-users.controller.spec.js +15 -0
  61. package/server/applications/users/admin-users.controller.spec.js.map +1 -1
  62. package/server/applications/users/constants/routes.js +5 -0
  63. package/server/applications/users/constants/routes.js.map +1 -1
  64. package/server/applications/users/constants/user.js +8 -0
  65. package/server/applications/users/constants/user.js.map +1 -1
  66. package/server/applications/users/dto/delete-user.dto.js +5 -23
  67. package/server/applications/users/dto/delete-user.dto.js.map +1 -1
  68. package/server/applications/users/dto/user-properties.dto.js +38 -3
  69. package/server/applications/users/dto/user-properties.dto.js.map +1 -1
  70. package/server/applications/users/interfaces/admin-user.interface.js.map +1 -1
  71. package/server/applications/users/interfaces/user-secrets.interface.js +10 -0
  72. package/server/applications/users/interfaces/user-secrets.interface.js.map +1 -0
  73. package/server/applications/users/models/user.model.js +84 -50
  74. package/server/applications/users/models/user.model.js.map +1 -1
  75. package/server/applications/users/schemas/user.interface.js.map +1 -1
  76. package/server/applications/users/schemas/users.schema.js +2 -0
  77. package/server/applications/users/schemas/users.schema.js.map +1 -1
  78. package/server/applications/users/services/admin-users-manager.service.js +7 -19
  79. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  80. package/server/applications/users/services/admin-users-manager.service.spec.js +7 -26
  81. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  82. package/server/applications/users/services/admin-users-queries.service.js +1 -0
  83. package/server/applications/users/services/admin-users-queries.service.js.map +1 -1
  84. package/server/applications/users/services/users-manager.service.js +138 -28
  85. package/server/applications/users/services/users-manager.service.js.map +1 -1
  86. package/server/applications/users/services/users-manager.service.spec.js +11 -9
  87. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  88. package/server/applications/users/services/users-queries.service.js +63 -57
  89. package/server/applications/users/services/users-queries.service.js.map +1 -1
  90. package/server/applications/users/users.controller.js +48 -1
  91. package/server/applications/users/users.controller.js.map +1 -1
  92. package/server/applications/users/users.controller.spec.js +8 -1
  93. package/server/applications/users/users.controller.spec.js.map +1 -1
  94. package/server/applications/users/users.e2e-spec.js +2 -1
  95. package/server/applications/users/users.e2e-spec.js.map +1 -1
  96. package/server/applications/users/utils/avatar.js +48 -0
  97. package/server/applications/users/utils/avatar.js.map +1 -0
  98. package/server/authentication/auth.config.js +89 -26
  99. package/server/authentication/auth.config.js.map +1 -1
  100. package/server/authentication/auth.controller.js +117 -9
  101. package/server/authentication/auth.controller.js.map +1 -1
  102. package/server/authentication/auth.controller.spec.js +16 -1
  103. package/server/authentication/auth.controller.spec.js.map +1 -1
  104. package/server/authentication/auth.e2e-spec.js +4 -3
  105. package/server/authentication/auth.e2e-spec.js.map +1 -1
  106. package/server/authentication/auth.module.js +4 -1
  107. package/server/authentication/auth.module.js.map +1 -1
  108. package/server/authentication/constants/auth-ldap.js +44 -0
  109. package/server/authentication/constants/auth-ldap.js.map +1 -0
  110. package/server/authentication/constants/auth.js +37 -4
  111. package/server/authentication/constants/auth.js.map +1 -1
  112. package/server/authentication/constants/routes.js +21 -0
  113. package/server/authentication/constants/routes.js.map +1 -1
  114. package/server/authentication/constants/scope.js +20 -0
  115. package/server/authentication/constants/scope.js.map +1 -0
  116. package/server/authentication/dto/login-response.dto.js +27 -4
  117. package/server/authentication/dto/login-response.dto.js.map +1 -1
  118. package/server/authentication/dto/token-response.dto.js +5 -0
  119. package/server/authentication/dto/token-response.dto.js.map +1 -1
  120. package/server/{applications/users/dto/user-password.dto.js → authentication/dto/two-fa-verify.dto.js} +27 -9
  121. package/server/authentication/dto/two-fa-verify.dto.js.map +1 -0
  122. package/server/authentication/guards/auth-basic.strategy.js +6 -5
  123. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  124. package/server/authentication/guards/auth-token-access.strategy.js +3 -2
  125. package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
  126. package/server/authentication/guards/auth-token-refresh.strategy.js +3 -2
  127. package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
  128. package/server/authentication/guards/auth-two-fa-guard.js +81 -0
  129. package/server/authentication/guards/auth-two-fa-guard.js.map +1 -0
  130. package/server/authentication/interfaces/jwt-payload.interface.js +5 -0
  131. package/server/authentication/interfaces/jwt-payload.interface.js.map +1 -1
  132. package/server/authentication/interfaces/token.interface.js +2 -0
  133. package/server/authentication/interfaces/token.interface.js.map +1 -1
  134. package/server/authentication/interfaces/two-fa-setup.interface.js +10 -0
  135. package/server/authentication/interfaces/two-fa-setup.interface.js.map +1 -0
  136. package/server/authentication/models/auth-method.js.map +1 -1
  137. package/server/authentication/services/auth-manager.service.js +72 -49
  138. package/server/authentication/services/auth-manager.service.js.map +1 -1
  139. package/server/authentication/services/auth-methods/auth-method-database.service.js +3 -3
  140. package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
  141. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +5 -0
  142. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
  143. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +151 -66
  144. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  145. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +52 -50
  146. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  147. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js +251 -0
  148. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js.map +1 -0
  149. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js +41 -0
  150. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js.map +1 -0
  151. package/server/authentication/utils/crypt-secret.js +68 -0
  152. package/server/authentication/utils/crypt-secret.js.map +1 -0
  153. package/server/common/functions.js +18 -2
  154. package/server/common/functions.js.map +1 -1
  155. package/server/common/qrcode.js +34 -0
  156. package/server/common/qrcode.js.map +1 -0
  157. package/server/common/shared.js +18 -0
  158. package/server/common/shared.js.map +1 -1
  159. package/server/configuration/config.environment.js +23 -6
  160. package/server/configuration/config.environment.js.map +1 -1
  161. package/server/configuration/config.interfaces.js +10 -0
  162. package/server/configuration/config.interfaces.js.map +1 -0
  163. package/server/configuration/config.loader.js.map +1 -1
  164. package/server/configuration/config.validation.js +13 -13
  165. package/server/configuration/config.validation.js.map +1 -1
  166. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +6 -6
  167. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
  168. package/server/infrastructure/cache/schemas/mysql-cache.schema.js +2 -1
  169. package/server/infrastructure/cache/schemas/mysql-cache.schema.js.map +1 -1
  170. package/server/infrastructure/cache/services/cache.service.js.map +1 -1
  171. package/server/infrastructure/database/columns.js +39 -0
  172. package/server/infrastructure/database/columns.js.map +1 -0
  173. package/server/infrastructure/database/database.config.js +0 -1
  174. package/server/infrastructure/database/database.config.js.map +1 -1
  175. package/server/infrastructure/mailer/interfaces/mail.interface.js.map +1 -1
  176. package/server/infrastructure/mailer/mailer.config.js +12 -0
  177. package/server/infrastructure/mailer/mailer.config.js.map +1 -1
  178. package/server/infrastructure/mailer/mailer.service.js +2 -1
  179. package/server/infrastructure/mailer/mailer.service.js.map +1 -1
  180. package/static/assets/mimes/text-x-c.svg +1 -0
  181. package/static/assets/pdfjs/build/pdf.mjs +2522 -914
  182. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  183. package/static/assets/pdfjs/build/pdf.sandbox.mjs +2 -2
  184. package/static/assets/pdfjs/build/pdf.worker.mjs +1024 -566
  185. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  186. package/static/assets/pdfjs/version +1 -1
  187. package/static/assets/pdfjs/web/debugger.mjs +116 -37
  188. package/static/assets/pdfjs/web/images/comment-popup-editButton.svg +5 -0
  189. package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -12
  190. package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -12
  191. package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -16
  192. package/static/assets/pdfjs/web/locale/ar/viewer.ftl +0 -32
  193. package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -19
  194. package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -16
  195. package/static/assets/pdfjs/web/locale/be/viewer.ftl +0 -32
  196. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -32
  197. package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -16
  198. package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -12
  199. package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -22
  200. package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -16
  201. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -32
  202. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +12 -23
  203. package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -23
  204. package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -16
  205. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +0 -32
  206. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +0 -32
  207. package/static/assets/pdfjs/web/locale/da/viewer.ftl +3 -35
  208. package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -32
  209. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -32
  210. package/static/assets/pdfjs/web/locale/el/viewer.ftl +0 -32
  211. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +0 -32
  212. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -32
  213. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -13
  214. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +0 -32
  215. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -32
  216. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +0 -32
  217. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +5 -32
  218. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -32
  219. package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -16
  220. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +38 -32
  221. package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -19
  222. package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -12
  223. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -32
  224. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -32
  225. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -32
  226. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +0 -32
  227. package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -12
  228. package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -23
  229. package/static/assets/pdfjs/web/locale/gl/viewer.ftl +0 -32
  230. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +0 -32
  231. package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -12
  232. package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -32
  233. package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -16
  234. package/static/assets/pdfjs/web/locale/hr/viewer.ftl +0 -32
  235. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -32
  236. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -32
  237. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +372 -16
  238. package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -16
  239. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -32
  240. package/static/assets/pdfjs/web/locale/id/viewer.ftl +38 -32
  241. package/static/assets/pdfjs/web/locale/is/viewer.ftl +27 -32
  242. package/static/assets/pdfjs/web/locale/it/viewer.ftl +0 -33
  243. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +31 -33
  244. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +0 -32
  245. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -32
  246. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +31 -32
  247. package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -12
  248. package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -12
  249. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -32
  250. package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -12
  251. package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -23
  252. package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -16
  253. package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -12
  254. package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -12
  255. package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -14
  256. package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -19
  257. package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -31
  258. package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -16
  259. package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -12
  260. package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -12
  261. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +0 -32
  262. package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -12
  263. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -32
  264. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +0 -32
  265. package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -24
  266. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +0 -32
  267. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +0 -32
  268. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +0 -32
  269. package/static/assets/pdfjs/web/locale/pt-PT/viewer.ftl +0 -32
  270. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -32
  271. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +5 -37
  272. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +0 -32
  273. package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -23
  274. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +8 -27
  275. package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -16
  276. package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -22
  277. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -32
  278. package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -32
  279. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +30 -32
  280. package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -12
  281. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +0 -32
  282. package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -32
  283. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -32
  284. package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -16
  285. package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -12
  286. package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -16
  287. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +0 -32
  288. package/static/assets/pdfjs/web/locale/th/viewer.ftl +38 -32
  289. package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -16
  290. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +0 -32
  291. package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -12
  292. package/static/assets/pdfjs/web/locale/uk/viewer.ftl +0 -32
  293. package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -16
  294. package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -12
  295. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -32
  296. package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -12
  297. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +0 -32
  298. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -32
  299. package/static/assets/pdfjs/web/viewer.css +586 -437
  300. package/static/assets/pdfjs/web/viewer.html +12 -23
  301. package/static/assets/pdfjs/web/viewer.mjs +955 -514
  302. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  303. package/static/assets/pdfjs/web/wasm/openjpeg.wasm +0 -0
  304. package/static/assets/pdfjs/web/wasm/openjpeg_nowasm_fallback.js +10 -22
  305. package/static/{chunk-SPTF6FSM.js → chunk-27YQB3TE.js} +1 -1
  306. package/static/chunk-2I4CUFUA.js +1 -0
  307. package/static/chunk-2MTM6SWN.js +4 -0
  308. package/static/{chunk-7VRUZRJG.js → chunk-34MKICK5.js} +2 -2
  309. package/static/chunk-5O3DIUU3.js +1 -0
  310. package/static/{chunk-VJRTMDEJ.js → chunk-6NMVZIIT.js} +1 -1
  311. package/static/{chunk-L6MU6S2V.js → chunk-7DN7ZAPU.js} +1 -1
  312. package/static/{chunk-MVO4WZLK.js → chunk-7FUM3JGM.js} +1 -1
  313. package/static/{chunk-RSS6GYNE.js → chunk-7ITZXYYJ.js} +1 -1
  314. package/static/chunk-7P27WBGC.js +4 -0
  315. package/static/chunk-ATP3BFHV.js +562 -0
  316. package/static/chunk-AWQ2YTVC.js +1 -0
  317. package/static/chunk-DSOE3FEP.js +1 -0
  318. package/static/{chunk-2R6HHGUR.js → chunk-EFKMBLRE.js} +1 -1
  319. package/static/chunk-FUFKVHPU.js +1 -0
  320. package/static/{chunk-MRSWNAVB.js → chunk-HCDLWTMW.js} +1 -1
  321. package/static/chunk-IPAC4VAF.js +1 -0
  322. package/static/{chunk-ZC5NIT55.js → chunk-IQOALFYU.js} +1 -1
  323. package/static/chunk-JASU3CIH.js +1 -0
  324. package/static/{chunk-6OJZWYRZ.js → chunk-JQ5FTO2M.js} +1 -1
  325. package/static/chunk-JUNZFADM.js +1 -0
  326. package/static/{chunk-LLWSLOSX.js → chunk-LJUKI4SQ.js} +1 -1
  327. package/static/{chunk-WI7FOANP.js → chunk-LUWQFIWR.js} +1 -1
  328. package/static/{chunk-BIUNUYZ5.js → chunk-ORMRCEGT.js} +1 -1
  329. package/static/{chunk-IZL7JPTS.js → chunk-Q7D6RN4N.js} +1 -1
  330. package/static/{chunk-JYXLQRHG.js → chunk-QJX6ITLW.js} +1 -1
  331. package/static/{chunk-YJMN3B4N.js → chunk-QQ6UQQBR.js} +1 -1
  332. package/static/chunk-S2HDY3OL.js +1 -0
  333. package/static/{chunk-NE4NDO45.js → chunk-S75P2FFI.js} +1 -1
  334. package/static/{chunk-CRQNEHTX.js → chunk-T3EYFSVZ.js} +1 -1
  335. package/static/{chunk-MCLQFZ3S.js → chunk-U34OZUZ7.js} +1 -1
  336. package/static/chunk-Y7EH7G5K.js +1 -0
  337. package/static/{chunk-MGGT6MIJ.js → chunk-ZQQPUYLU.js} +1 -1
  338. package/static/index.html +2 -2
  339. package/static/main-7SQDDVMD.js +9 -0
  340. package/static/{styles-FYUSO6OJ.css → styles-A5VYX3CE.css} +1 -1
  341. package/server/applications/users/dto/user-password.dto.js.map +0 -1
  342. package/static/chunk-4U5A2DEP.js +0 -4
  343. package/static/chunk-54EAZ2UD.js +0 -1
  344. package/static/chunk-7ZRXJONB.js +0 -1
  345. package/static/chunk-F2J2IIJE.js +0 -1
  346. package/static/chunk-FNFGUIQH.js +0 -4
  347. package/static/chunk-GGLK52CG.js +0 -1
  348. package/static/chunk-HW2H3ISM.js +0 -559
  349. package/static/chunk-HX6BBYVD.js +0 -1
  350. package/static/chunk-JF7S3UYQ.js +0 -1
  351. package/static/chunk-KSHPKI4G.js +0 -1
  352. package/static/chunk-VPJ2V27B.js +0 -1
  353. package/static/chunk-VUI3KV7V.js +0 -1
  354. package/static/chunk-ZXS4V7J2.js +0 -1
  355. package/static/main-FFIWFD2F.js +0 -7
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/mails/models.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 { SERVER_NAME } from '../../../app.constants'\nimport { ACTION } from '../../../common/constants'\nimport { capitalizeString } from '../../../common/shared'\nimport { fileName } from '../../files/utils/files'\nimport { UserModel } from '../../users/models/user.model'\nimport { translateObject } from '../i18n'\nimport { NotificationContent } from '../interfaces/notification-properties.interface'\nimport { defaultFooter, mailAuthor, mailEventOnElement, mailItalicContent, mailTemplate } from './templates'\nimport { urlFromLink, urlFromSpace, urlFromSpaceFile, urlFromSync } from './urls'\n\nexport function commentMail(\n language: string,\n notification: NotificationContent,\n options: {\n content: string\n currentUrl: string\n author: UserModel\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Comment',\n defaultFooter: defaultFooter,\n footer: 'You receive this notification if you are the owner of the file or if you have also commented on this file',\n urlText: 'Access it from',\n event: notification.event\n })\n\n const content = `${mailAuthor(options.author)}${mailEventOnElement(tr.event, notification.element)}${mailItalicContent(options.content)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromSpaceFile(options.currentUrl, notification)}\">${SERVER_NAME}</a><br>${tr.footer}<br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function spaceMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Space',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your spaces from',\n event: notification.event\n })\n\n const spaceUrl = urlFromSpace(options.currentUrl, options.action === ACTION.ADD ? notification.element : undefined)\n\n const content = `${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${spaceUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function spaceRootMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Space',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access this space from',\n event: notification.event,\n originEvent: options.action === ACTION.ADD ? 'to the space' : 'from the space'\n })\n\n const spaceName = fileName(notification.url)\n const spaceRootUrl =\n options.action === ACTION.ADD ? urlFromSpaceFile(options.currentUrl, notification) : urlFromSpace(options.currentUrl, spaceName)\n\n const content = `${mailAuthor(options.author)}${mailEventOnElement(tr.event, notification.element)}&nbsp;${tr.originEvent}&nbsp;<b>${spaceName}</b>`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${spaceRootUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(spaceName)}`, mailTemplate(content, footer)]\n}\n\nexport function shareMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Share',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your shares from',\n event: notification.event\n })\n\n const content = `${options.author ? mailAuthor(options.author) : ''}${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromSpaceFile(options.currentUrl, notification)}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function linkMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n linkUUID: string\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: options.action === ACTION.ADD ? 'Share' : 'Space',\n defaultFooter: defaultFooter,\n urlText: 'Access it from',\n event: notification.event\n })\n\n const content = `${options.author ? mailAuthor(options.author) : ''}${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromLink(options.currentUrl, options.linkUUID)}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function syncMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Sync',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your syncs from',\n event: notification.event\n })\n\n const syncUrl = urlFromSync(options.currentUrl)\n\n const content = `${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${syncUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n"],"names":["commentMail","linkMail","shareMail","spaceMail","spaceRootMail","syncMail","language","notification","options","tr","translateObject","title","defaultFooter","footer","urlText","event","content","mailAuthor","author","mailEventOnElement","element","mailItalicContent","urlFromSpaceFile","currentUrl","SERVER_NAME","capitalizeString","mailTemplate","action","ACTION","ADD","spaceUrl","urlFromSpace","undefined","originEvent","spaceName","fileName","url","spaceRootUrl","urlFromLink","linkUUID","syncUrl","urlFromSync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/mails/models.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 { SERVER_NAME } from '../../../app.constants'\nimport { ACTION } from '../../../common/constants'\nimport { capitalizeString } from '../../../common/shared'\nimport { fileName } from '../../files/utils/files'\nimport { UserModel } from '../../users/models/user.model'\nimport { translateObject } from '../i18n'\nimport { NotificationContent } from '../interfaces/notification-properties.interface'\nimport { defaultFooter, mailAuthor, mailEventOnElement, mailItalicContent, mailTemplate } from './templates'\nimport { urlFromLink, urlFromSpace, urlFromSpaceFile, urlFromSync } from './urls'\n\nexport function commentMail(\n language: string,\n notification: NotificationContent,\n options: {\n content: string\n currentUrl: string\n author: UserModel\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Comment',\n defaultFooter: defaultFooter,\n footer: 'You receive this notification if you are the owner of the file or if you have also commented on this file',\n urlText: 'Access it from',\n event: notification.event\n })\n\n const content = `${mailAuthor(options.author)}${mailEventOnElement(tr.event, notification.element)}${mailItalicContent(options.content)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromSpaceFile(options.currentUrl, notification)}\">${SERVER_NAME}</a><br>${tr.footer}<br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function spaceMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Space',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your spaces from',\n event: notification.event\n })\n\n const spaceUrl = urlFromSpace(options.currentUrl, options.action === ACTION.ADD ? notification.element : undefined)\n\n const content = `${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${spaceUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function spaceRootMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Space',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access this space from',\n event: notification.event,\n originEvent: options.action === ACTION.ADD ? 'to the space' : 'from the space'\n })\n\n const spaceName = fileName(notification.url)\n const spaceRootUrl =\n options.action === ACTION.ADD ? urlFromSpaceFile(options.currentUrl, notification) : urlFromSpace(options.currentUrl, spaceName)\n\n const content = `${mailAuthor(options.author)}${mailEventOnElement(tr.event, notification.element)}&nbsp;${tr.originEvent}&nbsp;<b>${spaceName}</b>`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${spaceRootUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(spaceName)}`, mailTemplate(content, footer)]\n}\n\nexport function shareMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Share',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your shares from',\n event: notification.event\n })\n\n const content = `${options.author ? mailAuthor(options.author) : ''}${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromSpaceFile(options.currentUrl, notification)}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function linkMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n author: UserModel\n action: ACTION\n linkUUID: string\n linkPassword: string\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: options.action === ACTION.ADD ? 'Share' : 'Space',\n passwordText: 'Access password',\n urlText: 'Access it from',\n event: notification.event\n })\n\n let content = `${options.author ? mailAuthor(options.author) : ''}${mailEventOnElement(tr.event, notification.element)}`\n\n if (options.linkPassword) {\n content += `<br><br>${tr.passwordText}:&nbsp;<div style=\"border:1px solid #000; padding:8px; display:inline-block;\">${options.linkPassword}</div>`\n }\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${urlFromLink(options.currentUrl, options.linkUUID)}\">${SERVER_NAME}</a>`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function syncMail(\n language: string,\n notification: NotificationContent,\n options: {\n currentUrl: string\n action: ACTION\n }\n): [string, string] {\n const tr = translateObject(language, {\n title: 'Sync',\n defaultFooter: defaultFooter,\n urlText: options.action === ACTION.ADD ? 'Access it from' : 'Access your syncs from',\n event: notification.event\n })\n\n const syncUrl = urlFromSync(options.currentUrl)\n\n const content = `${mailEventOnElement(tr.event, notification.element)}`\n\n const footer = `<br>${tr.urlText}&nbsp;<a href=\"${syncUrl}\">${SERVER_NAME}</a><br>${tr.defaultFooter}`\n\n return [`${tr.title}: ${capitalizeString(notification.element)}`, mailTemplate(content, footer)]\n}\n\nexport function auth2FaMail(language: string, notification: NotificationContent): [string, string] {\n const tr = translateObject(language, {\n title: 'Security notification',\n footer:\n 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.',\n event: notification.event,\n addressIp: 'Address IP',\n browser: 'Browser'\n })\n\n const content = `${tr.event}<br><br>${tr.addressIp}:&nbsp;${notification.url}<br>${tr.browser}:&nbsp;${notification.element}`\n\n const footer = `<br>${tr.footer}<br>`\n\n return [tr.title, mailTemplate(content, footer)]\n}\n\nexport function authLocked(language: string, notification: NotificationContent): [string, string] {\n const tr = translateObject(language, {\n title: 'Security notification',\n footer:\n 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.',\n event: notification.event,\n addressIp: 'Address IP'\n })\n\n const content = `${tr.event}<br><br>${tr.addressIp}:&nbsp;${notification.url}<br>`\n\n const footer = `<br>${tr.footer}<br>`\n\n return [tr.title, mailTemplate(content, footer)]\n}\n"],"names":["auth2FaMail","authLocked","commentMail","linkMail","shareMail","spaceMail","spaceRootMail","syncMail","language","notification","options","tr","translateObject","title","defaultFooter","footer","urlText","event","content","mailAuthor","author","mailEventOnElement","element","mailItalicContent","urlFromSpaceFile","currentUrl","SERVER_NAME","capitalizeString","mailTemplate","action","ACTION","ADD","spaceUrl","urlFromSpace","undefined","originEvent","spaceName","fileName","url","spaceRootUrl","passwordText","linkPassword","urlFromLink","linkUUID","syncUrl","urlFromSync","addressIp","browser"],"mappings":"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"}
@@ -45,7 +45,7 @@ ${footer}
45
45
  </body
46
46
  </html>`;
47
47
  const mailAuthor = (author)=>`<img style="border-radius: 50% !important; vertical-align: middle; object-fit: cover;" height="40" width="40" src="${author.avatarBase64}" alt="avatar">&nbsp;<b>${author.fullName}</b>&nbsp;`;
48
- const mailEventOnElement = (event, element)=>`${event}&nbsp;:&nbsp;<b>${(0, _shared.capitalizeString)(element)}</b>`;
48
+ const mailEventOnElement = (event, element)=>`${event}:&nbsp;<b>${(0, _shared.capitalizeString)(element)}</b>`;
49
49
  const mailItalicContent = (content)=>`<p><i>${content}</i></p>`;
50
50
 
51
51
  //# sourceMappingURL=templates.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/mails/templates.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 { capitalizeString } from '../../../common/shared'\nimport { UserModel } from '../../users/models/user.model'\n\nexport const defaultFooter = 'If you no longer wish to receive notifications, change your preferences directly from your user space'\n\nexport const mailTemplate = (content: string, footer: string) => `\n<html lang=\"en\">\n<meta charset=\"utf-8\"/>\n<body>\n<div>\n${content}\n</div>\n<small style=\"color:#666\">\n--\n${footer}\n</small>\n</body\n</html>`\n\nexport const mailAuthor = (author: UserModel) =>\n `<img style=\"border-radius: 50% !important; vertical-align: middle; object-fit: cover;\" height=\"40\" width=\"40\" src=\"${author.avatarBase64}\" alt=\"avatar\">&nbsp;<b>${author.fullName}</b>&nbsp;`\n\nexport const mailEventOnElement = (event: string, element: string) => `${event}&nbsp;:&nbsp;<b>${capitalizeString(element)}</b>`\n\nexport const mailItalicContent = (content: string) => `<p><i>${content}</i></p>`\n"],"names":["defaultFooter","mailAuthor","mailEventOnElement","mailItalicContent","mailTemplate","content","footer","author","avatarBase64","fullName","event","element","capitalizeString"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAKYA;eAAAA;;QAgBAC;eAAAA;;QAGAC;eAAAA;;QAEAC;eAAAA;;QAnBAC;eAAAA;;;wBALoB;AAG1B,MAAMJ,gBAAgB;AAEtB,MAAMI,eAAe,CAACC,SAAiBC,SAAmB,CAAC;;;;;AAKlE,EAAED,QAAQ;;;;AAIV,EAAEC,OAAO;;;OAGF,CAAC;AAED,MAAML,aAAa,CAACM,SACzB,CAAC,mHAAmH,EAAEA,OAAOC,YAAY,CAAC,wBAAwB,EAAED,OAAOE,QAAQ,CAAC,UAAU,CAAC;AAE1L,MAAMP,qBAAqB,CAACQ,OAAeC,UAAoB,GAAGD,MAAM,gBAAgB,EAAEE,IAAAA,wBAAgB,EAACD,SAAS,IAAI,CAAC;AAEzH,MAAMR,oBAAoB,CAACE,UAAoB,CAAC,MAAM,EAAEA,QAAQ,QAAQ,CAAC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/mails/templates.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 { capitalizeString } from '../../../common/shared'\nimport { UserModel } from '../../users/models/user.model'\n\nexport const defaultFooter = 'If you no longer wish to receive notifications, change your preferences directly from your user space'\n\nexport const mailTemplate = (content: string, footer: string) => `\n<html lang=\"en\">\n<meta charset=\"utf-8\"/>\n<body>\n<div>\n${content}\n</div>\n<small style=\"color:#666\">\n--\n${footer}\n</small>\n</body\n</html>`\n\nexport const mailAuthor = (author: UserModel) =>\n `<img style=\"border-radius: 50% !important; vertical-align: middle; object-fit: cover;\" height=\"40\" width=\"40\" src=\"${author.avatarBase64}\" alt=\"avatar\">&nbsp;<b>${author.fullName}</b>&nbsp;`\n\nexport const mailEventOnElement = (event: string, element: string) => `${event}:&nbsp;<b>${capitalizeString(element)}</b>`\n\nexport const mailItalicContent = (content: string) => `<p><i>${content}</i></p>`\n"],"names":["defaultFooter","mailAuthor","mailEventOnElement","mailItalicContent","mailTemplate","content","footer","author","avatarBase64","fullName","event","element","capitalizeString"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAKYA;eAAAA;;QAgBAC;eAAAA;;QAGAC;eAAAA;;QAEAC;eAAAA;;QAnBAC;eAAAA;;;wBALoB;AAG1B,MAAMJ,gBAAgB;AAEtB,MAAMI,eAAe,CAACC,SAAiBC,SAAmB,CAAC;;;;;AAKlE,EAAED,QAAQ;;;;AAIV,EAAEC,OAAO;;;OAGF,CAAC;AAED,MAAML,aAAa,CAACM,SACzB,CAAC,mHAAmH,EAAEA,OAAOC,YAAY,CAAC,wBAAwB,EAAED,OAAOE,QAAQ,CAAC,UAAU,CAAC;AAE1L,MAAMP,qBAAqB,CAACQ,OAAeC,UAAoB,GAAGD,MAAM,UAAU,EAAEE,IAAAA,wBAAgB,EAACD,SAAS,IAAI,CAAC;AAEnH,MAAMR,oBAAoB,CAACE,UAAoB,CAAC,MAAM,EAAEA,QAAQ,QAAQ,CAAC"}
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "notifications", {
14
14
  });
15
15
  const _drizzleorm = require("drizzle-orm");
16
16
  const _mysqlcore = require("drizzle-orm/mysql-core");
17
+ const _columns = require("../../../infrastructure/database/columns");
17
18
  const _usersschema = require("../../users/schemas/users.schema");
18
19
  const notifications = (0, _mysqlcore.mysqlTable)('notifications', {
19
20
  id: (0, _mysqlcore.bigint)('id', {
@@ -32,7 +33,7 @@ const notifications = (0, _mysqlcore.mysqlTable)('notifications', {
32
33
  }).references(()=>_usersschema.users.id, {
33
34
  onDelete: 'cascade'
34
35
  }).notNull(),
35
- content: (0, _mysqlcore.json)('content').$type(),
36
+ content: (0, _columns.jsonColumn)()('content'),
36
37
  wasRead: (0, _mysqlcore.boolean)('wasRead').default(false).notNull(),
37
38
  createdAt: (0, _mysqlcore.datetime)('createdAt', {
38
39
  mode: 'date'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/schemas/notifications.schema.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 { sql } from 'drizzle-orm'\nimport { bigint, boolean, datetime, index, json, mysqlTable } from 'drizzle-orm/mysql-core'\nimport { users } from '../../users/schemas/users.schema'\nimport type { NotificationContent } from '../interfaces/notification-properties.interface'\n\nexport const notifications = mysqlTable(\n 'notifications',\n {\n id: bigint('id', { mode: 'number', unsigned: true }).autoincrement().primaryKey(),\n fromUserId: bigint('fromUserId', { mode: 'number', unsigned: true }).references(() => users.id, { onDelete: 'cascade' }),\n toUserId: bigint('toUserId', { mode: 'number', unsigned: true })\n .references(() => users.id, { onDelete: 'cascade' })\n .notNull(),\n content: json('content').$type<NotificationContent>(),\n wasRead: boolean('wasRead').default(false).notNull(),\n createdAt: datetime('createdAt', { mode: 'date' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull()\n },\n (table) => [index('from_user_idx').on(table.fromUserId), index('to_user_idx').on(table.toUserId)]\n)\n"],"names":["notifications","mysqlTable","id","bigint","mode","unsigned","autoincrement","primaryKey","fromUserId","references","users","onDelete","toUserId","notNull","content","json","$type","wasRead","boolean","default","createdAt","datetime","sql","table","index","on"],"mappings":"AAAA;;;;CAIC;;;;+BAOYA;;;eAAAA;;;4BALO;2BAC+C;6BAC7C;AAGf,MAAMA,gBAAgBC,IAAAA,qBAAU,EACrC,iBACA;IACEC,IAAIC,IAAAA,iBAAM,EAAC,MAAM;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAAGC,aAAa,GAAGC,UAAU;IAC/EC,YAAYL,IAAAA,iBAAM,EAAC,cAAc;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAAGI,UAAU,CAAC,IAAMC,kBAAK,CAACR,EAAE,EAAE;QAAES,UAAU;IAAU;IACtHC,UAAUT,IAAAA,iBAAM,EAAC,YAAY;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAC3DI,UAAU,CAAC,IAAMC,kBAAK,CAACR,EAAE,EAAE;QAAES,UAAU;IAAU,GACjDE,OAAO;IACVC,SAASC,IAAAA,eAAI,EAAC,WAAWC,KAAK;IAC9BC,SAASC,IAAAA,kBAAO,EAAC,WAAWC,OAAO,CAAC,OAAON,OAAO;IAClDO,WAAWC,IAAAA,mBAAQ,EAAC,aAAa;QAAEjB,MAAM;IAAO,GAC7Ce,OAAO,CAACG,IAAAA,eAAG,CAAA,CAAC,iBAAiB,CAAC,EAC9BT,OAAO;AACZ,GACA,CAACU,QAAU;QAACC,IAAAA,gBAAK,EAAC,iBAAiBC,EAAE,CAACF,MAAMf,UAAU;QAAGgB,IAAAA,gBAAK,EAAC,eAAeC,EAAE,CAACF,MAAMX,QAAQ;KAAE"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/schemas/notifications.schema.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 { sql } from 'drizzle-orm'\nimport { bigint, boolean, datetime, index, mysqlTable } from 'drizzle-orm/mysql-core'\nimport { jsonColumn } from '../../../infrastructure/database/columns'\nimport { users } from '../../users/schemas/users.schema'\nimport type { NotificationContent } from '../interfaces/notification-properties.interface'\n\nexport const notifications = mysqlTable(\n 'notifications',\n {\n id: bigint('id', { mode: 'number', unsigned: true }).autoincrement().primaryKey(),\n fromUserId: bigint('fromUserId', { mode: 'number', unsigned: true }).references(() => users.id, { onDelete: 'cascade' }),\n toUserId: bigint('toUserId', { mode: 'number', unsigned: true })\n .references(() => users.id, { onDelete: 'cascade' })\n .notNull(),\n content: jsonColumn<NotificationContent>()('content'),\n wasRead: boolean('wasRead').default(false).notNull(),\n createdAt: datetime('createdAt', { mode: 'date' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull()\n },\n (table) => [index('from_user_idx').on(table.fromUserId), index('to_user_idx').on(table.toUserId)]\n)\n"],"names":["notifications","mysqlTable","id","bigint","mode","unsigned","autoincrement","primaryKey","fromUserId","references","users","onDelete","toUserId","notNull","content","jsonColumn","wasRead","boolean","default","createdAt","datetime","sql","table","index","on"],"mappings":"AAAA;;;;CAIC;;;;+BAQYA;;;eAAAA;;;4BANO;2BACyC;yBAClC;6BACL;AAGf,MAAMA,gBAAgBC,IAAAA,qBAAU,EACrC,iBACA;IACEC,IAAIC,IAAAA,iBAAM,EAAC,MAAM;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAAGC,aAAa,GAAGC,UAAU;IAC/EC,YAAYL,IAAAA,iBAAM,EAAC,cAAc;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAAGI,UAAU,CAAC,IAAMC,kBAAK,CAACR,EAAE,EAAE;QAAES,UAAU;IAAU;IACtHC,UAAUT,IAAAA,iBAAM,EAAC,YAAY;QAAEC,MAAM;QAAUC,UAAU;IAAK,GAC3DI,UAAU,CAAC,IAAMC,kBAAK,CAACR,EAAE,EAAE;QAAES,UAAU;IAAU,GACjDE,OAAO;IACVC,SAASC,IAAAA,mBAAU,IAAwB;IAC3CC,SAASC,IAAAA,kBAAO,EAAC,WAAWC,OAAO,CAAC,OAAOL,OAAO;IAClDM,WAAWC,IAAAA,mBAAQ,EAAC,aAAa;QAAEhB,MAAM;IAAO,GAC7Cc,OAAO,CAACG,IAAAA,eAAG,CAAA,CAAC,iBAAiB,CAAC,EAC9BR,OAAO;AACZ,GACA,CAACS,QAAU;QAACC,IAAAA,gBAAK,EAAC,iBAAiBC,EAAE,CAACF,MAAMd,UAAU;QAAGe,IAAAA,gBAAK,EAAC,eAAeC,EAAE,CAACF,MAAMV,QAAQ;KAAE"}
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "NotificationsManager", {
15
15
  const _common = require("@nestjs/common");
16
16
  const _mailerservice = require("../../../infrastructure/mailer/mailer.service");
17
17
  const _user = require("../../users/constants/user");
18
- const _usersmanagerservice = require("../../users/services/users-manager.service");
18
+ const _avatar = require("../../users/utils/avatar");
19
19
  const _notifications = require("../constants/notifications");
20
20
  const _websocket = require("../constants/websocket");
21
21
  const _models = require("../mails/models");
@@ -56,20 +56,12 @@ let NotificationsManager = class NotificationsManager {
56
56
  async delete(user, notificationId) {
57
57
  return this.notificationsQueries.delete(user.id, notificationId);
58
58
  }
59
- async storeNotification(toUserIds, content, authorId) {
60
- // store it in db
61
- try {
62
- await this.notificationsQueries.create(authorId || null, toUserIds, content);
63
- } catch (e) {
64
- this.logger.error(`${this.create.name} - ${e}`);
65
- }
66
- }
67
59
  async sendEmailNotification(toUsers, content, options) {
68
60
  if (!this.mailer.available) {
69
61
  return;
70
62
  }
71
63
  if (options?.author) {
72
- options.author.avatarBase64 = await this.usersManager.getAvatarBase64(options.author.login);
64
+ options.author.avatarBase64 = await (0, _avatar.getAvatarBase64)(options.author.login);
73
65
  }
74
66
  this.mailer.sendMails(await Promise.all(toUsers.map(async (m)=>{
75
67
  const [title, html] = this.genMail(m.language, content, options);
@@ -80,6 +72,14 @@ let NotificationsManager = class NotificationsManager {
80
72
  };
81
73
  }))).catch((e)=>this.logger.error(`${this.sendEmailNotification.name} - ${e}`));
82
74
  }
75
+ async storeNotification(toUserIds, content, authorId) {
76
+ // store it in db
77
+ try {
78
+ await this.notificationsQueries.create(authorId || null, toUserIds, content);
79
+ } catch (e) {
80
+ this.logger.error(`${this.create.name} - ${e}`);
81
+ }
82
+ }
83
83
  genMail(language, content, options) {
84
84
  switch(content.app){
85
85
  case _notifications.NOTIFICATION_APP.COMMENTS:
@@ -110,6 +110,7 @@ let NotificationsManager = class NotificationsManager {
110
110
  currentUrl: options.currentUrl,
111
111
  author: options.author,
112
112
  linkUUID: options.linkUUID,
113
+ linkPassword: options.linkPassword,
113
114
  action: options.action
114
115
  });
115
116
  case _notifications.NOTIFICATION_APP.SYNC:
@@ -117,12 +118,15 @@ let NotificationsManager = class NotificationsManager {
117
118
  currentUrl: options.currentUrl,
118
119
  action: options.action
119
120
  });
121
+ case _notifications.NOTIFICATION_APP.AUTH_2FA:
122
+ return (0, _models.auth2FaMail)(language, content);
123
+ case _notifications.NOTIFICATION_APP.AUTH_LOCKED:
124
+ return (0, _models.authLocked)(language, content);
120
125
  default:
121
126
  this.logger.error(`${this.genMail.name} - case not handled : ${content.app}`);
122
127
  }
123
128
  }
124
- constructor(usersManager, mailer, notificationsQueries, webSocketNotifications){
125
- this.usersManager = usersManager;
129
+ constructor(mailer, notificationsQueries, webSocketNotifications){
126
130
  this.mailer = mailer;
127
131
  this.notificationsQueries = notificationsQueries;
128
132
  this.webSocketNotifications = webSocketNotifications;
@@ -133,7 +137,6 @@ NotificationsManager = _ts_decorate([
133
137
  (0, _common.Injectable)(),
134
138
  _ts_metadata("design:type", Function),
135
139
  _ts_metadata("design:paramtypes", [
136
- typeof _usersmanagerservice.UsersManager === "undefined" ? Object : _usersmanagerservice.UsersManager,
137
140
  typeof _mailerservice.Mailer === "undefined" ? Object : _mailerservice.Mailer,
138
141
  typeof _notificationsqueriesservice.NotificationsQueries === "undefined" ? Object : _notificationsqueriesservice.NotificationsQueries,
139
142
  typeof _notificationsgateway.WebSocketNotifications === "undefined" ? Object : _notificationsgateway.WebSocketNotifications
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-manager.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, Logger } from '@nestjs/common'\nimport { MailProps } from '../../../infrastructure/mailer/interfaces/mail.interface'\nimport { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { NOTIFICATION_APP } from '../constants/notifications'\nimport { NOTIFICATIONS_WS } from '../constants/websocket'\nimport type { NotificationContent, NotificationFromUser, NotificationOptions } from '../interfaces/notification-properties.interface'\nimport type { UserMailNotification } from '../interfaces/user-mail-notification'\nimport { commentMail, linkMail, shareMail, spaceMail, spaceRootMail, syncMail } from '../mails/models'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsQueries } from './notifications-queries.service'\n\n@Injectable()\nexport class NotificationsManager {\n private readonly logger = new Logger(NotificationsManager.name)\n\n constructor(\n private readonly usersManager: UsersManager,\n private readonly mailer: Mailer,\n private readonly notificationsQueries: NotificationsQueries,\n private readonly webSocketNotifications: WebSocketNotifications\n ) {}\n\n list(user: UserModel, onlyUnread: boolean = false): Promise<NotificationFromUser[]> {\n return this.notificationsQueries.list(user.id, onlyUnread)\n }\n\n async create(toUsers: UserMailNotification[] | number[], content: NotificationContent, options?: NotificationOptions): Promise<void> {\n // store it in db\n const isArrayOfUsers: boolean = typeof toUsers[0] === 'object'\n const toUserIds = isArrayOfUsers ? (toUsers as UserMailNotification[]).map((m) => m.id) : (toUsers as number[])\n this.storeNotification(toUserIds, content, options?.author?.id).catch((e: Error) => this.logger.error(`${this.create.name} - ${e}`))\n\n // send websocket notification\n this.webSocketNotifications.sendMessageToUsers(toUserIds, NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n\n // send emails\n if (this.mailer.available) {\n const usersNotifiedByEmail: UserMailNotification[] = isArrayOfUsers\n ? (toUsers as UserMailNotification[]).filter((u) => u.notification === USER_NOTIFICATION.APPLICATION_EMAIL)\n : await this.notificationsQueries.usersNotifiedByEmail(toUsers as number[])\n if (!usersNotifiedByEmail.length) {\n return\n }\n this.sendEmailNotification(usersNotifiedByEmail, content, options).catch((e: Error) => this.logger.error(`${this.create.name} - ${e}`))\n }\n }\n\n wasRead(user: UserModel, notificationId?: number): void {\n this.notificationsQueries.wasRead(user.id, notificationId).catch((e: Error) => this.logger.error(`${this.wasRead.name} - ${e}`))\n }\n\n async delete(user: UserModel, notificationId?: number): Promise<void> {\n return this.notificationsQueries.delete(user.id, notificationId)\n }\n\n private async storeNotification(toUserIds: number[], content: NotificationContent, authorId?: number): Promise<void> {\n // store it in db\n try {\n await this.notificationsQueries.create(authorId || null, toUserIds, content)\n } catch (e) {\n this.logger.error(`${this.create.name} - ${e}`)\n }\n }\n\n async sendEmailNotification(toUsers: UserMailNotification[], content: NotificationContent, options?: NotificationOptions): Promise<void> {\n if (!this.mailer.available) {\n return\n }\n if (options?.author) {\n options.author.avatarBase64 = await this.usersManager.getAvatarBase64(options.author.login)\n }\n this.mailer\n .sendMails(\n await Promise.all(\n toUsers.map(async (m) => {\n const [title, html] = this.genMail(m.language, content, options)\n return {\n to: m.email,\n subject: title,\n html: html\n } satisfies MailProps\n })\n )\n )\n .catch((e: Error) => this.logger.error(`${this.sendEmailNotification.name} - ${e}`))\n }\n\n private genMail(language: string, content: NotificationContent, options?: NotificationOptions): [string, string] {\n switch (content.app) {\n case NOTIFICATION_APP.COMMENTS:\n return commentMail(language, content, { content: options.content, currentUrl: options.currentUrl, author: options.author })\n case NOTIFICATION_APP.SPACES:\n return spaceMail(language, content, { currentUrl: options.currentUrl, action: options.action })\n case NOTIFICATION_APP.SPACE_ROOTS:\n return spaceRootMail(language, content, { currentUrl: options.currentUrl, author: options.author, action: options.action })\n case NOTIFICATION_APP.SHARES:\n return shareMail(language, content, { currentUrl: options.currentUrl, author: options.author, action: options.action })\n case NOTIFICATION_APP.LINKS:\n return linkMail(language, content, {\n currentUrl: options.currentUrl,\n author: options.author,\n linkUUID: options.linkUUID,\n action: options.action\n })\n case NOTIFICATION_APP.SYNC:\n return syncMail(language, content, { currentUrl: options.currentUrl, action: options.action })\n default:\n this.logger.error(`${this.genMail.name} - case not handled : ${content.app}`)\n }\n }\n}\n"],"names":["NotificationsManager","list","user","onlyUnread","notificationsQueries","id","create","toUsers","content","options","isArrayOfUsers","toUserIds","map","m","storeNotification","author","catch","e","logger","error","name","webSocketNotifications","sendMessageToUsers","NOTIFICATIONS_WS","EVENTS","NOTIFICATION","mailer","available","usersNotifiedByEmail","filter","u","notification","USER_NOTIFICATION","APPLICATION_EMAIL","length","sendEmailNotification","wasRead","notificationId","delete","authorId","avatarBase64","usersManager","getAvatarBase64","login","sendMails","Promise","all","title","html","genMail","language","to","email","subject","app","NOTIFICATION_APP","COMMENTS","commentMail","currentUrl","SPACES","spaceMail","action","SPACE_ROOTS","spaceRootMail","SHARES","shareMail","LINKS","linkMail","linkUUID","SYNC","syncMail","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-manager.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, Logger } from '@nestjs/common'\nimport { MailProps } from '../../../infrastructure/mailer/interfaces/mail.interface'\nimport { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { NOTIFICATION_APP } from '../constants/notifications'\nimport { NOTIFICATIONS_WS } from '../constants/websocket'\nimport type { NotificationContent, NotificationFromUser, NotificationOptions } from '../interfaces/notification-properties.interface'\nimport type { UserMailNotification } from '../interfaces/user-mail-notification'\nimport { auth2FaMail, authLocked, commentMail, linkMail, shareMail, spaceMail, spaceRootMail, syncMail } from '../mails/models'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsQueries } from './notifications-queries.service'\n\n@Injectable()\nexport class NotificationsManager {\n private readonly logger = new Logger(NotificationsManager.name)\n\n constructor(\n private readonly mailer: Mailer,\n private readonly notificationsQueries: NotificationsQueries,\n private readonly webSocketNotifications: WebSocketNotifications\n ) {}\n\n list(user: UserModel, onlyUnread: boolean = false): Promise<NotificationFromUser[]> {\n return this.notificationsQueries.list(user.id, onlyUnread)\n }\n\n async create(toUsers: UserMailNotification[] | number[], content: NotificationContent, options?: NotificationOptions): Promise<void> {\n // store it in db\n const isArrayOfUsers: boolean = typeof toUsers[0] === 'object'\n const toUserIds = isArrayOfUsers ? (toUsers as UserMailNotification[]).map((m) => m.id) : (toUsers as number[])\n this.storeNotification(toUserIds, content, options?.author?.id).catch((e: Error) => this.logger.error(`${this.create.name} - ${e}`))\n\n // send websocket notification\n this.webSocketNotifications.sendMessageToUsers(toUserIds, NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n\n // send emails\n if (this.mailer.available) {\n const usersNotifiedByEmail: UserMailNotification[] = isArrayOfUsers\n ? (toUsers as UserMailNotification[]).filter((u) => u.notification === USER_NOTIFICATION.APPLICATION_EMAIL)\n : await this.notificationsQueries.usersNotifiedByEmail(toUsers as number[])\n if (!usersNotifiedByEmail.length) {\n return\n }\n this.sendEmailNotification(usersNotifiedByEmail, content, options).catch((e: Error) => this.logger.error(`${this.create.name} - ${e}`))\n }\n }\n\n wasRead(user: UserModel, notificationId?: number): void {\n this.notificationsQueries.wasRead(user.id, notificationId).catch((e: Error) => this.logger.error(`${this.wasRead.name} - ${e}`))\n }\n\n async delete(user: UserModel, notificationId?: number): Promise<void> {\n return this.notificationsQueries.delete(user.id, notificationId)\n }\n\n async sendEmailNotification(toUsers: UserMailNotification[], content: NotificationContent, options?: NotificationOptions): Promise<void> {\n if (!this.mailer.available) {\n return\n }\n if (options?.author) {\n options.author.avatarBase64 = await getAvatarBase64(options.author.login)\n }\n this.mailer\n .sendMails(\n await Promise.all(\n toUsers.map(async (m) => {\n const [title, html] = this.genMail(m.language, content, options)\n return {\n to: m.email,\n subject: title,\n html: html\n } satisfies MailProps\n })\n )\n )\n .catch((e: Error) => this.logger.error(`${this.sendEmailNotification.name} - ${e}`))\n }\n\n private async storeNotification(toUserIds: number[], content: NotificationContent, authorId?: number): Promise<void> {\n // store it in db\n try {\n await this.notificationsQueries.create(authorId || null, toUserIds, content)\n } catch (e) {\n this.logger.error(`${this.create.name} - ${e}`)\n }\n }\n\n private genMail(language: string, content: NotificationContent, options?: NotificationOptions): [string, string] {\n switch (content.app) {\n case NOTIFICATION_APP.COMMENTS:\n return commentMail(language, content, { content: options.content, currentUrl: options.currentUrl, author: options.author })\n case NOTIFICATION_APP.SPACES:\n return spaceMail(language, content, { currentUrl: options.currentUrl, action: options.action })\n case NOTIFICATION_APP.SPACE_ROOTS:\n return spaceRootMail(language, content, { currentUrl: options.currentUrl, author: options.author, action: options.action })\n case NOTIFICATION_APP.SHARES:\n return shareMail(language, content, { currentUrl: options.currentUrl, author: options.author, action: options.action })\n case NOTIFICATION_APP.LINKS:\n return linkMail(language, content, {\n currentUrl: options.currentUrl,\n author: options.author,\n linkUUID: options.linkUUID,\n linkPassword: options.linkPassword,\n action: options.action\n })\n case NOTIFICATION_APP.SYNC:\n return syncMail(language, content, { currentUrl: options.currentUrl, action: options.action })\n case NOTIFICATION_APP.AUTH_2FA:\n return auth2FaMail(language, content)\n case NOTIFICATION_APP.AUTH_LOCKED:\n return authLocked(language, content)\n default:\n this.logger.error(`${this.genMail.name} - case not handled : ${content.app}`)\n }\n }\n}\n"],"names":["NotificationsManager","list","user","onlyUnread","notificationsQueries","id","create","toUsers","content","options","isArrayOfUsers","toUserIds","map","m","storeNotification","author","catch","e","logger","error","name","webSocketNotifications","sendMessageToUsers","NOTIFICATIONS_WS","EVENTS","NOTIFICATION","mailer","available","usersNotifiedByEmail","filter","u","notification","USER_NOTIFICATION","APPLICATION_EMAIL","length","sendEmailNotification","wasRead","notificationId","delete","avatarBase64","getAvatarBase64","login","sendMails","Promise","all","title","html","genMail","language","to","email","subject","authorId","app","NOTIFICATION_APP","COMMENTS","commentMail","currentUrl","SPACES","spaceMail","action","SPACE_ROOTS","spaceRootMail","SHARES","shareMail","LINKS","linkMail","linkUUID","linkPassword","SYNC","syncMail","AUTH_2FA","auth2FaMail","AUTH_LOCKED","authLocked","Logger"],"mappings":"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"}
@@ -10,6 +10,7 @@ const _testing = require("@nestjs/testing");
10
10
  const _mailerservice = require("../../../infrastructure/mailer/mailer.service");
11
11
  const _user = require("../../users/constants/user");
12
12
  const _usersmanagerservice = require("../../users/services/users-manager.service");
13
+ const _avatar = require("../../users/utils/avatar");
13
14
  const _notifications = require("../constants/notifications");
14
15
  const _websocket = require("../constants/websocket");
15
16
  const _models = /*#__PURE__*/ _interop_require_wildcard(require("../mails/models"));
@@ -84,11 +85,11 @@ jest.mock('../mails/models', ()=>({
84
85
  'sync html'
85
86
  ])
86
87
  }));
88
+ jest.mock('../../users/utils/avatar', ()=>({
89
+ getAvatarBase64: jest.fn()
90
+ }));
87
91
  describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
88
92
  let service;
89
- const usersManagerMock = {
90
- getAvatarBase64: jest.fn()
91
- };
92
93
  const mailerMock = {
93
94
  available: true,
94
95
  sendMails: jest.fn()
@@ -114,13 +115,12 @@ describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
114
115
  notificationsQueriesMock.delete.mockResolvedValue(undefined);
115
116
  notificationsQueriesMock.list.mockResolvedValue([]);
116
117
  notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValue([]);
117
- usersManagerMock.getAvatarBase64.mockResolvedValue('avatar-base64');
118
118
  const module = await _testing.Test.createTestingModule({
119
119
  providers: [
120
120
  _notificationsmanagerservice.NotificationsManager,
121
121
  {
122
122
  provide: _usersmanagerservice.UsersManager,
123
- useValue: usersManagerMock
123
+ useValue: {}
124
124
  },
125
125
  {
126
126
  provide: _mailerservice.Mailer,
@@ -342,11 +342,12 @@ describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
342
342
  login: 'john'
343
343
  }
344
344
  });
345
- expect(usersManagerMock.getAvatarBase64).not.toHaveBeenCalled();
345
+ expect(_avatar.getAvatarBase64).not.toHaveBeenCalled();
346
346
  expect(mailerMock.sendMails).not.toHaveBeenCalled();
347
347
  });
348
348
  it('enriches author avatar and sends mapped mails', async ()=>{
349
- usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-xxx');
349
+ ;
350
+ _avatar.getAvatarBase64.mockResolvedValueOnce('base64-xxx');
350
351
  const toUsers = [
351
352
  {
352
353
  id: 1,
@@ -371,7 +372,7 @@ describe(_notificationsmanagerservice.NotificationsManager.name, ()=>{
371
372
  app: _notifications.NOTIFICATION_APP.COMMENTS
372
373
  };
373
374
  await service.sendEmailNotification(toUsers, content, options);
374
- expect(usersManagerMock.getAvatarBase64).toHaveBeenCalledWith('jdoe');
375
+ expect(_avatar.getAvatarBase64).toHaveBeenCalledWith('jdoe');
375
376
  expect(options.author.avatarBase64).toBe('base64-xxx');
376
377
  expect(mailerMock.sendMails).toHaveBeenCalledTimes(1);
377
378
  expect(mailerMock.sendMails.mock.calls[0][0]).toEqual([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-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 { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { NOTIFICATION_APP } from '../constants/notifications'\nimport { NOTIFICATIONS_WS } from '../constants/websocket'\nimport * as mailModels from '../mails/models'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsManager } from './notifications-manager.service'\nimport { NotificationsQueries } from './notifications-queries.service'\n\n// Compact mock for mail generators\njest.mock('../mails/models', () => ({\n commentMail: jest.fn(() => ['comment title', 'comment html']),\n spaceMail: jest.fn(() => ['space title', 'space html']),\n spaceRootMail: jest.fn(() => ['spaceRoot title', 'spaceRoot html']),\n shareMail: jest.fn(() => ['share title', 'share html']),\n linkMail: jest.fn(() => ['link title', 'link html']),\n syncMail: jest.fn(() => ['sync title', 'sync html'])\n}))\n\ndescribe(NotificationsManager.name, () => {\n let service: NotificationsManager\n\n const usersManagerMock = { getAvatarBase64: jest.fn() }\n const mailerMock = { available: true, sendMails: jest.fn() }\n const notificationsQueriesMock = {\n list: jest.fn(),\n usersNotifiedByEmail: jest.fn(),\n create: jest.fn(),\n wasRead: jest.fn(),\n delete: jest.fn()\n }\n const webSocketNotificationsMock = { sendMessageToUsers: jest.fn() }\n\n const flushPromises = () => new Promise<void>((r) => setImmediate(r))\n const spyLogger = () => jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n\n beforeEach(async () => {\n jest.clearAllMocks()\n mailerMock.available = true\n mailerMock.sendMails.mockResolvedValue(undefined)\n notificationsQueriesMock.create.mockResolvedValue(undefined)\n notificationsQueriesMock.wasRead.mockResolvedValue(undefined)\n notificationsQueriesMock.delete.mockResolvedValue(undefined)\n notificationsQueriesMock.list.mockResolvedValue([])\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValue([])\n usersManagerMock.getAvatarBase64.mockResolvedValue('avatar-base64')\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n NotificationsManager,\n { provide: UsersManager, useValue: usersManagerMock },\n { provide: Mailer, useValue: mailerMock },\n { provide: WebSocketNotifications, useValue: webSocketNotificationsMock },\n { provide: NotificationsQueries, useValue: notificationsQueriesMock }\n ]\n }).compile()\n service = module.get<NotificationsManager>(NotificationsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('list', () => {\n it.each`\n userId | onlyUnread | expected\n ${42} | ${true} | ${true}\n ${1} | ${undefined} | ${false}\n `('should list notifications (userId=$userId, onlyUnread=$onlyUnread)', async ({ userId, onlyUnread, expected }) => {\n const expectedRes = [{ id: userId }] as any\n notificationsQueriesMock.list.mockResolvedValueOnce(expectedRes)\n const res = await service.list({ id: userId } as any, onlyUnread as any)\n expect(notificationsQueriesMock.list).toHaveBeenCalledWith(userId, expected)\n expect(res).toBe(expectedRes)\n })\n })\n\n describe('create', () => {\n it('stores, sends WS and no email when filtered list empty (object input)', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUsers = [\n { id: 10, email: 'u1@test.tld', language: 'en', notification: USER_NOTIFICATION.APPLICATION },\n { id: 11, email: 'u2@test.tld', language: 'fr', notification: USER_NOTIFICATION.APPLICATION }\n ]\n await service.create(toUsers as any, { app: NOTIFICATION_APP.COMMENTS } as any, { author: { id: 99, login: 'john' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(99, [10, 11], { app: NOTIFICATION_APP.COMMENTS })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([10, 11], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(sendEmailSpy).not.toHaveBeenCalled()\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n })\n\n it('stores, sends WS and email for ids input', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUserIds = [1, 2, 3]\n const content = { app: NOTIFICATION_APP.SHARES } as any\n const emailUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 3, email: 'c@test', language: 'fr' }\n ]\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce(emailUsers as any)\n await service.create(toUserIds, content)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(null, toUserIds, content)\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith(toUserIds, NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).toHaveBeenCalledWith(toUserIds)\n expect(sendEmailSpy).toHaveBeenCalledWith(emailUsers as any, content, undefined)\n })\n\n it('does not try email when mailer is unavailable', async () => {\n mailerMock.available = false\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n await service.create([7], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 12, login: 'jane' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(12, [7], { app: NOTIFICATION_APP.SYNC })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([7], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n expect(sendEmailSpy).not.toHaveBeenCalled()\n })\n\n it('logs error when storeNotification internal try/catch catches create error', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.create.mockRejectedValueOnce(new Error('DB fail'))\n await service.create([1], { app: NOTIFICATION_APP.LINKS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when storeNotification promise rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n jest.spyOn<any, any>(service as any, 'storeNotification').mockRejectedValueOnce(new Error('store reject'))\n await service.create([1, 2], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 5, login: 'xx' } } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when sendEmailNotification rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce([{ id: 1, email: 'a@test', language: 'en' }] as any)\n jest.spyOn(service, 'sendEmailNotification').mockRejectedValueOnce(new Error('email reject'))\n await service.create([1], { app: NOTIFICATION_APP.COMMENTS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n })\n\n describe('wasRead', () => {\n it('calls queries.wasRead and logs on error', async () => {\n service.wasRead({ id: 5 } as any, 123)\n expect(notificationsQueriesMock.wasRead).toHaveBeenCalledWith(5, 123)\n const loggerSpy = spyLogger()\n notificationsQueriesMock.wasRead.mockRejectedValueOnce(new Error('fail'))\n service.wasRead({ id: 8 } as any, undefined)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/wasRead/i)\n })\n })\n\n describe('delete', () => {\n it('forwards to queries.delete', async () => {\n await service.delete({ id: 77 } as any, 456)\n expect(notificationsQueriesMock.delete).toHaveBeenCalledWith(77, 456)\n })\n })\n\n describe('sendEmailNotification', () => {\n it('returns early when mailer is not available', async () => {\n mailerMock.available = false\n await service.sendEmailNotification(\n [{ id: 1, email: 'a@test', language: 'en' }] as any,\n { app: NOTIFICATION_APP.COMMENTS } as any,\n {\n author: { id: 1, login: 'john' }\n } as any\n )\n expect(usersManagerMock.getAvatarBase64).not.toHaveBeenCalled()\n expect(mailerMock.sendMails).not.toHaveBeenCalled()\n })\n\n it('enriches author avatar and sends mapped mails', async () => {\n usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-xxx')\n const toUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 2, email: 'b@test', language: 'fr' }\n ]\n const options: any = { author: { id: 9, login: 'jdoe' }, content: 'hello', currentUrl: 'https://app.test/path' }\n const content = { app: NOTIFICATION_APP.COMMENTS } as any\n await service.sendEmailNotification(toUsers as any, content, options)\n expect(usersManagerMock.getAvatarBase64).toHaveBeenCalledWith('jdoe')\n expect(options.author.avatarBase64).toBe('base64-xxx')\n expect(mailerMock.sendMails).toHaveBeenCalledTimes(1)\n expect((mailerMock.sendMails as jest.Mock).mock.calls[0][0]).toEqual([\n { to: 'a@test', subject: 'comment title', html: 'comment html' },\n { to: 'b@test', subject: 'comment title', html: 'comment html' }\n ])\n })\n\n it('logs error when sendMails rejects', async () => {\n mailerMock.sendMails.mockRejectedValueOnce(new Error('smtp down'))\n const loggerSpy = spyLogger()\n await service.sendEmailNotification([{ id: 1, email: 'a@test', language: 'en' }] as any, { app: NOTIFICATION_APP.SYNC } as any, {} as any)\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/sendEmailNotification/i)\n })\n })\n\n describe('genMail (private) - switch coverage', () => {\n const cases = [\n {\n name: 'COMMENTS',\n app: NOTIFICATION_APP.COMMENTS,\n fn: 'commentMail',\n options: { content: 'c', currentUrl: 'u', author: { id: 1, login: 'x' } }\n },\n { name: 'SPACES', app: NOTIFICATION_APP.SPACES, fn: 'spaceMail', options: { currentUrl: 'u', action: 'A' } },\n {\n name: 'SPACE_ROOTS',\n app: NOTIFICATION_APP.SPACE_ROOTS,\n fn: 'spaceRootMail',\n options: { currentUrl: 'u', author: { id: 2, login: 'y' }, action: 'B' }\n },\n { name: 'SHARES', app: NOTIFICATION_APP.SHARES, fn: 'shareMail', options: { currentUrl: 'u', author: { id: 3, login: 'z' }, action: 'C' } },\n {\n name: 'LINKS',\n app: NOTIFICATION_APP.LINKS,\n fn: 'linkMail',\n options: { currentUrl: 'u', author: { id: 4, login: 'w' }, linkUUID: 'uuid', action: 'D' }\n },\n { name: 'SYNC', app: NOTIFICATION_APP.SYNC, fn: 'syncMail', options: { currentUrl: 'u', action: 'E' } }\n ] as const\n\n it.each(cases)('uses $fn for $name', ({ app, fn, options }) => {\n const res = (service as any).genMail('en', { app } as any, options as any)\n expect(res).toEqual([\n `${fn.replace('Mail', '')} title`.replace('spaceRoot', 'spaceRoot'),\n `${fn.replace('Mail', '')} html`.replace('spaceRoot', 'spaceRoot')\n ])\n expect((mailModels as any)[fn]).toHaveBeenCalled()\n })\n\n it('logs error for unhandled app', () => {\n const loggerSpy = spyLogger()\n const result = (service as any).genMail('en', { app: 99999 } as any, {} as any)\n expect(result).toBeUndefined()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/case not handled/i)\n })\n })\n})\n"],"names":["jest","mock","commentMail","fn","spaceMail","spaceRootMail","shareMail","linkMail","syncMail","describe","NotificationsManager","name","service","usersManagerMock","getAvatarBase64","mailerMock","available","sendMails","notificationsQueriesMock","list","usersNotifiedByEmail","create","wasRead","delete","webSocketNotificationsMock","sendMessageToUsers","flushPromises","Promise","r","setImmediate","spyLogger","spyOn","logger","mockImplementation","undefined","beforeEach","clearAllMocks","mockResolvedValue","module","Test","createTestingModule","providers","provide","UsersManager","useValue","Mailer","WebSocketNotifications","NotificationsQueries","compile","get","it","expect","toBeDefined","each","userId","onlyUnread","expected","expectedRes","id","mockResolvedValueOnce","res","toHaveBeenCalledWith","toBe","sendEmailSpy","toUsers","email","language","notification","USER_NOTIFICATION","APPLICATION","app","NOTIFICATION_APP","COMMENTS","author","login","NOTIFICATIONS_WS","EVENTS","NOTIFICATION","not","toHaveBeenCalled","toUserIds","content","SHARES","emailUsers","SYNC","loggerSpy","mockRejectedValueOnce","Error","LINKS","calls","toMatch","sendEmailNotification","options","currentUrl","avatarBase64","toHaveBeenCalledTimes","toEqual","to","subject","html","cases","SPACES","action","SPACE_ROOTS","linkUUID","genMail","replace","mailModels","result","toBeUndefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-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 { Mailer } from '../../../infrastructure/mailer/mailer.service'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { NOTIFICATION_APP } from '../constants/notifications'\nimport { NOTIFICATIONS_WS } from '../constants/websocket'\nimport * as mailModels from '../mails/models'\nimport { WebSocketNotifications } from '../notifications.gateway'\nimport { NotificationsManager } from './notifications-manager.service'\nimport { NotificationsQueries } from './notifications-queries.service'\n\n// Compact mock for mail generators\njest.mock('../mails/models', () => ({\n commentMail: jest.fn(() => ['comment title', 'comment html']),\n spaceMail: jest.fn(() => ['space title', 'space html']),\n spaceRootMail: jest.fn(() => ['spaceRoot title', 'spaceRoot html']),\n shareMail: jest.fn(() => ['share title', 'share html']),\n linkMail: jest.fn(() => ['link title', 'link html']),\n syncMail: jest.fn(() => ['sync title', 'sync html'])\n}))\n\njest.mock('../../users/utils/avatar', () => ({\n getAvatarBase64: jest.fn()\n}))\n\ndescribe(NotificationsManager.name, () => {\n let service: NotificationsManager\n\n const mailerMock = { available: true, sendMails: jest.fn() }\n const notificationsQueriesMock = {\n list: jest.fn(),\n usersNotifiedByEmail: jest.fn(),\n create: jest.fn(),\n wasRead: jest.fn(),\n delete: jest.fn()\n }\n const webSocketNotificationsMock = { sendMessageToUsers: jest.fn() }\n\n const flushPromises = () => new Promise<void>((r) => setImmediate(r))\n const spyLogger = () => jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n\n beforeEach(async () => {\n jest.clearAllMocks()\n mailerMock.available = true\n mailerMock.sendMails.mockResolvedValue(undefined)\n notificationsQueriesMock.create.mockResolvedValue(undefined)\n notificationsQueriesMock.wasRead.mockResolvedValue(undefined)\n notificationsQueriesMock.delete.mockResolvedValue(undefined)\n notificationsQueriesMock.list.mockResolvedValue([])\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValue([])\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n NotificationsManager,\n { provide: UsersManager, useValue: {} },\n { provide: Mailer, useValue: mailerMock },\n { provide: WebSocketNotifications, useValue: webSocketNotificationsMock },\n { provide: NotificationsQueries, useValue: notificationsQueriesMock }\n ]\n }).compile()\n service = module.get<NotificationsManager>(NotificationsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('list', () => {\n it.each`\n userId | onlyUnread | expected\n ${42} | ${true} | ${true}\n ${1} | ${undefined} | ${false}\n `('should list notifications (userId=$userId, onlyUnread=$onlyUnread)', async ({ userId, onlyUnread, expected }) => {\n const expectedRes = [{ id: userId }] as any\n notificationsQueriesMock.list.mockResolvedValueOnce(expectedRes)\n const res = await service.list({ id: userId } as any, onlyUnread as any)\n expect(notificationsQueriesMock.list).toHaveBeenCalledWith(userId, expected)\n expect(res).toBe(expectedRes)\n })\n })\n\n describe('create', () => {\n it('stores, sends WS and no email when filtered list empty (object input)', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUsers = [\n { id: 10, email: 'u1@test.tld', language: 'en', notification: USER_NOTIFICATION.APPLICATION },\n { id: 11, email: 'u2@test.tld', language: 'fr', notification: USER_NOTIFICATION.APPLICATION }\n ]\n await service.create(toUsers as any, { app: NOTIFICATION_APP.COMMENTS } as any, { author: { id: 99, login: 'john' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(99, [10, 11], { app: NOTIFICATION_APP.COMMENTS })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([10, 11], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(sendEmailSpy).not.toHaveBeenCalled()\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n })\n\n it('stores, sends WS and email for ids input', async () => {\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n const toUserIds = [1, 2, 3]\n const content = { app: NOTIFICATION_APP.SHARES } as any\n const emailUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 3, email: 'c@test', language: 'fr' }\n ]\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce(emailUsers as any)\n await service.create(toUserIds, content)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(null, toUserIds, content)\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith(toUserIds, NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).toHaveBeenCalledWith(toUserIds)\n expect(sendEmailSpy).toHaveBeenCalledWith(emailUsers as any, content, undefined)\n })\n\n it('does not try email when mailer is unavailable', async () => {\n mailerMock.available = false\n const sendEmailSpy = jest.spyOn(service, 'sendEmailNotification').mockResolvedValue(undefined)\n await service.create([7], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 12, login: 'jane' } } as any)\n expect(notificationsQueriesMock.create).toHaveBeenCalledWith(12, [7], { app: NOTIFICATION_APP.SYNC })\n expect(webSocketNotificationsMock.sendMessageToUsers).toHaveBeenCalledWith([7], NOTIFICATIONS_WS.EVENTS.NOTIFICATION, 'check')\n expect(notificationsQueriesMock.usersNotifiedByEmail).not.toHaveBeenCalled()\n expect(sendEmailSpy).not.toHaveBeenCalled()\n })\n\n it('logs error when storeNotification internal try/catch catches create error', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.create.mockRejectedValueOnce(new Error('DB fail'))\n await service.create([1], { app: NOTIFICATION_APP.LINKS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when storeNotification promise rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n jest.spyOn<any, any>(service as any, 'storeNotification').mockRejectedValueOnce(new Error('store reject'))\n await service.create([1, 2], { app: NOTIFICATION_APP.SYNC } as any, { author: { id: 5, login: 'xx' } } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n\n it('logs error when sendEmailNotification rejects (create catch)', async () => {\n const loggerSpy = spyLogger()\n notificationsQueriesMock.usersNotifiedByEmail.mockResolvedValueOnce([{ id: 1, email: 'a@test', language: 'en' }] as any)\n jest.spyOn(service, 'sendEmailNotification').mockRejectedValueOnce(new Error('email reject'))\n await service.create([1], { app: NOTIFICATION_APP.COMMENTS } as any)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/create/i)\n })\n })\n\n describe('wasRead', () => {\n it('calls queries.wasRead and logs on error', async () => {\n service.wasRead({ id: 5 } as any, 123)\n expect(notificationsQueriesMock.wasRead).toHaveBeenCalledWith(5, 123)\n const loggerSpy = spyLogger()\n notificationsQueriesMock.wasRead.mockRejectedValueOnce(new Error('fail'))\n service.wasRead({ id: 8 } as any, undefined)\n await flushPromises()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/wasRead/i)\n })\n })\n\n describe('delete', () => {\n it('forwards to queries.delete', async () => {\n await service.delete({ id: 77 } as any, 456)\n expect(notificationsQueriesMock.delete).toHaveBeenCalledWith(77, 456)\n })\n })\n\n describe('sendEmailNotification', () => {\n it('returns early when mailer is not available', async () => {\n mailerMock.available = false\n await service.sendEmailNotification(\n [{ id: 1, email: 'a@test', language: 'en' }] as any,\n { app: NOTIFICATION_APP.COMMENTS } as any,\n {\n author: { id: 1, login: 'john' }\n } as any\n )\n expect(getAvatarBase64).not.toHaveBeenCalled()\n expect(mailerMock.sendMails).not.toHaveBeenCalled()\n })\n\n it('enriches author avatar and sends mapped mails', async () => {\n ;(getAvatarBase64 as jest.Mock).mockResolvedValueOnce('base64-xxx')\n const toUsers = [\n { id: 1, email: 'a@test', language: 'en' },\n { id: 2, email: 'b@test', language: 'fr' }\n ]\n const options: any = { author: { id: 9, login: 'jdoe' }, content: 'hello', currentUrl: 'https://app.test/path' }\n const content = { app: NOTIFICATION_APP.COMMENTS } as any\n await service.sendEmailNotification(toUsers as any, content, options)\n expect(getAvatarBase64).toHaveBeenCalledWith('jdoe')\n expect(options.author.avatarBase64).toBe('base64-xxx')\n expect(mailerMock.sendMails).toHaveBeenCalledTimes(1)\n expect((mailerMock.sendMails as jest.Mock).mock.calls[0][0]).toEqual([\n { to: 'a@test', subject: 'comment title', html: 'comment html' },\n { to: 'b@test', subject: 'comment title', html: 'comment html' }\n ])\n })\n\n it('logs error when sendMails rejects', async () => {\n mailerMock.sendMails.mockRejectedValueOnce(new Error('smtp down'))\n const loggerSpy = spyLogger()\n await service.sendEmailNotification([{ id: 1, email: 'a@test', language: 'en' }] as any, { app: NOTIFICATION_APP.SYNC } as any, {} as any)\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/sendEmailNotification/i)\n })\n })\n\n describe('genMail (private) - switch coverage', () => {\n const cases = [\n {\n name: 'COMMENTS',\n app: NOTIFICATION_APP.COMMENTS,\n fn: 'commentMail',\n options: { content: 'c', currentUrl: 'u', author: { id: 1, login: 'x' } }\n },\n { name: 'SPACES', app: NOTIFICATION_APP.SPACES, fn: 'spaceMail', options: { currentUrl: 'u', action: 'A' } },\n {\n name: 'SPACE_ROOTS',\n app: NOTIFICATION_APP.SPACE_ROOTS,\n fn: 'spaceRootMail',\n options: { currentUrl: 'u', author: { id: 2, login: 'y' }, action: 'B' }\n },\n { name: 'SHARES', app: NOTIFICATION_APP.SHARES, fn: 'shareMail', options: { currentUrl: 'u', author: { id: 3, login: 'z' }, action: 'C' } },\n {\n name: 'LINKS',\n app: NOTIFICATION_APP.LINKS,\n fn: 'linkMail',\n options: { currentUrl: 'u', author: { id: 4, login: 'w' }, linkUUID: 'uuid', action: 'D' }\n },\n { name: 'SYNC', app: NOTIFICATION_APP.SYNC, fn: 'syncMail', options: { currentUrl: 'u', action: 'E' } }\n ] as const\n\n it.each(cases)('uses $fn for $name', ({ app, fn, options }) => {\n const res = (service as any).genMail('en', { app } as any, options as any)\n expect(res).toEqual([\n `${fn.replace('Mail', '')} title`.replace('spaceRoot', 'spaceRoot'),\n `${fn.replace('Mail', '')} html`.replace('spaceRoot', 'spaceRoot')\n ])\n expect((mailModels as any)[fn]).toHaveBeenCalled()\n })\n\n it('logs error for unhandled app', () => {\n const loggerSpy = spyLogger()\n const result = (service as any).genMail('en', { app: 99999 } as any, {} as any)\n expect(result).toBeUndefined()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0]?.[0] as string).toMatch(/case not handled/i)\n })\n })\n})\n"],"names":["jest","mock","commentMail","fn","spaceMail","spaceRootMail","shareMail","linkMail","syncMail","getAvatarBase64","describe","NotificationsManager","name","service","mailerMock","available","sendMails","notificationsQueriesMock","list","usersNotifiedByEmail","create","wasRead","delete","webSocketNotificationsMock","sendMessageToUsers","flushPromises","Promise","r","setImmediate","spyLogger","spyOn","logger","mockImplementation","undefined","beforeEach","clearAllMocks","mockResolvedValue","module","Test","createTestingModule","providers","provide","UsersManager","useValue","Mailer","WebSocketNotifications","NotificationsQueries","compile","get","it","expect","toBeDefined","each","userId","onlyUnread","expected","expectedRes","id","mockResolvedValueOnce","res","toHaveBeenCalledWith","toBe","sendEmailSpy","toUsers","email","language","notification","USER_NOTIFICATION","APPLICATION","app","NOTIFICATION_APP","COMMENTS","author","login","NOTIFICATIONS_WS","EVENTS","NOTIFICATION","not","toHaveBeenCalled","toUserIds","content","SHARES","emailUsers","SYNC","loggerSpy","mockRejectedValueOnce","Error","LINKS","calls","toMatch","sendEmailNotification","options","currentUrl","avatarBase64","toHaveBeenCalledTimes","toEqual","to","subject","html","cases","SPACES","action","SPACE_ROOTS","linkUUID","genMail","replace","mailModels","result","toBeUndefined"],"mappings":"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"}
@@ -50,7 +50,7 @@ let NotificationsQueries = class NotificationsQueries {
50
50
  email: _usersschema.users.email,
51
51
  fullName: (0, _usersschema.userFullNameSQL)(_usersschema.users)
52
52
  },
53
- content: (0, _drizzleorm.sql)`${_notificationsschema.notifications.content}`.mapWith(JSON.parse),
53
+ content: _notificationsschema.notifications.content,
54
54
  wasRead: _notificationsschema.notifications.wasRead,
55
55
  createdAt: _notificationsschema.notifications.createdAt
56
56
  }).from(_notificationsschema.notifications).leftJoin(_usersschema.users, (0, _drizzleorm.eq)(_usersschema.users.id, _notificationsschema.notifications.fromUserId)).where((0, _drizzleorm.and)(...where)).orderBy((0, _drizzleorm.desc)(_notificationsschema.notifications.id));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-queries.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 { Inject, Injectable } from '@nestjs/common'\nimport { and, desc, eq, inArray, SelectedFields, sql, SQL } from 'drizzle-orm'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbCheckAffectedRows } from '../../../infrastructure/database/utils'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport type { NotificationContent, NotificationFromUser } from '../interfaces/notification-properties.interface'\nimport type { UserMailNotification } from '../interfaces/user-mail-notification'\nimport { Notification } from '../schemas/notification.interface'\nimport { notifications } from '../schemas/notifications.schema'\n\n@Injectable()\nexport class NotificationsQueries {\n constructor(@Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema) {}\n\n list(userId: number, onlyUnread: boolean = false): Promise<NotificationFromUser[]> {\n const where: SQL[] = [eq(notifications.toUserId, userId), ...(onlyUnread ? [eq(notifications.wasRead, false)] : [])]\n return this.db\n .select({\n id: notifications.id,\n fromUser: { id: users.id, login: users.login, email: users.email, fullName: userFullNameSQL(users) },\n content: sql`${notifications.content}`.mapWith(JSON.parse),\n wasRead: notifications.wasRead,\n createdAt: notifications.createdAt\n } satisfies NotificationFromUser | SelectedFields<any, any>)\n .from(notifications)\n .leftJoin(users, eq(users.id, notifications.fromUserId))\n .where(and(...where))\n .orderBy(desc(notifications.id))\n }\n\n async create(fromUserId: number, toUserIds: number[], content: NotificationContent): Promise<void> {\n dbCheckAffectedRows(\n await this.db.insert(notifications).values(\n toUserIds.map((toUserId: number) => ({\n fromUserId: fromUserId,\n toUserId: toUserId,\n content: content\n }))\n ),\n toUserIds.length\n )\n }\n\n async wasRead(userId: number, notificationId: number): Promise<void> {\n await this.db\n .update(notifications)\n .set({ wasRead: true } as Notification)\n .where(and(eq(notifications.toUserId, userId), eq(notifications.id, notificationId), eq(notifications.wasRead, false)))\n }\n\n async delete(userId: number, notificationId?: number): Promise<void> {\n const where: SQL[] = [eq(notifications.toUserId, userId), ...(notificationId ? [eq(notifications.id, notificationId)] : [])]\n await this.db.delete(notifications).where(and(...where))\n }\n\n usersNotifiedByEmail(userIds: number[]): Promise<UserMailNotification[]> {\n return this.db\n .select({\n id: users.id,\n email: users.email,\n language: users.language,\n notification: users.notification\n } satisfies UserMailNotification | SelectedFields<any, any>)\n .from(users)\n .where(and(inArray(users.id, userIds), eq(users.notification, USER_NOTIFICATION.APPLICATION_EMAIL)))\n }\n}\n"],"names":["NotificationsQueries","list","userId","onlyUnread","where","eq","notifications","toUserId","wasRead","db","select","id","fromUser","users","login","email","fullName","userFullNameSQL","content","sql","mapWith","JSON","parse","createdAt","from","leftJoin","fromUserId","and","orderBy","desc","create","toUserIds","dbCheckAffectedRows","insert","values","map","length","notificationId","update","set","delete","usersNotifiedByEmail","userIds","language","notification","inArray","USER_NOTIFICATION","APPLICATION_EMAIL"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/services/notifications-queries.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 { Inject, Injectable } from '@nestjs/common'\nimport { and, desc, eq, inArray, SelectedFields, SQL } from 'drizzle-orm'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbCheckAffectedRows } from '../../../infrastructure/database/utils'\nimport { USER_NOTIFICATION } from '../../users/constants/user'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport type { NotificationContent, NotificationFromUser } from '../interfaces/notification-properties.interface'\nimport type { UserMailNotification } from '../interfaces/user-mail-notification'\nimport { Notification } from '../schemas/notification.interface'\nimport { notifications } from '../schemas/notifications.schema'\n\n@Injectable()\nexport class NotificationsQueries {\n constructor(@Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema) {}\n\n list(userId: number, onlyUnread: boolean = false): Promise<NotificationFromUser[]> {\n const where: SQL[] = [eq(notifications.toUserId, userId), ...(onlyUnread ? [eq(notifications.wasRead, false)] : [])]\n return this.db\n .select({\n id: notifications.id,\n fromUser: { id: users.id, login: users.login, email: users.email, fullName: userFullNameSQL(users) },\n content: notifications.content,\n wasRead: notifications.wasRead,\n createdAt: notifications.createdAt\n } satisfies NotificationFromUser | SelectedFields<any, any>)\n .from(notifications)\n .leftJoin(users, eq(users.id, notifications.fromUserId))\n .where(and(...where))\n .orderBy(desc(notifications.id))\n }\n\n async create(fromUserId: number, toUserIds: number[], content: NotificationContent): Promise<void> {\n dbCheckAffectedRows(\n await this.db.insert(notifications).values(\n toUserIds.map((toUserId: number) => ({\n fromUserId: fromUserId,\n toUserId: toUserId,\n content: content\n }))\n ),\n toUserIds.length\n )\n }\n\n async wasRead(userId: number, notificationId: number): Promise<void> {\n await this.db\n .update(notifications)\n .set({ wasRead: true } as Notification)\n .where(and(eq(notifications.toUserId, userId), eq(notifications.id, notificationId), eq(notifications.wasRead, false)))\n }\n\n async delete(userId: number, notificationId?: number): Promise<void> {\n const where: SQL[] = [eq(notifications.toUserId, userId), ...(notificationId ? [eq(notifications.id, notificationId)] : [])]\n await this.db.delete(notifications).where(and(...where))\n }\n\n usersNotifiedByEmail(userIds: number[]): Promise<UserMailNotification[]> {\n return this.db\n .select({\n id: users.id,\n email: users.email,\n language: users.language,\n notification: users.notification\n } satisfies UserMailNotification | SelectedFields<any, any>)\n .from(users)\n .where(and(inArray(users.id, userIds), eq(users.notification, USER_NOTIFICATION.APPLICATION_EMAIL)))\n }\n}\n"],"names":["NotificationsQueries","list","userId","onlyUnread","where","eq","notifications","toUserId","wasRead","db","select","id","fromUser","users","login","email","fullName","userFullNameSQL","content","createdAt","from","leftJoin","fromUserId","and","orderBy","desc","create","toUserIds","dbCheckAffectedRows","insert","values","map","length","notificationId","update","set","delete","usersNotifiedByEmail","userIds","language","notification","inArray","USER_NOTIFICATION","APPLICATION_EMAIL"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbsB;4BACyB;2BAC1B;mCACT;uBACW;sBACF;6BACK;qCAIT;;;;;;;;;;;;;;;AAGvB,IAAA,AAAMA,uBAAN,MAAMA;IAGXC,KAAKC,MAAc,EAAEC,aAAsB,KAAK,EAAmC;QACjF,MAAMC,QAAe;YAACC,IAAAA,cAAE,EAACC,kCAAa,CAACC,QAAQ,EAAEL;eAAaC,aAAa;gBAACE,IAAAA,cAAE,EAACC,kCAAa,CAACE,OAAO,EAAE;aAAO,GAAG,EAAE;SAAE;QACpH,OAAO,IAAI,CAACC,EAAE,CACXC,MAAM,CAAC;YACNC,IAAIL,kCAAa,CAACK,EAAE;YACpBC,UAAU;gBAAED,IAAIE,kBAAK,CAACF,EAAE;gBAAEG,OAAOD,kBAAK,CAACC,KAAK;gBAAEC,OAAOF,kBAAK,CAACE,KAAK;gBAAEC,UAAUC,IAAAA,4BAAe,EAACJ,kBAAK;YAAE;YACnGK,SAASZ,kCAAa,CAACY,OAAO;YAC9BV,SAASF,kCAAa,CAACE,OAAO;YAC9BW,WAAWb,kCAAa,CAACa,SAAS;QACpC,GACCC,IAAI,CAACd,kCAAa,EAClBe,QAAQ,CAACR,kBAAK,EAAER,IAAAA,cAAE,EAACQ,kBAAK,CAACF,EAAE,EAAEL,kCAAa,CAACgB,UAAU,GACrDlB,KAAK,CAACmB,IAAAA,eAAG,KAAInB,QACboB,OAAO,CAACC,IAAAA,gBAAI,EAACnB,kCAAa,CAACK,EAAE;IAClC;IAEA,MAAMe,OAAOJ,UAAkB,EAAEK,SAAmB,EAAET,OAA4B,EAAiB;QACjGU,IAAAA,0BAAmB,EACjB,MAAM,IAAI,CAACnB,EAAE,CAACoB,MAAM,CAACvB,kCAAa,EAAEwB,MAAM,CACxCH,UAAUI,GAAG,CAAC,CAACxB,WAAsB,CAAA;gBACnCe,YAAYA;gBACZf,UAAUA;gBACVW,SAASA;YACX,CAAA,KAEFS,UAAUK,MAAM;IAEpB;IAEA,MAAMxB,QAAQN,MAAc,EAAE+B,cAAsB,EAAiB;QACnE,MAAM,IAAI,CAACxB,EAAE,CACVyB,MAAM,CAAC5B,kCAAa,EACpB6B,GAAG,CAAC;YAAE3B,SAAS;QAAK,GACpBJ,KAAK,CAACmB,IAAAA,eAAG,EAAClB,IAAAA,cAAE,EAACC,kCAAa,CAACC,QAAQ,EAAEL,SAASG,IAAAA,cAAE,EAACC,kCAAa,CAACK,EAAE,EAAEsB,iBAAiB5B,IAAAA,cAAE,EAACC,kCAAa,CAACE,OAAO,EAAE;IACnH;IAEA,MAAM4B,OAAOlC,MAAc,EAAE+B,cAAuB,EAAiB;QACnE,MAAM7B,QAAe;YAACC,IAAAA,cAAE,EAACC,kCAAa,CAACC,QAAQ,EAAEL;eAAa+B,iBAAiB;gBAAC5B,IAAAA,cAAE,EAACC,kCAAa,CAACK,EAAE,EAAEsB;aAAgB,GAAG,EAAE;SAAE;QAC5H,MAAM,IAAI,CAACxB,EAAE,CAAC2B,MAAM,CAAC9B,kCAAa,EAAEF,KAAK,CAACmB,IAAAA,eAAG,KAAInB;IACnD;IAEAiC,qBAAqBC,OAAiB,EAAmC;QACvE,OAAO,IAAI,CAAC7B,EAAE,CACXC,MAAM,CAAC;YACNC,IAAIE,kBAAK,CAACF,EAAE;YACZI,OAAOF,kBAAK,CAACE,KAAK;YAClBwB,UAAU1B,kBAAK,CAAC0B,QAAQ;YACxBC,cAAc3B,kBAAK,CAAC2B,YAAY;QAClC,GACCpB,IAAI,CAACP,kBAAK,EACVT,KAAK,CAACmB,IAAAA,eAAG,EAACkB,IAAAA,mBAAO,EAAC5B,kBAAK,CAACF,EAAE,EAAE2B,UAAUjC,IAAAA,cAAE,EAACQ,kBAAK,CAAC2B,YAAY,EAAEE,uBAAiB,CAACC,iBAAiB;IACrG;IArDA,YAAY,AAA4ClC,EAAY,CAAE;aAAdA,KAAAA;IAAe;AAsDzE"}
@@ -599,7 +599,7 @@ let SharesManager = class SharesManager {
599
599
  }
600
600
  }
601
601
  async createGuestLink(permission, password, language, isActive = true) {
602
- const random = (0, _functions.generateShortUUID)(32);
602
+ const random = (0, _functions.generateShortUUID)(64);
603
603
  const guestLink = {
604
604
  login: random,
605
605
  email: `${random}@sync-in`,
@@ -607,7 +607,7 @@ let SharesManager = class SharesManager {
607
607
  lastName: 'Link',
608
608
  language: language || null,
609
609
  permissions: permission,
610
- password: await (0, _functions.hashPassword)(password || (0, _functions.generateShortUUID)(12)),
610
+ password: await (0, _functions.hashPassword)(password || (0, _functions.generateShortUUID)(24)),
611
611
  role: _user.USER_ROLE.LINK,
612
612
  isActive: isActive
613
613
  };
@@ -980,6 +980,7 @@ let SharesManager = class SharesManager {
980
980
  }, {
981
981
  author: user,
982
982
  linkUUID: link.linkSettings.uuid,
983
+ linkPassword: link.linkSettings.password,
983
984
  currentUrl: this.contextManager.get('headerOriginUrl'),
984
985
  action: action
985
986
  }).catch((e)=>this.logger.error(`${this.notifyGuestLink.name} - ${e}`));