@sync-in/server 1.4.0 → 1.5.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 (229) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +2 -1
  3. package/package.json +5 -5
  4. package/server/applications/comments/comments.controller.spec.js +103 -4
  5. package/server/applications/comments/comments.controller.spec.js.map +1 -1
  6. package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
  7. package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
  8. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
  9. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
  10. package/server/applications/files/constants/routes.js +6 -1
  11. package/server/applications/files/constants/routes.js.map +1 -1
  12. package/server/applications/files/files-only-office.controller.js +11 -0
  13. package/server/applications/files/files-only-office.controller.js.map +1 -1
  14. package/server/applications/files/files-only-office.controller.spec.js +97 -3
  15. package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
  16. package/server/applications/files/files-tasks.controller.spec.js +91 -1
  17. package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
  18. package/server/applications/files/files.controller.spec.js +268 -46
  19. package/server/applications/files/files.controller.spec.js.map +1 -1
  20. package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
  21. package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
  22. package/server/applications/files/services/files-only-office-manager.service.js +5 -0
  23. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  24. package/server/applications/links/links.controller.spec.js +91 -58
  25. package/server/applications/links/links.controller.spec.js.map +1 -1
  26. package/server/applications/links/services/links-manager.service.js +4 -6
  27. package/server/applications/links/services/links-manager.service.js.map +1 -1
  28. package/server/applications/links/services/links-manager.service.spec.js +378 -14
  29. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  30. package/server/applications/links/services/links-queries.service.js +1 -1
  31. package/server/applications/links/services/links-queries.service.js.map +1 -1
  32. package/server/applications/notifications/notifications.controller.spec.js +56 -1
  33. package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
  34. package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
  35. package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
  36. package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
  37. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  38. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
  39. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
  40. package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
  41. package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
  42. package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
  43. package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
  44. package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
  45. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  46. package/server/applications/users/services/admin-users-manager.service.js +22 -24
  47. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  48. package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
  49. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  50. package/server/applications/users/services/users-manager.service.js +1 -1
  51. package/server/applications/users/services/users-manager.service.js.map +1 -1
  52. package/server/applications/users/services/users-manager.service.spec.js +938 -49
  53. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  54. package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
  55. package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
  56. package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
  57. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
  58. package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
  59. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  60. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
  61. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
  62. package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
  63. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  64. package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
  65. package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
  66. package/server/applications/webdav/webdav.controller.js +2 -2
  67. package/server/applications/webdav/webdav.controller.js.map +1 -1
  68. package/server/authentication/guards/auth-basic.guard.js.map +1 -1
  69. package/server/authentication/guards/auth-digest.guard.js +1 -2
  70. package/server/authentication/guards/auth-digest.guard.js.map +1 -1
  71. package/server/authentication/guards/auth-local.guard.js.map +1 -1
  72. package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
  73. package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
  74. package/static/3rdpartylicenses.txt +26 -26
  75. package/static/assets/pdfjs/build/pdf.mjs +1177 -255
  76. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  77. package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
  78. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  79. package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
  80. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  81. package/static/assets/pdfjs/version +1 -1
  82. package/static/assets/pdfjs/web/debugger.css +31 -0
  83. package/static/assets/pdfjs/web/debugger.mjs +144 -2
  84. package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
  85. package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
  86. package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
  87. package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
  88. package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
  89. package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
  90. package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
  91. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
  92. package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
  93. package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
  94. package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
  95. package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
  96. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
  97. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
  98. package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
  99. package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
  100. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
  101. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
  102. package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
  103. package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
  104. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
  105. package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
  106. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
  107. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
  108. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
  109. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
  110. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
  111. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
  112. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
  113. package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
  114. package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
  115. package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
  116. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
  117. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
  118. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
  119. package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
  120. package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
  121. package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
  122. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
  123. package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
  124. package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
  125. package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
  126. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
  127. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
  128. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
  129. package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
  130. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
  131. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
  132. package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
  133. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
  134. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
  135. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
  136. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
  137. package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
  138. package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
  139. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
  140. package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
  141. package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
  142. package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
  143. package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
  144. package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
  145. package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
  146. package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
  147. package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
  148. package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
  149. package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
  150. package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
  151. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
  152. package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
  153. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
  154. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
  155. package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
  156. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
  157. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
  158. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
  159. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
  160. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
  161. package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
  162. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
  163. package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
  164. package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
  165. package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
  166. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
  167. package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
  168. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
  169. package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
  170. package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
  171. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
  172. package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
  173. package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
  174. package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
  175. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
  176. package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
  177. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
  178. package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
  179. package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
  180. package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
  181. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
  182. package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
  183. package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
  184. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
  185. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
  186. package/static/assets/pdfjs/web/viewer.css +649 -120
  187. package/static/assets/pdfjs/web/viewer.html +19 -0
  188. package/static/assets/pdfjs/web/viewer.mjs +489 -38
  189. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  190. package/static/chunk-22EANI6R.js +1 -0
  191. package/static/{chunk-N2LYWNTC.js → chunk-2456KVFZ.js} +1 -1
  192. package/static/{chunk-YCINY2YI.js → chunk-2LVCLKCK.js} +1 -1
  193. package/static/{chunk-5YKWZT33.js → chunk-2V5S7DWD.js} +1 -1
  194. package/static/{chunk-3GC2BQZD.js → chunk-44YDXGNZ.js} +1 -1
  195. package/static/{chunk-W3QXNDI5.js → chunk-4LSJLWYV.js} +1 -1
  196. package/static/{chunk-T55FAU2O.js → chunk-4UT5VH7R.js} +1 -1
  197. package/static/{chunk-VMQMD36Z.js → chunk-5GOMMRRE.js} +1 -1
  198. package/static/{chunk-TXPODW5Q.js → chunk-5J4VRDKB.js} +1 -1
  199. package/static/{chunk-FQ4AFNGE.js → chunk-6PVKNZ7Q.js} +1 -1
  200. package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
  201. package/static/{chunk-X43VWRFP.js → chunk-DFQKHCDR.js} +1 -1
  202. package/static/{chunk-TDQAEVZN.js → chunk-EE2TDTY4.js} +1 -1
  203. package/static/{chunk-MOVWEZ7J.js → chunk-ESNDJ5T6.js} +1 -1
  204. package/static/{chunk-TCFKH6K6.js → chunk-GDKKLLEU.js} +1 -1
  205. package/static/{chunk-VHYIXL7R.js → chunk-GSR2MCQG.js} +1 -1
  206. package/static/{chunk-LJIGRUEF.js → chunk-HR7KS5BR.js} +1 -1
  207. package/static/chunk-HW2H3ISM.js +559 -0
  208. package/static/{chunk-HZA7R43P.js → chunk-IMB3C547.js} +1 -1
  209. package/static/{chunk-B2Y2RNFP.js → chunk-J4ALHUDX.js} +1 -1
  210. package/static/{chunk-PF4K7MVG.js → chunk-KP6LSQTK.js} +1 -1
  211. package/static/{chunk-C23BPTJZ.js → chunk-LUZCOHFN.js} +1 -1
  212. package/static/{chunk-GBCYYDCI.js → chunk-MHSCCXVL.js} +1 -1
  213. package/static/{chunk-PY3BGNJN.js → chunk-OMRQYBXV.js} +1 -1
  214. package/static/chunk-P7CTJ5BG.js +27 -0
  215. package/static/{chunk-Y2CDUS4J.js → chunk-P7PX67IR.js} +4 -4
  216. package/static/{chunk-VMUOUCEI.js → chunk-PPO7DBVO.js} +1 -1
  217. package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
  218. package/static/{chunk-WWIC7UW3.js → chunk-SLGGINMR.js} +1 -1
  219. package/static/{chunk-KZQCFEPT.js → chunk-UHD5XD3G.js} +1 -1
  220. package/static/{chunk-TNW2CGK6.js → chunk-UPYYAJCJ.js} +1 -1
  221. package/static/{chunk-6F55D74O.js → chunk-VHYPQ3D4.js} +1 -1
  222. package/static/{chunk-DGVNNICG.js → chunk-YQSDS6BO.js} +1 -1
  223. package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
  224. package/static/index.html +1 -1
  225. package/static/main-FYD34UEC.js +7 -0
  226. package/static/chunk-RSNLYAN6.js +0 -560
  227. package/static/chunk-WHMS3PJ3.js +0 -24
  228. package/static/chunk-ZZ3LHYOY.js +0 -1
  229. package/static/main-7LDKYVXO.js +0 -10
