@sync-in/server 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. package/CHANGELOG.md +56 -11
  2. package/environment/environment.dist.yaml +29 -26
  3. package/package.json +15 -15
  4. package/server/app.constants.js +9 -0
  5. package/server/app.constants.js.map +1 -1
  6. package/server/app.module.js +4 -0
  7. package/server/app.module.js.map +1 -1
  8. package/server/applications/admin/admin.module.js +6 -1
  9. package/server/applications/admin/admin.module.js.map +1 -1
  10. package/server/applications/{notifications/interfaces/user-mail-notification.js → admin/interfaces/check-update.interfaces.js} +1 -1
  11. package/server/applications/admin/interfaces/check-update.interfaces.js.map +1 -0
  12. package/server/applications/admin/services/admin-scheduler.service.js +53 -0
  13. package/server/applications/admin/services/admin-scheduler.service.js.map +1 -0
  14. package/server/applications/admin/services/admin.service.js +102 -0
  15. package/server/applications/admin/services/admin.service.js.map +1 -0
  16. package/server/applications/admin/services/admin.service.spec.js +46 -0
  17. package/server/applications/admin/services/admin.service.spec.js.map +1 -0
  18. package/server/applications/admin/utils/check-update.js +28 -0
  19. package/server/applications/admin/utils/check-update.js.map +1 -0
  20. package/server/applications/comments/services/comments-manager.service.js +1 -1
  21. package/server/applications/comments/services/comments-manager.service.js.map +1 -1
  22. package/server/applications/comments/services/comments-manager.service.spec.js +1 -1
  23. package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
  24. package/server/applications/comments/services/comments-queries.service.js.map +1 -1
  25. package/server/applications/files/constants/cache.js +10 -1
  26. package/server/applications/files/constants/cache.js.map +1 -1
  27. package/server/applications/files/constants/only-office.js +0 -25
  28. package/server/applications/files/constants/only-office.js.map +1 -1
  29. package/server/applications/files/constants/operations.js +20 -3
  30. package/server/applications/files/constants/operations.js.map +1 -1
  31. package/server/applications/files/dto/file-operations.dto.js +7 -0
  32. package/server/applications/files/dto/file-operations.dto.js.map +1 -1
  33. package/server/applications/files/files-only-office.controller.js +3 -2
  34. package/server/applications/files/files-only-office.controller.js.map +1 -1
  35. package/server/applications/files/files-only-office.controller.spec.js +6 -5
  36. package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
  37. package/server/applications/files/files.controller.js +88 -8
  38. package/server/applications/files/files.controller.js.map +1 -1
  39. package/server/applications/files/files.controller.spec.js +11 -4
  40. package/server/applications/files/files.controller.spec.js.map +1 -1
  41. package/server/applications/files/guards/files-only-office.guard.js +6 -0
  42. package/server/applications/files/guards/files-only-office.guard.js.map +1 -1
  43. package/server/applications/files/interfaces/file-db-props.interface.js.map +1 -1
  44. package/server/applications/files/interfaces/file-props.interface.js.map +1 -1
  45. package/server/applications/files/interfaces/only-office-config.interface.js.map +1 -1
  46. package/server/applications/files/services/files-content-manager.service.js +3 -3
  47. package/server/applications/files/services/files-content-manager.service.js.map +1 -1
  48. package/server/applications/files/services/files-lock-manager.service.js +61 -22
  49. package/server/applications/files/services/files-lock-manager.service.js.map +1 -1
  50. package/server/applications/files/services/files-manager.service.js +122 -24
  51. package/server/applications/files/services/files-manager.service.js.map +1 -1
  52. package/server/applications/files/services/files-manager.service.spec.js +15 -0
  53. package/server/applications/files/services/files-manager.service.spec.js.map +1 -1
  54. package/server/applications/files/services/files-methods.service.js +38 -8
  55. package/server/applications/files/services/files-methods.service.js.map +1 -1
  56. package/server/applications/files/services/files-only-office-manager.service.js +12 -12
  57. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  58. package/server/applications/files/services/files-parser.service.js +1 -1
  59. package/server/applications/files/services/files-parser.service.js.map +1 -1
  60. package/server/applications/files/services/files-queries.service.js +10 -0
  61. package/server/applications/files/services/files-queries.service.js.map +1 -1
  62. package/server/applications/files/utils/files.js +1 -1
  63. package/server/applications/files/utils/files.js.map +1 -1
  64. package/server/applications/files/utils/send-file.js +3 -2
  65. package/server/applications/files/utils/send-file.js.map +1 -1
  66. package/server/applications/links/services/links-queries.service.js +1 -1
  67. package/server/applications/links/services/links-queries.service.js.map +1 -1
  68. package/server/applications/notifications/constants/notifications.js +5 -1
  69. package/server/applications/notifications/constants/notifications.js.map +1 -1
  70. package/server/applications/notifications/i18n/de.js +8 -2
  71. package/server/applications/notifications/i18n/de.js.map +1 -1
  72. package/server/applications/notifications/i18n/es.js +8 -2
  73. package/server/applications/notifications/i18n/es.js.map +1 -1
  74. package/server/applications/notifications/i18n/fr.js +8 -2
  75. package/server/applications/notifications/i18n/fr.js.map +1 -1
  76. package/server/applications/notifications/i18n/hi.js +8 -2
  77. package/server/applications/notifications/i18n/hi.js.map +1 -1
  78. package/server/applications/notifications/i18n/it.js +8 -2
  79. package/server/applications/notifications/i18n/it.js.map +1 -1
  80. package/server/applications/notifications/i18n/ja.js +8 -2
  81. package/server/applications/notifications/i18n/ja.js.map +1 -1
  82. package/server/applications/notifications/i18n/ko.js +8 -2
  83. package/server/applications/notifications/i18n/ko.js.map +1 -1
  84. package/server/applications/notifications/i18n/pl.js +8 -2
  85. package/server/applications/notifications/i18n/pl.js.map +1 -1
  86. package/server/applications/notifications/i18n/pt.js +8 -2
  87. package/server/applications/notifications/i18n/pt.js.map +1 -1
  88. package/server/applications/notifications/i18n/pt_br.js +8 -2
  89. package/server/applications/notifications/i18n/pt_br.js.map +1 -1
  90. package/server/applications/notifications/i18n/ru.js +8 -2
  91. package/server/applications/notifications/i18n/ru.js.map +1 -1
  92. package/server/applications/notifications/i18n/tr.js +8 -2
  93. package/server/applications/notifications/i18n/tr.js.map +1 -1
  94. package/server/applications/notifications/i18n/zh.js +8 -2
  95. package/server/applications/notifications/i18n/zh.js.map +1 -1
  96. package/server/applications/notifications/interfaces/notification-properties.interface.js.map +1 -1
  97. package/server/applications/notifications/interfaces/user-mail-notification.interface.js +10 -0
  98. package/server/applications/notifications/interfaces/user-mail-notification.interface.js.map +1 -0
  99. package/server/applications/notifications/mails/models.js +38 -3
  100. package/server/applications/notifications/mails/models.js.map +1 -1
  101. package/server/applications/notifications/mails/templates.js +1 -1
  102. package/server/applications/notifications/mails/templates.js.map +1 -1
  103. package/server/applications/notifications/services/notifications-manager.service.js +8 -1
  104. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  105. package/server/applications/notifications/services/notifications-queries.service.js.map +1 -1
  106. package/server/applications/shares/services/shares-manager.service.js +17 -10
  107. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  108. package/server/applications/shares/services/shares-manager.service.spec.js +10 -3
  109. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  110. package/server/applications/shares/services/shares-queries.service.js +11 -1
  111. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  112. package/server/applications/spaces/guards/space.guard.spec.js +2 -2
  113. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  114. package/server/applications/spaces/services/spaces-browser.service.js +31 -11
  115. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  116. package/server/applications/spaces/services/spaces-manager.service.js +2 -2
  117. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  118. package/server/applications/spaces/services/spaces-queries.service.js +6 -2
  119. package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
  120. package/server/applications/spaces/utils/permissions.js +2 -2
  121. package/server/applications/spaces/utils/permissions.js.map +1 -1
  122. package/server/applications/sync/services/sync-manager.service.js +1 -0
  123. package/server/applications/sync/services/sync-manager.service.js.map +1 -1
  124. package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
  125. package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
  126. package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
  127. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  128. package/server/applications/users/constants/user.js +1 -1
  129. package/server/applications/users/constants/user.js.map +1 -1
  130. package/server/applications/users/services/admin-users-queries.service.js +8 -0
  131. package/server/applications/users/services/admin-users-queries.service.js.map +1 -1
  132. package/server/applications/users/services/users-queries.service.js +67 -68
  133. package/server/applications/users/services/users-queries.service.js.map +1 -1
  134. package/server/applications/users/users.module.js +2 -1
  135. package/server/applications/users/users.module.js.map +1 -1
  136. package/server/applications/webdav/guards/webdav-protocol.guard.js +4 -4
  137. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  138. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +6 -6
  139. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -1
  140. package/server/applications/webdav/services/webdav-methods.service.js +3 -2
  141. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  142. package/server/applications/webdav/services/webdav-methods.service.spec.js +2 -2
  143. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  144. package/server/authentication/constants/auth-ldap.js +2 -0
  145. package/server/authentication/constants/auth-ldap.js.map +1 -1
  146. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +34 -21
  147. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  148. package/server/common/functions.js +0 -8
  149. package/server/common/functions.js.map +1 -1
  150. package/server/common/image.js +1 -0
  151. package/server/common/image.js.map +1 -1
  152. package/server/common/shared.js +18 -1
  153. package/server/common/shared.js.map +1 -1
  154. package/server/infrastructure/context/services/context-manager.service.js +3 -0
  155. package/server/infrastructure/context/services/context-manager.service.js.map +1 -1
  156. package/server/infrastructure/websocket/adapters/cluster.adapter.js +4 -4
  157. package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
  158. package/static/3rdpartylicenses.txt +1393 -44
  159. package/static/assets/favicon.svg +2 -25
  160. package/static/assets/logo-dark.svg +2 -32
  161. package/static/assets/logo.svg +2 -32
  162. package/static/assets/mimes/application-sql.svg +29 -1
  163. package/static/assets/mimes/application-x-sql.svg +29 -0
  164. package/static/assets/mimes/image-bmp.svg +12 -0
  165. package/static/assets/pdfjs/build/pdf.mjs +4869 -4454
  166. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  167. package/static/assets/pdfjs/build/pdf.sandbox.mjs +3 -3
  168. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  169. package/static/assets/pdfjs/build/pdf.worker.mjs +885 -596
  170. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  171. package/static/assets/pdfjs/version +1 -1
  172. package/static/assets/pdfjs/web/locale/be/viewer.ftl +40 -0
  173. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +2 -0
  174. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +41 -0
  175. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +43 -0
  176. package/static/assets/pdfjs/web/locale/da/viewer.ftl +39 -0
  177. package/static/assets/pdfjs/web/locale/de/viewer.ftl +41 -0
  178. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +43 -0
  179. package/static/assets/pdfjs/web/locale/el/viewer.ftl +39 -0
  180. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +35 -0
  181. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +41 -0
  182. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +2 -2
  183. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +39 -0
  184. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +41 -0
  185. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +39 -0
  186. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +72 -0
  187. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +120 -0
  188. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +41 -0
  189. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +41 -0
  190. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +41 -0
  191. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +77 -0
  192. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +41 -0
  193. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +39 -0
  194. package/static/assets/pdfjs/web/locale/he/viewer.ftl +41 -0
  195. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +43 -0
  196. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +41 -0
  197. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +1 -1
  198. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +41 -0
  199. package/static/assets/pdfjs/web/locale/it/viewer.ftl +41 -0
  200. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +32 -0
  201. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +41 -0
  202. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +73 -0
  203. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +21 -0
  204. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -1
  205. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +39 -0
  206. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +41 -0
  207. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +37 -0
  208. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +37 -0
  209. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -0
  210. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +39 -0
  211. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +73 -0
  212. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +41 -0
  213. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +42 -0
  214. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +6 -0
  215. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +43 -0
  216. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +42 -1
  217. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +77 -0
  218. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +41 -0
  219. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +39 -0
  220. package/static/assets/pdfjs/web/locale/th/viewer.ftl +35 -0
  221. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +39 -0
  222. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +42 -5
  223. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +35 -0
  224. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +37 -0
  225. package/static/assets/pdfjs/web/viewer.css +141 -110
  226. package/static/assets/pdfjs/web/viewer.html +7 -7
  227. package/static/assets/pdfjs/web/viewer.mjs +97 -14
  228. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  229. package/static/chunk-22DWHRCL.js +1 -0
  230. package/static/chunk-23UUFZSR.js +1 -0
  231. package/static/{chunk-MTVSJTIW.js → chunk-24Q7OUU2.js} +1 -1
  232. package/static/chunk-25QTY2GI.js +1 -0
  233. package/static/chunk-2E7IJZLL.js +1 -0
  234. package/static/chunk-2FC5EKS5.js +1 -0
  235. package/static/chunk-2FOWUJQF.js +1 -0
  236. package/static/chunk-2XPHUNYN.js +1 -0
  237. package/static/chunk-32L7RG2G.js +1 -0
  238. package/static/chunk-3IISSX63.js +1 -0
  239. package/static/chunk-3OHSTP3R.js +1 -0
  240. package/static/chunk-42L6C5MT.js +1 -0
  241. package/static/chunk-4AGQL5GV.js +1 -0
  242. package/static/chunk-4BPSQMI2.js +1 -0
  243. package/static/chunk-4FDRWZWT.js +1 -0
  244. package/static/chunk-4FJUCMEG.js +1 -0
  245. package/static/chunk-4GCCF6PF.js +1 -0
  246. package/static/chunk-4ORP3SBY.js +1 -0
  247. package/static/chunk-4QBOHIC3.js +1 -0
  248. package/static/chunk-4YT6K5KY.js +1 -0
  249. package/static/chunk-556I6YIW.js +1 -0
  250. package/static/chunk-5DPIGJU4.js +1 -0
  251. package/static/chunk-5HNQLBSW.js +3 -0
  252. package/static/chunk-5IL7C45D.js +1 -0
  253. package/static/chunk-5KJXGMKR.js +1 -0
  254. package/static/chunk-5SPGSHKL.js +1 -0
  255. package/static/chunk-5WCQBTXW.js +1 -0
  256. package/static/chunk-5XUIPWOH.js +1 -0
  257. package/static/chunk-62WT7PI3.js +1 -0
  258. package/static/chunk-6F6OMQ5H.js +1 -0
  259. package/static/chunk-6I5BGQHT.js +1 -0
  260. package/static/chunk-6NOS45DG.js +1 -0
  261. package/static/chunk-6OKLPRCD.js +1 -0
  262. package/static/chunk-6VEJCG43.js +1 -0
  263. package/static/chunk-77SS36Z2.js +1 -0
  264. package/static/chunk-7AXEPO3G.js +1 -0
  265. package/static/chunk-7CFSJ4BO.js +1 -0
  266. package/static/chunk-7CKHC72R.js +1 -0
  267. package/static/chunk-7DUTYOJG.js +1 -0
  268. package/static/chunk-7HKFYRPF.js +1 -0
  269. package/static/chunk-7NZJZATZ.js +1 -0
  270. package/static/chunk-AADK5D2H.js +1 -0
  271. package/static/chunk-ACUF7IKP.js +1 -0
  272. package/static/chunk-AGREZPV4.js +1 -0
  273. package/static/chunk-ATBJWFA3.js +1 -0
  274. package/static/chunk-ATXLZN2B.js +1 -0
  275. package/static/chunk-AZ5TF5Y3.js +1 -0
  276. package/static/chunk-BBHYIURC.js +1 -0
  277. package/static/chunk-BHZEPHRI.js +13 -0
  278. package/static/chunk-BQZWSZNN.js +1 -0
  279. package/static/chunk-BSB4VROD.js +2 -0
  280. package/static/chunk-BYWSTP3P.js +1 -0
  281. package/static/chunk-C3AAEQKW.js +1 -0
  282. package/static/chunk-CCGGCHGN.js +1 -0
  283. package/static/chunk-CFTKW432.js +1 -0
  284. package/static/chunk-CNOVT6KU.js +1 -0
  285. package/static/chunk-D56H3XE2.js +1 -0
  286. package/static/chunk-DFOOSIIA.js +1 -0
  287. package/static/chunk-DHFQIFOF.js +1 -0
  288. package/static/{chunk-3GMLWAFZ.js → chunk-DIC2MVRI.js} +1 -1
  289. package/static/chunk-DJDRX53V.js +2 -0
  290. package/static/chunk-DKGXUMLT.js +1 -0
  291. package/static/chunk-DRHPEERW.js +2 -0
  292. package/static/chunk-DWYP6ZGG.js +1 -0
  293. package/static/chunk-EDJAISWO.js +13 -0
  294. package/static/chunk-EIYRBM4J.js +1 -0
  295. package/static/chunk-EKEGRXCV.js +7 -0
  296. package/static/chunk-EL6QL4TP.js +1 -0
  297. package/static/chunk-ERDZ7IVF.js +1 -0
  298. package/static/chunk-EVQKKVUZ.js +1 -0
  299. package/static/chunk-F2XG7EWI.js +1 -0
  300. package/static/chunk-F672FY5I.js +1 -0
  301. package/static/chunk-F6V37MKG.js +1 -0
  302. package/static/chunk-F7TXTNZC.js +1 -0
  303. package/static/chunk-FCGTI42I.js +1 -0
  304. package/static/chunk-FQHOSSCO.js +1 -0
  305. package/static/chunk-FTSIPHMG.js +1 -0
  306. package/static/chunk-GAGHHYLF.js +1 -0
  307. package/static/{chunk-JPT5WEAT.js → chunk-GOJYWL2M.js} +1 -1
  308. package/static/chunk-H6WOTGQ5.js +1 -0
  309. package/static/{chunk-CHJ64RJM.js → chunk-H6ZXFINQ.js} +1 -1
  310. package/static/chunk-HC7F57NA.js +1 -0
  311. package/static/chunk-HHWXIK2M.js +7 -0
  312. package/static/chunk-HKRGIRKB.js +3 -0
  313. package/static/chunk-HNMGPG72.js +1 -0
  314. package/static/chunk-HS4S6BV3.js +1 -0
  315. package/static/chunk-IJ7K7ATQ.js +1 -0
  316. package/static/chunk-IOIBQGHN.js +562 -0
  317. package/static/chunk-ITVA26X2.js +2 -0
  318. package/static/chunk-J6YSFHLZ.js +1 -0
  319. package/static/chunk-JAEJ6IMV.js +1 -0
  320. package/static/chunk-JB5R6V33.js +1 -0
  321. package/static/chunk-JF6WIV6M.js +1 -0
  322. package/static/chunk-JGB4LLUT.js +1 -0
  323. package/static/chunk-JGXVTKLG.js +1 -0
  324. package/static/chunk-JMYAD7E2.js +1 -0
  325. package/static/chunk-JSE63Q5X.js +1 -0
  326. package/static/chunk-JVV3ZL6L.js +1 -0
  327. package/static/chunk-JXZCNFW7.js +1 -0
  328. package/static/chunk-KAVP6UXH.js +1 -0
  329. package/static/{chunk-3R74L4UU.js → chunk-KDEEERWZ.js} +1 -1
  330. package/static/chunk-KHRF67SG.js +1 -0
  331. package/static/chunk-KLOUBIO4.js +1 -0
  332. package/static/chunk-KMF3ZRAO.js +1 -0
  333. package/static/chunk-KNZ3AQPR.js +1 -0
  334. package/static/chunk-KT3TWCST.js +1 -0
  335. package/static/chunk-L6SYG23T.js +1 -0
  336. package/static/chunk-LJSVNPPQ.js +1 -0
  337. package/static/{chunk-LNTUR3GU.js → chunk-LRDKG274.js} +1 -1
  338. package/static/chunk-LRQSPCYZ.js +1 -0
  339. package/static/chunk-LUSVISM6.js +1 -0
  340. package/static/chunk-LXQGVNU2.js +1 -0
  341. package/static/{chunk-LVSNIS5P.js → chunk-LYZGJZNP.js} +1 -1
  342. package/static/chunk-LZKI5P5T.js +1 -0
  343. package/static/chunk-M4XL3JN5.js +6 -0
  344. package/static/{chunk-UNCPXHHT.js → chunk-MGWG7OD7.js} +1 -1
  345. package/static/chunk-MKUUWY6Y.js +1 -0
  346. package/static/{chunk-VJTXJ43D.js → chunk-MNNCSSHN.js} +1 -1
  347. package/static/chunk-MR3U7TKQ.js +1 -0
  348. package/static/chunk-MRF3CNLZ.js +1 -0
  349. package/static/chunk-MRMSMTWD.js +1 -0
  350. package/static/chunk-MVZJSG5R.js +1 -0
  351. package/static/chunk-MYM43ENO.js +1 -0
  352. package/static/chunk-N3P6P6GW.js +7 -0
  353. package/static/chunk-NAH4V2R6.js +2 -0
  354. package/static/chunk-NBBDVVUF.js +1 -0
  355. package/static/chunk-NMF2ZFBE.js +1 -0
  356. package/static/chunk-NN4ONTOT.js +1 -0
  357. package/static/chunk-NOPACN4F.js +1 -0
  358. package/static/chunk-NYJPOP4L.js +1 -0
  359. package/static/chunk-OJCAIKUK.js +1 -0
  360. package/static/chunk-OQRWXCLY.js +1 -0
  361. package/static/chunk-PCFH5HCI.js +2 -0
  362. package/static/chunk-PG54TWBO.js +4 -0
  363. package/static/chunk-PJF5XUTO.js +1 -0
  364. package/static/{chunk-FJE6BOFL.js → chunk-PSUAQBYM.js} +1 -1
  365. package/static/chunk-PTLYIUFW.js +1 -0
  366. package/static/chunk-PZGLDZZM.js +1 -0
  367. package/static/chunk-Q4VNZGFI.js +1 -0
  368. package/static/chunk-Q556XB3S.js +1 -0
  369. package/static/{chunk-PB4AIT7O.js → chunk-Q7IXRPOO.js} +1 -1
  370. package/static/chunk-Q7U2VPIS.js +1 -0
  371. package/static/chunk-QM6CQMEX.js +1 -0
  372. package/static/chunk-QMHUIHSR.js +1 -0
  373. package/static/chunk-QNFNXDSX.js +1 -0
  374. package/static/chunk-QVFPHTOH.js +1 -0
  375. package/static/chunk-R4MI25E2.js +1 -0
  376. package/static/chunk-R7JRAR3P.js +1 -0
  377. package/static/chunk-R7PNKQU2.js +1 -0
  378. package/static/chunk-RCAORRB7.js +1 -0
  379. package/static/chunk-RK7XRDNB.js +1 -0
  380. package/static/chunk-RO7SAOLK.js +1 -0
  381. package/static/chunk-RQUUINHV.js +1 -0
  382. package/static/chunk-RT3K6DZR.js +1 -0
  383. package/static/chunk-RUN556VW.js +1 -0
  384. package/static/chunk-RX3YQ67K.js +1 -0
  385. package/static/chunk-S6EVLDHA.js +5 -0
  386. package/static/chunk-S7S5M3AZ.js +1 -0
  387. package/static/chunk-SBLNYV74.js +1 -0
  388. package/static/chunk-SIZCHHUA.js +1 -0
  389. package/static/chunk-SRBOO7AO.js +1 -0
  390. package/static/{chunk-PVDHBQRM.js → chunk-STA7NTYL.js} +1 -1
  391. package/static/chunk-T3YI3BSS.js +1 -0
  392. package/static/chunk-T74SMT7I.js +1 -0
  393. package/static/chunk-TAL3RTTQ.js +1 -0
  394. package/static/chunk-TJZKTNNS.js +1 -0
  395. package/static/chunk-UJTFWZEC.js +1 -0
  396. package/static/chunk-UPGVU5LG.js +1 -0
  397. package/static/chunk-UQ6O3I6W.js +1 -0
  398. package/static/{chunk-5NMSIIQB.js → chunk-V43RGNXA.js} +1 -1
  399. package/static/chunk-VWIRXLNE.js +1 -0
  400. package/static/chunk-VZMVGIVW.js +1 -0
  401. package/static/chunk-VZPCXSRG.js +2 -0
  402. package/static/chunk-WR3MA3L3.js +1 -0
  403. package/static/chunk-XCLK7NJL.js +1 -0
  404. package/static/{chunk-DSWEWLXJ.js → chunk-XCPDPB5G.js} +1 -1
  405. package/static/chunk-XEGHEUP5.js +1 -0
  406. package/static/chunk-XKEBQNQJ.js +1 -0
  407. package/static/chunk-XOF4UW3S.js +1 -0
  408. package/static/chunk-XOTKK2NJ.js +1 -0
  409. package/static/chunk-XX7JXKA6.js +1 -0
  410. package/static/chunk-Y2I36A4K.js +1 -0
  411. package/static/chunk-Y44XDRM5.js +1 -0
  412. package/static/{chunk-QO6BTONN.js → chunk-Y4MAPE2C.js} +1 -1
  413. package/static/chunk-Y5RLD72B.js +1 -0
  414. package/static/{chunk-DPUVSXRB.js → chunk-Y5XTRCFK.js} +1 -1
  415. package/static/chunk-Y63UUJGJ.js +1 -0
  416. package/static/chunk-YBNAC7QM.js +1 -0
  417. package/static/chunk-YCTCESL4.js +1 -0
  418. package/static/chunk-YMAN4LIU.js +1 -0
  419. package/static/chunk-YTDE6SXT.js +1 -0
  420. package/static/chunk-YZPIUJB3.js +1 -0
  421. package/static/chunk-ZCOWBVOT.js +1 -0
  422. package/static/chunk-ZHRYYMYE.js +1 -0
  423. package/static/chunk-ZNXTOQFG.js +1 -0
  424. package/static/{chunk-URHTCJ7G.js → chunk-ZQLBPLXI.js} +1 -1
  425. package/static/favicon.ico +0 -0
  426. package/static/index.html +2 -2
  427. package/static/main-3PLRDZTO.js +11 -0
  428. package/static/styles-Q4OZOSSK.css +1 -0
  429. package/server/applications/notifications/interfaces/user-mail-notification.js.map +0 -1
  430. package/static/assets/codemirror/mode/apl/apl.js +0 -174
  431. package/static/assets/codemirror/mode/asciiarmor/asciiarmor.js +0 -74
  432. package/static/assets/codemirror/mode/asn.1/asn.1.js +0 -204
  433. package/static/assets/codemirror/mode/asterisk/asterisk.js +0 -220
  434. package/static/assets/codemirror/mode/brainfuck/brainfuck.js +0 -85
  435. package/static/assets/codemirror/mode/clike/clike.js +0 -942
  436. package/static/assets/codemirror/mode/clojure/clojure.js +0 -293
  437. package/static/assets/codemirror/mode/cmake/cmake.js +0 -97
  438. package/static/assets/codemirror/mode/cobol/cobol.js +0 -255
  439. package/static/assets/codemirror/mode/coffeescript/coffeescript.js +0 -359
  440. package/static/assets/codemirror/mode/commonlisp/commonlisp.js +0 -125
  441. package/static/assets/codemirror/mode/crystal/crystal.js +0 -433
  442. package/static/assets/codemirror/mode/css/css.js +0 -862
  443. package/static/assets/codemirror/mode/cypher/cypher.js +0 -152
  444. package/static/assets/codemirror/mode/d/d.js +0 -223
  445. package/static/assets/codemirror/mode/dart/dart.js +0 -168
  446. package/static/assets/codemirror/mode/diff/diff.js +0 -47
  447. package/static/assets/codemirror/mode/django/django.js +0 -356
  448. package/static/assets/codemirror/mode/dockerfile/dockerfile.js +0 -211
  449. package/static/assets/codemirror/mode/dtd/dtd.js +0 -142
  450. package/static/assets/codemirror/mode/dylan/dylan.js +0 -352
  451. package/static/assets/codemirror/mode/ebnf/ebnf.js +0 -195
  452. package/static/assets/codemirror/mode/ecl/ecl.js +0 -206
  453. package/static/assets/codemirror/mode/eiffel/eiffel.js +0 -160
  454. package/static/assets/codemirror/mode/elm/elm.js +0 -245
  455. package/static/assets/codemirror/mode/erlang/erlang.js +0 -619
  456. package/static/assets/codemirror/mode/factor/factor.js +0 -85
  457. package/static/assets/codemirror/mode/fcl/fcl.js +0 -173
  458. package/static/assets/codemirror/mode/forth/forth.js +0 -180
  459. package/static/assets/codemirror/mode/fortran/fortran.js +0 -188
  460. package/static/assets/codemirror/mode/gas/gas.js +0 -355
  461. package/static/assets/codemirror/mode/gfm/gfm.js +0 -129
  462. package/static/assets/codemirror/mode/gherkin/gherkin.js +0 -194
  463. package/static/assets/codemirror/mode/go/go.js +0 -187
  464. package/static/assets/codemirror/mode/groovy/groovy.js +0 -245
  465. package/static/assets/codemirror/mode/haml/haml.js +0 -161
  466. package/static/assets/codemirror/mode/handlebars/handlebars.js +0 -70
  467. package/static/assets/codemirror/mode/haskell/haskell.js +0 -268
  468. package/static/assets/codemirror/mode/haskell-literate/haskell-literate.js +0 -43
  469. package/static/assets/codemirror/mode/haxe/haxe.js +0 -515
  470. package/static/assets/codemirror/mode/htmlembedded/htmlembedded.js +0 -37
  471. package/static/assets/codemirror/mode/htmlmixed/htmlmixed.js +0 -153
  472. package/static/assets/codemirror/mode/http/http.js +0 -113
  473. package/static/assets/codemirror/mode/idl/idl.js +0 -290
  474. package/static/assets/codemirror/mode/javascript/javascript.js +0 -960
  475. package/static/assets/codemirror/mode/jinja2/jinja2.js +0 -193
  476. package/static/assets/codemirror/mode/jsx/jsx.js +0 -149
  477. package/static/assets/codemirror/mode/julia/julia.js +0 -390
  478. package/static/assets/codemirror/mode/livescript/livescript.js +0 -280
  479. package/static/assets/codemirror/mode/lua/lua.js +0 -160
  480. package/static/assets/codemirror/mode/markdown/markdown.js +0 -886
  481. package/static/assets/codemirror/mode/mathematica/mathematica.js +0 -176
  482. package/static/assets/codemirror/mode/mbox/mbox.js +0 -129
  483. package/static/assets/codemirror/mode/meta.js +0 -221
  484. package/static/assets/codemirror/mode/mirc/mirc.js +0 -193
  485. package/static/assets/codemirror/mode/mllike/mllike.js +0 -359
  486. package/static/assets/codemirror/mode/modelica/modelica.js +0 -245
  487. package/static/assets/codemirror/mode/mscgen/mscgen.js +0 -175
  488. package/static/assets/codemirror/mode/mumps/mumps.js +0 -148
  489. package/static/assets/codemirror/mode/nginx/nginx.js +0 -178
  490. package/static/assets/codemirror/mode/nsis/nsis.js +0 -95
  491. package/static/assets/codemirror/mode/ntriples/ntriples.js +0 -195
  492. package/static/assets/codemirror/mode/octave/octave.js +0 -139
  493. package/static/assets/codemirror/mode/oz/oz.js +0 -252
  494. package/static/assets/codemirror/mode/pascal/pascal.js +0 -136
  495. package/static/assets/codemirror/mode/pegjs/pegjs.js +0 -111
  496. package/static/assets/codemirror/mode/perl/perl.js +0 -836
  497. package/static/assets/codemirror/mode/php/php.js +0 -234
  498. package/static/assets/codemirror/mode/pig/pig.js +0 -178
  499. package/static/assets/codemirror/mode/powershell/powershell.js +0 -398
  500. package/static/assets/codemirror/mode/properties/properties.js +0 -78
  501. package/static/assets/codemirror/mode/protobuf/protobuf.js +0 -72
  502. package/static/assets/codemirror/mode/pug/pug.js +0 -591
  503. package/static/assets/codemirror/mode/puppet/puppet.js +0 -220
  504. package/static/assets/codemirror/mode/python/python.js +0 -402
  505. package/static/assets/codemirror/mode/q/q.js +0 -139
  506. package/static/assets/codemirror/mode/r/r.js +0 -190
  507. package/static/assets/codemirror/mode/rpm/changes/index.html +0 -66
  508. package/static/assets/codemirror/mode/rpm/rpm.js +0 -109
  509. package/static/assets/codemirror/mode/rst/rst.js +0 -557
  510. package/static/assets/codemirror/mode/ruby/ruby.js +0 -303
  511. package/static/assets/codemirror/mode/rust/rust.js +0 -72
  512. package/static/assets/codemirror/mode/sas/sas.js +0 -303
  513. package/static/assets/codemirror/mode/sass/sass.js +0 -459
  514. package/static/assets/codemirror/mode/scheme/scheme.js +0 -284
  515. package/static/assets/codemirror/mode/shell/shell.js +0 -168
  516. package/static/assets/codemirror/mode/sieve/sieve.js +0 -193
  517. package/static/assets/codemirror/mode/slim/slim.js +0 -575
  518. package/static/assets/codemirror/mode/smalltalk/smalltalk.js +0 -168
  519. package/static/assets/codemirror/mode/smarty/smarty.js +0 -225
  520. package/static/assets/codemirror/mode/solr/solr.js +0 -104
  521. package/static/assets/codemirror/mode/soy/soy.js +0 -665
  522. package/static/assets/codemirror/mode/sparql/sparql.js +0 -184
  523. package/static/assets/codemirror/mode/spreadsheet/spreadsheet.js +0 -112
  524. package/static/assets/codemirror/mode/sql/sql.js +0 -529
  525. package/static/assets/codemirror/mode/stex/stex.js +0 -264
  526. package/static/assets/codemirror/mode/stylus/stylus.js +0 -775
  527. package/static/assets/codemirror/mode/swift/swift.js +0 -221
  528. package/static/assets/codemirror/mode/tcl/tcl.js +0 -140
  529. package/static/assets/codemirror/mode/textile/textile.js +0 -469
  530. package/static/assets/codemirror/mode/tiddlywiki/tiddlywiki.css +0 -14
  531. package/static/assets/codemirror/mode/tiddlywiki/tiddlywiki.js +0 -308
  532. package/static/assets/codemirror/mode/tiki/tiki.css +0 -26
  533. package/static/assets/codemirror/mode/tiki/tiki.js +0 -312
  534. package/static/assets/codemirror/mode/toml/toml.js +0 -88
  535. package/static/assets/codemirror/mode/tornado/tornado.js +0 -68
  536. package/static/assets/codemirror/mode/troff/troff.js +0 -84
  537. package/static/assets/codemirror/mode/ttcn/ttcn.js +0 -283
  538. package/static/assets/codemirror/mode/ttcn-cfg/ttcn-cfg.js +0 -214
  539. package/static/assets/codemirror/mode/turtle/turtle.js +0 -162
  540. package/static/assets/codemirror/mode/twig/twig.js +0 -141
  541. package/static/assets/codemirror/mode/vb/vb.js +0 -275
  542. package/static/assets/codemirror/mode/vbscript/vbscript.js +0 -350
  543. package/static/assets/codemirror/mode/velocity/velocity.js +0 -202
  544. package/static/assets/codemirror/mode/verilog/verilog.js +0 -781
  545. package/static/assets/codemirror/mode/vhdl/vhdl.js +0 -189
  546. package/static/assets/codemirror/mode/vue/vue.js +0 -77
  547. package/static/assets/codemirror/mode/wast/wast.js +0 -132
  548. package/static/assets/codemirror/mode/webidl/webidl.js +0 -195
  549. package/static/assets/codemirror/mode/xml/xml.js +0 -417
  550. package/static/assets/codemirror/mode/xquery/xquery.js +0 -448
  551. package/static/assets/codemirror/mode/yacas/yacas.js +0 -204
  552. package/static/assets/codemirror/mode/yaml/yaml.js +0 -120
  553. package/static/assets/codemirror/mode/yaml-frontmatter/yaml-frontmatter.js +0 -72
  554. package/static/assets/codemirror/mode/z80/z80.js +0 -116
  555. package/static/chunk-2KLC4T2Z.js +0 -1
  556. package/static/chunk-2VMSXRCB.js +0 -12
  557. package/static/chunk-3OHSRRKH.js +0 -4
  558. package/static/chunk-3R4WKOHQ.js +0 -1
  559. package/static/chunk-3XVM35O2.js +0 -1
  560. package/static/chunk-3YVRP3VM.js +0 -2
  561. package/static/chunk-5UKZLU5H.js +0 -1
  562. package/static/chunk-AF24EYXU.js +0 -1
  563. package/static/chunk-AKQVEHO6.js +0 -2
  564. package/static/chunk-BCVX464U.js +0 -2
  565. package/static/chunk-BQV4FRM6.js +0 -1
  566. package/static/chunk-CETH7UYS.js +0 -1
  567. package/static/chunk-DIT6W7VM.js +0 -562
  568. package/static/chunk-DKSEQTMX.js +0 -1
  569. package/static/chunk-FZ3JPGYZ.js +0 -1
  570. package/static/chunk-IQSKQXC3.js +0 -1
  571. package/static/chunk-ITUFI2BJ.js +0 -1
  572. package/static/chunk-LCTZJ537.js +0 -1
  573. package/static/chunk-LK2UCQJ6.js +0 -1
  574. package/static/chunk-LP5TBXEN.js +0 -7
  575. package/static/chunk-N3U6637P.js +0 -1
  576. package/static/chunk-NNV4OXSB.js +0 -1
  577. package/static/chunk-O6FYXVHI.js +0 -1
  578. package/static/chunk-OOGP4WSH.js +0 -2
  579. package/static/chunk-PCWDQPOM.js +0 -2
  580. package/static/chunk-PNR6M34W.js +0 -1
  581. package/static/chunk-Q5KM7LTX.js +0 -1
  582. package/static/chunk-QHC6ZPQ4.js +0 -1
  583. package/static/chunk-QMRBZHE4.js +0 -1
  584. package/static/chunk-QSJRY3TF.js +0 -1
  585. package/static/chunk-QUUIRSYT.js +0 -1
  586. package/static/chunk-RFH46UW3.js +0 -1
  587. package/static/chunk-RSXHRKM5.js +0 -1
  588. package/static/chunk-RV3VZJPZ.js +0 -1
  589. package/static/chunk-S7HNXVRB.js +0 -1
  590. package/static/chunk-SBZ572Q4.js +0 -2
  591. package/static/chunk-SJR5R3Y4.js +0 -1
  592. package/static/chunk-SLHTEGRU.js +0 -1
  593. package/static/chunk-SSFF27P2.js +0 -24
  594. package/static/chunk-V3LHHZYN.js +0 -1
  595. package/static/chunk-VQQKMY2C.js +0 -1
  596. package/static/chunk-WSSU2HXE.js +0 -1
  597. package/static/chunk-XDZGW64M.js +0 -3
  598. package/static/chunk-XTRDKGKG.js +0 -1
  599. package/static/chunk-YLWTEC3X.js +0 -1
  600. package/static/chunk-Z5J5F5SX.js +0 -1
  601. package/static/main-4H5BJY3J.js +0 -9
  602. package/static/scripts-WRDOQIU5.js +0 -24
  603. package/static/styles-2C2UNCNB.css +0 -1