@@ -22,6 +22,7 @@ const _sharesmanagerservice = require("../../shares/services/shares-manager.serv
22
22
  const _sharesqueriesservice = require("../../shares/services/shares-queries.service");
23
23
  const _spacesmanagerservice = require("../../spaces/services/spaces-manager.service");
24
24
  const _spacesqueriesservice = require("../../spaces/services/spaces-queries.service");
25
+ const _usermodel = require("../../users/models/user.model");
25
26
  const _adminusersmanagerservice = require("../../users/services/admin-users-manager.service");
26
27
  const _adminusersqueriesservice = require("../../users/services/admin-users-queries.service");
27
28
  const _usersmanagerservice = require("../../users/services/users-manager.service");
@@ -30,7 +31,47 @@ const _linksmanagerservice = require("./links-manager.service");
30
31
  const _linksqueriesservice = require("./links-queries.service");
31
32
  describe(_linksmanagerservice.LinksManager.name, ()=>{
32
33
  let service;
34
+ let linksQueriesMock;
35
+ let usersManagerMock;
36
+ let filesManagerMock;
37
+ let spacesManagerMock;
38
+ let authManagerMock;
39
+ const identity = {
40
+ id: 42,
41
+ login: 'visitor'
42
+ };
43
+ const baseLink = {
44
+ uuid: 'uuid-123',
45
+ user: {
46
+ id: 7,
47
+ login: 'john',
48
+ isActive: true
49
+ },
50
+ requireAuth: false,
51
+ limitAccess: 0,
52
+ nbAccess: 0,
53
+ expiresAt: null
54
+ };
33
55
  beforeAll(async ()=>{
56
+ linksQueriesMock = {
57
+ linkFromUUID: jest.fn(),
58
+ spaceLink: jest.fn(),
59
+ incrementLinkNbAccess: jest.fn().mockResolvedValue(undefined)
60
+ };
61
+ usersManagerMock = {
62
+ getAvatarBase64: jest.fn(),
63
+ compareUserPassword: jest.fn(),
64
+ updateAccesses: jest.fn()
65
+ };
66
+ filesManagerMock = {
67
+ sendFileFromSpace: jest.fn()
68
+ };
69
+ spacesManagerMock = {
70
+ spaceEnv: jest.fn()
71
+ };
72
+ authManagerMock = {
73
+ setCookies: jest.fn()
74
+ };
34
75
  const module = await _testing.Test.createTestingModule({
35
76
  providers: [
36
77
  {
@@ -57,28 +98,351 @@ describe(_linksmanagerservice.LinksManager.name, ()=>{
57
98
  provide: _fileslockmanagerservice.FilesLockManager,
58
99
  useValue: {}
59
100
  },
60
- _config.ConfigService,
61
- _jwt.JwtService,
62
- _authmanagerservice.AuthManager,
63
- _usersmanagerservice.UsersManager,
64
- _usersqueriesservice.UsersQueries,
65
- _adminusersmanagerservice.AdminUsersManager,
66
- _adminusersqueriesservice.AdminUsersQueries,
67
- _filesqueriesservice.FilesQueries,
68
- _filesmanagerservice.FilesManager,
69
- _spacesqueriesservice.SpacesQueries,
70
- _spacesmanagerservice.SpacesManager,
71
- _sharesqueriesservice.SharesQueries,
72
- _sharesmanagerservice.SharesManager,
73
- _linksqueriesservice.LinksQueries,
101
+ {
102
+ provide: _config.ConfigService,
103
+ useValue: {}
104
+ },
105
+ {
106
+ provide: _jwt.JwtService,
107
+ useValue: {}
108
+ },
109
+ {
110
+ provide: _authmanagerservice.AuthManager,
111
+ useValue: authManagerMock
112
+ },
113
+ {
114
+ provide: _usersmanagerservice.UsersManager,
115
+ useValue: usersManagerMock
116
+ },
117
+ {
118
+ provide: _usersqueriesservice.UsersQueries,
119
+ useValue: {}
120
+ },
121
+ {
122
+ provide: _adminusersmanagerservice.AdminUsersManager,
123
+ useValue: {}
124
+ },
125
+ {
126
+ provide: _adminusersqueriesservice.AdminUsersQueries,
127
+ useValue: {}
128
+ },
129
+ {
130
+ provide: _filesqueriesservice.FilesQueries,
131
+ useValue: {}
132
+ },
133
+ {
134
+ provide: _filesmanagerservice.FilesManager,
135
+ useValue: filesManagerMock
136
+ },
137
+ {
138
+ provide: _spacesqueriesservice.SpacesQueries,
139
+ useValue: {}
140
+ },
141
+ {
142
+ provide: _spacesmanagerservice.SpacesManager,
143
+ useValue: spacesManagerMock
144
+ },
145
+ {
146
+ provide: _sharesqueriesservice.SharesQueries,
147
+ useValue: {}
148
+ },
149
+ {
150
+ provide: _sharesmanagerservice.SharesManager,
151
+ useValue: {}
152
+ },
153
+ {
154
+ provide: _linksqueriesservice.LinksQueries,
155
+ useValue: linksQueriesMock
156
+ },
74
157
  _linksmanagerservice.LinksManager
75
158
  ]
76
159
  }).compile();
160
+ module.useLogger([
161
+ 'fatal'
162
+ ]);
77
163
  service = module.get(_linksmanagerservice.LinksManager);
78
164
  });
165
+ beforeEach(()=>{
166
+ jest.clearAllMocks();
167
+ });
79
168
  it('should be defined', ()=>{
80
169
  expect(service).toBeDefined();
81
170
  });
171
+ describe('linkValidation', ()=>{
172
+ it('returns ok with sanitized owner and avatar when link is valid', async ()=>{
173
+ const link = {
174
+ ...baseLink
175
+ };
176
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
177
+ const spaceLink = {
178
+ owner: {
179
+ login: 'jane'
180
+ },
181
+ share: {
182
+ isDir: true,
183
+ alias: 's-alias',
184
+ name: 'Docs'
185
+ },
186
+ space: null
187
+ };
188
+ linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
189
+ usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-avatar');
190
+ const res = await service.linkValidation(identity, link.uuid);
191
+ expect(res.ok).toBe(true);
192
+ expect(res.error).toBeNull();
193
+ expect(res.link).toBe(spaceLink);
194
+ expect(spaceLink.owner.avatar).toBe('base64-avatar');
195
+ expect(spaceLink.owner.login).toBeUndefined();
196
+ expect(linksQueriesMock.spaceLink).toHaveBeenCalledWith(link.uuid);
197
+ // extra coverage: directly assert private checkLink with default ignoreAuth=false
198
+ const directCheck = service.checkLink(identity, link);
199
+ expect(directCheck).toBe(true);
200
+ });
201
+ it('returns error and null link when uuid is not found', async ()=>{
202
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(null);
203
+ const res = await service.linkValidation(identity, 'missing-uuid');
204
+ expect(res.ok).toBe(false);
205
+ expect(res.error).toBeDefined();
206
+ expect(res.link).toBeNull();
207
+ });
208
+ it('returns unauthorized when auth is required and identity differs', async ()=>{
209
+ const link = {
210
+ ...baseLink,
211
+ requireAuth: true
212
+ };
213
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
214
+ const res = await service.linkValidation(identity, link.uuid);
215
+ expect(res.ok).toBe(false);
216
+ expect(String(res.error).toLowerCase()).toContain('unauthorized');
217
+ expect(res.link).toBeNull();
218
+ // extra coverage: directly assert private checkLink with default ignoreAuth=false
219
+ const directCheck = service.checkLink(identity, link);
220
+ expect(String(directCheck).toLowerCase()).toContain('unauthorized');
221
+ });
222
+ it('returns exceeded when nbAccess >= limitAccess', async ()=>{
223
+ const link = {
224
+ ...baseLink,
225
+ limitAccess: 5,
226
+ nbAccess: 5
227
+ };
228
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
229
+ const res = await service.linkValidation(identity, link.uuid);
230
+ expect(res.ok).toBe(false);
231
+ expect(String(res.error).toLowerCase()).toContain('exceeded');
232
+ });
233
+ });
234
+ describe('linkAccess', ()=>{
235
+ const req = {
236
+ ip: '127.0.0.1'
237
+ };
238
+ const res = {};
239
+ it('streams a file when link targets a single file', async ()=>{
240
+ const link = {
241
+ ...baseLink,
242
+ limitAccess: 10
243
+ };
244
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
245
+ const spaceLink = {
246
+ space: null,
247
+ share: {
248
+ isDir: false,
249
+ name: 'file.txt',
250
+ alias: 'share-alias'
251
+ }
252
+ };
253
+ linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
254
+ spacesManagerMock.spaceEnv.mockResolvedValueOnce({});
255
+ const streamable = {
256
+ some: 'stream'
257
+ };
258
+ filesManagerMock.sendFileFromSpace.mockReturnValueOnce({
259
+ checks: jest.fn().mockResolvedValueOnce(undefined),
260
+ stream: jest.fn().mockResolvedValueOnce(streamable)
261
+ });
262
+ // cover: incrementLinkNbAccess.catch(...) should log an error when the query rejects
263
+ const logErrorSpy = jest.spyOn(service.logger, 'error').mockImplementation(()=>undefined);
264
+ linksQueriesMock.incrementLinkNbAccess.mockRejectedValueOnce(new Error('increment boom'));
265
+ const result = await service.linkAccess(identity, link.uuid, req, res);
266
+ expect(result).toBe(streamable);
267
+ expect(filesManagerMock.sendFileFromSpace).toHaveBeenCalled();
268
+ expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid);
269
+ // Assert repository selection for a share file (space falsy)
270
+ // should call spacesManager.spaceEnv with SHARES and share alias when link.space is falsy
271
+ expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), [
272
+ 'shares',
273
+ 'share-alias'
274
+ ]);
275
+ // should log error when increment fails
276
+ expect(logErrorSpy).toHaveBeenCalled();
277
+ });
278
+ it('authenticates and returns cookies when link targets a directory and user is different', async ()=>{
279
+ const link = {
280
+ ...baseLink,
281
+ requireAuth: false,
282
+ user: {
283
+ id: 7,
284
+ login: 'john',
285
+ isActive: true
286
+ }
287
+ };
288
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
289
+ const spaceLink = {
290
+ space: {
291
+ alias: 'files',
292
+ name: 'My Space'
293
+ },
294
+ share: {
295
+ isDir: true,
296
+ name: 'ignored',
297
+ alias: 'ignored'
298
+ }
299
+ };
300
+ linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
301
+ const loginDto = {
302
+ token: 'jwt'
303
+ };
304
+ authManagerMock.setCookies.mockResolvedValueOnce(loginDto);
305
+ // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects
306
+ const logErrorSpy = jest.spyOn(service.logger, 'error').mockImplementation(()=>undefined);
307
+ usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses boom'));
308
+ const result = await service.linkAccess(identity, link.uuid, req, res);
309
+ expect(result).toBe(loginDto);
310
+ expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true);
311
+ expect(authManagerMock.setCookies).toHaveBeenCalled();
312
+ // additionally cover the "space truthy" branch by calling the private helper directly
313
+ // should call spacesManager.spaceEnv with FILES and space alias when link.space is truthy
314
+ await service.spaceEnvFromLink(new _usermodel.UserModel(link.user), spaceLink);
315
+ expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), [
316
+ 'files',
317
+ 'files'
318
+ ]);
319
+ // should log error when updateAccesses fails
320
+ expect(logErrorSpy).toHaveBeenCalled();
321
+ });
322
+ it('throws BAD_REQUEST when link is invalid', async ()=>{
323
+ const disabledLink = {
324
+ ...baseLink,
325
+ user: {
326
+ id: 7,
327
+ login: 'john',
328
+ isActive: false
329
+ }
330
+ };
331
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(disabledLink);
332
+ await expect(service.linkAccess(identity, disabledLink.uuid, req, res)).rejects.toMatchObject({
333
+ status: 400
334
+ });
335
+ });
336
+ it('returns undefined for already authenticated directory access (same user) and does not set cookies or increment', async ()=>{
337
+ const sameUserIdentity = {
338
+ id: baseLink.user.id,
339
+ login: 'john'
340
+ };
341
+ const link = {
342
+ ...baseLink,
343
+ requireAuth: true
344
+ };
345
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
346
+ const spaceLink = {
347
+ space: {
348
+ alias: 'files',
349
+ name: 'Space'
350
+ },
351
+ share: {
352
+ isDir: true,
353
+ name: 'dir',
354
+ alias: 'share'
355
+ }
356
+ };
357
+ linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
358
+ const result = await service.linkAccess(sameUserIdentity, link.uuid, req, res);
359
+ expect(result).toBeUndefined();
360
+ expect(authManagerMock.setCookies).not.toHaveBeenCalled();
361
+ expect(linksQueriesMock.incrementLinkNbAccess).not.toHaveBeenCalled();
362
+ });
363
+ it('throws INTERNAL_SERVER_ERROR when file checks fail during streaming', async ()=>{
364
+ const link = {
365
+ ...baseLink,
366
+ limitAccess: 10
367
+ };
368
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
369
+ const spaceLink = {
370
+ space: null,
371
+ share: {
372
+ isDir: false,
373
+ name: 'bad.txt',
374
+ alias: 'share'
375
+ }
376
+ };
377
+ linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
378
+ spacesManagerMock.spaceEnv.mockResolvedValueOnce({});
379
+ filesManagerMock.sendFileFromSpace.mockReturnValueOnce({
380
+ checks: jest.fn().mockRejectedValueOnce(new Error('disk error')),
381
+ stream: jest.fn()
382
+ });
383
+ await expect(service.linkAccess(identity, link.uuid, req, res)).rejects.toMatchObject({
384
+ status: 500
385
+ });
386
+ expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid);
387
+ });
388
+ });
389
+ describe('linkAuthentication', ()=>{
390
+ const req = {
391
+ ip: '10.0.0.1'
392
+ };
393
+ const res = {};
394
+ it('returns cookies when password is correct', async ()=>{
395
+ const link = {
396
+ ...baseLink,
397
+ requireAuth: true
398
+ };
399
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
400
+ usersManagerMock.compareUserPassword.mockResolvedValueOnce(true);
401
+ // usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined) // removed to ensure rejection is hit
402
+ const loginDto = {
403
+ token: 'abc'
404
+ };
405
+ authManagerMock.setCookies.mockResolvedValueOnce(loginDto);
406
+ // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects (success flow)
407
+ const logErrorSpy = jest.spyOn(service.logger, 'error').mockImplementation(()=>undefined);
408
+ usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses auth success boom'));
409
+ const result = await service.linkAuthentication(identity, link.uuid, {
410
+ password: 'secret'
411
+ }, req, res);
412
+ expect(result).toBe(loginDto);
413
+ expect(usersManagerMock.compareUserPassword).toHaveBeenCalledWith(link.user.id, 'secret');
414
+ expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true);
415
+ expect(authManagerMock.setCookies).toHaveBeenCalled();
416
+ // should log error when updateAccesses fails in successful authentication
417
+ expect(logErrorSpy).toHaveBeenCalled();
418
+ });
419
+ it('throws FORBIDDEN when password is incorrect', async ()=>{
420
+ const link = {
421
+ ...baseLink,
422
+ requireAuth: true
423
+ };
424
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link);
425
+ usersManagerMock.compareUserPassword.mockResolvedValueOnce(false);
426
+ usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined);
427
+ await expect(service.linkAuthentication(identity, link.uuid, {
428
+ password: 'bad'
429
+ }, req, res)).rejects.toMatchObject({
430
+ status: 403
431
+ });
432
+ });
433
+ it('throws BAD_REQUEST when link is invalid (e.g., expired)', async ()=>{
434
+ const expired = {
435
+ ...baseLink,
436
+ expiresAt: new Date(Date.now() - 60_000)
437
+ };
438
+ linksQueriesMock.linkFromUUID.mockResolvedValueOnce(expired);
439
+ await expect(service.linkAuthentication(identity, expired.uuid, {
440
+ password: 'whatever'
441
+ }, req, res)).rejects.toMatchObject({
442
+ status: 400
443
+ });
444
+ });
445
+ });
82
446
  });
83
447
 
84
448
  //# sourceMappingURL=links-manager.service.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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 { HttpService } from '@nestjs/axios'\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { FilesLockManager } from '../../files/services/files-lock-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { AdminUsersManager } from '../../users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../users/services/admin-users-queries.service'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { LinksManager } from './links-manager.service'\nimport { LinksQueries } from './links-queries.service'\n\ndescribe(LinksManager.name, () => {\n let service: LinksManager\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n {\n provide: Cache,\n useValue: {}\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: HttpService, useValue: {} },\n { provide: FilesLockManager, useValue: {} },\n ConfigService,\n JwtService,\n AuthManager,\n UsersManager,\n UsersQueries,\n AdminUsersManager,\n AdminUsersQueries,\n FilesQueries,\n FilesManager,\n SpacesQueries,\n SpacesManager,\n SharesQueries,\n SharesManager,\n LinksQueries,\n LinksManager\n ]\n }).compile()\n\n service = module.get<LinksManager>(LinksManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","LinksManager","name","service","beforeAll","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","ContextManager","NotificationsManager","HttpService","FilesLockManager","ConfigService","JwtService","AuthManager","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","FilesQueries","FilesManager","SpacesQueries","SpacesManager","SharesQueries","SharesManager","LinksQueries","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;uBAE2B;wBACE;qBACH;yBACS;oCACR;8BACN;uCACS;2BACG;yCACD;qCACJ;qCACA;6CACQ;sCACP;sCACA;sCACA;sCACA;0CACI;0CACA;qCACL;qCACA;qCACA;qCACA;AAE7BA,SAASC,iCAAY,CAACC,IAAI,EAAE;IAC1B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACT;oBACEC,SAASC,4BAAiB;oBAC1BC,UAAU,CAAC;gBACb;gBACA;oBACEF,SAASG,mBAAK;oBACdD,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASI,qCAAc;oBAAEF,UAAU,CAAC;gBAAE;gBACxC;oBACEF,SAASK,iDAAoB;oBAC7BH,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASM,kBAAW;oBAAEJ,UAAU,CAAC;gBAAE;gBACrC;oBAAEF,SAASO,yCAAgB;oBAAEL,UAAU,CAAC;gBAAE;gBAC1CM,qBAAa;gBACbC,eAAU;gBACVC,+BAAW;gBACXC,iCAAY;gBACZC,iCAAY;gBACZC,2CAAiB;gBACjBC,2CAAiB;gBACjBC,iCAAY;gBACZC,iCAAY;gBACZC,mCAAa;gBACbC,mCAAa;gBACbC,mCAAa;gBACbC,mCAAa;gBACbC,iCAAY;gBACZ7B,iCAAY;aACb;QACH,GAAG8B,OAAO;QAEV5B,UAAUE,OAAO2B,GAAG,CAAe/B,iCAAY;IACjD;IAEAgC,GAAG,qBAAqB;QACtBC,OAAO/B,SAASgC,WAAW;IAC7B;AACF"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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 { HttpService } from '@nestjs/axios'\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { FilesLockManager } from '../../files/services/files-lock-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { AdminUsersManager } from '../../users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../users/services/admin-users-queries.service'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { LinksManager } from './links-manager.service'\nimport { LinksQueries } from './links-queries.service'\n\ndescribe(LinksManager.name, () => {\n let service: LinksManager\n let linksQueriesMock: jest.Mocked<LinksQueries>\n let usersManagerMock: jest.Mocked<UsersManager>\n let filesManagerMock: jest.Mocked<FilesManager>\n let spacesManagerMock: jest.Mocked<SpacesManager>\n let authManagerMock: jest.Mocked<AuthManager>\n\n const identity: any = { id: 42, login: 'visitor' }\n const baseLink: any = {\n uuid: 'uuid-123',\n user: { id: 7, login: 'john', isActive: true },\n requireAuth: false,\n limitAccess: 0,\n nbAccess: 0,\n expiresAt: null\n }\n\n beforeAll(async () => {\n linksQueriesMock = {\n linkFromUUID: jest.fn(),\n spaceLink: jest.fn(),\n incrementLinkNbAccess: jest.fn().mockResolvedValue(undefined)\n } as any\n\n usersManagerMock = {\n getAvatarBase64: jest.fn(),\n compareUserPassword: jest.fn(),\n updateAccesses: jest.fn()\n } as any\n\n filesManagerMock = {\n sendFileFromSpace: jest.fn()\n } as any\n\n spacesManagerMock = {\n spaceEnv: jest.fn()\n } as any\n\n authManagerMock = {\n setCookies: jest.fn()\n } as any\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n {\n provide: Cache,\n useValue: {}\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: HttpService, useValue: {} },\n { provide: FilesLockManager, useValue: {} },\n { provide: ConfigService, useValue: {} },\n { provide: JwtService, useValue: {} },\n { provide: AuthManager, useValue: authManagerMock },\n { provide: UsersManager, useValue: usersManagerMock },\n { provide: UsersQueries, useValue: {} },\n { provide: AdminUsersManager, useValue: {} },\n { provide: AdminUsersQueries, useValue: {} },\n { provide: FilesQueries, useValue: {} },\n { provide: FilesManager, useValue: filesManagerMock },\n { provide: SpacesQueries, useValue: {} },\n { provide: SpacesManager, useValue: spacesManagerMock },\n { provide: SharesQueries, useValue: {} },\n { provide: SharesManager, useValue: {} },\n { provide: LinksQueries, useValue: linksQueriesMock },\n LinksManager\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<LinksManager>(LinksManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('linkValidation', () => {\n it('returns ok with sanitized owner and avatar when link is valid', async () => {\n const link = { ...baseLink }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n owner: { login: 'jane' },\n share: { isDir: true, alias: 's-alias', name: 'Docs' },\n space: null\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-avatar')\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(true)\n expect(res.error).toBeNull()\n expect(res.link).toBe(spaceLink)\n expect(spaceLink.owner.avatar).toBe('base64-avatar')\n expect((spaceLink.owner as any).login).toBeUndefined()\n expect(linksQueriesMock.spaceLink).toHaveBeenCalledWith(link.uuid)\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(directCheck).toBe(true)\n })\n\n it('returns error and null link when uuid is not found', async () => {\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(null)\n\n const res = await service.linkValidation(identity, 'missing-uuid')\n\n expect(res.ok).toBe(false)\n expect(res.error).toBeDefined()\n expect(res.link).toBeNull()\n })\n\n it('returns unauthorized when auth is required and identity differs', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('unauthorized')\n expect(res.link).toBeNull()\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(String(directCheck).toLowerCase()).toContain('unauthorized')\n })\n\n it('returns exceeded when nbAccess >= limitAccess', async () => {\n const link = { ...baseLink, limitAccess: 5, nbAccess: 5 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('exceeded')\n })\n })\n\n describe('linkAccess', () => {\n const req: any = { ip: '127.0.0.1' }\n const res: any = {}\n\n it('streams a file when link targets a single file', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'file.txt', alias: 'share-alias' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n const streamable: any = { some: 'stream' }\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockResolvedValueOnce(undefined),\n stream: jest.fn().mockResolvedValueOnce(streamable)\n } as any)\n\n // cover: incrementLinkNbAccess.catch(...) should log an error when the query rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n linksQueriesMock.incrementLinkNbAccess.mockRejectedValueOnce(new Error('increment boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(streamable)\n expect(filesManagerMock.sendFileFromSpace).toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n // Assert repository selection for a share file (space falsy)\n // should call spacesManager.spaceEnv with SHARES and share alias when link.space is falsy\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['shares', 'share-alias'])\n // should log error when increment fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('authenticates and returns cookies when link targets a directory and user is different', async () => {\n const link = { ...baseLink, requireAuth: false, user: { id: 7, login: 'john', isActive: true } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'My Space' },\n share: { isDir: true, name: 'ignored', alias: 'ignored' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const loginDto: any = { token: 'jwt' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // additionally cover the \"space truthy\" branch by calling the private helper directly\n // should call spacesManager.spaceEnv with FILES and space alias when link.space is truthy\n await (service as any).spaceEnvFromLink(new UserModel(link.user as any), spaceLink as any)\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['files', 'files'])\n // should log error when updateAccesses fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws BAD_REQUEST when link is invalid', async () => {\n const disabledLink = { ...baseLink, user: { id: 7, login: 'john', isActive: false } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(disabledLink)\n\n await expect(service.linkAccess(identity, disabledLink.uuid, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n\n it('returns undefined for already authenticated directory access (same user) and does not set cookies or increment', async () => {\n const sameUserIdentity = { id: baseLink.user.id, login: 'john' }\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'Space' },\n share: { isDir: true, name: 'dir', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const result = await service.linkAccess(sameUserIdentity as any, link.uuid, req, res)\n\n expect(result).toBeUndefined()\n expect(authManagerMock.setCookies).not.toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).not.toHaveBeenCalled()\n })\n\n it('throws INTERNAL_SERVER_ERROR when file checks fail during streaming', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'bad.txt', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockRejectedValueOnce(new Error('disk error')),\n stream: jest.fn()\n } as any)\n\n await expect(service.linkAccess(identity, link.uuid, req, res)).rejects.toMatchObject({\n status: 500\n })\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n })\n })\n\n describe('linkAuthentication', () => {\n const req: any = { ip: '10.0.0.1' }\n const res: any = {}\n\n it('returns cookies when password is correct', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(true)\n // usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined) // removed to ensure rejection is hit\n const loginDto: any = { token: 'abc' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects (success flow)\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses auth success boom'))\n\n const result = await service.linkAuthentication(identity, link.uuid, { password: 'secret' } as any, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.compareUserPassword).toHaveBeenCalledWith(link.user.id, 'secret')\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // should log error when updateAccesses fails in successful authentication\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws FORBIDDEN when password is incorrect', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(false)\n usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined)\n\n await expect(service.linkAuthentication(identity, link.uuid, { password: 'bad' } as any, req, res)).rejects.toMatchObject({ status: 403 })\n })\n\n it('throws BAD_REQUEST when link is invalid (e.g., expired)', async () => {\n const expired = { ...baseLink, expiresAt: new Date(Date.now() - 60_000) }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(expired)\n\n await expect(service.linkAuthentication(identity, expired.uuid, { password: 'whatever' } as any, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n })\n})\n"],"names":["describe","LinksManager","name","service","linksQueriesMock","usersManagerMock","filesManagerMock","spacesManagerMock","authManagerMock","identity","id","login","baseLink","uuid","user","isActive","requireAuth","limitAccess","nbAccess","expiresAt","beforeAll","linkFromUUID","jest","fn","spaceLink","incrementLinkNbAccess","mockResolvedValue","undefined","getAvatarBase64","compareUserPassword","updateAccesses","sendFileFromSpace","spaceEnv","setCookies","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","ContextManager","NotificationsManager","HttpService","FilesLockManager","ConfigService","JwtService","AuthManager","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","FilesQueries","FilesManager","SpacesQueries","SpacesManager","SharesQueries","SharesManager","LinksQueries","compile","useLogger","get","beforeEach","clearAllMocks","it","expect","toBeDefined","link","mockResolvedValueOnce","owner","share","isDir","alias","space","res","linkValidation","ok","toBe","error","toBeNull","avatar","toBeUndefined","toHaveBeenCalledWith","directCheck","checkLink","String","toLowerCase","toContain","req","ip","streamable","some","mockReturnValueOnce","checks","stream","logErrorSpy","spyOn","logger","mockImplementation","mockRejectedValueOnce","Error","result","linkAccess","toHaveBeenCalled","anything","loginDto","token","spaceEnvFromLink","UserModel","disabledLink","rejects","toMatchObject","status","sameUserIdentity","not","linkAuthentication","password","expired","Date","now"],"mappings":"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"}