@@ -131,7 +131,7 @@ let FilesContentManager = class FilesContentManager {
131
131
  }
132
132
  }
133
133
  } catch (e) {
134
- this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`);
134
+ this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse: ${dir} - ${e}`);
135
135
  }
136
136
  }
137
137
  async analyzeFile(realPath, context, isRootFile = false) {
@@ -144,7 +144,7 @@ let FilesContentManager = class FilesContentManager {
144
144
  try {
145
145
  stats = await _promises.default.stat(realPath);
146
146
  } catch (e) {
147
- this.logger.warn(`${this.analyzeFile.name} - unable to stats ${realPath} : ${e}`);
147
+ this.logger.warn(`${this.analyzeFile.name} - unable to stats: ${realPath} - ${e}`);
148
148
  return null;
149
149
  }
150
150
  if (stats.size === 0 || stats.size > this.maxDocumentSize) {
@@ -181,7 +181,7 @@ let FilesContentManager = class FilesContentManager {
181
181
  });
182
182
  return content.length ? content : null;
183
183
  } catch (e) {
184
- this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`);
184
+ this.logger.warn(`${this.parseContent.name} - unable to index: ${rPath} - ${e}`);
185
185
  }
186
186
  return null;
187
187
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-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 fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // clean up old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // Handles the space root file or shared file case\n const rootFileContent = await this.analyzeFile(p.realPath, context, true)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (entry.isDirectory()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext, isRootFile = false): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = isRootFile ? path.basename(context.pathPrefix) : path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to stats ${realPath} : ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = isRootFile\n ? path.dirname(context.pathPrefix) || '.'\n : path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","isRootFile","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbsB;iEACpB;iEAEE;0BACwE;8BAE5D;4BAEF;uBACC;oCACA;;;;;;;;;;;;;;;AAGrB,IAAA,AAAMA,sBAAN,MAAMA;IASX,MAAMC,wBAAuC;QAC3C,MAAMC,gBAA0B,EAAE;QAClC,WAAW,MAAM,CAACC,IAAIC,MAAMC,MAAM,IAAI,IAAI,CAACC,WAAW,CAACC,QAAQ,GAAI;YACjE,IAAIC;YACJ,OAAQJ;gBACN,KAAK;oBACHI,cAAc,GAAGC,yBAAe,GAAGN,IAAI;oBACvC;gBACF,KAAK;oBACHK,cAAc,GAAGE,0BAAgB,GAAGP,IAAI;oBACxC;gBACF,KAAK;oBACHK,cAAc,GAAGG,0BAAgB,GAAGR,IAAI;YAC5C;YACA,IAAI;gBACF,MAAM,IAAI,CAACS,UAAU,CAACJ,aAAaH;YACrC,EAAE,OAAOQ,GAAG;gBACV,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACd,qBAAqB,CAACe,IAAI,CAAC,GAAG,EAAEH,GAAG;YAC/D;YACAX,cAAce,IAAI,CAACT;QACrB;QACA,sBAAsB;QACtB,MAAM,IAAI,CAACU,YAAY,CAACC,YAAY,CAACjB;IACvC;IAEA,MAAcU,WAAWJ,WAAmB,EAAEH,KAAyB,EAAiB;QACtF,MAAMe,YAAY,IAAI,CAACF,YAAY,CAACG,YAAY,CAACb;QACjD,IAAI,CAAE,MAAM,IAAI,CAACU,YAAY,CAACI,WAAW,CAACF,YAAa;YACrD;QACF;QACA,MAAMG,UAA4B;YAChCf,aAAaA;YACbgB,YAAY;YACZC,eAAeC;YACfC,IAAI,MAAM,IAAI,CAACT,YAAY,CAACU,cAAc,CAACR;YAC3CS,IAAI,IAAIC;QACV;QACA,IAAIC,iBAAiB;QACrB,IAAIC,eAAe;QAEnB,KAAK,MAAMC,KAAK5B,MAAO;YACrBkB,QAAQE,aAAa,GAAG,IAAIS,OAAO,CAAC,GAAG,EAAED,EAAEE,QAAQ,CAAC,EAAE,CAAC;YACvDZ,QAAQC,UAAU,GAAGS,EAAET,UAAU,IAAI;YACrC,IAAI,CAACS,EAAEG,KAAK,EAAE;gBACZ,kDAAkD;gBAClD,MAAMC,kBAAkB,MAAM,IAAI,CAACC,WAAW,CAACL,EAAEE,QAAQ,EAAEZ,SAAS;gBACpE,IAAIc,oBAAoB,MAAM;oBAC5B,IAAI,CAACnB,YAAY,CAACqB,YAAY,CAACnB,WAAWiB,iBAAiBG,KAAK,CAAC,CAAC3B;wBAChEmB;wBACA,IAAI,CAAClB,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,GAAG,EAAE6B,gBAAgBrB,IAAI,CAAC,GAAG,EAAEH,GAAG;oBAC/F;oBACAkB;gBACF;gBACA;YACF;YACA,WAAW,MAAMU,eAAe,IAAI,CAACC,UAAU,CAACT,EAAEE,QAAQ,EAAEZ,SAAU;gBACpE,IAAI,CAACL,YAAY,CAACqB,YAAY,CAACnB,WAAWqB,aAAaD,KAAK,CAAC,CAAC3B;oBAC5DmB;oBACA,IAAI,CAAClB,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,GAAG,EAAEiC,YAAYzB,IAAI,CAAC,GAAG,EAAEH,GAAG;gBAC3F;gBACAkB;YACF;QACF;QAEA,IAAIR,QAAQI,EAAE,CAACgB,IAAI,KAAK,KAAKZ,mBAAmB,GAAG;YACjD,oBAAoB;YACpB,IAAI,CAACb,YAAY,CACd0B,SAAS,CAACxB,WACVoB,KAAK,CAAC,CAAC3B,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,0BAA0B,EAAEK,GAAG;YACjH,IAAI,CAACC,MAAM,CAAC+B,GAAG,CAAC,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,4BAA4B,CAAC;QACxF,OAAO;YACL,uBAAuB;YACvB,MAAMsC,kBAA4B;mBAAIvB,QAAQI,EAAE,CAACoB,IAAI;aAAG,CAACC,MAAM,CAAC,CAACC,MAAQ,CAAC1B,QAAQM,EAAE,CAACqB,GAAG,CAACD;YACzF,IAAIH,gBAAgBK,MAAM,GAAG,GAAG;gBAC9B,IAAI,CAACjC,YAAY,CACdkC,aAAa,CAAChC,WAAW0B,iBACzBN,KAAK,CAAC,CAAC3B,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,8BAA8B,EAAEK,GAAG;YACvH;YACA,IAAIkB,mBAAmB,KAAKC,iBAAiB,KAAKc,gBAAgBK,MAAM,KAAK,GAAG;gBAC9E,IAAI,CAACrC,MAAM,CAAC+B,GAAG,CAAC,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,cAAc,CAAC;YAC1E,OAAO;gBACL,IAAI,CAACM,MAAM,CAAC+B,GAAG,CACb,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,YAAY,EAAEuB,iBAAiBC,aAAa,UAAU,EAAEA,aAAa,WAAW,EAAEc,gBAAgBK,MAAM,EAAE;YAEvJ;QACF;IACF;IAEA,OAAeT,WAAWW,GAAW,EAAE9B,OAAyB,EAA+B;QAC7F,IAAI;YACF,KAAK,MAAM+B,SAAS,CAAA,MAAMzB,iBAAE,CAAC0B,OAAO,CAACF,KAAK;gBAAEG,eAAe;YAAK,EAAC,EAAG;gBAClE,MAAMrB,WAAWsB,iBAAI,CAACC,IAAI,CAACJ,MAAMK,UAAU,EAAEL,MAAMtC,IAAI;gBACvD,IAAIsC,MAAMM,WAAW,IAAI;oBACvB,OAAO,IAAI,CAAClB,UAAU,CAACP,UAAUZ;oBACjC;gBACF;gBACA,MAAMkB,cAAc,MAAM,IAAI,CAACH,WAAW,CAACH,UAAUZ;gBACrD,IAAIkB,gBAAgB,MAAM;oBACxB,MAAMA;gBACR;YACF;QACF,EAAE,OAAO5B,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACnB,UAAU,CAAC1B,IAAI,CAAC,GAAG,EAAEO,QAAQf,WAAW,CAAC,qBAAqB,EAAE6C,IAAI,GAAG,EAAExC,GAAG;QACvG;IACF;IAEA,MAAcyB,YAAYH,QAAgB,EAAEZ,OAAyB,EAAEuC,aAAa,KAAK,EAAwB;QAC/G,MAAMC,YAAYN,iBAAI,CAACO,OAAO,CAAC7B,UAAU8B,KAAK,CAAC,GAAGC,WAAW;QAC7D,IAAI,CAACC,6BAAmB,CAACjB,GAAG,CAACa,YAAY,OAAO;QAEhD,MAAMK,WAAWN,aAAaL,iBAAI,CAACY,QAAQ,CAAC9C,QAAQC,UAAU,IAAIiC,iBAAI,CAACY,QAAQ,CAAClC;QAEhF,6BAA6B;QAC7B,IAAIiC,SAASE,UAAU,CAAC,OAAO,OAAO;QAEtC,IAAIC;QACJ,IAAI;YACFA,QAAQ,MAAM1C,iBAAE,CAAC2C,IAAI,CAACrC;QACxB,EAAE,OAAOtB,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACvB,WAAW,CAACtB,IAAI,CAAC,mBAAmB,EAAEmB,SAAS,GAAG,EAAEtB,GAAG;YAChF,OAAO;QACT;QACA,IAAI0D,MAAM5B,IAAI,KAAK,KAAK4B,MAAM5B,IAAI,GAAG,IAAI,CAAC8B,eAAe,EAAE;YACzD,OAAO;QACT;QAEA,MAAMC,WAAWZ,aACbL,iBAAI,CAACkB,OAAO,CAACpD,QAAQC,UAAU,KAAK,MACpCiC,iBAAI,CAACC,IAAI,CAACnC,QAAQC,UAAU,EAAEiC,iBAAI,CAACkB,OAAO,CAACxC,UAAUyC,OAAO,CAACrD,QAAQE,aAAa,EAAE,OAAO;QAE/F,MAAMoD,IAAItD,QAAQI,EAAE,CAACmD,GAAG,CAACP,MAAMQ,GAAG;QAClC,IAAIF,KAAKA,EAAElC,IAAI,KAAK4B,MAAM5B,IAAI,IAAIkC,EAAEpB,IAAI,KAAKiB,YAAYG,EAAE7D,IAAI,KAAKoD,UAAU;YAC5E,uCAAuC;YACvC7C,QAAQM,EAAE,CAACmD,GAAG,CAACT,MAAMQ,GAAG;YACxB,OAAO;QACT;QAEA,iBAAiB;QACjBxD,QAAQM,EAAE,CAACmD,GAAG,CAACT,MAAMQ,GAAG;QAExB,0DAA0D;QAC1D,OAAO;YACL5E,IAAIoE,MAAMQ,GAAG;YACbtB,MAAMiB;YACN1D,MAAMoD;YACNa,MAAMC,IAAAA,kBAAW,EAAC/C,UAAU;YAC5BQ,MAAM4B,MAAM5B,IAAI;YAChBwC,OAAOZ,MAAMY,KAAK,CAACC,OAAO;YAC1BC,SAAS,MAAM,IAAI,CAACC,YAAY,CAACnD,UAAU4B;QAC7C;IACF;IAEA,MAAcuB,aAAaC,KAAa,EAAExB,SAAiB,EAAmB;QAC5E,IAAI;YACF,MAAMsB,UAAU,MAAMG,IAAAA,sBAAU,EAC9BD,OACA;gBAAEE,kBAAkB;gBAAKC,mBAAmB;YAAG,GAC/C;gBACE3B,WAAWA;gBACX4B,UAAU;YACZ;YAEF,OAAON,QAAQlC,MAAM,GAAGkC,UAAU;QACpC,EAAE,OAAOxE,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACyB,YAAY,CAACtE,IAAI,CAAC,qBAAqB,EAAEuE,MAAM,GAAG,EAAE1E,GAAG;QAClF;QACA,OAAO;IACT;IA5KA,YACE,AAAiBK,YAA0B,EAC3C,AAAiBZ,WAAwB,CACzC;aAFiBY,eAAAA;aACAZ,cAAAA;aALFmE,kBAAkB,MAAM;aACxB3D,SAAS,IAAI8E,cAAM,CAAC5F,oBAAoBgB,IAAI;IAK1D;AA0KL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-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 fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // clean up old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // Handles the space root file or shared file case\n const rootFileContent = await this.analyzeFile(p.realPath, context, true)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (entry.isDirectory()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse: ${dir} - ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext, isRootFile = false): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = isRootFile ? path.basename(context.pathPrefix) : path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to stats: ${realPath} - ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = isRootFile\n ? path.dirname(context.pathPrefix) || '.'\n : path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index: ${rPath} - ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","isRootFile","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"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"}
@@ -36,7 +36,7 @@ function _ts_metadata(k, v) {
36
36
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
37
37
  }
38
38
  let FilesLockManager = class FilesLockManager {
39
- async create(user, dbFile, depth, ttl, davLock) {
39
+ async create(user, dbFile, depth, davLock, ttl) {
40
40
  let token;
41
41
  let lockscope;
42
42
  if (davLock) {
@@ -62,7 +62,7 @@ let FilesLockManager = class FilesLockManager {
62
62
  }
63
63
  throw new Error(e);
64
64
  }
65
- ttl ??= FilesLockManager.defaultLockTimeoutSeconds;
65
+ ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
66
66
  const key = `${_cache.CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, {
67
67
  depth: depth,
68
68
  token: token
@@ -83,6 +83,38 @@ let FilesLockManager = class FilesLockManager {
83
83
  lock
84
84
  ];
85
85
  }
86
+ async createOrRefresh(user, dbFile, depth, ttl) {
87
+ // Returns: [created, lock]
88
+ ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
89
+ const locks = await this.getLocksByPath(dbFile);
90
+ // Check the existing lock and refresh it if needed
91
+ if (locks.length > 0) {
92
+ for (const lock of locks){
93
+ if (lock.owner.id === user.id) {
94
+ // Refresh if more than half of the TTL has passed
95
+ const mustRefresh = lock.expiration - (0, _shared.currentTimeStamp)() < ttl / 2;
96
+ if (mustRefresh) {
97
+ this.refreshLockTimeout(lock, ttl).catch((e)=>this.logger.error(`${this.createOrRefresh.name} - ${e}`));
98
+ }
99
+ } else {
100
+ throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
101
+ }
102
+ }
103
+ return [
104
+ false,
105
+ locks[0]
106
+ ];
107
+ }
108
+ // Create the lock
109
+ const [ok, lock] = await this.create(user, dbFile, depth, null, ttl);
110
+ if (!ok) {
111
+ throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
112
+ }
113
+ return [
114
+ true,
115
+ lock
116
+ ];
117
+ }
86
118
  removeLock(key) {
87
119
  this.logger.verbose(`${this.removeLock.name} - ${key}`);
88
120
  return this.cache.del(key);
@@ -159,7 +191,7 @@ let FilesLockManager = class FilesLockManager {
159
191
  }
160
192
  async checkConflicts(dbFile, depth, options) {
161
193
  /* Checks if a file could be modified, created, moved, or deleted
162
- Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modifications
194
+ Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification
163
195
  Returns on the first conflict (compliant with the RFC 4918)
164
196
  */ for await (const l of this.searchParentLocks(dbFile, {
165
197
  includeRoot: true,
@@ -186,6 +218,28 @@ let FilesLockManager = class FilesLockManager {
186
218
  }
187
219
  }
188
220
  }
221
+ async *searchChildLocks(dbFile) {
222
+ const props = this.genSuffixKey(dbFile, {
223
+ ignorePath: true
224
+ });
225
+ const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`;
226
+ this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`);
227
+ const keys = await this.searchKeysByPath(path, props);
228
+ if (keys.length) {
229
+ for (const l of (await this.cache.mget(keys)).filter(Boolean)){
230
+ this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`);
231
+ yield l;
232
+ }
233
+ }
234
+ }
235
+ convertLockToFileLockProps(lock) {
236
+ if (!lock) return null;
237
+ return {
238
+ owner: lock?.davLock?.owner || `${lock.owner.fullName} (${lock.owner.email})`,
239
+ ownerLogin: lock.owner.login,
240
+ isExclusive: lock?.davLock?.lockscope ? lock?.davLock?.lockscope === _webdav.LOCK_SCOPE.EXCLUSIVE : true
241
+ };
242
+ }
189
243
  async *searchParentLocks(dbFile, options = {}) {
190
244
  const props = this.genSuffixKey(dbFile, {
191
245
  ignorePath: true
@@ -209,20 +263,6 @@ let FilesLockManager = class FilesLockManager {
209
263
  path = (0, _files.dirName)(path);
210
264
  }
211
265
  }
212
- async *searchChildLocks(dbFile) {
213
- const props = this.genSuffixKey(dbFile, {
214
- ignorePath: true
215
- });
216
- const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`;
217
- this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`);
218
- const keys = await this.searchKeysByPath(path, props);
219
- if (keys.length) {
220
- for (const l of (await this.cache.mget(keys)).filter(Boolean)){
221
- this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`);
222
- yield l;
223
- }
224
- }
225
- }
226
266
  async searchKeyByToken(token) {
227
267
  const keys = await this.cache.keys(`${_cache.CACHE_LOCK_PREFIX}|token:${token}|*`);
228
268
  if (!keys.length) {
@@ -258,10 +298,7 @@ let FilesLockManager = class FilesLockManager {
258
298
  }
259
299
  constructor(cache){
260
300
  this.cache = cache;
261
- this.logger = new _common.Logger(FilesLockManager.name);
262
- }
263
- };
264
- /* Philosophy
301
+ /* Philosophy
265
302
  Currently this manager only handle conflicting locks between multiple users, not between clients
266
303
  - The locks created from api
267
304
  * They do not contain a token key or a davLock property
@@ -273,7 +310,9 @@ let FilesLockManager = class FilesLockManager {
273
310
  * If created with WebDAV, they are stored with a token and a davLock property
274
311
  * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null
275
312
  Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock
276
- */ FilesLockManager.defaultLockTimeoutSeconds = 86400; // 1 day
313
+ */ this.logger = new _common.Logger(FilesLockManager.name);
314
+ }
315
+ };
277
316
  FilesLockManager = _ts_decorate([
278
317
  (0, _common.Injectable)(),
279
318
  _ts_metadata("design:type", Function),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-lock-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 crypto from 'node:crypto'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH, LOCK_PREFIX, LOCK_SCOPE } from '../../webdav/constants/webdav'\nimport { WebDAVLock } from '../../webdav/interfaces/webdav.interface'\nimport { CACHE_LOCK_PREFIX } from '../constants/cache'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { LockConflict } from '../models/file-lock-error'\nimport { files } from '../schemas/files.schema'\nimport { dirName, fileName } from '../utils/files'\n\n@Injectable()\nexport class FilesLockManager {\n /* Philosophy\n Currently this manager only handle conflicting locks between multiple users, not between clients\n - The locks created from api\n * They do not contain a token key or a davLock property\n * They are exclusive only\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n - The locks created from WebDAV or OnlyOffice are stored with a token and a davLock property\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n * They can be exclusive (WebDAV) or shared (OnlyOffice)\n * If created with WebDAV, they are stored with a token and a davLock property\n * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null\n Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock\n */\n public static readonly defaultLockTimeoutSeconds = 86400 // 1 day\n private readonly logger = new Logger(FilesLockManager.name)\n\n constructor(private readonly cache: Cache) {}\n\n async create(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, ttl?: number, davLock?: WebDAVLock): Promise<[boolean, FileLock]> {\n let token: string\n let lockscope: LOCK_SCOPE\n if (davLock) {\n // webdav context\n davLock.locktoken = this.genDAVToken()\n token = davLock.locktoken\n lockscope = davLock.lockscope\n } else {\n // api context\n token = null\n lockscope = null\n }\n try {\n await this.checkConflicts(dbFile, depth, { lockScope: lockscope })\n } catch (e) {\n if (e instanceof LockConflict) {\n return [false, e.lock]\n }\n throw new Error(e)\n }\n ttl ??= FilesLockManager.defaultLockTimeoutSeconds\n const key = `${CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, { depth: depth, token: token })}`\n const expiration = Math.floor(currentTimeStamp() + ttl)\n const lock: FileLock = {\n owner: user.asOwner(),\n dbFilePath: dbFile.path,\n key: key,\n depth: depth,\n expiration: expiration,\n davLock: davLock\n }\n this.logger.verbose(`${this.create.name} - ${key}`)\n await this.cache.set(key, lock, ttl)\n return [true, lock]\n }\n\n removeLock(key: string): Promise<boolean> {\n this.logger.verbose(`${this.removeLock.name} - ${key}`)\n return this.cache.del(key)\n }\n\n async removeChildLocks(user: UserModel, dbFile: FileDBProps) {\n const ownedLockKeys: string[] = []\n for await (const lock of this.searchChildLocks(dbFile)) {\n if (user.id === lock.owner.id) {\n ownedLockKeys.push(lock.key)\n continue\n }\n const conflict = `cannot remove conflicting child lock : ${dbFile.path} (${user.login}) -> ${lock.dbFilePath} (${lock.owner.login})`\n this.logger.debug(`${this.removeChildLocks.name} - ${conflict}`)\n throw new LockConflict(lock, conflict)\n }\n for (const key of ownedLockKeys) {\n this.logger.verbose(`${this.removeChildLocks.name} - child locks: ${key}`)\n await this.removeLock(key)\n }\n }\n\n async isLockedWithToken(token: string, dbFilePath: string): Promise<FileLock> {\n // check if url (or any of its parents) is locked by the token\n const lock = await this.getLockByToken(token)\n return lock ? (dbFilePath.startsWith(lock.dbFilePath) ? lock : null) : null\n }\n\n async browseParentChildLocks(dbFile: FileDBProps, includeRoot = true): Promise<Record<string, FileLock>> {\n // find child locks inside the path\n const childLocks: Record<string, FileLock> = includeRoot ? await this.browseLocks(dbFile) : {}\n const lengthFilter = dbFile.path === '.' ? 1 : dbFile.path.split('/').length + 1\n for await (const lock of this.searchChildLocks(dbFile)) {\n // filter child locks on length\n if (lengthFilter === lock.dbFilePath.split('/').length) {\n // !!! locks with shared scope can have the same file name, in this case we only keep the first entry\n const dbFileName = fileName(lock.dbFilePath)\n if (!(dbFileName in childLocks)) {\n childLocks[fileName(lock.dbFilePath)] = lock\n }\n }\n }\n return childLocks\n }\n\n async browseLocks(dbFile: FileDBProps): Promise<Record<string, FileLock>> {\n return Object.fromEntries((await this.getLocksByPath(dbFile)).map((l) => [fileName(l.dbFilePath), l]))\n }\n\n async refreshLockTimeout(lock: FileLock, ttl: number) {\n lock.expiration = currentTimeStamp() + ttl\n this.cache.set(lock.key, lock, ttl).catch((e: Error) => this.logger.error(`${this.refreshLockTimeout.name} - ${e}`))\n }\n\n async getLockByToken(token: string): Promise<FileLock> {\n const key = await this.searchKeyByToken(token)\n return key ? (await this.cache.get(key)) || null : null\n }\n\n async getLocksByPath(dbFile: FileDBProps): Promise<FileLock[]> {\n if (dbFile.path !== '.') {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const keys = await this.searchKeysByPath(dbFile.path, props)\n if (keys.length) {\n return (await this.cache.mget(keys)).filter(Boolean)\n }\n }\n return []\n }\n\n async isPathLocked(dbFile: FileDBProps): Promise<boolean> {\n if (dbFile.path !== '.') return false\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n return !!(await this.searchKeysByPath(dbFile.path, props)).length\n }\n\n async checkConflicts(\n dbFile: FileDBProps,\n depth: LOCK_DEPTH,\n options?: { userId?: number; lockScope?: LOCK_SCOPE; lockTokens?: string[] }\n ): Promise<void> {\n /* Checks if a file could be modified, created, moved, or deleted\n Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modifications\n Returns on the first conflict (compliant with the RFC 4918)\n */\n for await (const l of this.searchParentLocks(dbFile, { includeRoot: true, depth: DEPTH.INFINITY })) {\n if (options?.lockScope && options?.lockScope === LOCK_SCOPE.SHARED && l.davLock.lockscope === LOCK_SCOPE.SHARED) {\n // Only compatible with shared locks (even by same owner)\n continue\n }\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting parent lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n if (depth === DEPTH.INFINITY) {\n for await (const l of this.searchChildLocks(dbFile)) {\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting child lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n }\n }\n\n private async *searchParentLocks(dbFile: FileDBProps, options: { includeRoot?: boolean; depth?: LOCK_DEPTH } = {}): AsyncGenerator<FileLock> {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n let path = dbFile.path\n const parentPath = dirName(path)\n this.logger.verbose(`${this.searchParentLocks.name} - (including root : ${options.includeRoot}) : ${path} (${props})`)\n if (!options.includeRoot) {\n path = dirName(path)\n }\n while (path !== '.') {\n // Even if the depth is \"infinite\", the path and the parent path could be locked with depth \"0\"\n const depth = options.depth && (dbFile.path === path || parentPath === path) ? null : options.depth\n const keys = await this.searchKeysByPath(path, props, depth)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath}`)\n yield l\n }\n }\n path = dirName(path)\n }\n }\n\n async *searchChildLocks(dbFile: FileDBProps) {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`\n this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`)\n const keys = await this.searchKeysByPath(path, props)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`)\n yield l\n }\n }\n }\n\n private async searchKeyByToken(token: string): Promise<string> {\n const keys = await this.cache.keys(`${CACHE_LOCK_PREFIX}|token:${token}|*`)\n if (!keys.length) {\n return null\n } else if (keys.length > 1) {\n this.logger.warn(`Several keys found for token : ${token} => ${JSON.stringify(keys)}`)\n }\n return keys[0]\n }\n\n private searchKeysByPath(path: string, props = '*', depth?: LOCK_DEPTH): Promise<string[]> {\n return this.cache.keys(`${CACHE_LOCK_PREFIX}*${depth ? `|depth:${depth}` : ''}|path:${path}|${props}`)\n }\n\n private genDAVToken(): string {\n return `${LOCK_PREFIX}${crypto.randomUUID()}`\n }\n\n private genSuffixKey(dbFile: FileDBProps, options: { ignorePath?: boolean; depth?: LOCK_DEPTH; token?: string } = {}): string {\n // return -> `depth:infinity|path:code/sync-in|spaceId:1` | `token:xxx|depth:0|path:code/sync-in.ts|ownerId:1`\n // ignorePath -> `spaceId:1`\n const suffixes = []\n for (const k of Object.keys(dbFile)\n .filter((k) => k !== files.inTrash.name && dbFile[k] !== null)\n .sort()) {\n if (k === files.path.name) {\n if (options.ignorePath) {\n continue\n }\n suffixes.unshift(`${k}:${dbFile[k]}`)\n } else {\n suffixes.push(`${k}:${dbFile[k]}`)\n }\n }\n if (options.depth) suffixes.unshift(`depth:${options.depth}`)\n if (options.token) suffixes.unshift(`token:${options.token}`)\n return suffixes.join('|')\n }\n}\n"],"names":["FilesLockManager","create","user","dbFile","depth","ttl","davLock","token","lockscope","locktoken","genDAVToken","checkConflicts","lockScope","e","LockConflict","lock","Error","defaultLockTimeoutSeconds","key","CACHE_LOCK_PREFIX","genSuffixKey","expiration","Math","floor","currentTimeStamp","owner","asOwner","dbFilePath","path","logger","verbose","name","cache","set","removeLock","del","removeChildLocks","ownedLockKeys","searchChildLocks","id","push","conflict","login","debug","isLockedWithToken","getLockByToken","startsWith","browseParentChildLocks","includeRoot","childLocks","browseLocks","lengthFilter","split","length","dbFileName","fileName","Object","fromEntries","getLocksByPath","map","l","refreshLockTimeout","catch","error","searchKeyByToken","get","props","ignorePath","keys","searchKeysByPath","mget","filter","Boolean","isPathLocked","options","searchParentLocks","DEPTH","INFINITY","LOCK_SCOPE","SHARED","userId","lockTokens","indexOf","parentPath","dirName","warn","JSON","stringify","LOCK_PREFIX","crypto","randomUUID","suffixes","k","files","inTrash","sort","unshift","join","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAkBYA;;;eAAAA;;;wBAhBsB;mEAChB;wBAEc;8BACX;wBAEqC;uBAEzB;+BAGL;6BACP;uBACY;;;;;;;;;;;;;;;AAG3B,IAAA,AAAMA,mBAAN,MAAMA;IAmBX,MAAMC,OAAOC,IAAe,EAAEC,MAAmB,EAAEC,KAAiB,EAAEC,GAAY,EAAEC,OAAoB,EAAgC;QACtI,IAAIC;QACJ,IAAIC;QACJ,IAAIF,SAAS;YACX,iBAAiB;YACjBA,QAAQG,SAAS,GAAG,IAAI,CAACC,WAAW;YACpCH,QAAQD,QAAQG,SAAS;YACzBD,YAAYF,QAAQE,SAAS;QAC/B,OAAO;YACL,cAAc;YACdD,QAAQ;YACRC,YAAY;QACd;QACA,IAAI;YACF,MAAM,IAAI,CAACG,cAAc,CAACR,QAAQC,OAAO;gBAAEQ,WAAWJ;YAAU;QAClE,EAAE,OAAOK,GAAG;YACV,IAAIA,aAAaC,2BAAY,EAAE;gBAC7B,OAAO;oBAAC;oBAAOD,EAAEE,IAAI;iBAAC;YACxB;YACA,MAAM,IAAIC,MAAMH;QAClB;QACAR,QAAQL,iBAAiBiB,yBAAyB;QAClD,MAAMC,MAAM,GAAGC,wBAAiB,CAAC,CAAC,EAAE,IAAI,CAACC,YAAY,CAACjB,QAAQ;YAAEC,OAAOA;YAAOG,OAAOA;QAAM,IAAI;QAC/F,MAAMc,aAAaC,KAAKC,KAAK,CAACC,IAAAA,wBAAgB,MAAKnB;QACnD,MAAMU,OAAiB;YACrBU,OAAOvB,KAAKwB,OAAO;YACnBC,YAAYxB,OAAOyB,IAAI;YACvBV,KAAKA;YACLd,OAAOA;YACPiB,YAAYA;YACZf,SAASA;QACX;QACA,IAAI,CAACuB,MAAM,CAACC,OAAO,CAAC,GAAG,IAAI,CAAC7B,MAAM,CAAC8B,IAAI,CAAC,GAAG,EAAEb,KAAK;QAClD,MAAM,IAAI,CAACc,KAAK,CAACC,GAAG,CAACf,KAAKH,MAAMV;QAChC,OAAO;YAAC;YAAMU;SAAK;IACrB;IAEAmB,WAAWhB,GAAW,EAAoB;QACxC,IAAI,CAACW,MAAM,CAACC,OAAO,CAAC,GAAG,IAAI,CAACI,UAAU,CAACH,IAAI,CAAC,GAAG,EAAEb,KAAK;QACtD,OAAO,IAAI,CAACc,KAAK,CAACG,GAAG,CAACjB;IACxB;IAEA,MAAMkB,iBAAiBlC,IAAe,EAAEC,MAAmB,EAAE;QAC3D,MAAMkC,gBAA0B,EAAE;QAClC,WAAW,MAAMtB,QAAQ,IAAI,CAACuB,gBAAgB,CAACnC,QAAS;YACtD,IAAID,KAAKqC,EAAE,KAAKxB,KAAKU,KAAK,CAACc,EAAE,EAAE;gBAC7BF,cAAcG,IAAI,CAACzB,KAAKG,GAAG;gBAC3B;YACF;YACA,MAAMuB,WAAW,CAAC,uCAAuC,EAAEtC,OAAOyB,IAAI,CAAC,EAAE,EAAE1B,KAAKwC,KAAK,CAAC,KAAK,EAAE3B,KAAKY,UAAU,CAAC,EAAE,EAAEZ,KAAKU,KAAK,CAACiB,KAAK,CAAC,CAAC,CAAC;YACpI,IAAI,CAACb,MAAM,CAACc,KAAK,CAAC,GAAG,IAAI,CAACP,gBAAgB,CAACL,IAAI,CAAC,GAAG,EAAEU,UAAU;YAC/D,MAAM,IAAI3B,2BAAY,CAACC,MAAM0B;QAC/B;QACA,KAAK,MAAMvB,OAAOmB,cAAe;YAC/B,IAAI,CAACR,MAAM,CAACC,OAAO,CAAC,GAAG,IAAI,CAACM,gBAAgB,CAACL,IAAI,CAAC,gBAAgB,EAAEb,KAAK;YACzE,MAAM,IAAI,CAACgB,UAAU,CAAChB;QACxB;IACF;IAEA,MAAM0B,kBAAkBrC,KAAa,EAAEoB,UAAkB,EAAqB;QAC5E,8DAA8D;QAC9D,MAAMZ,OAAO,MAAM,IAAI,CAAC8B,cAAc,CAACtC;QACvC,OAAOQ,OAAQY,WAAWmB,UAAU,CAAC/B,KAAKY,UAAU,IAAIZ,OAAO,OAAQ;IACzE;IAEA,MAAMgC,uBAAuB5C,MAAmB,EAAE6C,cAAc,IAAI,EAAqC;QACvG,mCAAmC;QACnC,MAAMC,aAAuCD,cAAc,MAAM,IAAI,CAACE,WAAW,CAAC/C,UAAU,CAAC;QAC7F,MAAMgD,eAAehD,OAAOyB,IAAI,KAAK,MAAM,IAAIzB,OAAOyB,IAAI,CAACwB,KAAK,CAAC,KAAKC,MAAM,GAAG;QAC/E,WAAW,MAAMtC,QAAQ,IAAI,CAACuB,gBAAgB,CAACnC,QAAS;YACtD,+BAA+B;YAC/B,IAAIgD,iBAAiBpC,KAAKY,UAAU,CAACyB,KAAK,CAAC,KAAKC,MAAM,EAAE;gBACtD,qGAAqG;gBACrG,MAAMC,aAAaC,IAAAA,eAAQ,EAACxC,KAAKY,UAAU;gBAC3C,IAAI,CAAE2B,CAAAA,cAAcL,UAAS,GAAI;oBAC/BA,UAAU,CAACM,IAAAA,eAAQ,EAACxC,KAAKY,UAAU,EAAE,GAAGZ;gBAC1C;YACF;QACF;QACA,OAAOkC;IACT;IAEA,MAAMC,YAAY/C,MAAmB,EAAqC;QACxE,OAAOqD,OAAOC,WAAW,CAAC,AAAC,CAAA,MAAM,IAAI,CAACC,cAAc,CAACvD,OAAM,EAAGwD,GAAG,CAAC,CAACC,IAAM;gBAACL,IAAAA,eAAQ,EAACK,EAAEjC,UAAU;gBAAGiC;aAAE;IACtG;IAEA,MAAMC,mBAAmB9C,IAAc,EAAEV,GAAW,EAAE;QACpDU,KAAKM,UAAU,GAAGG,IAAAA,wBAAgB,MAAKnB;QACvC,IAAI,CAAC2B,KAAK,CAACC,GAAG,CAAClB,KAAKG,GAAG,EAAEH,MAAMV,KAAKyD,KAAK,CAAC,CAACjD,IAAa,IAAI,CAACgB,MAAM,CAACkC,KAAK,CAAC,GAAG,IAAI,CAACF,kBAAkB,CAAC9B,IAAI,CAAC,GAAG,EAAElB,GAAG;IACpH;IAEA,MAAMgC,eAAetC,KAAa,EAAqB;QACrD,MAAMW,MAAM,MAAM,IAAI,CAAC8C,gBAAgB,CAACzD;QACxC,OAAOW,MAAM,AAAC,MAAM,IAAI,CAACc,KAAK,CAACiC,GAAG,CAAC/C,QAAS,OAAO;IACrD;IAEA,MAAMwC,eAAevD,MAAmB,EAAuB;QAC7D,IAAIA,OAAOyB,IAAI,KAAK,KAAK;YACvB,MAAMsC,QAAQ,IAAI,CAAC9C,YAAY,CAACjB,QAAQ;gBAAEgE,YAAY;YAAK;YAC3D,MAAMC,OAAO,MAAM,IAAI,CAACC,gBAAgB,CAAClE,OAAOyB,IAAI,EAAEsC;YACtD,IAAIE,KAAKf,MAAM,EAAE;gBACf,OAAO,AAAC,CAAA,MAAM,IAAI,CAACrB,KAAK,CAACsC,IAAI,CAACF,KAAI,EAAGG,MAAM,CAACC;YAC9C;QACF;QACA,OAAO,EAAE;IACX;IAEA,MAAMC,aAAatE,MAAmB,EAAoB;QACxD,IAAIA,OAAOyB,IAAI,KAAK,KAAK,OAAO;QAChC,MAAMsC,QAAQ,IAAI,CAAC9C,YAAY,CAACjB,QAAQ;YAAEgE,YAAY;QAAK;QAC3D,OAAO,CAAC,CAAC,AAAC,CAAA,MAAM,IAAI,CAACE,gBAAgB,CAAClE,OAAOyB,IAAI,EAAEsC,MAAK,EAAGb,MAAM;IACnE;IAEA,MAAM1C,eACJR,MAAmB,EACnBC,KAAiB,EACjBsE,OAA4E,EAC7D;QACf;;;IAGA,GACA,WAAW,MAAMd,KAAK,IAAI,CAACe,iBAAiB,CAACxE,QAAQ;YAAE6C,aAAa;YAAM5C,OAAOwE,aAAK,CAACC,QAAQ;QAAC,GAAI;YAClG,IAAIH,SAAS9D,aAAa8D,SAAS9D,cAAckE,kBAAU,CAACC,MAAM,IAAInB,EAAEtD,OAAO,CAACE,SAAS,KAAKsE,kBAAU,CAACC,MAAM,EAAE;gBAE/G;YACF;YACA,IAAIL,SAASM,WAAWpB,EAAEnC,KAAK,CAACc,EAAE,IAAK,CAAA,CAACqB,EAAEtD,OAAO,IAAKoE,SAASO,YAAY5B,UAAUqB,QAAQO,UAAU,CAACC,OAAO,CAACtB,EAAEtD,OAAO,CAACG,SAAS,IAAI,CAAC,CAAC,GAAI;gBAE3I;YACF;YACA,MAAMgC,WAAW,CAAC,0BAA0B,EAAEtC,OAAOyB,IAAI,CAAC,IAAI,EAAEgC,EAAEjC,UAAU,CAAC,EAAE,EAAEiC,EAAEnC,KAAK,CAACiB,KAAK,CAAC,CAAC,CAAC;YACjG,IAAI,CAACb,MAAM,CAACc,KAAK,CAAC,GAAG,IAAI,CAAChC,cAAc,CAACoB,IAAI,CAAC,GAAG,EAAEU,UAAU;YAC7D,MAAM,IAAI3B,2BAAY,CAAC8C,GAAGnB;QAC5B;QACA,IAAIrC,UAAUwE,aAAK,CAACC,QAAQ,EAAE;YAC5B,WAAW,MAAMjB,KAAK,IAAI,CAACtB,gBAAgB,CAACnC,QAAS;gBACnD,IAAIuE,SAASM,WAAWpB,EAAEnC,KAAK,CAACc,EAAE,IAAK,CAAA,CAACqB,EAAEtD,OAAO,IAAKoE,SAASO,YAAY5B,UAAUqB,QAAQO,UAAU,CAACC,OAAO,CAACtB,EAAEtD,OAAO,CAACG,SAAS,IAAI,CAAC,CAAC,GAAI;oBAE3I;gBACF;gBACA,MAAMgC,WAAW,CAAC,yBAAyB,EAAEtC,OAAOyB,IAAI,CAAC,IAAI,EAAEgC,EAAEjC,UAAU,CAAC,EAAE,EAAEiC,EAAEnC,KAAK,CAACiB,KAAK,CAAC,CAAC,CAAC;gBAChG,IAAI,CAACb,MAAM,CAACc,KAAK,CAAC,GAAG,IAAI,CAAChC,cAAc,CAACoB,IAAI,CAAC,GAAG,EAAEU,UAAU;gBAC7D,MAAM,IAAI3B,2BAAY,CAAC8C,GAAGnB;YAC5B;QACF;IACF;IAEA,OAAekC,kBAAkBxE,MAAmB,EAAEuE,UAAyD,CAAC,CAAC,EAA4B;QAC3I,MAAMR,QAAQ,IAAI,CAAC9C,YAAY,CAACjB,QAAQ;YAAEgE,YAAY;QAAK;QAC3D,IAAIvC,OAAOzB,OAAOyB,IAAI;QACtB,MAAMuD,aAAaC,IAAAA,cAAO,EAACxD;QAC3B,IAAI,CAACC,MAAM,CAACC,OAAO,CAAC,GAAG,IAAI,CAAC6C,iBAAiB,CAAC5C,IAAI,CAAC,qBAAqB,EAAE2C,QAAQ1B,WAAW,CAAC,IAAI,EAAEpB,KAAK,EAAE,EAAEsC,MAAM,CAAC,CAAC;QACrH,IAAI,CAACQ,QAAQ1B,WAAW,EAAE;YACxBpB,OAAOwD,IAAAA,cAAO,EAACxD;QACjB;QACA,MAAOA,SAAS,IAAK;YACnB,+FAA+F;YAC/F,MAAMxB,QAAQsE,QAAQtE,KAAK,IAAKD,CAAAA,OAAOyB,IAAI,KAAKA,QAAQuD,eAAevD,IAAG,IAAK,OAAO8C,QAAQtE,KAAK;YACnG,MAAMgE,OAAO,MAAM,IAAI,CAACC,gBAAgB,CAACzC,MAAMsC,OAAO9D;YACtD,IAAIgE,KAAKf,MAAM,EAAE;gBACf,KAAK,MAAMO,KAAK,AAAC,CAAA,MAAM,IAAI,CAAC5B,KAAK,CAACsC,IAAI,CAACF,KAAI,EAAGG,MAAM,CAACC,SAAwB;oBAC3E,IAAI,CAAC3C,MAAM,CAACC,OAAO,CAAC,CAAC,GAAG,EAAE8B,EAAEjC,UAAU,EAAE;oBACxC,MAAMiC;gBACR;YACF;YACAhC,OAAOwD,IAAAA,cAAO,EAACxD;QACjB;IACF;IAEA,OAAOU,iBAAiBnC,MAAmB,EAAE;QAC3C,MAAM+D,QAAQ,IAAI,CAAC9C,YAAY,CAACjB,QAAQ;YAAEgE,YAAY;QAAK;QAC3D,MAAMvC,OAAOzB,OAAOyB,IAAI,KAAK,MAAM,MAAM,GAAGzB,OAAOyB,IAAI,CAAC,EAAE,CAAC;QAC3D,IAAI,CAACC,MAAM,CAACC,OAAO,CAAC,GAAG,IAAI,CAACQ,gBAAgB,CAACP,IAAI,CAAC,GAAG,EAAEH,KAAK,EAAE,EAAEsC,MAAM,CAAC,CAAC;QACxE,MAAME,OAAO,MAAM,IAAI,CAACC,gBAAgB,CAACzC,MAAMsC;QAC/C,IAAIE,KAAKf,MAAM,EAAE;YACf,KAAK,MAAMO,KAAK,AAAC,CAAA,MAAM,IAAI,CAAC5B,KAAK,CAACsC,IAAI,CAACF,KAAI,EAAGG,MAAM,CAACC,SAAwB;gBAC3E,IAAI,CAAC3C,MAAM,CAACC,OAAO,CAAC,CAAC,GAAG,EAAE8B,EAAEjC,UAAU,CAAC,SAAS,EAAEiC,EAAEnC,KAAK,CAACiB,KAAK,CAAC,CAAC,CAAC;gBAClE,MAAMkB;YACR;QACF;IACF;IAEA,MAAcI,iBAAiBzD,KAAa,EAAmB;QAC7D,MAAM6D,OAAO,MAAM,IAAI,CAACpC,KAAK,CAACoC,IAAI,CAAC,GAAGjD,wBAAiB,CAAC,OAAO,EAAEZ,MAAM,EAAE,CAAC;QAC1E,IAAI,CAAC6D,KAAKf,MAAM,EAAE;YAChB,OAAO;QACT,OAAO,IAAIe,KAAKf,MAAM,GAAG,GAAG;YAC1B,IAAI,CAACxB,MAAM,CAACwD,IAAI,CAAC,CAAC,+BAA+B,EAAE9E,MAAM,IAAI,EAAE+E,KAAKC,SAAS,CAACnB,OAAO;QACvF;QACA,OAAOA,IAAI,CAAC,EAAE;IAChB;IAEQC,iBAAiBzC,IAAY,EAAEsC,QAAQ,GAAG,EAAE9D,KAAkB,EAAqB;QACzF,OAAO,IAAI,CAAC4B,KAAK,CAACoC,IAAI,CAAC,GAAGjD,wBAAiB,CAAC,CAAC,EAAEf,QAAQ,CAAC,OAAO,EAAEA,OAAO,GAAG,GAAG,MAAM,EAAEwB,KAAK,CAAC,EAAEsC,OAAO;IACvG;IAEQxD,cAAsB;QAC5B,OAAO,GAAG8E,mBAAW,GAAGC,mBAAM,CAACC,UAAU,IAAI;IAC/C;IAEQtE,aAAajB,MAAmB,EAAEuE,UAAwE,CAAC,CAAC,EAAU;QAC5H,8GAA8G;QAC9G,4BAA4B;QAC5B,MAAMiB,WAAW,EAAE;QACnB,KAAK,MAAMC,KAAKpC,OAAOY,IAAI,CAACjE,QACzBoE,MAAM,CAAC,CAACqB,IAAMA,MAAMC,kBAAK,CAACC,OAAO,CAAC/D,IAAI,IAAI5B,MAAM,CAACyF,EAAE,KAAK,MACxDG,IAAI,GAAI;YACT,IAAIH,MAAMC,kBAAK,CAACjE,IAAI,CAACG,IAAI,EAAE;gBACzB,IAAI2C,QAAQP,UAAU,EAAE;oBACtB;gBACF;gBACAwB,SAASK,OAAO,CAAC,GAAGJ,EAAE,CAAC,EAAEzF,MAAM,CAACyF,EAAE,EAAE;YACtC,OAAO;gBACLD,SAASnD,IAAI,CAAC,GAAGoD,EAAE,CAAC,EAAEzF,MAAM,CAACyF,EAAE,EAAE;YACnC;QACF;QACA,IAAIlB,QAAQtE,KAAK,EAAEuF,SAASK,OAAO,CAAC,CAAC,MAAM,EAAEtB,QAAQtE,KAAK,EAAE;QAC5D,IAAIsE,QAAQnE,KAAK,EAAEoF,SAASK,OAAO,CAAC,CAAC,MAAM,EAAEtB,QAAQnE,KAAK,EAAE;QAC5D,OAAOoF,SAASM,IAAI,CAAC;IACvB;IA9NA,YAAY,AAAiBjE,KAAY,CAAE;aAAdA,QAAAA;aAFZH,SAAS,IAAIqE,cAAM,CAAClG,iBAAiB+B,IAAI;IAEd;AA+N9C;AA/OE;;;;;;;;;;;;EAYA,GAbW/B,iBAcYiB,4BAA4B,OAAM,QAAQ"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-lock-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 crypto from 'node:crypto'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH, LOCK_PREFIX, LOCK_SCOPE } from '../../webdav/constants/webdav'\nimport { WebDAVLock } from '../../webdav/interfaces/webdav.interface'\nimport { CACHE_LOCK_DEFAULT_TTL, CACHE_LOCK_PREFIX } from '../constants/cache'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { FileLockProps } from '../interfaces/file-props.interface'\nimport { LockConflict } from '../models/file-lock-error'\nimport { files } from '../schemas/files.schema'\nimport { dirName, fileName } from '../utils/files'\n\n@Injectable()\nexport class FilesLockManager {\n /* Philosophy\n Currently this manager only handle conflicting locks between multiple users, not between clients\n - The locks created from api\n * They do not contain a token key or a davLock property\n * They are exclusive only\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n - The locks created from WebDAV or OnlyOffice are stored with a token and a davLock property\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n * They can be exclusive (WebDAV) or shared (OnlyOffice)\n * If created with WebDAV, they are stored with a token and a davLock property\n * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null\n Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock\n */\n private readonly logger = new Logger(FilesLockManager.name)\n\n constructor(private readonly cache: Cache) {}\n\n async create(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, davLock?: WebDAVLock, ttl?: number): Promise<[boolean, FileLock]> {\n let token: string\n let lockscope: LOCK_SCOPE\n if (davLock) {\n // webdav context\n davLock.locktoken = this.genDAVToken()\n token = davLock.locktoken\n lockscope = davLock.lockscope\n } else {\n // api context\n token = null\n lockscope = null\n }\n try {\n await this.checkConflicts(dbFile, depth, { lockScope: lockscope })\n } catch (e) {\n if (e instanceof LockConflict) {\n return [false, e.lock]\n }\n throw new Error(e)\n }\n ttl ??= CACHE_LOCK_DEFAULT_TTL\n const key = `${CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, { depth: depth, token: token })}`\n const expiration = Math.floor(currentTimeStamp() + ttl)\n const lock: FileLock = {\n owner: user.asOwner(),\n dbFilePath: dbFile.path,\n key: key,\n depth: depth,\n expiration: expiration,\n davLock: davLock\n }\n this.logger.verbose(`${this.create.name} - ${key}`)\n await this.cache.set(key, lock, ttl)\n return [true, lock]\n }\n\n async createOrRefresh(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, ttl?: number): Promise<[boolean, FileLock]> {\n // Returns: [created, lock]\n ttl ??= CACHE_LOCK_DEFAULT_TTL\n const locks = await this.getLocksByPath(dbFile)\n // Check the existing lock and refresh it if needed\n if (locks.length > 0) {\n for (const lock of locks) {\n if (lock.owner.id === user.id) {\n // Refresh if more than half of the TTL has passed\n const mustRefresh = lock.expiration - currentTimeStamp() < ttl / 2\n if (mustRefresh) {\n this.refreshLockTimeout(lock, ttl).catch((e: Error) => this.logger.error(`${this.createOrRefresh.name} - ${e}`))\n }\n } else {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n }\n return [false, locks[0]]\n }\n // Create the lock\n const [ok, lock] = await this.create(user, dbFile, depth, null, ttl)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n return [true, lock]\n }\n\n removeLock(key: string): Promise<boolean> {\n this.logger.verbose(`${this.removeLock.name} - ${key}`)\n return this.cache.del(key)\n }\n\n async removeChildLocks(user: UserModel, dbFile: FileDBProps) {\n const ownedLockKeys: string[] = []\n for await (const lock of this.searchChildLocks(dbFile)) {\n if (user.id === lock.owner.id) {\n ownedLockKeys.push(lock.key)\n continue\n }\n const conflict = `cannot remove conflicting child lock : ${dbFile.path} (${user.login}) -> ${lock.dbFilePath} (${lock.owner.login})`\n this.logger.debug(`${this.removeChildLocks.name} - ${conflict}`)\n throw new LockConflict(lock, conflict)\n }\n for (const key of ownedLockKeys) {\n this.logger.verbose(`${this.removeChildLocks.name} - child locks: ${key}`)\n await this.removeLock(key)\n }\n }\n\n async isLockedWithToken(token: string, dbFilePath: string): Promise<FileLock> {\n // check if url (or any of its parents) is locked by the token\n const lock = await this.getLockByToken(token)\n return lock ? (dbFilePath.startsWith(lock.dbFilePath) ? lock : null) : null\n }\n\n async browseParentChildLocks(dbFile: FileDBProps, includeRoot = true): Promise<Record<string, FileLock>> {\n // find child locks inside the path\n const childLocks: Record<string, FileLock> = includeRoot ? await this.browseLocks(dbFile) : {}\n const lengthFilter = dbFile.path === '.' ? 1 : dbFile.path.split('/').length + 1\n for await (const lock of this.searchChildLocks(dbFile)) {\n // filter child locks on length\n if (lengthFilter === lock.dbFilePath.split('/').length) {\n // !!! locks with shared scope can have the same file name, in this case we only keep the first entry\n const dbFileName = fileName(lock.dbFilePath)\n if (!(dbFileName in childLocks)) {\n childLocks[fileName(lock.dbFilePath)] = lock\n }\n }\n }\n return childLocks\n }\n\n async browseLocks(dbFile: FileDBProps): Promise<Record<string, FileLock>> {\n return Object.fromEntries((await this.getLocksByPath(dbFile)).map((l) => [fileName(l.dbFilePath), l]))\n }\n\n async refreshLockTimeout(lock: FileLock, ttl: number) {\n lock.expiration = currentTimeStamp() + ttl\n this.cache.set(lock.key, lock, ttl).catch((e: Error) => this.logger.error(`${this.refreshLockTimeout.name} - ${e}`))\n }\n\n async getLockByToken(token: string): Promise<FileLock> {\n const key = await this.searchKeyByToken(token)\n return key ? (await this.cache.get(key)) || null : null\n }\n\n async getLocksByPath(dbFile: FileDBProps): Promise<FileLock[]> {\n if (dbFile.path !== '.') {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const keys = await this.searchKeysByPath(dbFile.path, props)\n if (keys.length) {\n return (await this.cache.mget(keys)).filter(Boolean)\n }\n }\n return []\n }\n\n async isPathLocked(dbFile: FileDBProps): Promise<boolean> {\n if (dbFile.path !== '.') return false\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n return !!(await this.searchKeysByPath(dbFile.path, props)).length\n }\n\n async checkConflicts(\n dbFile: FileDBProps,\n depth: LOCK_DEPTH,\n options?: { userId?: number; lockScope?: LOCK_SCOPE; lockTokens?: string[] }\n ): Promise<void> {\n /* Checks if a file could be modified, created, moved, or deleted\n Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification\n Returns on the first conflict (compliant with the RFC 4918)\n */\n for await (const l of this.searchParentLocks(dbFile, { includeRoot: true, depth: DEPTH.INFINITY })) {\n if (options?.lockScope && options?.lockScope === LOCK_SCOPE.SHARED && l.davLock.lockscope === LOCK_SCOPE.SHARED) {\n // Only compatible with shared locks (even by same owner)\n continue\n }\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting parent lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n if (depth === DEPTH.INFINITY) {\n for await (const l of this.searchChildLocks(dbFile)) {\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting child lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n }\n }\n\n async *searchChildLocks(dbFile: FileDBProps) {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`\n this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`)\n const keys = await this.searchKeysByPath(path, props)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`)\n yield l\n }\n }\n }\n\n convertLockToFileLockProps(lock: FileLock): FileLockProps {\n if (!lock) return null\n return {\n owner: lock?.davLock?.owner || `${lock.owner.fullName} (${lock.owner.email})`,\n ownerLogin: lock.owner.login,\n isExclusive: lock?.davLock?.lockscope ? lock?.davLock?.lockscope === LOCK_SCOPE.EXCLUSIVE : true\n }\n }\n\n private async *searchParentLocks(dbFile: FileDBProps, options: { includeRoot?: boolean; depth?: LOCK_DEPTH } = {}): AsyncGenerator<FileLock> {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n let path = dbFile.path\n const parentPath = dirName(path)\n this.logger.verbose(`${this.searchParentLocks.name} - (including root : ${options.includeRoot}) : ${path} (${props})`)\n if (!options.includeRoot) {\n path = dirName(path)\n }\n while (path !== '.') {\n // Even if the depth is \"infinite\", the path and the parent path could be locked with depth \"0\"\n const depth = options.depth && (dbFile.path === path || parentPath === path) ? null : options.depth\n const keys = await this.searchKeysByPath(path, props, depth)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath}`)\n yield l\n }\n }\n path = dirName(path)\n }\n }\n\n private async searchKeyByToken(token: string): Promise<string> {\n const keys = await this.cache.keys(`${CACHE_LOCK_PREFIX}|token:${token}|*`)\n if (!keys.length) {\n return null\n } else if (keys.length > 1) {\n this.logger.warn(`Several keys found for token : ${token} => ${JSON.stringify(keys)}`)\n }\n return keys[0]\n }\n\n private searchKeysByPath(path: string, props = '*', depth?: LOCK_DEPTH): Promise<string[]> {\n return this.cache.keys(`${CACHE_LOCK_PREFIX}*${depth ? `|depth:${depth}` : ''}|path:${path}|${props}`)\n }\n\n private genDAVToken(): string {\n return `${LOCK_PREFIX}${crypto.randomUUID()}`\n }\n\n private genSuffixKey(dbFile: FileDBProps, options: { ignorePath?: boolean; depth?: LOCK_DEPTH; token?: string } = {}): string {\n // return -> `depth:infinity|path:code/sync-in|spaceId:1` | `token:xxx|depth:0|path:code/sync-in.ts|ownerId:1`\n // ignorePath -> `spaceId:1`\n const suffixes = []\n for (const k of Object.keys(dbFile)\n .filter((k) => k !== files.inTrash.name && dbFile[k] !== null)\n .sort()) {\n if (k === files.path.name) {\n if (options.ignorePath) {\n continue\n }\n suffixes.unshift(`${k}:${dbFile[k]}`)\n } else {\n suffixes.push(`${k}:${dbFile[k]}`)\n }\n }\n if (options.depth) suffixes.unshift(`depth:${options.depth}`)\n if (options.token) suffixes.unshift(`token:${options.token}`)\n return suffixes.join('|')\n }\n}\n"],"names":["FilesLockManager","create","user","dbFile","depth","davLock","ttl","token","lockscope","locktoken","genDAVToken","checkConflicts","lockScope","e","LockConflict","lock","Error","CACHE_LOCK_DEFAULT_TTL","key","CACHE_LOCK_PREFIX","genSuffixKey","expiration","Math","floor","currentTimeStamp","owner","asOwner","dbFilePath","path","logger","verbose","name","cache","set","createOrRefresh","locks","getLocksByPath","length","id","mustRefresh","refreshLockTimeout","catch","error","ok","removeLock","del","removeChildLocks","ownedLockKeys","searchChildLocks","push","conflict","login","debug","isLockedWithToken","getLockByToken","startsWith","browseParentChildLocks","includeRoot","childLocks","browseLocks","lengthFilter","split","dbFileName","fileName","Object","fromEntries","map","l","searchKeyByToken","get","props","ignorePath","keys","searchKeysByPath","mget","filter","Boolean","isPathLocked","options","searchParentLocks","DEPTH","INFINITY","LOCK_SCOPE","SHARED","userId","lockTokens","indexOf","convertLockToFileLockProps","fullName","email","ownerLogin","isExclusive","EXCLUSIVE","parentPath","dirName","warn","JSON","stringify","LOCK_PREFIX","crypto","randomUUID","suffixes","k","files","inTrash","sort","unshift","join","Logger"],"mappings":"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"}
@@ -17,14 +17,18 @@ const _common = require("@nestjs/common");
17
17
  const _archiver = /*#__PURE__*/ _interop_require_default(require("archiver"));
18
18
  const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
19
19
  const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
20
- const _promises = require("node:stream/promises");
21
20
  const _tar = require("tar");
22
21
  const _image = require("../../../common/image");
22
+ const _contextmanagerservice = require("../../../infrastructure/context/services/context-manager.service");
23
23
  const _applicationsconstants = require("../../applications.constants");
24
+ const _notifications = require("../../notifications/constants/notifications");
25
+ const _notificationsmanagerservice = require("../../notifications/services/notifications-manager.service");
24
26
  const _spaces = require("../../spaces/constants/spaces");
27
+ const _spacesmanagerservice = require("../../spaces/services/spaces-manager.service");
25
28
  const _paths = require("../../spaces/utils/paths");
26
29
  const _permissions = require("../../spaces/utils/permissions");
27
30
  const _webdav = require("../../webdav/constants/webdav");
31
+ const _cache = require("../constants/cache");
28
32
  const _compress = require("../constants/compress");
29
33
  const _files = require("../constants/files");
30
34
  const _operations = require("../constants/operations");
@@ -142,11 +146,16 @@ let FilesManager = class FilesManager {
142
146
  }
143
147
  async saveMultipart(user, space, req) {
144
148
  /* Accepted methods:
145
- POST: create new resource
146
- PUT: create or update new resource (even if parent path does not exist)
147
- */ const realParentPath = (0, _files1.dirName)(space.realPath);
148
- if (req.method === _applicationsconstants.HTTP_METHOD.POST) {
149
- if (await (0, _files1.isPathExists)(space.realPath)) {
149
+ POST: Creates new resource
150
+ PUT: Creates or fully replaces a resource at the given URI (even if intermediate paths do not exist)
151
+ PATCH: Updates the content of an existing resource without creating a new one.
152
+ In this text-editing scenario, locking and refreshing occur automatically, but unlocking must be handled explicitly via
153
+ the `unlock` method.
154
+ */ const overwrite = req.method === _applicationsconstants.HTTP_METHOD.PUT;
155
+ const patch = req.method === _applicationsconstants.HTTP_METHOD.PATCH;
156
+ const realParentPath = (0, _files1.dirName)(space.realPath);
157
+ if (!overwrite) {
158
+ if (!patch && await (0, _files1.isPathExists)(space.realPath)) {
150
159
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Resource already exists');
151
160
  }
152
161
  if (!await (0, _files1.isPathExists)(realParentPath)) {
@@ -158,31 +167,53 @@ let FilesManager = class FilesManager {
158
167
  }
159
168
  const basePath = realParentPath + _nodepath.default.sep;
160
169
  for await (const part of req.files()){
161
- // part.filename may contain a path like foo/bar.txt.
162
- const dstFile = _nodepath.default.resolve(basePath, part.filename);
163
- // prevent path traversal
170
+ // If the request uses the PATCH method, the file name corresponds to the space
171
+ const partFileName = patch ? (0, _files1.fileName)(space.realPath) : part.filename;
172
+ // `part.filename` may contain a path like foo/bar.txt
173
+ const dstFile = _nodepath.default.resolve(basePath, partFileName);
174
+ // Prevent path traversal
164
175
  if (!dstFile.startsWith(basePath)) {
165
176
  throw new _fileerror.FileError(_common.HttpStatus.FORBIDDEN, 'Location is not allowed');
166
177
  }
167
- // make dir in space
168
178
  const dstDir = (0, _files1.dirName)(dstFile);
179
+ if (overwrite) {
180
+ // Prevent errors when an uploaded file would replace a directory with the same name
181
+ // Only applies in `overwrite` cases
182
+ if (await (0, _files1.isPathExists)(dstFile) && await (0, _files1.isPathIsDir)(dstFile)) {
183
+ // If a directory already exists at the destination path, delete it to allow overwriting with the uploaded file
184
+ const dstUrl = _nodepath.default.join(_nodepath.default.dirname(space.url), partFileName);
185
+ const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'));
186
+ await this.delete(user, dstSpace);
187
+ } else if (await (0, _files1.isPathExists)(dstDir) && !await (0, _files1.isPathIsDir)(dstDir)) {
188
+ // If the destination's parent exists but is a file, remove it so we can create the directory
189
+ const dstUrl = _nodepath.default.join(_nodepath.default.dirname(space.url), _nodepath.default.dirname(partFileName));
190
+ const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'));
191
+ await this.delete(user, dstSpace);
192
+ }
193
+ }
194
+ // Create the directory in the space
169
195
  if (!await (0, _files1.isPathExists)(dstDir)) {
170
196
  await (0, _files1.makeDir)(dstDir, true);
171
197
  }
172
- // create lock
198
+ // Create or refresh lock
173
199
  const dbFile = {
174
200
  ...space.dbFile,
175
- path: _nodepath.default.join((0, _files1.dirName)(space.dbFile.path), part.filename)
201
+ path: _nodepath.default.join((0, _files1.dirName)(space.dbFile.path), partFileName)
176
202
  };
177
- const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, _webdav.DEPTH.RESOURCE);
178
- if (!ok) throw new _filelockerror.LockConflict(fileLock, 'Conflicting lock');
179
- // do
203
+ // Use a short TTL for the PATCH method (which is also used for refreshing)
204
+ const ttl = patch ? _cache.CACHE_LOCK_FILE_TTL : undefined;
205
+ const [created, fileLock] = await this.filesLockManager.createOrRefresh(user, dbFile, _webdav.DEPTH.RESOURCE, ttl);
206
+ // Do
180
207
  try {
181
- await (0, _promises.pipeline)(part.file, _nodefs.default.createWriteStream(dstFile, {
182
- highWaterMark: _files.DEFAULT_HIGH_WATER_MARK
183
- }));
208
+ await (0, _files1.writeFromStream)(dstFile, part.file);
184
209
  } finally{
185
- await this.filesLockManager.removeLock(fileLock.key);
210
+ if (!patch && created) {
211
+ // Remove the file lock only if it has not been refreshed
212
+ await this.filesLockManager.removeLock(fileLock.key);
213
+ }
214
+ }
215
+ if (patch) {
216
+ break;
186
217
  }
187
218
  }
188
219
  }
@@ -212,7 +243,7 @@ let FilesManager = class FilesManager {
212
243
  const fileExtension = _nodepath.default.extname(space.realPath);
213
244
  if (checkDocument && fileExtension !== '.txt' && Object.values(_samples.DOCUMENT_TYPE).indexOf(fileExtension) > -1) {
214
245
  const srcSample = _nodepath.default.join(__dirname, `${_samples.SAMPLE_PATH_WITHOUT_EXT}${fileExtension}`);
215
- return (0, _files1.copyFiles)(srcSample, space.realPath, false, false, false);
246
+ return (0, _files1.copyFileContent)(srcSample, space.realPath);
216
247
  } else {
217
248
  return (0, _files1.createEmptyFile)(space.realPath);
218
249
  }
@@ -370,12 +401,12 @@ let FilesManager = class FilesManager {
370
401
  ...trashFileDB,
371
402
  path: _nodepath.default.join((0, _files1.dirName)(trashFileDB.path), (0, _files1.fileName)(dstTrash.path))
372
403
  };
373
- this.filesQueries.moveFiles(trashFileDB, dstTrashFileDB, dstTrash.isDir).catch((e)=>this.logger.error(`${this.delete.name} - ${e}`));
404
+ await this.filesQueries.moveFiles(trashFileDB, dstTrashFileDB, dstTrash.isDir);
374
405
  }
375
406
  await (0, _files1.moveFiles)(space.realPath, trashFile, true);
376
407
  } else {
377
- this.logger.log(`Unable to find trash path for space - *${space.alias}* (${space.id}) : delete permanently : ${space.realPath}`);
378
- // todo: define a default trash for external paths
408
+ // unsupported case: delete the file (this shouldn't happen)
409
+ this.logger.error(`Unable to find trash path for space - *${space.alias}* (${space.id}) : delete permanently : ${space.realPath}`);
379
410
  forceDeleteInDB = true;
380
411
  await (0, _files1.removeFiles)(space.realPath);
381
412
  }
@@ -553,9 +584,73 @@ let FilesManager = class FilesManager {
553
584
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'File is not an image');
554
585
  }
555
586
  }
556
- constructor(http, filesQueries, filesLockManager){
587
+ async lock(user, space) {
588
+ const rExists = await (0, _files1.isPathExists)(space.realPath);
589
+ if (!rExists) {
590
+ this.logger.warn('Lock refresh must specify an existing resource');
591
+ throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Lock refresh must specify an existing resource');
592
+ }
593
+ const [_created, lock] = await this.filesLockManager.createOrRefresh(user, space.dbFile, _webdav.DEPTH.RESOURCE, _cache.CACHE_LOCK_FILE_TTL);
594
+ return this.filesLockManager.convertLockToFileLockProps(lock);
595
+ }
596
+ async unlock(user, space, forceAsOwner = false) {
597
+ if (!await (0, _files1.isPathExists)(space.realPath)) {
598
+ this.logger.warn(`Unable to unlock: ${space.url} - resource does not exist`);
599
+ throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Unlock must specify an existing resource');
600
+ }
601
+ const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile);
602
+ if (fileLocks.length === 0) {
603
+ this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`);
604
+ return;
605
+ }
606
+ for (const lock of fileLocks){
607
+ if (forceAsOwner && space.dbFile?.ownerId === user.id || lock.owner.id === user.id) {
608
+ // Refresh if more than half of the TTL has passed
609
+ await this.filesLockManager.removeLock(lock.key);
610
+ } else {
611
+ throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
612
+ }
613
+ }
614
+ }
615
+ async unlockRequest(user, space) {
616
+ const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile);
617
+ if (fileLocks.length === 0) {
618
+ this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`);
619
+ throw new _fileerror.FileError(_common.HttpStatus.NOT_FOUND, 'Lock not found');
620
+ }
621
+ for (const lock of fileLocks){
622
+ if (lock.owner.id !== user.id) {
623
+ const notification = {
624
+ app: _notifications.NOTIFICATION_APP.UNLOCK_REQUEST,
625
+ event: _notifications.NOTIFICATION_APP_EVENT.UNLOCK_REQUEST,
626
+ element: (0, _files1.fileName)(space.url),
627
+ url: (0, _files1.dirName)(space.url)
628
+ };
629
+ this.notificationsManager.create([
630
+ lock.owner.id
631
+ ], notification, {
632
+ author: user,
633
+ currentUrl: this.contextManager.headerOriginUrl()
634
+ }).catch((e)=>this.logger.error(`${this.unlockRequest.name} - ${e}`));
635
+ }
636
+ }
637
+ }
638
+ async getSize(space) {
639
+ if (!await (0, _files1.isPathExists)(space.realPath)) {
640
+ throw new _fileerror.FileError(_common.HttpStatus.NOT_FOUND, 'Location not found');
641
+ }
642
+ if (await (0, _files1.isPathIsDir)(space.realPath)) {
643
+ return (await (0, _files1.dirSize)(space.realPath))[0];
644
+ } else {
645
+ return await (0, _files1.fileSize)(space.realPath);
646
+ }
647
+ }
648
+ constructor(http, filesQueries, spacesManager, contextManager, notificationsManager, filesLockManager){
557
649
  this.http = http;
558
650
  this.filesQueries = filesQueries;
651
+ this.spacesManager = spacesManager;
652
+ this.contextManager = contextManager;
653
+ this.notificationsManager = notificationsManager;
559
654
  this.filesLockManager = filesLockManager;
560
655
  /* Spaces permissions are checked in the space guard, except for the copy/move destination */ this.logger = new _common.Logger(FilesManager.name);
561
656
  }
@@ -566,6 +661,9 @@ FilesManager = _ts_decorate([
566
661
  _ts_metadata("design:paramtypes", [
567
662
  typeof _axios.HttpService === "undefined" ? Object : _axios.HttpService,
568
663
  typeof _filesqueriesservice.FilesQueries === "undefined" ? Object : _filesqueriesservice.FilesQueries,
664
+ typeof _spacesmanagerservice.SpacesManager === "undefined" ? Object : _spacesmanagerservice.SpacesManager,
665
+ typeof _contextmanagerservice.ContextManager === "undefined" ? Object : _contextmanagerservice.ContextManager,
666
+ typeof _notificationsmanagerservice.NotificationsManager === "undefined" ? Object : _notificationsmanagerservice.NotificationsManager,
569
667
  typeof _fileslockmanagerservice.FilesLockManager === "undefined" ? Object : _fileslockmanagerservice.FilesLockManager
570
668
  ])
571
669
  ], FilesManager);