@@ -137,7 +137,7 @@ let LinksQueries = class LinksQueries {
137
137
  }).from(_linksschema.links).leftJoin(_sharesmembersschema.sharesMembers, (0, _drizzleorm.eq)(_sharesmembersschema.sharesMembers.linkId, _linksschema.links.id)).leftJoin(_sharesschema.shares, (0, _drizzleorm.eq)(_sharesschema.shares.id, _sharesmembersschema.sharesMembers.shareId)).leftJoin(shareOwner, (0, _drizzleorm.eq)(shareOwner.id, _sharesschema.shares.ownerId)).leftJoin(_spacesmembersschema.spacesMembers, (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.linkId, _linksschema.links.id)).leftJoin(_spacesschema.spaces, (0, _drizzleorm.eq)(_spacesschema.spaces.id, _spacesmembersschema.spacesMembers.spaceId)).leftJoin(shareSpaceRoot, (0, _drizzleorm.and)((0, _drizzleorm.isNull)(_sharesschema.shares.externalPath), (0, _drizzleorm.isNull)(_sharesschema.shares.fileId), (0, _drizzleorm.eq)(shareSpaceRoot.id, _sharesschema.shares.spaceRootId))).leftJoin(_filesschema.files, (0, _drizzleorm.or)((0, _drizzleorm.and)((0, _drizzleorm.isNotNull)(_sharesschema.shares.fileId), (0, _drizzleorm.eq)(_filesschema.files.id, _sharesschema.shares.fileId)), (0, _drizzleorm.and)((0, _drizzleorm.isNull)(_sharesschema.shares.externalPath), (0, _drizzleorm.isNotNull)(shareSpaceRoot.fileId), (0, _drizzleorm.eq)(_filesschema.files.id, shareSpaceRoot.fileId)))).where((0, _drizzleorm.eq)(_linksschema.links.uuid, uuid)).limit(1);
138
138
  return r;
139
139
  }
140
- async incrementLinkAccess(uuid) {
140
+ async incrementLinkNbAccess(uuid) {
141
141
  await this.db.update(_linksschema.links).set({
142
142
  nbAccess: (0, _drizzleorm.sql)`${_linksschema.links.nbAccess} + 1`
143
143
  }).where((0, _drizzleorm.eq)(_linksschema.links.uuid, uuid)).limit(1);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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, eq, getTableColumns, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { alias } from 'drizzle-orm/mysql-core'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport type { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbGetInsertedId } from '../../../infrastructure/database/utils'\nimport { files } from '../../files/schemas/files.schema'\nimport type { ShareMembers } from '../../shares/schemas/share-members.interface'\nimport type { Share } from '../../shares/schemas/share.interface'\nimport { sharesMembers } from '../../shares/schemas/shares-members.schema'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SPACE_ROLE } from '../../spaces/constants/spaces'\nimport type { SpaceMembers } from '../../spaces/schemas/space-members.interface'\nimport { spacesMembers } from '../../spaces/schemas/spaces-members.schema'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { USER_ROLE } from '../../users/constants/user'\nimport type { User } from '../../users/schemas/user.interface'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport { CACHE_LINK_UUID_PREFIX, CACHE_LINK_UUID_TTL } from '../constants/cache'\nimport { LINK_TYPE } from '../constants/links'\nimport type { LinkAsUser, LinkGuest } from '../interfaces/link-guest.interface'\nimport type { SpaceLink } from '../interfaces/link-space.interface'\nimport type { Link } from '../schemas/link.interface'\nimport { links } from '../schemas/links.schema'\n\n@Injectable()\nexport class LinksQueries {\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache\n ) {}\n\n async linkFromShare(ownerId: number, linkId: number, shareId: number, isAdmin: number = 0): Promise<LinkGuest> {\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n permissions: sharesMembers.permissions,\n language: users.language,\n isActive: users.isActive\n })\n .from(links)\n .innerJoin(shares, and(eq(shares.id, shareId), or(eq(shares.ownerId, ownerId), and(eq(sql`${isAdmin}`, 1), isNull(shares.ownerId)))))\n .innerJoin(sharesMembers, and(eq(sharesMembers.shareId, shares.id), eq(sharesMembers.userId, links.userId), eq(sharesMembers.linkId, linkId)))\n .innerJoin(users, eq(users.id, links.userId))\n .where(eq(links.id, linkId))\n .limit(1)\n return r as LinkGuest\n }\n\n async linkFromSpace(managerId: number, linkId: number, spaceId: number): Promise<LinkGuest> {\n const linkMember: any = alias(spacesMembers, 'linkMember')\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n permissions: linkMember.permissions,\n language: users.language,\n isActive: users.isActive\n })\n .from(links)\n .innerJoin(\n spacesMembers,\n and(eq(spacesMembers.spaceId, spaceId), eq(spacesMembers.userId, managerId), eq(spacesMembers.role, SPACE_ROLE.IS_MANAGER))\n )\n .innerJoin(linkMember, and(eq(linkMember.spaceId, spacesMembers.spaceId), eq(linkMember.userId, links.userId), eq(linkMember.linkId, linkId)))\n .innerJoin(users, eq(users.id, links.userId))\n .where(eq(links.id, linkId))\n .limit(1)\n return r as LinkGuest\n }\n\n async updateLinkFromSpaceOrShare(\n link: LinkGuest,\n shareId: number,\n diffUser: Partial<User>,\n diffLink: Partial<Link>,\n diffShare: Partial<Share>,\n diffMember: Partial<ShareMembers>\n ) {\n if (Object.keys(diffUser).length) {\n await this.db.update(users).set(diffUser).where(eq(users.id, link.userId))\n }\n if (Object.keys(diffLink).length) {\n await this.db.update(links).set(diffLink).where(eq(links.id, link.id))\n }\n if (Object.keys(diffShare).length) {\n await this.db.update(shares).set(diffShare).where(eq(shares.id, shareId))\n }\n if (Object.keys(diffMember).length) {\n await this.db\n .update(sharesMembers)\n .set(diffMember)\n .where(and(eq(sharesMembers.shareId, shareId), eq(sharesMembers.userId, link.userId), eq(sharesMembers.linkId, link.id)))\n }\n }\n\n async createLinkToSpaceOrShare(guestId: number, spaceOrShareId: number, type: LINK_TYPE, link: Partial<LinkGuest>): Promise<number> {\n const linkId = dbGetInsertedId(await this.db.insert(links).values(link as Link))\n if (type === LINK_TYPE.SPACE) {\n await this.db.insert(spacesMembers).values({\n userId: guestId,\n spaceId: spaceOrShareId,\n permissions: link.permissions,\n role: SPACE_ROLE.IS_MEMBER,\n linkId: linkId\n } as SpaceMembers)\n } else {\n await this.db.insert(sharesMembers).values({\n userId: guestId,\n shareId: spaceOrShareId,\n linkId: linkId,\n permissions: link.permissions\n } as ShareMembers)\n }\n return linkId\n }\n\n allLinksFromSpaceOrShare(spaceOrShareId: number, type: LINK_TYPE): Promise<{ id: number; linkId: number }[]> {\n const members: any = alias(type == 'share' ? sharesMembers : spacesMembers, 'members')\n return this.db\n .select({ id: users.id, linkId: members.linkId })\n .from(members)\n .innerJoin(users, and(eq(users.id, members.userId), eq(users.role, USER_ROLE.LINK)))\n .where(and(eq(type == 'share' ? members.shareId : members.spaceId, spaceOrShareId), isNotNull(members.linkId)))\n }\n\n async linkFromUUID(uuid: string): Promise<LinkAsUser> {\n const { password, ...userColumns } = getTableColumns(users)\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n user: { ...userColumns }\n })\n .from(links)\n .leftJoin(users, eq(users.id, links.userId))\n .where(eq(links.uuid, uuid))\n .limit(1)\n return r\n }\n\n async spaceLink(uuid: string): Promise<SpaceLink> {\n const shareOwner: any = alias(users, 'shareOwner')\n const shareSpaceRoot: any = alias(spacesRoots, 'shareSpaceRoot')\n const [r]: SpaceLink[] = await this.db\n .select({\n share: {\n name: shares.name,\n alias: shares.alias,\n hasParent: isNotNull(shares.parentId).mapWith(Boolean),\n isDir: sql`IF (${isNotNull(shares.externalPath)}, 1 ,${files.isDir})`.mapWith(Boolean),\n mime: files.mime\n },\n space: { name: spaces.name, alias: spaces.alias },\n owner: { login: shareOwner.login, fullName: userFullNameSQL(shareOwner) }\n })\n .from(links)\n .leftJoin(sharesMembers, eq(sharesMembers.linkId, links.id))\n .leftJoin(shares, eq(shares.id, sharesMembers.shareId))\n .leftJoin(shareOwner, eq(shareOwner.id, shares.ownerId))\n .leftJoin(spacesMembers, eq(spacesMembers.linkId, links.id))\n .leftJoin(spaces, eq(spaces.id, spacesMembers.spaceId))\n .leftJoin(shareSpaceRoot, and(isNull(shares.externalPath), isNull(shares.fileId), eq(shareSpaceRoot.id, shares.spaceRootId)))\n .leftJoin(\n files,\n or(\n and(isNotNull(shares.fileId), eq(files.id, shares.fileId)),\n and(isNull(shares.externalPath), isNotNull(shareSpaceRoot.fileId), eq(files.id, shareSpaceRoot.fileId))\n )\n )\n .where(eq(links.uuid, uuid))\n .limit(1)\n return r\n }\n\n async incrementLinkAccess(uuid: string) {\n await this.db\n .update(links)\n .set({ nbAccess: sql`${links.nbAccess} + 1` } as Record<keyof Link, any>)\n .where(eq(links.uuid, uuid))\n .limit(1)\n }\n\n async isUniqueUUID(userId: number, uuid: string) {\n const [r] = await this.db.select({ check: links.uuid }).from(links).where(eq(links.uuid, uuid)).limit(1)\n if (!r) {\n // uuid does not exist in db\n const cacheKey = this.cache.genSlugKey(CACHE_LINK_UUID_PREFIX, userId, uuid)\n // check if uuid was already requested\n if (!(await this.cache.has(cacheKey))) {\n // store uuid to prevent reuse\n await this.cache.set(cacheKey, uuid, CACHE_LINK_UUID_TTL)\n return true\n }\n return false\n }\n return false\n }\n\n isReservedUUID(userId: number, uuid: string): Promise<boolean> {\n // check if uuid is reserved\n return this.cache.has(this.cache.genSlugKey(CACHE_LINK_UUID_PREFIX, userId, uuid))\n }\n}\n"],"names":["LinksQueries","linkFromShare","ownerId","linkId","shareId","isAdmin","r","db","select","getTableColumns","links","permissions","sharesMembers","language","users","isActive","from","innerJoin","shares","and","eq","id","or","sql","isNull","userId","where","limit","linkFromSpace","managerId","spaceId","linkMember","alias","spacesMembers","role","SPACE_ROLE","IS_MANAGER","updateLinkFromSpaceOrShare","link","diffUser","diffLink","diffShare","diffMember","Object","keys","length","update","set","createLinkToSpaceOrShare","guestId","spaceOrShareId","type","dbGetInsertedId","insert","values","LINK_TYPE","SPACE","IS_MEMBER","allLinksFromSpaceOrShare","members","USER_ROLE","LINK","isNotNull","linkFromUUID","uuid","password","userColumns","user","leftJoin","spaceLink","shareOwner","shareSpaceRoot","spacesRoots","share","name","hasParent","parentId","mapWith","Boolean","isDir","externalPath","files","mime","space","spaces","owner","login","fullName","userFullNameSQL","fileId","spaceRootId","incrementLinkAccess","nbAccess","isUniqueUUID","check","cacheKey","cache","genSlugKey","CACHE_LINK_UUID_PREFIX","has","CACHE_LINK_UUID_TTL","isReservedUUID"],"mappings":"AAAA;;;;CAIC;;;;+BA8BYA;;;eAAAA;;;wBA5BsB;4BACkC;2BAC/C;8BACA;2BACY;uBAEF;6BACV;qCAGQ;8BACP;wBACI;qCAEG;mCACF;8BACL;sBACG;6BAEa;uBACqB;uBAClC;6BAIJ;;;;;;;;;;;;;;;AAGf,IAAA,AAAMA,eAAN,MAAMA;IAMX,MAAMC,cAAcC,OAAe,EAAEC,MAAc,EAAEC,OAAe,EAAEC,UAAkB,CAAC,EAAsB;QAC7G,MAAM,CAACC,EAAE,GAAG,MAAM,IAAI,CAACC,EAAE,CACtBC,MAAM,CAAC;YACN,GAAGC,IAAAA,2BAAe,EAACC,kBAAK,CAAC;YACzBC,aAAaC,kCAAa,CAACD,WAAW;YACtCE,UAAUC,kBAAK,CAACD,QAAQ;YACxBE,UAAUD,kBAAK,CAACC,QAAQ;QAC1B,GACCC,IAAI,CAACN,kBAAK,EACVO,SAAS,CAACC,oBAAM,EAAEC,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACF,oBAAM,CAACG,EAAE,EAAEjB,UAAUkB,IAAAA,cAAE,EAACF,IAAAA,cAAE,EAACF,oBAAM,CAAChB,OAAO,EAAEA,UAAUiB,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACG,IAAAA,eAAG,CAAA,CAAC,EAAElB,QAAQ,CAAC,EAAE,IAAImB,IAAAA,kBAAM,EAACN,oBAAM,CAAChB,OAAO,MAC/He,SAAS,CAACL,kCAAa,EAAEO,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACR,kCAAa,CAACR,OAAO,EAAEc,oBAAM,CAACG,EAAE,GAAGD,IAAAA,cAAE,EAACR,kCAAa,CAACa,MAAM,EAAEf,kBAAK,CAACe,MAAM,GAAGL,IAAAA,cAAE,EAACR,kCAAa,CAACT,MAAM,EAAEA,UACpIc,SAAS,CAACH,kBAAK,EAAEM,IAAAA,cAAE,EAACN,kBAAK,CAACO,EAAE,EAAEX,kBAAK,CAACe,MAAM,GAC1CC,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACW,EAAE,EAAElB,SACnBwB,KAAK,CAAC;QACT,OAAOrB;IACT;IAEA,MAAMsB,cAAcC,SAAiB,EAAE1B,MAAc,EAAE2B,OAAe,EAAsB;QAC1F,MAAMC,aAAkBC,IAAAA,gBAAK,EAACC,kCAAa,EAAE;QAC7C,MAAM,CAAC3B,EAAE,GAAG,MAAM,IAAI,CAACC,EAAE,CACtBC,MAAM,CAAC;YACN,GAAGC,IAAAA,2BAAe,EAACC,kBAAK,CAAC;YACzBC,aAAaoB,WAAWpB,WAAW;YACnCE,UAAUC,kBAAK,CAACD,QAAQ;YACxBE,UAAUD,kBAAK,CAACC,QAAQ;QAC1B,GACCC,IAAI,CAACN,kBAAK,EACVO,SAAS,CACRgB,kCAAa,EACbd,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACa,kCAAa,CAACH,OAAO,EAAEA,UAAUV,IAAAA,cAAE,EAACa,kCAAa,CAACR,MAAM,EAAEI,YAAYT,IAAAA,cAAE,EAACa,kCAAa,CAACC,IAAI,EAAEC,kBAAU,CAACC,UAAU,IAE1HnB,SAAS,CAACc,YAAYZ,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACW,WAAWD,OAAO,EAAEG,kCAAa,CAACH,OAAO,GAAGV,IAAAA,cAAE,EAACW,WAAWN,MAAM,EAAEf,kBAAK,CAACe,MAAM,GAAGL,IAAAA,cAAE,EAACW,WAAW5B,MAAM,EAAEA,UACpIc,SAAS,CAACH,kBAAK,EAAEM,IAAAA,cAAE,EAACN,kBAAK,CAACO,EAAE,EAAEX,kBAAK,CAACe,MAAM,GAC1CC,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACW,EAAE,EAAElB,SACnBwB,KAAK,CAAC;QACT,OAAOrB;IACT;IAEA,MAAM+B,2BACJC,IAAe,EACflC,OAAe,EACfmC,QAAuB,EACvBC,QAAuB,EACvBC,SAAyB,EACzBC,UAAiC,EACjC;QACA,IAAIC,OAAOC,IAAI,CAACL,UAAUM,MAAM,EAAE;YAChC,MAAM,IAAI,CAACtC,EAAE,CAACuC,MAAM,CAAChC,kBAAK,EAAEiC,GAAG,CAACR,UAAUb,KAAK,CAACN,IAAAA,cAAE,EAACN,kBAAK,CAACO,EAAE,EAAEiB,KAAKb,MAAM;QAC1E;QACA,IAAIkB,OAAOC,IAAI,CAACJ,UAAUK,MAAM,EAAE;YAChC,MAAM,IAAI,CAACtC,EAAE,CAACuC,MAAM,CAACpC,kBAAK,EAAEqC,GAAG,CAACP,UAAUd,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACW,EAAE,EAAEiB,KAAKjB,EAAE;QACtE;QACA,IAAIsB,OAAOC,IAAI,CAACH,WAAWI,MAAM,EAAE;YACjC,MAAM,IAAI,CAACtC,EAAE,CAACuC,MAAM,CAAC5B,oBAAM,EAAE6B,GAAG,CAACN,WAAWf,KAAK,CAACN,IAAAA,cAAE,EAACF,oBAAM,CAACG,EAAE,EAAEjB;QAClE;QACA,IAAIuC,OAAOC,IAAI,CAACF,YAAYG,MAAM,EAAE;YAClC,MAAM,IAAI,CAACtC,EAAE,CACVuC,MAAM,CAAClC,kCAAa,EACpBmC,GAAG,CAACL,YACJhB,KAAK,CAACP,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACR,kCAAa,CAACR,OAAO,EAAEA,UAAUgB,IAAAA,cAAE,EAACR,kCAAa,CAACa,MAAM,EAAEa,KAAKb,MAAM,GAAGL,IAAAA,cAAE,EAACR,kCAAa,CAACT,MAAM,EAAEmC,KAAKjB,EAAE;QAC1H;IACF;IAEA,MAAM2B,yBAAyBC,OAAe,EAAEC,cAAsB,EAAEC,IAAe,EAAEb,IAAwB,EAAmB;QAClI,MAAMnC,SAASiD,IAAAA,sBAAe,EAAC,MAAM,IAAI,CAAC7C,EAAE,CAAC8C,MAAM,CAAC3C,kBAAK,EAAE4C,MAAM,CAAChB;QAClE,IAAIa,SAASI,gBAAS,CAACC,KAAK,EAAE;YAC5B,MAAM,IAAI,CAACjD,EAAE,CAAC8C,MAAM,CAACpB,kCAAa,EAAEqB,MAAM,CAAC;gBACzC7B,QAAQwB;gBACRnB,SAASoB;gBACTvC,aAAa2B,KAAK3B,WAAW;gBAC7BuB,MAAMC,kBAAU,CAACsB,SAAS;gBAC1BtD,QAAQA;YACV;QACF,OAAO;YACL,MAAM,IAAI,CAACI,EAAE,CAAC8C,MAAM,CAACzC,kCAAa,EAAE0C,MAAM,CAAC;gBACzC7B,QAAQwB;gBACR7C,SAAS8C;gBACT/C,QAAQA;gBACRQ,aAAa2B,KAAK3B,WAAW;YAC/B;QACF;QACA,OAAOR;IACT;IAEAuD,yBAAyBR,cAAsB,EAAEC,IAAe,EAA6C;QAC3G,MAAMQ,UAAe3B,IAAAA,gBAAK,EAACmB,QAAQ,UAAUvC,kCAAa,GAAGqB,kCAAa,EAAE;QAC5E,OAAO,IAAI,CAAC1B,EAAE,CACXC,MAAM,CAAC;YAAEa,IAAIP,kBAAK,CAACO,EAAE;YAAElB,QAAQwD,QAAQxD,MAAM;QAAC,GAC9Ca,IAAI,CAAC2C,SACL1C,SAAS,CAACH,kBAAK,EAAEK,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAACN,kBAAK,CAACO,EAAE,EAAEsC,QAAQlC,MAAM,GAAGL,IAAAA,cAAE,EAACN,kBAAK,CAACoB,IAAI,EAAE0B,eAAS,CAACC,IAAI,IAChFnC,KAAK,CAACP,IAAAA,eAAG,EAACC,IAAAA,cAAE,EAAC+B,QAAQ,UAAUQ,QAAQvD,OAAO,GAAGuD,QAAQ7B,OAAO,EAAEoB,iBAAiBY,IAAAA,qBAAS,EAACH,QAAQxD,MAAM;IAChH;IAEA,MAAM4D,aAAaC,IAAY,EAAuB;QACpD,MAAM,EAAEC,QAAQ,EAAE,GAAGC,aAAa,GAAGzD,IAAAA,2BAAe,EAACK,kBAAK;QAC1D,MAAM,CAACR,EAAE,GAAG,MAAM,IAAI,CAACC,EAAE,CACtBC,MAAM,CAAC;YACN,GAAGC,IAAAA,2BAAe,EAACC,kBAAK,CAAC;YACzByD,MAAM;gBAAE,GAAGD,WAAW;YAAC;QACzB,GACClD,IAAI,CAACN,kBAAK,EACV0D,QAAQ,CAACtD,kBAAK,EAAEM,IAAAA,cAAE,EAACN,kBAAK,CAACO,EAAE,EAAEX,kBAAK,CAACe,MAAM,GACzCC,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACsD,IAAI,EAAEA,OACrBrC,KAAK,CAAC;QACT,OAAOrB;IACT;IAEA,MAAM+D,UAAUL,IAAY,EAAsB;QAChD,MAAMM,aAAkBtC,IAAAA,gBAAK,EAAClB,kBAAK,EAAE;QACrC,MAAMyD,iBAAsBvC,IAAAA,gBAAK,EAACwC,8BAAW,EAAE;QAC/C,MAAM,CAAClE,EAAE,GAAgB,MAAM,IAAI,CAACC,EAAE,CACnCC,MAAM,CAAC;YACNiE,OAAO;gBACLC,MAAMxD,oBAAM,CAACwD,IAAI;gBACjB1C,OAAOd,oBAAM,CAACc,KAAK;gBACnB2C,WAAWb,IAAAA,qBAAS,EAAC5C,oBAAM,CAAC0D,QAAQ,EAAEC,OAAO,CAACC;gBAC9CC,OAAOxD,IAAAA,eAAG,CAAA,CAAC,IAAI,EAAEuC,IAAAA,qBAAS,EAAC5C,oBAAM,CAAC8D,YAAY,EAAE,KAAK,EAAEC,kBAAK,CAACF,KAAK,CAAC,CAAC,CAAC,CAACF,OAAO,CAACC;gBAC9EI,MAAMD,kBAAK,CAACC,IAAI;YAClB;YACAC,OAAO;gBAAET,MAAMU,oBAAM,CAACV,IAAI;gBAAE1C,OAAOoD,oBAAM,CAACpD,KAAK;YAAC;YAChDqD,OAAO;gBAAEC,OAAOhB,WAAWgB,KAAK;gBAAEC,UAAUC,IAAAA,4BAAe,EAAClB;YAAY;QAC1E,GACCtD,IAAI,CAACN,kBAAK,EACV0D,QAAQ,CAACxD,kCAAa,EAAEQ,IAAAA,cAAE,EAACR,kCAAa,CAACT,MAAM,EAAEO,kBAAK,CAACW,EAAE,GACzD+C,QAAQ,CAAClD,oBAAM,EAAEE,IAAAA,cAAE,EAACF,oBAAM,CAACG,EAAE,EAAET,kCAAa,CAACR,OAAO,GACpDgE,QAAQ,CAACE,YAAYlD,IAAAA,cAAE,EAACkD,WAAWjD,EAAE,EAAEH,oBAAM,CAAChB,OAAO,GACrDkE,QAAQ,CAACnC,kCAAa,EAAEb,IAAAA,cAAE,EAACa,kCAAa,CAAC9B,MAAM,EAAEO,kBAAK,CAACW,EAAE,GACzD+C,QAAQ,CAACgB,oBAAM,EAAEhE,IAAAA,cAAE,EAACgE,oBAAM,CAAC/D,EAAE,EAAEY,kCAAa,CAACH,OAAO,GACpDsC,QAAQ,CAACG,gBAAgBpD,IAAAA,eAAG,EAACK,IAAAA,kBAAM,EAACN,oBAAM,CAAC8D,YAAY,GAAGxD,IAAAA,kBAAM,EAACN,oBAAM,CAACuE,MAAM,GAAGrE,IAAAA,cAAE,EAACmD,eAAelD,EAAE,EAAEH,oBAAM,CAACwE,WAAW,IACzHtB,QAAQ,CACPa,kBAAK,EACL3D,IAAAA,cAAE,EACAH,IAAAA,eAAG,EAAC2C,IAAAA,qBAAS,EAAC5C,oBAAM,CAACuE,MAAM,GAAGrE,IAAAA,cAAE,EAAC6D,kBAAK,CAAC5D,EAAE,EAAEH,oBAAM,CAACuE,MAAM,IACxDtE,IAAAA,eAAG,EAACK,IAAAA,kBAAM,EAACN,oBAAM,CAAC8D,YAAY,GAAGlB,IAAAA,qBAAS,EAACS,eAAekB,MAAM,GAAGrE,IAAAA,cAAE,EAAC6D,kBAAK,CAAC5D,EAAE,EAAEkD,eAAekB,MAAM,KAGxG/D,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACsD,IAAI,EAAEA,OACrBrC,KAAK,CAAC;QACT,OAAOrB;IACT;IAEA,MAAMqF,oBAAoB3B,IAAY,EAAE;QACtC,MAAM,IAAI,CAACzD,EAAE,CACVuC,MAAM,CAACpC,kBAAK,EACZqC,GAAG,CAAC;YAAE6C,UAAUrE,IAAAA,eAAG,CAAA,CAAC,EAAEb,kBAAK,CAACkF,QAAQ,CAAC,IAAI,CAAC;QAAC,GAC3ClE,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACsD,IAAI,EAAEA,OACrBrC,KAAK,CAAC;IACX;IAEA,MAAMkE,aAAapE,MAAc,EAAEuC,IAAY,EAAE;QAC/C,MAAM,CAAC1D,EAAE,GAAG,MAAM,IAAI,CAACC,EAAE,CAACC,MAAM,CAAC;YAAEsF,OAAOpF,kBAAK,CAACsD,IAAI;QAAC,GAAGhD,IAAI,CAACN,kBAAK,EAAEgB,KAAK,CAACN,IAAAA,cAAE,EAACV,kBAAK,CAACsD,IAAI,EAAEA,OAAOrC,KAAK,CAAC;QACtG,IAAI,CAACrB,GAAG;YACN,4BAA4B;YAC5B,MAAMyF,WAAW,IAAI,CAACC,KAAK,CAACC,UAAU,CAACC,6BAAsB,EAAEzE,QAAQuC;YACvE,sCAAsC;YACtC,IAAI,CAAE,MAAM,IAAI,CAACgC,KAAK,CAACG,GAAG,CAACJ,WAAY;gBACrC,8BAA8B;gBAC9B,MAAM,IAAI,CAACC,KAAK,CAACjD,GAAG,CAACgD,UAAU/B,MAAMoC,0BAAmB;gBACxD,OAAO;YACT;YACA,OAAO;QACT;QACA,OAAO;IACT;IAEAC,eAAe5E,MAAc,EAAEuC,IAAY,EAAoB;QAC7D,4BAA4B;QAC5B,OAAO,IAAI,CAACgC,KAAK,CAACG,GAAG,CAAC,IAAI,CAACH,KAAK,CAACC,UAAU,CAACC,6BAAsB,EAAEzE,QAAQuC;IAC9E;IA7KA,YACE,AAA4CzD,EAAY,EACxD,AAAiByF,KAAY,CAC7B;aAF4CzF,KAAAA;aAC3ByF,QAAAA;IAChB;AA2KL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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, eq, getTableColumns, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { alias } from 'drizzle-orm/mysql-core'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport type { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbGetInsertedId } from '../../../infrastructure/database/utils'\nimport { files } from '../../files/schemas/files.schema'\nimport type { ShareMembers } from '../../shares/schemas/share-members.interface'\nimport type { Share } from '../../shares/schemas/share.interface'\nimport { sharesMembers } from '../../shares/schemas/shares-members.schema'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SPACE_ROLE } from '../../spaces/constants/spaces'\nimport type { SpaceMembers } from '../../spaces/schemas/space-members.interface'\nimport { spacesMembers } from '../../spaces/schemas/spaces-members.schema'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { USER_ROLE } from '../../users/constants/user'\nimport type { User } from '../../users/schemas/user.interface'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport { CACHE_LINK_UUID_PREFIX, CACHE_LINK_UUID_TTL } from '../constants/cache'\nimport { LINK_TYPE } from '../constants/links'\nimport type { LinkAsUser, LinkGuest } from '../interfaces/link-guest.interface'\nimport type { SpaceLink } from '../interfaces/link-space.interface'\nimport type { Link } from '../schemas/link.interface'\nimport { links } from '../schemas/links.schema'\n\n@Injectable()\nexport class LinksQueries {\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache\n ) {}\n\n async linkFromShare(ownerId: number, linkId: number, shareId: number, isAdmin: number = 0): Promise<LinkGuest> {\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n permissions: sharesMembers.permissions,\n language: users.language,\n isActive: users.isActive\n })\n .from(links)\n .innerJoin(shares, and(eq(shares.id, shareId), or(eq(shares.ownerId, ownerId), and(eq(sql`${isAdmin}`, 1), isNull(shares.ownerId)))))\n .innerJoin(sharesMembers, and(eq(sharesMembers.shareId, shares.id), eq(sharesMembers.userId, links.userId), eq(sharesMembers.linkId, linkId)))\n .innerJoin(users, eq(users.id, links.userId))\n .where(eq(links.id, linkId))\n .limit(1)\n return r as LinkGuest\n }\n\n async linkFromSpace(managerId: number, linkId: number, spaceId: number): Promise<LinkGuest> {\n const linkMember: any = alias(spacesMembers, 'linkMember')\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n permissions: linkMember.permissions,\n language: users.language,\n isActive: users.isActive\n })\n .from(links)\n .innerJoin(\n spacesMembers,\n and(eq(spacesMembers.spaceId, spaceId), eq(spacesMembers.userId, managerId), eq(spacesMembers.role, SPACE_ROLE.IS_MANAGER))\n )\n .innerJoin(linkMember, and(eq(linkMember.spaceId, spacesMembers.spaceId), eq(linkMember.userId, links.userId), eq(linkMember.linkId, linkId)))\n .innerJoin(users, eq(users.id, links.userId))\n .where(eq(links.id, linkId))\n .limit(1)\n return r as LinkGuest\n }\n\n async updateLinkFromSpaceOrShare(\n link: LinkGuest,\n shareId: number,\n diffUser: Partial<User>,\n diffLink: Partial<Link>,\n diffShare: Partial<Share>,\n diffMember: Partial<ShareMembers>\n ) {\n if (Object.keys(diffUser).length) {\n await this.db.update(users).set(diffUser).where(eq(users.id, link.userId))\n }\n if (Object.keys(diffLink).length) {\n await this.db.update(links).set(diffLink).where(eq(links.id, link.id))\n }\n if (Object.keys(diffShare).length) {\n await this.db.update(shares).set(diffShare).where(eq(shares.id, shareId))\n }\n if (Object.keys(diffMember).length) {\n await this.db\n .update(sharesMembers)\n .set(diffMember)\n .where(and(eq(sharesMembers.shareId, shareId), eq(sharesMembers.userId, link.userId), eq(sharesMembers.linkId, link.id)))\n }\n }\n\n async createLinkToSpaceOrShare(guestId: number, spaceOrShareId: number, type: LINK_TYPE, link: Partial<LinkGuest>): Promise<number> {\n const linkId = dbGetInsertedId(await this.db.insert(links).values(link as Link))\n if (type === LINK_TYPE.SPACE) {\n await this.db.insert(spacesMembers).values({\n userId: guestId,\n spaceId: spaceOrShareId,\n permissions: link.permissions,\n role: SPACE_ROLE.IS_MEMBER,\n linkId: linkId\n } as SpaceMembers)\n } else {\n await this.db.insert(sharesMembers).values({\n userId: guestId,\n shareId: spaceOrShareId,\n linkId: linkId,\n permissions: link.permissions\n } as ShareMembers)\n }\n return linkId\n }\n\n allLinksFromSpaceOrShare(spaceOrShareId: number, type: LINK_TYPE): Promise<{ id: number; linkId: number }[]> {\n const members: any = alias(type == 'share' ? sharesMembers : spacesMembers, 'members')\n return this.db\n .select({ id: users.id, linkId: members.linkId })\n .from(members)\n .innerJoin(users, and(eq(users.id, members.userId), eq(users.role, USER_ROLE.LINK)))\n .where(and(eq(type == 'share' ? members.shareId : members.spaceId, spaceOrShareId), isNotNull(members.linkId)))\n }\n\n async linkFromUUID(uuid: string): Promise<LinkAsUser> {\n const { password, ...userColumns } = getTableColumns(users)\n const [r] = await this.db\n .select({\n ...getTableColumns(links),\n user: { ...userColumns }\n })\n .from(links)\n .leftJoin(users, eq(users.id, links.userId))\n .where(eq(links.uuid, uuid))\n .limit(1)\n return r\n }\n\n async spaceLink(uuid: string): Promise<SpaceLink> {\n const shareOwner: any = alias(users, 'shareOwner')\n const shareSpaceRoot: any = alias(spacesRoots, 'shareSpaceRoot')\n const [r]: SpaceLink[] = await this.db\n .select({\n share: {\n name: shares.name,\n alias: shares.alias,\n hasParent: isNotNull(shares.parentId).mapWith(Boolean),\n isDir: sql`IF (${isNotNull(shares.externalPath)}, 1 ,${files.isDir})`.mapWith(Boolean),\n mime: files.mime\n },\n space: { name: spaces.name, alias: spaces.alias },\n owner: { login: shareOwner.login, fullName: userFullNameSQL(shareOwner) }\n })\n .from(links)\n .leftJoin(sharesMembers, eq(sharesMembers.linkId, links.id))\n .leftJoin(shares, eq(shares.id, sharesMembers.shareId))\n .leftJoin(shareOwner, eq(shareOwner.id, shares.ownerId))\n .leftJoin(spacesMembers, eq(spacesMembers.linkId, links.id))\n .leftJoin(spaces, eq(spaces.id, spacesMembers.spaceId))\n .leftJoin(shareSpaceRoot, and(isNull(shares.externalPath), isNull(shares.fileId), eq(shareSpaceRoot.id, shares.spaceRootId)))\n .leftJoin(\n files,\n or(\n and(isNotNull(shares.fileId), eq(files.id, shares.fileId)),\n and(isNull(shares.externalPath), isNotNull(shareSpaceRoot.fileId), eq(files.id, shareSpaceRoot.fileId))\n )\n )\n .where(eq(links.uuid, uuid))\n .limit(1)\n return r\n }\n\n async incrementLinkNbAccess(uuid: string) {\n await this.db\n .update(links)\n .set({ nbAccess: sql`${links.nbAccess} + 1` } as Record<keyof Link, any>)\n .where(eq(links.uuid, uuid))\n .limit(1)\n }\n\n async isUniqueUUID(userId: number, uuid: string) {\n const [r] = await this.db.select({ check: links.uuid }).from(links).where(eq(links.uuid, uuid)).limit(1)\n if (!r) {\n // uuid does not exist in db\n const cacheKey = this.cache.genSlugKey(CACHE_LINK_UUID_PREFIX, userId, uuid)\n // check if uuid was already requested\n if (!(await this.cache.has(cacheKey))) {\n // store uuid to prevent reuse\n await this.cache.set(cacheKey, uuid, CACHE_LINK_UUID_TTL)\n return true\n }\n return false\n }\n return false\n }\n\n isReservedUUID(userId: number, uuid: string): Promise<boolean> {\n // check if uuid is reserved\n return this.cache.has(this.cache.genSlugKey(CACHE_LINK_UUID_PREFIX, userId, uuid))\n }\n}\n"],"names":["LinksQueries","linkFromShare","ownerId","linkId","shareId","isAdmin","r","db","select","getTableColumns","links","permissions","sharesMembers","language","users","isActive","from","innerJoin","shares","and","eq","id","or","sql","isNull","userId","where","limit","linkFromSpace","managerId","spaceId","linkMember","alias","spacesMembers","role","SPACE_ROLE","IS_MANAGER","updateLinkFromSpaceOrShare","link","diffUser","diffLink","diffShare","diffMember","Object","keys","length","update","set","createLinkToSpaceOrShare","guestId","spaceOrShareId","type","dbGetInsertedId","insert","values","LINK_TYPE","SPACE","IS_MEMBER","allLinksFromSpaceOrShare","members","USER_ROLE","LINK","isNotNull","linkFromUUID","uuid","password","userColumns","user","leftJoin","spaceLink","shareOwner","shareSpaceRoot","spacesRoots","share","name","hasParent","parentId","mapWith","Boolean","isDir","externalPath","files","mime","space","spaces","owner","login","fullName","userFullNameSQL","fileId","spaceRootId","incrementLinkNbAccess","nbAccess","isUniqueUUID","check","cacheKey","cache","genSlugKey","CACHE_LINK_UUID_PREFIX","has","CACHE_LINK_UUID_TTL","isReservedUUID"],"mappings":"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"}