@sync-in/server 1.6.1 → 1.8.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 (277) hide show
  1. package/CHANGELOG.md +169 -55
  2. package/environment/environment.dist.yaml +14 -5
  3. package/migrations/0003_giant_luckman.sql +6 -0
  4. package/migrations/meta/0003_snapshot.json +2463 -0
  5. package/migrations/meta/_journal.json +7 -0
  6. package/package.json +16 -15
  7. package/server/app.bootstrap.js +1 -0
  8. package/server/app.bootstrap.js.map +1 -1
  9. package/server/app.constants.js +0 -4
  10. package/server/app.constants.js.map +1 -1
  11. package/server/app.service.js +7 -6
  12. package/server/app.service.js.map +1 -1
  13. package/server/applications/files/constants/only-office.js +12 -0
  14. package/server/applications/files/constants/only-office.js.map +1 -1
  15. package/server/applications/files/files.config.js +5 -0
  16. package/server/applications/files/files.config.js.map +1 -1
  17. package/server/applications/files/services/files-content-manager.service.js +6 -6
  18. package/server/applications/files/services/files-content-manager.service.js.map +1 -1
  19. package/server/applications/files/services/files-manager.service.js +4 -4
  20. package/server/applications/files/services/files-manager.service.js.map +1 -1
  21. package/server/applications/files/services/files-methods.service.js +5 -3
  22. package/server/applications/files/services/files-methods.service.js.map +1 -1
  23. package/server/applications/files/services/files-only-office-manager.service.js +2 -2
  24. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  25. package/server/applications/files/services/files-parser.service.js +6 -3
  26. package/server/applications/files/services/files-parser.service.js.map +1 -1
  27. package/server/applications/files/services/files-scheduler.service.js +51 -3
  28. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  29. package/server/applications/files/services/files-search-manager.service.js +4 -0
  30. package/server/applications/files/services/files-search-manager.service.js.map +1 -1
  31. package/server/applications/files/utils/doc-textify/adapters/pdf.js +10 -1
  32. package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
  33. package/server/applications/notifications/i18n/de.js +56 -0
  34. package/server/applications/notifications/i18n/de.js.map +1 -0
  35. package/server/applications/notifications/i18n/es.js +52 -0
  36. package/server/applications/notifications/i18n/es.js.map +1 -0
  37. package/server/applications/notifications/i18n/hi.js +52 -0
  38. package/server/applications/notifications/i18n/hi.js.map +1 -0
  39. package/server/applications/notifications/i18n/index.js +73 -8
  40. package/server/applications/notifications/i18n/index.js.map +1 -1
  41. package/server/applications/notifications/i18n/it.js +52 -0
  42. package/server/applications/notifications/i18n/it.js.map +1 -0
  43. package/server/applications/notifications/i18n/ja.js +52 -0
  44. package/server/applications/notifications/i18n/ja.js.map +1 -0
  45. package/server/applications/notifications/i18n/ko.js +52 -0
  46. package/server/applications/notifications/i18n/ko.js.map +1 -0
  47. package/server/applications/notifications/i18n/pl.js +52 -0
  48. package/server/applications/notifications/i18n/pl.js.map +1 -0
  49. package/server/applications/notifications/i18n/pt.js +52 -0
  50. package/server/applications/notifications/i18n/pt.js.map +1 -0
  51. package/server/applications/notifications/i18n/pt_br.js +52 -0
  52. package/server/applications/notifications/i18n/pt_br.js.map +1 -0
  53. package/server/applications/notifications/i18n/ru.js +52 -0
  54. package/server/applications/notifications/i18n/ru.js.map +1 -0
  55. package/server/applications/notifications/i18n/tr.js +52 -0
  56. package/server/applications/notifications/i18n/tr.js.map +1 -0
  57. package/server/applications/notifications/i18n/zh.js +52 -0
  58. package/server/applications/notifications/i18n/zh.js.map +1 -0
  59. package/server/applications/notifications/mails/models.js +6 -7
  60. package/server/applications/notifications/mails/models.js.map +1 -1
  61. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  62. package/server/applications/shares/dto/create-or-update-share.dto.js +11 -0
  63. package/server/applications/shares/dto/create-or-update-share.dto.js.map +1 -1
  64. package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
  65. package/server/applications/shares/schemas/share.interface.js.map +1 -1
  66. package/server/applications/shares/schemas/shares.schema.js +9 -0
  67. package/server/applications/shares/schemas/shares.schema.js.map +1 -1
  68. package/server/applications/shares/services/shares-manager.service.js +46 -17
  69. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  70. package/server/applications/shares/services/shares-queries.service.js +24 -5
  71. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  72. package/server/applications/spaces/constants/cache.js +4 -0
  73. package/server/applications/spaces/constants/cache.js.map +1 -1
  74. package/server/applications/spaces/dto/create-or-update-space.dto.js +5 -0
  75. package/server/applications/spaces/dto/create-or-update-space.dto.js.map +1 -1
  76. package/server/applications/spaces/guards/space.guard.js +3 -3
  77. package/server/applications/spaces/guards/space.guard.js.map +1 -1
  78. package/server/applications/spaces/models/space-props.model.js.map +1 -1
  79. package/server/applications/spaces/models/space.model.js.map +1 -1
  80. package/server/applications/spaces/schemas/space.interface.js.map +1 -1
  81. package/server/applications/spaces/schemas/spaces.schema.js +1 -0
  82. package/server/applications/spaces/schemas/spaces.schema.js.map +1 -1
  83. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  84. package/server/applications/spaces/services/spaces-manager.service.js +34 -31
  85. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  86. package/server/applications/spaces/services/spaces-queries.service.js +23 -7
  87. package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
  88. package/server/applications/spaces/services/spaces-scheduler.service.js +21 -20
  89. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  90. package/server/applications/spaces/spaces.controller.js +4 -2
  91. package/server/applications/spaces/spaces.controller.js.map +1 -1
  92. package/server/applications/spaces/utils/paths.js +14 -16
  93. package/server/applications/spaces/utils/paths.js.map +1 -1
  94. package/server/applications/sync/services/sync-manager.service.js +4 -3
  95. package/server/applications/sync/services/sync-manager.service.js.map +1 -1
  96. package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
  97. package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
  98. package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
  99. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  100. package/server/applications/sync/sync.controller.js +2 -1
  101. package/server/applications/sync/sync.controller.js.map +1 -1
  102. package/server/applications/users/constants/routes.js +5 -0
  103. package/server/applications/users/constants/routes.js.map +1 -1
  104. package/server/applications/users/constants/user.js +0 -16
  105. package/server/applications/users/constants/user.js.map +1 -1
  106. package/server/applications/users/dto/user-properties.dto.js +10 -0
  107. package/server/applications/users/dto/user-properties.dto.js.map +1 -1
  108. package/server/applications/users/models/user.model.js.map +1 -1
  109. package/server/applications/users/schemas/user.interface.js.map +1 -1
  110. package/server/applications/users/schemas/users.schema.js +3 -2
  111. package/server/applications/users/schemas/users.schema.js.map +1 -1
  112. package/server/applications/users/services/admin-users-manager.service.js +1 -0
  113. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  114. package/server/applications/users/services/admin-users-manager.service.spec.js +2 -1
  115. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  116. package/server/applications/users/services/users-manager.service.js +8 -2
  117. package/server/applications/users/services/users-manager.service.js.map +1 -1
  118. package/server/applications/users/services/users-manager.service.spec.js +1 -0
  119. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  120. package/server/applications/users/services/users-queries.service.js +18 -4
  121. package/server/applications/users/services/users-queries.service.js.map +1 -1
  122. package/server/applications/users/users.controller.js +15 -0
  123. package/server/applications/users/users.controller.js.map +1 -1
  124. package/server/applications/users/utils/test.js +2 -2
  125. package/server/applications/users/utils/test.js.map +1 -1
  126. package/server/applications/webdav/constants/routes.js +2 -2
  127. package/server/applications/webdav/constants/routes.js.map +1 -1
  128. package/server/applications/webdav/constants/webdav.js +2 -2
  129. package/server/applications/webdav/constants/webdav.js.map +1 -1
  130. package/server/applications/webdav/filters/webdav.filter.js +2 -2
  131. package/server/applications/webdav/filters/webdav.filter.js.map +1 -1
  132. package/server/applications/webdav/filters/webdav.filter.spec.js +2 -2
  133. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -1
  134. package/server/applications/webdav/services/webdav-methods.service.js +3 -2
  135. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  136. package/server/applications/webdav/utils/webdav.js +1 -2
  137. package/server/applications/webdav/utils/webdav.js.map +1 -1
  138. package/server/authentication/auth.config.js +17 -2
  139. package/server/authentication/auth.config.js.map +1 -1
  140. package/server/authentication/constants/auth-ldap.js +2 -1
  141. package/server/authentication/constants/auth-ldap.js.map +1 -1
  142. package/server/authentication/guards/auth-basic.strategy.js +4 -2
  143. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  144. package/server/authentication/guards/auth-local.strategy.js +2 -0
  145. package/server/authentication/guards/auth-local.strategy.js.map +1 -1
  146. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +75 -32
  147. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  148. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +2 -1
  149. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  150. package/server/common/i18n.js +52 -0
  151. package/server/common/i18n.js.map +1 -0
  152. package/server/common/image.js +49 -33
  153. package/server/common/image.js.map +1 -1
  154. package/server/common/interfaces.js.map +1 -1
  155. package/server/common/shared.js +5 -2
  156. package/server/common/shared.js.map +1 -1
  157. package/server/configuration/config.validation.js +3 -3
  158. package/server/configuration/config.validation.js.map +1 -1
  159. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +8 -6
  160. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
  161. package/server/infrastructure/cache/adapters/redis-cache.adapter.js +22 -17
  162. package/server/infrastructure/cache/adapters/redis-cache.adapter.js.map +1 -1
  163. package/server/infrastructure/cache/cache.e2e-spec.js +1 -0
  164. package/server/infrastructure/cache/cache.e2e-spec.js.map +1 -1
  165. package/server/infrastructure/cache/cache.module.js +1 -14
  166. package/server/infrastructure/cache/cache.module.js.map +1 -1
  167. package/server/infrastructure/cache/services/cache.service.js.map +1 -1
  168. package/server/infrastructure/database/database.module.js +20 -1
  169. package/server/infrastructure/database/database.module.js.map +1 -1
  170. package/server/infrastructure/database/utils.js +48 -0
  171. package/server/infrastructure/database/utils.js.map +1 -1
  172. package/server/infrastructure/scheduler/scheduler.module.js +1 -1
  173. package/server/infrastructure/scheduler/scheduler.module.js.map +1 -1
  174. package/server/infrastructure/websocket/adapters/cluster.adapter.js +1 -3
  175. package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
  176. package/static/3rdpartylicenses.txt +137 -137
  177. package/static/chunk-2KLC4T2Z.js +1 -0
  178. package/static/chunk-373XVRXW.js +1 -0
  179. package/static/chunk-3GMLWAFZ.js +1 -0
  180. package/static/chunk-3XVM35O2.js +1 -0
  181. package/static/chunk-3YVRP3VM.js +2 -0
  182. package/static/chunk-5NMSIIQB.js +1 -0
  183. package/static/chunk-AF24EYXU.js +1 -0
  184. package/static/chunk-AKQVEHO6.js +2 -0
  185. package/static/{chunk-LUWQFIWR.js → chunk-AY2SZ3G6.js} +1 -1
  186. package/static/chunk-BCVX464U.js +2 -0
  187. package/static/{chunk-IPAC4VAF.js → chunk-BIKLW4YS.js} +1 -1
  188. package/static/chunk-C36MW4ME.js +562 -0
  189. package/static/chunk-CHJ64RJM.js +1 -0
  190. package/static/chunk-DKSEQTMX.js +1 -0
  191. package/static/chunk-DM4NXKEP.js +1 -0
  192. package/static/chunk-DPUVSXRB.js +1 -0
  193. package/static/chunk-DSWEWLXJ.js +1 -0
  194. package/static/chunk-FJE6BOFL.js +1 -0
  195. package/static/chunk-FZ3JPGYZ.js +1 -0
  196. package/static/chunk-GUGNR5TF.js +3 -0
  197. package/static/chunk-H6NE33VX.js +1 -0
  198. package/static/{chunk-S75P2FFI.js → chunk-HAS5ZOTR.js} +1 -1
  199. package/static/chunk-HNQRZALS.js +1 -0
  200. package/static/chunk-JPT5WEAT.js +1 -0
  201. package/static/{chunk-ZQQPUYLU.js → chunk-JSWCNGXJ.js} +1 -1
  202. package/static/chunk-KFJIQIGR.js +1 -0
  203. package/static/chunk-LNTUR3GU.js +1 -0
  204. package/static/chunk-LVM4QB22.js +1 -0
  205. package/static/chunk-M3XVNQZQ.js +1 -0
  206. package/static/{chunk-AWQ2YTVC.js → chunk-MFLIJH6T.js} +1 -1
  207. package/static/{chunk-IQOALFYU.js → chunk-MSUHTBB2.js} +1 -1
  208. package/static/chunk-N3U6637P.js +1 -0
  209. package/static/chunk-NNV4OXSB.js +1 -0
  210. package/static/chunk-NO2LTNW3.js +1 -0
  211. package/static/chunk-OOGP4WSH.js +2 -0
  212. package/static/chunk-PB4AIT7O.js +1 -0
  213. package/static/chunk-PCWDQPOM.js +2 -0
  214. package/static/chunk-PGZZP5W3.js +1 -0
  215. package/static/chunk-PVDHBQRM.js +1 -0
  216. package/static/chunk-Q5KM7LTX.js +1 -0
  217. package/static/chunk-QHC6ZPQ4.js +1 -0
  218. package/static/chunk-QO6BTONN.js +1 -0
  219. package/static/chunk-QZU2S5CV.js +1 -0
  220. package/static/chunk-SBZ572Q4.js +2 -0
  221. package/static/chunk-SHIVUDP3.js +1 -0
  222. package/static/chunk-SLHTEGRU.js +1 -0
  223. package/static/{chunk-SH5EVL4E.js → chunk-SSFF27P2.js} +1 -1
  224. package/static/chunk-TPYBFZS5.js +1 -0
  225. package/static/chunk-UEQCWMXD.js +1 -0
  226. package/static/chunk-UG5DMXYO.js +1 -0
  227. package/static/chunk-UJPPR4MX.js +1 -0
  228. package/static/chunk-UNCPXHHT.js +1 -0
  229. package/static/chunk-URHTCJ7G.js +1 -0
  230. package/static/chunk-V3AT2BKP.js +1 -0
  231. package/static/chunk-VKK5BSLX.js +1 -0
  232. package/static/{chunk-7DN7ZAPU.js → chunk-VM4YX6Q7.js} +1 -1
  233. package/static/chunk-WJW7CT6G.js +27 -0
  234. package/static/{chunk-7ITZXYYJ.js → chunk-WLMNXRBS.js} +1 -1
  235. package/static/chunk-X5XGK6T7.js +4 -0
  236. package/static/chunk-YEKR5OPO.js +1 -0
  237. package/static/chunk-YW57T2PF.js +1 -0
  238. package/static/chunk-Z5J5F5SX.js +1 -0
  239. package/static/chunk-ZIJQRARU.js +1 -0
  240. package/static/chunk-ZPF2DSQV.js +1 -0
  241. package/static/chunk-ZTCRGJ6Y.js +7 -0
  242. package/static/index.html +2 -2
  243. package/static/main-VOL6OMJ5.js +9 -0
  244. package/static/scripts-WRDOQIU5.js +24 -0
  245. package/static/{styles-A5VYX3CE.css → styles-2C2UNCNB.css} +1 -1
  246. package/server/applications/spaces/interfaces/space-quota.interface.js +0 -10
  247. package/server/applications/spaces/interfaces/space-quota.interface.js.map +0 -1
  248. package/static/chunk-22EANI6R.js +0 -1
  249. package/static/chunk-27YQB3TE.js +0 -1
  250. package/static/chunk-2I4CUFUA.js +0 -1
  251. package/static/chunk-2MTM6SWN.js +0 -4
  252. package/static/chunk-34MKICK5.js +0 -27
  253. package/static/chunk-5O3DIUU3.js +0 -1
  254. package/static/chunk-6NMVZIIT.js +0 -1
  255. package/static/chunk-7FUM3JGM.js +0 -1
  256. package/static/chunk-7P27WBGC.js +0 -4
  257. package/static/chunk-ATP3BFHV.js +0 -562
  258. package/static/chunk-DSOE3FEP.js +0 -1
  259. package/static/chunk-EFKMBLRE.js +0 -1
  260. package/static/chunk-FUFKVHPU.js +0 -1
  261. package/static/chunk-HCDLWTMW.js +0 -7
  262. package/static/chunk-JASU3CIH.js +0 -1
  263. package/static/chunk-JQ5FTO2M.js +0 -1
  264. package/static/chunk-JUNZFADM.js +0 -1
  265. package/static/chunk-JXZCNFW7.js +0 -1
  266. package/static/chunk-LJUKI4SQ.js +0 -1
  267. package/static/chunk-ORMRCEGT.js +0 -1
  268. package/static/chunk-Q7D6RN4N.js +0 -1
  269. package/static/chunk-QJX6ITLW.js +0 -1
  270. package/static/chunk-QQ6UQQBR.js +0 -1
  271. package/static/chunk-RTRJ3KFH.js +0 -1
  272. package/static/chunk-S2HDY3OL.js +0 -1
  273. package/static/chunk-T3EYFSVZ.js +0 -1
  274. package/static/chunk-U34OZUZ7.js +0 -1
  275. package/static/chunk-Y7EH7G5K.js +0 -1
  276. package/static/main-7SQDDVMD.js +0 -9
  277. package/static/scripts-VZVAP2P4.js +0 -30
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-parser.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { and, eq, inArray, isNotNull, isNull, lte, or, sql } from 'drizzle-orm'\nimport path from 'node:path'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { concatDistinctObjectsInArray } from '../../../infrastructure/database/utils'\nimport { SHARE_TYPE } from '../../shares/constants/shares'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SPACE_ALIAS, SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceModel } from '../../spaces/models/space.model'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { FileParseContext, FileParseType } from '../interfaces/file-parse-index'\nimport { filePathSQL, files } from '../schemas/files.schema'\nimport { isPathExists } from '../utils/files'\n\n@Injectable()\nexport class FilesParser {\n private readonly logger = new Logger(FilesParser.name)\n\n constructor(@Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema) {}\n\n async *allPaths(userId?: number, spaceIds?: number[], shareIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n yield* this.userPaths(userId)\n yield* this.spacePaths(spaceIds)\n yield* this.sharePaths(shareIds)\n }\n\n async *userPaths(userId?: number): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login\n })\n .from(users)\n .where(and(...[lte(users.role, USER_ROLE.USER), ...(userId ? [eq(users.id, userId)] : [])]))) {\n const userFilesPath = UserModel.getFilesPath(user.login)\n if (!(await isPathExists(userFilesPath))) {\n this.logger.warn(`${this.userPaths.name} - user path does not exist : ${userFilesPath}`)\n continue\n }\n yield [user.id, 'user', [{ realPath: userFilesPath, pathPrefix: `${SPACE_REPOSITORY.FILES}/${SPACE_ALIAS.PERSONAL}`, isDir: true }]]\n }\n }\n\n async *spacePaths(spaceIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const space of await this.db\n .select({\n id: spaces.id,\n alias: spaces.alias,\n roots: concatDistinctObjectsInArray(spacesRoots.alias, {\n alias: spacesRoots.alias,\n externalPath: spacesRoots.externalPath,\n isDir: sql<boolean>`IF (${spacesRoots.externalPath} IS NOT NULL, 1, ${files.isDir})`,\n file: {\n path: filePathSQL(files),\n fromOwner: users.login\n }\n })\n })\n .from(spaces)\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(files, eq(files.id, spacesRoots.fileId))\n .leftJoin(users, eq(users.id, files.ownerId))\n .where(and(...(spaceIds ? [inArray(spaces.id, spaceIds)] : [])))\n .groupBy(spaces.id)) {\n const spaceFilesPath = SpaceModel.getFilesPath(space.alias)\n if (!(await isPathExists(spaceFilesPath))) {\n this.logger.warn(`${this.spacePaths.name} - space path does not exist : ${spaceFilesPath}`)\n continue\n }\n const spacePath = [{ realPath: spaceFilesPath, pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}`, isDir: true }]\n const rootPaths = space.roots.map(\n (r: any): FileParseContext =>\n r.externalPath\n ? {\n realPath: r.externalPath,\n pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}/${r.alias}`,\n isDir: r.isDir\n }\n : {\n realPath: path.join(UserModel.getFilesPath(r.file.fromOwner), r.file.path),\n pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}/${r.alias}`,\n isDir: r.isDir\n }\n )\n yield [space.id, 'space', [...spacePath, ...rootPaths]]\n }\n }\n\n async *sharePaths(shareIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const share of await this.db\n .select({\n id: shares.id,\n alias: shares.alias,\n externalPath: sql<string>`IF (${shares.externalPath} IS NOT NULL, ${shares.externalPath}, ${spacesRoots.externalPath})`,\n isDir: sql<boolean>`IF (${shares.externalPath} IS NOT NULL, 1, ${files.isDir})`,\n file: { path: sql<string>`IF (${files.id} IS NOT NULL, ${filePathSQL(files)}, '.')`, fromOwner: users.login, fromSpace: spaces.alias }\n })\n .from(shares)\n .leftJoin(spacesRoots, eq(spacesRoots.id, shares.spaceRootId))\n .leftJoin(\n files,\n or(\n // if the child share is from a share with an external path, the child share should have an external path and a fileId\n and(isNotNull(shares.fileId), eq(files.id, shares.fileId)),\n and(isNull(shares.externalPath), isNull(shares.fileId), isNotNull(spacesRoots.fileId), eq(files.id, spacesRoots.fileId))\n )\n )\n .leftJoin(spaces, and(isNull(shares.externalPath), isNotNull(files.spaceId), eq(spaces.id, files.spaceId)))\n .leftJoin(users, eq(users.id, files.ownerId))\n .where(and(...[eq(shares.type, SHARE_TYPE.COMMON), ...(shareIds ? [inArray(shares.id, shareIds)] : [])]))\n .groupBy(shares.id)) {\n let shareFilesPath: string\n if (share.externalPath) {\n shareFilesPath = path.join(share.externalPath, share.file.path)\n } else if (share.file.fromOwner) {\n shareFilesPath = path.join(UserModel.getFilesPath(share.file.fromOwner), share.file.path)\n } else if (share.file.fromSpace) {\n shareFilesPath = path.join(SpaceModel.getFilesPath(share.file.fromSpace), share.file.path)\n }\n if (!(await isPathExists(shareFilesPath))) {\n this.logger.warn(`${this.sharePaths.name} - share path does not exist : ${shareFilesPath}`)\n continue\n }\n yield [share.id, 'share', [{ realPath: shareFilesPath, pathPrefix: `${SPACE_REPOSITORY.SHARES}/${share.alias}`, isDir: share.isDir }]]\n }\n }\n}\n"],"names":["FilesParser","allPaths","userId","spaceIds","shareIds","userPaths","spacePaths","sharePaths","user","db","select","id","users","login","from","where","and","lte","role","USER_ROLE","USER","eq","userFilesPath","UserModel","getFilesPath","isPathExists","logger","warn","name","realPath","pathPrefix","SPACE_REPOSITORY","FILES","SPACE_ALIAS","PERSONAL","isDir","space","spaces","alias","roots","concatDistinctObjectsInArray","spacesRoots","externalPath","sql","files","file","path","filePathSQL","fromOwner","leftJoin","spaceId","fileId","ownerId","inArray","groupBy","spaceFilesPath","SpaceModel","spacePath","rootPaths","map","r","join","share","shares","fromSpace","spaceRootId","or","isNotNull","isNull","type","SHARE_TYPE","COMMON","shareFilesPath","SHARES","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-parser.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { and, eq, inArray, isNotNull, isNull, lte, or, sql } from 'drizzle-orm'\nimport path from 'node:path'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { concatDistinctObjectsInArray } from '../../../infrastructure/database/utils'\nimport { SHARE_TYPE } from '../../shares/constants/shares'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SPACE_ALIAS, SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceModel } from '../../spaces/models/space.model'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { FileParseContext, FileParseType } from '../interfaces/file-parse-index'\nimport { filePathSQL, files } from '../schemas/files.schema'\nimport { isPathExists } from '../utils/files'\n\n@Injectable()\nexport class FilesParser {\n private readonly logger = new Logger(FilesParser.name)\n\n constructor(@Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema) {}\n\n async *allPaths(userId?: number, spaceIds?: number[], shareIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n yield* this.userPaths(userId)\n yield* this.spacePaths(spaceIds)\n yield* this.sharePaths(shareIds)\n }\n\n async *userPaths(userId?: number): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login\n })\n .from(users)\n .where(and(...[eq(users.storageIndexing, true), lte(users.role, USER_ROLE.USER), ...(userId ? [eq(users.id, userId)] : [])]))) {\n const userFilesPath = UserModel.getFilesPath(user.login)\n if (!(await isPathExists(userFilesPath))) {\n this.logger.warn(`${this.userPaths.name} - user path does not exist : ${userFilesPath}`)\n continue\n }\n yield [user.id, 'user', [{ realPath: userFilesPath, pathPrefix: `${SPACE_REPOSITORY.FILES}/${SPACE_ALIAS.PERSONAL}`, isDir: true }]]\n }\n }\n\n async *spacePaths(spaceIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const space of await this.db\n .select({\n id: spaces.id,\n alias: spaces.alias,\n roots: concatDistinctObjectsInArray(spacesRoots.alias, {\n alias: spacesRoots.alias,\n externalPath: spacesRoots.externalPath,\n isDir: sql<boolean>`IF (${spacesRoots.externalPath} IS NOT NULL, 1, ${files.isDir})`,\n file: {\n path: filePathSQL(files),\n fromOwner: users.login\n }\n })\n })\n .from(spaces)\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(files, eq(files.id, spacesRoots.fileId))\n .leftJoin(users, eq(users.id, files.ownerId))\n .where(and(eq(spaces.storageIndexing, true), ...(spaceIds ? [inArray(spaces.id, spaceIds)] : [])))\n .groupBy(spaces.id)) {\n const spaceFilesPath = SpaceModel.getFilesPath(space.alias)\n if (!(await isPathExists(spaceFilesPath))) {\n this.logger.warn(`${this.spacePaths.name} - space path does not exist : ${spaceFilesPath}`)\n continue\n }\n const spacePath = [{ realPath: spaceFilesPath, pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}`, isDir: true }]\n const rootPaths = space.roots.map(\n (r: any): FileParseContext =>\n r.externalPath\n ? {\n realPath: r.externalPath,\n pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}/${r.alias}`,\n isDir: r.isDir\n }\n : {\n realPath: path.join(UserModel.getFilesPath(r.file.fromOwner), r.file.path),\n pathPrefix: `${SPACE_REPOSITORY.FILES}/${space.alias}/${r.alias}`,\n isDir: r.isDir\n }\n )\n yield [space.id, 'space', [...spacePath, ...rootPaths]]\n }\n }\n\n async *sharePaths(shareIds?: number[]): AsyncGenerator<[number, FileParseType, FileParseContext[]]> {\n for (const share of await this.db\n .select({\n id: shares.id,\n alias: shares.alias,\n externalPath: sql<string>`IF (${shares.externalPath} IS NOT NULL, ${shares.externalPath}, ${spacesRoots.externalPath})`,\n isDir: sql<boolean>`IF (${shares.externalPath} IS NOT NULL, 1, ${files.isDir})`,\n file: { path: sql<string>`IF (${files.id} IS NOT NULL, ${filePathSQL(files)}, '.')`, fromOwner: users.login, fromSpace: spaces.alias }\n })\n .from(shares)\n .leftJoin(spacesRoots, eq(spacesRoots.id, shares.spaceRootId))\n .leftJoin(\n files,\n or(\n // If the child share is from a share with an external path, the child share should have an external path and a fileId\n and(isNotNull(shares.fileId), eq(files.id, shares.fileId)),\n and(isNull(shares.externalPath), isNull(shares.fileId), isNotNull(spacesRoots.fileId), eq(files.id, spacesRoots.fileId))\n )\n )\n .leftJoin(spaces, and(isNull(shares.externalPath), isNotNull(files.spaceId), eq(spaces.id, files.spaceId), eq(spaces.storageIndexing, true)))\n .leftJoin(users, and(eq(users.id, files.ownerId), eq(users.storageIndexing, true)))\n .where(and(eq(shares.storageIndexing, true), ...[eq(shares.type, SHARE_TYPE.COMMON), ...(shareIds ? [inArray(shares.id, shareIds)] : [])]))\n .groupBy(shares.id)) {\n let shareFilesPath: string\n if (share.externalPath) {\n shareFilesPath = path.join(share.externalPath, share.file.path)\n } else if (share.file.fromOwner) {\n shareFilesPath = path.join(UserModel.getFilesPath(share.file.fromOwner), share.file.path)\n } else if (share.file.fromSpace) {\n shareFilesPath = path.join(SpaceModel.getFilesPath(share.file.fromSpace), share.file.path)\n } else {\n // Exclude shares that don’t match these cases (join conditions)\n continue\n }\n if (!(await isPathExists(shareFilesPath))) {\n this.logger.warn(`${this.sharePaths.name} - share path does not exist : ${shareFilesPath}`)\n continue\n }\n yield [share.id, 'share', [{ realPath: shareFilesPath, pathPrefix: `${SPACE_REPOSITORY.SHARES}/${share.alias}`, isDir: share.isDir }]]\n }\n }\n}\n"],"names":["FilesParser","allPaths","userId","spaceIds","shareIds","userPaths","spacePaths","sharePaths","user","db","select","id","users","login","from","where","and","eq","storageIndexing","lte","role","USER_ROLE","USER","userFilesPath","UserModel","getFilesPath","isPathExists","logger","warn","name","realPath","pathPrefix","SPACE_REPOSITORY","FILES","SPACE_ALIAS","PERSONAL","isDir","space","spaces","alias","roots","concatDistinctObjectsInArray","spacesRoots","externalPath","sql","files","file","path","filePathSQL","fromOwner","leftJoin","spaceId","fileId","ownerId","inArray","groupBy","spaceFilesPath","SpaceModel","spacePath","rootPaths","map","r","join","share","shares","fromSpace","spaceRootId","or","isNotNull","isNull","type","SHARE_TYPE","COMMON","shareFilesPath","SHARES","Logger"],"mappings":"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"}
@@ -15,17 +15,21 @@ Object.defineProperty(exports, "FilesScheduler", {
15
15
  const _common = require("@nestjs/common");
16
16
  const _schedule = require("@nestjs/schedule");
17
17
  const _drizzleorm = require("drizzle-orm");
18
+ const _mysqlcore = require("drizzle-orm/mysql-core");
18
19
  const _promises = /*#__PURE__*/ _interop_require_default(require("node:fs/promises"));
19
20
  const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
21
+ const _configenvironment = require("../../../configuration/config.environment");
20
22
  const _cacheservice = require("../../../infrastructure/cache/services/cache.service");
21
23
  const _constants = require("../../../infrastructure/database/constants");
22
24
  const _databaseinterface = require("../../../infrastructure/database/interfaces/database.interface");
25
+ const _utils = require("../../../infrastructure/database/utils");
23
26
  const _user = require("../../users/constants/user");
24
27
  const _usermodel = require("../../users/models/user.model");
25
28
  const _usersschema = require("../../users/schemas/users.schema");
26
29
  const _cache = require("../constants/cache");
27
30
  const _filetask = require("../models/file-task");
28
31
  const _filesrecentsschema = require("../schemas/files-recents.schema");
32
+ const _filesschema = require("../schemas/files.schema");
29
33
  const _files = require("../utils/files");
30
34
  const _filescontentmanagerservice = require("./files-content-manager.service");
31
35
  const _filestasksmanagerservice = require("./files-tasks-manager.service");
@@ -78,7 +82,6 @@ let FilesScheduler = class FilesScheduler {
78
82
  }).from(_usersschema.users))){
79
83
  const userTasksPath = _usermodel.UserModel.getTasksPath(user.login, user.role === _user.USER_ROLE.GUEST, user.role === _user.USER_ROLE.LINK);
80
84
  if (!await (0, _files.isPathExists)(userTasksPath)) {
81
- this.logger.verbose(`${this.cleanupUserTaskFiles.name} - *${user.login}* tasks path does not exist`);
82
85
  continue;
83
86
  }
84
87
  if (await (0, _files.dirHasChildren)(userTasksPath, false)) {
@@ -128,10 +131,49 @@ let FilesScheduler = class FilesScheduler {
128
131
  this.logger.log(`${this.clearRecentFiles.name} - ${nbCleared} records cleared - END`);
129
132
  }
130
133
  async indexContentFiles() {
134
+ // Conditional loading of file content indexing
135
+ if (!_configenvironment.configuration.applications.files.contentIndexing) return;
131
136
  this.logger.log(`${this.indexContentFiles.name} - START`);
132
137
  await this.filesContentManager.parseAndIndexAllFiles();
133
138
  this.logger.log(`${this.indexContentFiles.name} - END`);
134
139
  }
140
+ async deleteOrphanFiles() {
141
+ this.logger.log(`${this.deleteOrphanFiles.name} - START`);
142
+ const selects = [];
143
+ for (const table of (0, _utils.getTablesWithFileIdColumn)()){
144
+ selects.push(this.db.selectDistinct({
145
+ id: table.fileId
146
+ }).from(table).where((0, _drizzleorm.isNotNull)(table.fileId)));
147
+ }
148
+ if (selects.length === 0) {
149
+ this.logger.warn(`${this.deleteOrphanFiles.name} - no tables with fileId column`);
150
+ return;
151
+ }
152
+ const unionSub = (selects.length === 1 ? selects[0] : (0, _mysqlcore.unionAll)(...selects)).as('u');
153
+ // Debug
154
+ // const [preview] = (await this.db.execute(sql`
155
+ // SELECT f.id
156
+ // FROM ${files} AS f
157
+ // LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id
158
+ // WHERE ${unionSub.id} IS NULL
159
+ // `)) as any[]
160
+ // console.log(preview.length, preview)
161
+ const deleteQuery = (0, _drizzleorm.sql)`
162
+ DELETE f
163
+ FROM ${_filesschema.files} AS f
164
+ LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id
165
+ WHERE ${unionSub.id} IS NULL
166
+ `;
167
+ try {
168
+ await this.db.transaction(async (tx)=>{
169
+ const [r] = await tx.execute(deleteQuery);
170
+ this.logger.log(`${this.deleteOrphanFiles.name} - files: ${r.affectedRows}`);
171
+ });
172
+ } catch (e) {
173
+ this.logger.log(`${this.deleteOrphanFiles.name} - ${e}`);
174
+ }
175
+ this.logger.log(`${this.deleteOrphanFiles.name} - END`);
176
+ }
135
177
  constructor(db, cache, filesContentManager){
136
178
  this.db = db;
137
179
  this.cache = cache;
@@ -153,18 +195,24 @@ _ts_decorate([
153
195
  ], FilesScheduler.prototype, "cleanupUserTaskFiles", null);
154
196
  _ts_decorate([
155
197
  (0, _schedule.Timeout)(30000),
156
- (0, _schedule.Cron)(_schedule.CronExpression.EVERY_DAY_AT_MIDNIGHT),
198
+ (0, _schedule.Cron)(_schedule.CronExpression.EVERY_8_HOURS),
157
199
  _ts_metadata("design:type", Function),
158
200
  _ts_metadata("design:paramtypes", []),
159
201
  _ts_metadata("design:returntype", Promise)
160
202
  ], FilesScheduler.prototype, "clearRecentFiles", null);
161
203
  _ts_decorate([
162
- (0, _schedule.Timeout)(60000),
204
+ (0, _schedule.Timeout)(120000),
163
205
  (0, _schedule.Cron)(_schedule.CronExpression.EVERY_4_HOURS),
164
206
  _ts_metadata("design:type", Function),
165
207
  _ts_metadata("design:paramtypes", []),
166
208
  _ts_metadata("design:returntype", Promise)
167
209
  ], FilesScheduler.prototype, "indexContentFiles", null);
210
+ _ts_decorate([
211
+ (0, _schedule.Cron)(_schedule.CronExpression.EVERY_DAY_AT_4AM),
212
+ _ts_metadata("design:type", Function),
213
+ _ts_metadata("design:paramtypes", []),
214
+ _ts_metadata("design:returntype", Promise)
215
+ ], FilesScheduler.prototype, "deleteOrphanFiles", null);
168
216
  FilesScheduler = _ts_decorate([
169
217
  (0, _common.Injectable)(),
170
218
  _ts_param(0, (0, _common.Inject)(_constants.DB_TOKEN_PROVIDER)),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-scheduler.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { sql } from 'drizzle-orm'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { CACHE_TASK_PREFIX } from '../constants/cache'\nimport { FileTask, FileTaskStatus } from '../models/file-task'\nimport { filesRecents } from '../schemas/files-recents.schema'\nimport { dirHasChildren, isPathExists, removeFiles } from '../utils/files'\nimport { FilesContentManager } from './files-content-manager.service'\nimport { FilesTasksManager } from './files-tasks-manager.service'\n\n@Injectable()\nexport class FilesScheduler {\n private readonly logger = new Logger(FilesScheduler.name)\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache,\n private readonly filesContentManager: FilesContentManager\n ) {}\n\n @Timeout(30000)\n async cleanupInterruptedTasks(): Promise<void> {\n this.logger.log(`${this.cleanupInterruptedTasks.name} - START`)\n try {\n let nb = 0\n const keys = await this.cache.keys(`${CACHE_TASK_PREFIX}-*`)\n for (const key of keys) {\n const task = await this.cache.get(key)\n if (task && task.status === FileTaskStatus.PENDING) {\n task.status = FileTaskStatus.ERROR\n task.result = 'Interrupted'\n nb++\n this.cache.set(key, task).catch((e: Error) => this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`))\n }\n }\n this.logger.log(`${this.cleanupInterruptedTasks.name} - ${nb} tasks cleaned : END`)\n } catch (e) {\n this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`)\n }\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)\n async cleanupUserTaskFiles(): Promise<void> {\n this.logger.log(`${this.cleanupUserTaskFiles.name} - START`)\n try {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login,\n role: users.role\n })\n .from(users)) {\n const userTasksPath = UserModel.getTasksPath(user.login, user.role === USER_ROLE.GUEST, user.role === USER_ROLE.LINK)\n if (!(await isPathExists(userTasksPath))) {\n this.logger.verbose(`${this.cleanupUserTaskFiles.name} - *${user.login}* tasks path does not exist`)\n continue\n }\n if (await dirHasChildren(userTasksPath, false)) {\n const cacheKey = FilesTasksManager.getCacheKey(user.id)\n const keys = await this.cache.keys(cacheKey)\n const excludeFiles = (await this.cache.mget(keys))\n .filter((task: FileTask) => task && task.status === FileTaskStatus.PENDING && task.props.compressInDirectory === false)\n .map((task: FileTask) => task.name)\n for (const f of (await fs.readdir(userTasksPath)).filter((f: string) => excludeFiles.indexOf(f) === -1)) {\n try {\n removeFiles(path.join(userTasksPath, f)).catch((e: Error) => this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - unable to remove ${path.join(userTasksPath, f)} : ${e}`)\n }\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`)\n }\n this.logger.log(`${this.cleanupUserTaskFiles.name} - END`)\n }\n\n @Timeout(30000)\n @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)\n async clearRecentFiles(): Promise<void> {\n this.logger.log(`${this.clearRecentFiles.name} - START`)\n const keepNumber = 100\n let nbCleared = 0\n try {\n for (const fk of [filesRecents.ownerId, filesRecents.spaceId, filesRecents.shareId]) {\n const [r] = await this.db.execute(sql`\n DELETE\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL\n AND id NOT IN (SELECT id\n FROM (SELECT id,\n ROW_NUMBER() OVER (PARTITION BY ${fk} ORDER BY ${filesRecents.mtime}) AS rn\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL) AS ranked\n WHERE ranked.rn <= ${keepNumber})\n `)\n nbCleared += r.affectedRows\n }\n } catch (e) {\n this.logger.error(`${this.clearRecentFiles.name} - ${e}`)\n }\n this.logger.log(`${this.clearRecentFiles.name} - ${nbCleared} records cleared - END`)\n }\n\n @Timeout(60000)\n @Cron(CronExpression.EVERY_4_HOURS)\n async indexContentFiles(): Promise<void> {\n this.logger.log(`${this.indexContentFiles.name} - START`)\n await this.filesContentManager.parseAndIndexAllFiles()\n this.logger.log(`${this.indexContentFiles.name} - END`)\n }\n}\n"],"names":["FilesScheduler","cleanupInterruptedTasks","logger","log","name","nb","keys","cache","CACHE_TASK_PREFIX","key","task","get","status","FileTaskStatus","PENDING","ERROR","result","set","catch","e","error","cleanupUserTaskFiles","user","db","select","id","users","login","role","from","userTasksPath","UserModel","getTasksPath","USER_ROLE","GUEST","LINK","isPathExists","verbose","dirHasChildren","cacheKey","FilesTasksManager","getCacheKey","excludeFiles","mget","filter","props","compressInDirectory","map","f","fs","readdir","indexOf","removeFiles","path","join","clearRecentFiles","keepNumber","nbCleared","fk","filesRecents","ownerId","spaceId","shareId","r","execute","sql","mtime","affectedRows","indexContentFiles","filesContentManager","parseAndIndexAllFiles","Logger","EVERY_DAY_AT_MIDNIGHT","EVERY_4_HOURS"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-scheduler.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { isNotNull, sql } from 'drizzle-orm'\nimport { unionAll } from 'drizzle-orm/mysql-core'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { getTablesWithFileIdColumn } from '../../../infrastructure/database/utils'\nimport { USER_ROLE } from '../../users/constants/user'\nimport { UserModel } from '../../users/models/user.model'\nimport { users } from '../../users/schemas/users.schema'\nimport { CACHE_TASK_PREFIX } from '../constants/cache'\nimport { FileTask, FileTaskStatus } from '../models/file-task'\nimport { filesRecents } from '../schemas/files-recents.schema'\nimport { files } from '../schemas/files.schema'\nimport { dirHasChildren, isPathExists, removeFiles } from '../utils/files'\nimport { FilesContentManager } from './files-content-manager.service'\nimport { FilesTasksManager } from './files-tasks-manager.service'\n\n@Injectable()\nexport class FilesScheduler {\n private readonly logger = new Logger(FilesScheduler.name)\n\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly cache: Cache,\n private readonly filesContentManager: FilesContentManager\n ) {}\n\n @Timeout(30000)\n async cleanupInterruptedTasks(): Promise<void> {\n this.logger.log(`${this.cleanupInterruptedTasks.name} - START`)\n try {\n let nb = 0\n const keys = await this.cache.keys(`${CACHE_TASK_PREFIX}-*`)\n for (const key of keys) {\n const task = await this.cache.get(key)\n if (task && task.status === FileTaskStatus.PENDING) {\n task.status = FileTaskStatus.ERROR\n task.result = 'Interrupted'\n nb++\n this.cache.set(key, task).catch((e: Error) => this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`))\n }\n }\n this.logger.log(`${this.cleanupInterruptedTasks.name} - ${nb} tasks cleaned : END`)\n } catch (e) {\n this.logger.error(`${this.cleanupInterruptedTasks.name} - ${e}`)\n }\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)\n async cleanupUserTaskFiles(): Promise<void> {\n this.logger.log(`${this.cleanupUserTaskFiles.name} - START`)\n try {\n for (const user of await this.db\n .select({\n id: users.id,\n login: users.login,\n role: users.role\n })\n .from(users)) {\n const userTasksPath = UserModel.getTasksPath(user.login, user.role === USER_ROLE.GUEST, user.role === USER_ROLE.LINK)\n if (!(await isPathExists(userTasksPath))) {\n continue\n }\n if (await dirHasChildren(userTasksPath, false)) {\n const cacheKey = FilesTasksManager.getCacheKey(user.id)\n const keys = await this.cache.keys(cacheKey)\n const excludeFiles = (await this.cache.mget(keys))\n .filter((task: FileTask) => task && task.status === FileTaskStatus.PENDING && task.props.compressInDirectory === false)\n .map((task: FileTask) => task.name)\n for (const f of (await fs.readdir(userTasksPath)).filter((f: string) => excludeFiles.indexOf(f) === -1)) {\n try {\n removeFiles(path.join(userTasksPath, f)).catch((e: Error) => this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - unable to remove ${path.join(userTasksPath, f)} : ${e}`)\n }\n }\n }\n }\n } catch (e) {\n this.logger.error(`${this.cleanupUserTaskFiles.name} - ${e}`)\n }\n this.logger.log(`${this.cleanupUserTaskFiles.name} - END`)\n }\n\n @Timeout(30000)\n @Cron(CronExpression.EVERY_8_HOURS)\n async clearRecentFiles(): Promise<void> {\n this.logger.log(`${this.clearRecentFiles.name} - START`)\n const keepNumber = 100\n let nbCleared = 0\n try {\n for (const fk of [filesRecents.ownerId, filesRecents.spaceId, filesRecents.shareId]) {\n const [r] = await this.db.execute(sql`\n DELETE\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL\n AND id NOT IN (SELECT id\n FROM (SELECT id,\n ROW_NUMBER() OVER (PARTITION BY ${fk} ORDER BY ${filesRecents.mtime}) AS rn\n FROM ${filesRecents}\n WHERE ${fk} IS NOT NULL) AS ranked\n WHERE ranked.rn <= ${keepNumber})\n `)\n nbCleared += r.affectedRows\n }\n } catch (e) {\n this.logger.error(`${this.clearRecentFiles.name} - ${e}`)\n }\n this.logger.log(`${this.clearRecentFiles.name} - ${nbCleared} records cleared - END`)\n }\n\n @Timeout(120000)\n @Cron(CronExpression.EVERY_4_HOURS)\n async indexContentFiles(): Promise<void> {\n // Conditional loading of file content indexing\n if (!configuration.applications.files.contentIndexing) return\n this.logger.log(`${this.indexContentFiles.name} - START`)\n await this.filesContentManager.parseAndIndexAllFiles()\n this.logger.log(`${this.indexContentFiles.name} - END`)\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_4AM)\n async deleteOrphanFiles() {\n this.logger.log(`${this.deleteOrphanFiles.name} - START`)\n const selects: any[] = []\n for (const table of getTablesWithFileIdColumn()) {\n selects.push(this.db.selectDistinct({ id: table.fileId }).from(table).where(isNotNull(table.fileId)))\n }\n if (selects.length === 0) {\n this.logger.warn(`${this.deleteOrphanFiles.name} - no tables with fileId column`)\n return\n }\n const unionSub = (selects.length === 1 ? selects[0] : unionAll(...(selects as [any, any, ...any[]]))).as('u')\n // Debug\n // const [preview] = (await this.db.execute(sql`\n // SELECT f.id\n // FROM ${files} AS f\n // LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n // WHERE ${unionSub.id} IS NULL\n // `)) as any[]\n // console.log(preview.length, preview)\n const deleteQuery = sql`\n DELETE f\n FROM ${files} AS f\n LEFT JOIN ${unionSub} ON ${unionSub.id} = f.id\n WHERE ${unionSub.id} IS NULL\n `\n try {\n await this.db.transaction(async (tx) => {\n const [r] = await tx.execute(deleteQuery)\n this.logger.log(`${this.deleteOrphanFiles.name} - files: ${r.affectedRows}`)\n })\n } catch (e) {\n this.logger.log(`${this.deleteOrphanFiles.name} - ${e}`)\n }\n this.logger.log(`${this.deleteOrphanFiles.name} - END`)\n }\n}\n"],"names":["FilesScheduler","cleanupInterruptedTasks","logger","log","name","nb","keys","cache","CACHE_TASK_PREFIX","key","task","get","status","FileTaskStatus","PENDING","ERROR","result","set","catch","e","error","cleanupUserTaskFiles","user","db","select","id","users","login","role","from","userTasksPath","UserModel","getTasksPath","USER_ROLE","GUEST","LINK","isPathExists","dirHasChildren","cacheKey","FilesTasksManager","getCacheKey","excludeFiles","mget","filter","props","compressInDirectory","map","f","fs","readdir","indexOf","removeFiles","path","join","clearRecentFiles","keepNumber","nbCleared","fk","filesRecents","ownerId","spaceId","shareId","r","execute","sql","mtime","affectedRows","indexContentFiles","configuration","applications","files","contentIndexing","filesContentManager","parseAndIndexAllFiles","deleteOrphanFiles","selects","table","getTablesWithFileIdColumn","push","selectDistinct","fileId","where","isNotNull","length","warn","unionSub","unionAll","as","deleteQuery","transaction","tx","Logger","EVERY_DAY_AT_MIDNIGHT","EVERY_8_HOURS","EVERY_4_HOURS","EVERY_DAY_AT_4AM"],"mappings":"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"}
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "FilesSearchManager", {
15
15
  const _common = require("@nestjs/common");
16
16
  const _promises = /*#__PURE__*/ _interop_require_default(require("node:fs/promises"));
17
17
  const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
18
+ const _configenvironment = require("../../../configuration/config.environment");
18
19
  const _sharesqueriesservice = require("../../shares/services/shares-queries.service");
19
20
  const _spacesqueriesservice = require("../../spaces/services/spaces-queries.service");
20
21
  const _indexing = require("../constants/indexing");
@@ -43,6 +44,9 @@ let FilesSearchManager = class FilesSearchManager {
43
44
  this.sharesQueries.shareIds(user.id, +user.isAdmin)
44
45
  ]);
45
46
  if (search.fullText) {
47
+ if (!_configenvironment.configuration.applications.files.contentIndexing) {
48
+ throw new _common.HttpException('Full-text search is disabled', _common.HttpStatus.BAD_REQUEST);
49
+ }
46
50
  return await this.searchFullText(user.id, spaceIds, shareIds, search.content, search.limit);
47
51
  } else {
48
52
  return await this.searchFileNames(user.id, spaceIds, shareIds, search.content, search.limit);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-search-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 { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { SearchFilesDto } from '../dto/file-operations.dto'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { dirName, fileName, getMimeType } from '../utils/files'\nimport { genRegexPositiveAndNegativeTerms } from '../utils/files-search'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesSearchManager {\n private readonly logger = new Logger(FilesSearchManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n async search(user: UserModel, search: SearchFilesDto): Promise<FileContent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n if (search.fullText) {\n return await this.searchFullText(user.id, spaceIds, shareIds, search.content, search.limit)\n } else {\n return await this.searchFileNames(user.id, spaceIds, shareIds, search.content, search.limit)\n }\n }\n\n private async searchFullText(userId: number, spaceIds: number[], shareIds: number[], search: string, limit: number): Promise<FileContent[]> {\n const indexNames = await this.filesIndexer.existingIndexes([\n `${userIndexPrefix}${userId}`,\n ...spaceIds.map((id) => `${spaceIndexPrefix}${id}`),\n ...shareIds.map((id) => `${shareIndexPrefix}${id}`)\n ])\n if (indexNames.length === 0) {\n return []\n }\n try {\n return await this.filesIndexer.searchRecords(indexNames, search, limit)\n } catch (e) {\n this.logger.error(`${this.searchFullText.name} - ${JSON.stringify(indexNames)} - ${search} : ${e}`)\n let msg: string\n if (/Invalid regular expression/.test(e.message)) {\n msg = 'SyntaxError (check special characters)'\n } else {\n msg = e.message\n }\n throw new HttpException(msg, HttpStatus.BAD_REQUEST)\n }\n }\n\n private async searchFileNames(userId: number, spaceIds: number[], shareIds: number[], search: string, limit: number): Promise<FileContent[]> {\n const fileContents: FileContent[] = []\n const regexpTerms = genRegexPositiveAndNegativeTerms(search)\n for await (const [_id, _type, paths] of this.filesParser.allPaths(userId, spaceIds, shareIds)) {\n for (const p of paths) {\n const regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n if (!p.isDir) {\n const f = await this.analyzeFile(p.realPath, p.pathPrefix, regexBasePath, regexpTerms)\n if (f !== null) {\n fileContents.push(f)\n }\n continue\n }\n for await (const fileContent of this.parseFileNames(p.realPath, p.pathPrefix, regexBasePath, regexpTerms)) {\n fileContents.push(fileContent)\n if (fileContents.length >= limit) {\n return fileContents\n }\n }\n }\n }\n return fileContents\n }\n\n private async *parseFileNames(dir: string, pathPrefix: string, regexBasePath: RegExp, regexpTerms: RegExp): 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 const fileContent = await this.analyzeFile(realPath, pathPrefix, regexBasePath, regexpTerms)\n if (fileContent !== null) {\n yield fileContent\n }\n if (entry.isDirectory()) {\n yield* this.parseFileNames(realPath, pathPrefix, regexBasePath, regexpTerms)\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFileNames.name} - unable to parse: ${dir} (${e})`)\n }\n }\n\n private async analyzeFile(realPath: string, pathPrefix: string, regexBasePath: RegExp, regexpTerms: RegExp): Promise<FileContent> {\n const filePath = realPath.replace(regexBasePath, '')\n if (!regexpTerms.test(filePath)) return null\n const stats: Stats = await fs.stat(realPath)\n return {\n id: stats.ino,\n path: path.join(pathPrefix, dirName(filePath)),\n name: fileName(filePath),\n mime: getMimeType(realPath, stats.isDirectory()),\n size: stats.size,\n mtime: stats.mtime.getTime()\n }\n }\n}\n"],"names":["FilesSearchManager","search","user","spaceIds","shareIds","Promise","all","spacesQueries","id","sharesQueries","isAdmin","fullText","searchFullText","content","limit","searchFileNames","userId","indexNames","filesIndexer","existingIndexes","userIndexPrefix","map","spaceIndexPrefix","shareIndexPrefix","length","searchRecords","e","logger","error","name","JSON","stringify","msg","test","message","HttpException","HttpStatus","BAD_REQUEST","fileContents","regexpTerms","genRegexPositiveAndNegativeTerms","_id","_type","paths","filesParser","allPaths","p","regexBasePath","RegExp","realPath","isDir","f","analyzeFile","pathPrefix","push","fileContent","parseFileNames","dir","entry","fs","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","filePath","replace","stats","stat","ino","dirName","fileName","mime","getMimeType","size","mtime","getTime","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAkBYA;;;eAAAA;;;wBAhBiD;iEAC/C;iEAEE;sCACa;sCACA;0BAEsC;8BAEvC;uBAEkB;6BACE;oCACrB;;;;;;;;;;;;;;;AAGrB,IAAA,AAAMA,qBAAN,MAAMA;IAUX,MAAMC,OAAOC,IAAe,EAAED,MAAsB,EAA0B;QAC5E,MAAM,CAACE,UAAUC,SAAS,GAAG,MAAMC,QAAQC,GAAG,CAAC;YAAC,IAAI,CAACC,aAAa,CAACJ,QAAQ,CAACD,KAAKM,EAAE;YAAG,IAAI,CAACC,aAAa,CAACL,QAAQ,CAACF,KAAKM,EAAE,EAAE,CAACN,KAAKQ,OAAO;SAAE;QAC1I,IAAIT,OAAOU,QAAQ,EAAE;YACnB,OAAO,MAAM,IAAI,CAACC,cAAc,CAACV,KAAKM,EAAE,EAAEL,UAAUC,UAAUH,OAAOY,OAAO,EAAEZ,OAAOa,KAAK;QAC5F,OAAO;YACL,OAAO,MAAM,IAAI,CAACC,eAAe,CAACb,KAAKM,EAAE,EAAEL,UAAUC,UAAUH,OAAOY,OAAO,EAAEZ,OAAOa,KAAK;QAC7F;IACF;IAEA,MAAcF,eAAeI,MAAc,EAAEb,QAAkB,EAAEC,QAAkB,EAAEH,MAAc,EAAEa,KAAa,EAA0B;QAC1I,MAAMG,aAAa,MAAM,IAAI,CAACC,YAAY,CAACC,eAAe,CAAC;YACzD,GAAGC,yBAAe,GAAGJ,QAAQ;eAC1Bb,SAASkB,GAAG,CAAC,CAACb,KAAO,GAAGc,0BAAgB,GAAGd,IAAI;eAC/CJ,SAASiB,GAAG,CAAC,CAACb,KAAO,GAAGe,0BAAgB,GAAGf,IAAI;SACnD;QACD,IAAIS,WAAWO,MAAM,KAAK,GAAG;YAC3B,OAAO,EAAE;QACX;QACA,IAAI;YACF,OAAO,MAAM,IAAI,CAACN,YAAY,CAACO,aAAa,CAACR,YAAYhB,QAAQa;QACnE,EAAE,OAAOY,GAAG;YACV,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAAChB,cAAc,CAACiB,IAAI,CAAC,GAAG,EAAEC,KAAKC,SAAS,CAACd,YAAY,GAAG,EAAEhB,OAAO,GAAG,EAAEyB,GAAG;YAClG,IAAIM;YACJ,IAAI,6BAA6BC,IAAI,CAACP,EAAEQ,OAAO,GAAG;gBAChDF,MAAM;YACR,OAAO;gBACLA,MAAMN,EAAEQ,OAAO;YACjB;YACA,MAAM,IAAIC,qBAAa,CAACH,KAAKI,kBAAU,CAACC,WAAW;QACrD;IACF;IAEA,MAActB,gBAAgBC,MAAc,EAAEb,QAAkB,EAAEC,QAAkB,EAAEH,MAAc,EAAEa,KAAa,EAA0B;QAC3I,MAAMwB,eAA8B,EAAE;QACtC,MAAMC,cAAcC,IAAAA,6CAAgC,EAACvC;QACrD,WAAW,MAAM,CAACwC,KAAKC,OAAOC,MAAM,IAAI,IAAI,CAACC,WAAW,CAACC,QAAQ,CAAC7B,QAAQb,UAAUC,UAAW;YAC7F,KAAK,MAAM0C,KAAKH,MAAO;gBACrB,MAAMI,gBAAgB,IAAIC,OAAO,CAAC,GAAG,EAAEF,EAAEG,QAAQ,CAAC,EAAE,CAAC;gBACrD,IAAI,CAACH,EAAEI,KAAK,EAAE;oBACZ,MAAMC,IAAI,MAAM,IAAI,CAACC,WAAW,CAACN,EAAEG,QAAQ,EAAEH,EAAEO,UAAU,EAAEN,eAAeR;oBAC1E,IAAIY,MAAM,MAAM;wBACdb,aAAagB,IAAI,CAACH;oBACpB;oBACA;gBACF;gBACA,WAAW,MAAMI,eAAe,IAAI,CAACC,cAAc,CAACV,EAAEG,QAAQ,EAAEH,EAAEO,UAAU,EAAEN,eAAeR,aAAc;oBACzGD,aAAagB,IAAI,CAACC;oBAClB,IAAIjB,aAAad,MAAM,IAAIV,OAAO;wBAChC,OAAOwB;oBACT;gBACF;YACF;QACF;QACA,OAAOA;IACT;IAEA,OAAekB,eAAeC,GAAW,EAAEJ,UAAkB,EAAEN,aAAqB,EAAER,WAAmB,EAA+B;QACtI,IAAI;YACF,KAAK,MAAMmB,SAAS,CAAA,MAAMC,iBAAE,CAACC,OAAO,CAACH,KAAK;gBAAEI,eAAe;YAAK,EAAC,EAAG;gBAClE,MAAMZ,WAAWa,iBAAI,CAACC,IAAI,CAACL,MAAMM,UAAU,EAAEN,MAAM7B,IAAI;gBACvD,MAAM0B,cAAc,MAAM,IAAI,CAACH,WAAW,CAACH,UAAUI,YAAYN,eAAeR;gBAChF,IAAIgB,gBAAgB,MAAM;oBACxB,MAAMA;gBACR;gBACA,IAAIG,MAAMO,WAAW,IAAI;oBACvB,OAAO,IAAI,CAACT,cAAc,CAACP,UAAUI,YAAYN,eAAeR;gBAClE;YACF;QACF,EAAE,OAAOb,GAAG;YACV,IAAI,CAACC,MAAM,CAACuC,IAAI,CAAC,GAAG,IAAI,CAACV,cAAc,CAAC3B,IAAI,CAAC,oBAAoB,EAAE4B,IAAI,EAAE,EAAE/B,EAAE,CAAC,CAAC;QACjF;IACF;IAEA,MAAc0B,YAAYH,QAAgB,EAAEI,UAAkB,EAAEN,aAAqB,EAAER,WAAmB,EAAwB;QAChI,MAAM4B,WAAWlB,SAASmB,OAAO,CAACrB,eAAe;QACjD,IAAI,CAACR,YAAYN,IAAI,CAACkC,WAAW,OAAO;QACxC,MAAME,QAAe,MAAMV,iBAAE,CAACW,IAAI,CAACrB;QACnC,OAAO;YACLzC,IAAI6D,MAAME,GAAG;YACbT,MAAMA,iBAAI,CAACC,IAAI,CAACV,YAAYmB,IAAAA,cAAO,EAACL;YACpCtC,MAAM4C,IAAAA,eAAQ,EAACN;YACfO,MAAMC,IAAAA,kBAAW,EAAC1B,UAAUoB,MAAMJ,WAAW;YAC7CW,MAAMP,MAAMO,IAAI;YAChBC,OAAOR,MAAMQ,KAAK,CAACC,OAAO;QAC5B;IACF;IA5FA,YACE,AAAiB5D,YAA0B,EAC3C,AAAiB0B,WAAwB,EACzC,AAAiBrC,aAA4B,EAC7C,AAAiBE,aAA4B,CAC7C;aAJiBS,eAAAA;aACA0B,cAAAA;aACArC,gBAAAA;aACAE,gBAAAA;aANFkB,SAAS,IAAIoD,cAAM,CAAC/E,mBAAmB6B,IAAI;IAOzD;AAwFL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-search-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 { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { configuration } from '../../../configuration/config.environment'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { SearchFilesDto } from '../dto/file-operations.dto'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { dirName, fileName, getMimeType } from '../utils/files'\nimport { genRegexPositiveAndNegativeTerms } from '../utils/files-search'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesSearchManager {\n private readonly logger = new Logger(FilesSearchManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n async search(user: UserModel, search: SearchFilesDto): Promise<FileContent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n if (search.fullText) {\n if (!configuration.applications.files.contentIndexing) {\n throw new HttpException('Full-text search is disabled', HttpStatus.BAD_REQUEST)\n }\n return await this.searchFullText(user.id, spaceIds, shareIds, search.content, search.limit)\n } else {\n return await this.searchFileNames(user.id, spaceIds, shareIds, search.content, search.limit)\n }\n }\n\n private async searchFullText(userId: number, spaceIds: number[], shareIds: number[], search: string, limit: number): Promise<FileContent[]> {\n const indexNames = await this.filesIndexer.existingIndexes([\n `${userIndexPrefix}${userId}`,\n ...spaceIds.map((id) => `${spaceIndexPrefix}${id}`),\n ...shareIds.map((id) => `${shareIndexPrefix}${id}`)\n ])\n if (indexNames.length === 0) {\n return []\n }\n try {\n return await this.filesIndexer.searchRecords(indexNames, search, limit)\n } catch (e) {\n this.logger.error(`${this.searchFullText.name} - ${JSON.stringify(indexNames)} - ${search} : ${e}`)\n let msg: string\n if (/Invalid regular expression/.test(e.message)) {\n msg = 'SyntaxError (check special characters)'\n } else {\n msg = e.message\n }\n throw new HttpException(msg, HttpStatus.BAD_REQUEST)\n }\n }\n\n private async searchFileNames(userId: number, spaceIds: number[], shareIds: number[], search: string, limit: number): Promise<FileContent[]> {\n const fileContents: FileContent[] = []\n const regexpTerms = genRegexPositiveAndNegativeTerms(search)\n for await (const [_id, _type, paths] of this.filesParser.allPaths(userId, spaceIds, shareIds)) {\n for (const p of paths) {\n const regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n if (!p.isDir) {\n const f = await this.analyzeFile(p.realPath, p.pathPrefix, regexBasePath, regexpTerms)\n if (f !== null) {\n fileContents.push(f)\n }\n continue\n }\n for await (const fileContent of this.parseFileNames(p.realPath, p.pathPrefix, regexBasePath, regexpTerms)) {\n fileContents.push(fileContent)\n if (fileContents.length >= limit) {\n return fileContents\n }\n }\n }\n }\n return fileContents\n }\n\n private async *parseFileNames(dir: string, pathPrefix: string, regexBasePath: RegExp, regexpTerms: RegExp): 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 const fileContent = await this.analyzeFile(realPath, pathPrefix, regexBasePath, regexpTerms)\n if (fileContent !== null) {\n yield fileContent\n }\n if (entry.isDirectory()) {\n yield* this.parseFileNames(realPath, pathPrefix, regexBasePath, regexpTerms)\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFileNames.name} - unable to parse: ${dir} (${e})`)\n }\n }\n\n private async analyzeFile(realPath: string, pathPrefix: string, regexBasePath: RegExp, regexpTerms: RegExp): Promise<FileContent> {\n const filePath = realPath.replace(regexBasePath, '')\n if (!regexpTerms.test(filePath)) return null\n const stats: Stats = await fs.stat(realPath)\n return {\n id: stats.ino,\n path: path.join(pathPrefix, dirName(filePath)),\n name: fileName(filePath),\n mime: getMimeType(realPath, stats.isDirectory()),\n size: stats.size,\n mtime: stats.mtime.getTime()\n }\n }\n}\n"],"names":["FilesSearchManager","search","user","spaceIds","shareIds","Promise","all","spacesQueries","id","sharesQueries","isAdmin","fullText","configuration","applications","files","contentIndexing","HttpException","HttpStatus","BAD_REQUEST","searchFullText","content","limit","searchFileNames","userId","indexNames","filesIndexer","existingIndexes","userIndexPrefix","map","spaceIndexPrefix","shareIndexPrefix","length","searchRecords","e","logger","error","name","JSON","stringify","msg","test","message","fileContents","regexpTerms","genRegexPositiveAndNegativeTerms","_id","_type","paths","filesParser","allPaths","p","regexBasePath","RegExp","realPath","isDir","f","analyzeFile","pathPrefix","push","fileContent","parseFileNames","dir","entry","fs","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","filePath","replace","stats","stat","ino","dirName","fileName","mime","getMimeType","size","mtime","getTime","Logger"],"mappings":"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"}
@@ -12,9 +12,17 @@ Object.defineProperty(exports, "parsePdf", {
12
12
  return parsePdf;
13
13
  }
14
14
  });
15
+ const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
15
16
  const _pdf = require("pdfjs-dist/legacy/build/pdf.mjs");
17
+ function _interop_require_default(obj) {
18
+ return obj && obj.__esModule ? obj : {
19
+ default: obj
20
+ };
21
+ }
16
22
  // Enable parallel PDF parsing via Node.js worker threads
17
23
  _pdf.GlobalWorkerOptions.workerSrc = require.resolve('pdfjs-dist/legacy/build/pdf.worker.mjs');
24
+ const pdfjsDistDir = _nodepath.default.dirname(require.resolve('pdfjs-dist/package.json'));
25
+ const standardFontsDir = _nodepath.default.join(pdfjsDistDir, 'standard_fonts') + '/';
18
26
  // Type guard to filter true text items
19
27
  function isTextItem(item) {
20
28
  return typeof item.str === 'string' && Array.isArray(item.transform);
@@ -29,7 +37,8 @@ async function parsePdf(filePath, options) {
29
37
  // Load the document, allowing system fonts as fallback
30
38
  const loadingTask = (0, _pdf.getDocument)({
31
39
  url: filePath,
32
- useSystemFonts: true
40
+ disableFontFace: true,
41
+ standardFontDataUrl: standardFontsDir
33
42
  });
34
43
  doc = await loadingTask.promise;
35
44
  const fragments = [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../backend/src/applications/files/utils/doc-textify/adapters/pdf.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 */\nimport { getDocument, GlobalWorkerOptions, PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs'\nimport { DocTextifyOptions } from '../interfaces/doc-textify.interfaces'\n\n// Enable parallel PDF parsing via Node.js worker threads\nGlobalWorkerOptions.workerSrc = require.resolve('pdfjs-dist/legacy/build/pdf.worker.mjs')\n\n// Type guard to filter true text items\nfunction isTextItem(item: any): item is { str: string; transform: [number, number, number, number, number, number] } {\n return typeof item.str === 'string' && Array.isArray(item.transform)\n}\n\nconst ignorePdfBadFormat = new Set([0x0000, 0x0001])\n\n/** Parse PDF files */\nexport async function parsePdf(filePath: string, options: DocTextifyOptions): Promise<string> {\n let doc: PDFDocumentProxy\n\n try {\n // Load the document, allowing system fonts as fallback\n const loadingTask = getDocument({ url: filePath, useSystemFonts: true })\n doc = await loadingTask.promise\n const fragments: string[] = []\n let lastY: number | undefined = undefined\n\n for (let pageNum = 1; pageNum <= doc.numPages; pageNum++) {\n const page = await doc.getPage(pageNum)\n const { items } = await page.getTextContent()\n\n for (const item of items) {\n // Skip non-text items\n if (!isTextItem(item)) continue\n\n const currentY = item.transform[5]\n if (lastY !== undefined && currentY !== lastY) {\n fragments.push(options.newlineDelimiter)\n }\n\n fragments.push(item.str)\n lastY = currentY\n }\n page.cleanup()\n }\n\n const content = fragments.join('')\n if (ignorePdfBadFormat.has(content.charCodeAt(0))) {\n return ''\n }\n return content\n } catch (e) {\n if (options.outputErrorToConsole) {\n console.error('Error parsing PDF:', e)\n }\n throw e\n } finally {\n doc?.destroy().catch((e: Error) => console.error(e))\n }\n}\n"],"names":["parsePdf","GlobalWorkerOptions","workerSrc","require","resolve","isTextItem","item","str","Array","isArray","transform","ignorePdfBadFormat","Set","filePath","options","doc","loadingTask","getDocument","url","useSystemFonts","promise","fragments","lastY","undefined","pageNum","numPages","page","getPage","items","getTextContent","currentY","push","newlineDelimiter","cleanup","content","join","has","charCodeAt","e","outputErrorToConsole","console","error","destroy","catch"],"mappings":"AAAA;;;;CAIC;;;;+BAeqBA;;;eAAAA;;;qBAd6C;AAGnE,yDAAyD;AACzDC,wBAAmB,CAACC,SAAS,GAAGC,QAAQC,OAAO,CAAC;AAEhD,uCAAuC;AACvC,SAASC,WAAWC,IAAS;IAC3B,OAAO,OAAOA,KAAKC,GAAG,KAAK,YAAYC,MAAMC,OAAO,CAACH,KAAKI,SAAS;AACrE;AAEA,MAAMC,qBAAqB,IAAIC,IAAI;IAAC;IAAQ;CAAO;AAG5C,eAAeZ,SAASa,QAAgB,EAAEC,OAA0B;IACzE,IAAIC;IAEJ,IAAI;QACF,uDAAuD;QACvD,MAAMC,cAAcC,IAAAA,gBAAW,EAAC;YAAEC,KAAKL;YAAUM,gBAAgB;QAAK;QACtEJ,MAAM,MAAMC,YAAYI,OAAO;QAC/B,MAAMC,YAAsB,EAAE;QAC9B,IAAIC,QAA4BC;QAEhC,IAAK,IAAIC,UAAU,GAAGA,WAAWT,IAAIU,QAAQ,EAAED,UAAW;YACxD,MAAME,OAAO,MAAMX,IAAIY,OAAO,CAACH;YAC/B,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAMF,KAAKG,cAAc;YAE3C,KAAK,MAAMvB,QAAQsB,MAAO;gBACxB,sBAAsB;gBACtB,IAAI,CAACvB,WAAWC,OAAO;gBAEvB,MAAMwB,WAAWxB,KAAKI,SAAS,CAAC,EAAE;gBAClC,IAAIY,UAAUC,aAAaO,aAAaR,OAAO;oBAC7CD,UAAUU,IAAI,CAACjB,QAAQkB,gBAAgB;gBACzC;gBAEAX,UAAUU,IAAI,CAACzB,KAAKC,GAAG;gBACvBe,QAAQQ;YACV;YACAJ,KAAKO,OAAO;QACd;QAEA,MAAMC,UAAUb,UAAUc,IAAI,CAAC;QAC/B,IAAIxB,mBAAmByB,GAAG,CAACF,QAAQG,UAAU,CAAC,KAAK;YACjD,OAAO;QACT;QACA,OAAOH;IACT,EAAE,OAAOI,GAAG;QACV,IAAIxB,QAAQyB,oBAAoB,EAAE;YAChCC,QAAQC,KAAK,CAAC,sBAAsBH;QACtC;QACA,MAAMA;IACR,SAAU;QACRvB,KAAK2B,UAAUC,MAAM,CAACL,IAAaE,QAAQC,KAAK,CAACH;IACnD;AACF"}
1
+ {"version":3,"sources":["../../../../../../../backend/src/applications/files/utils/doc-textify/adapters/pdf.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 */\nimport path from 'node:path'\nimport { getDocument, GlobalWorkerOptions, PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs'\nimport { DocTextifyOptions } from '../interfaces/doc-textify.interfaces'\n\n// Enable parallel PDF parsing via Node.js worker threads\nGlobalWorkerOptions.workerSrc = require.resolve('pdfjs-dist/legacy/build/pdf.worker.mjs')\nconst pdfjsDistDir = path.dirname(require.resolve('pdfjs-dist/package.json'))\nconst standardFontsDir = path.join(pdfjsDistDir, 'standard_fonts') + '/'\n\n// Type guard to filter true text items\nfunction isTextItem(item: any): item is { str: string; transform: [number, number, number, number, number, number] } {\n return typeof item.str === 'string' && Array.isArray(item.transform)\n}\n\nconst ignorePdfBadFormat = new Set([0x0000, 0x0001])\n\n/** Parse PDF files */\nexport async function parsePdf(filePath: string, options: DocTextifyOptions): Promise<string> {\n let doc: PDFDocumentProxy\n\n try {\n // Load the document, allowing system fonts as fallback\n const loadingTask = getDocument({ url: filePath, disableFontFace: true, standardFontDataUrl: standardFontsDir })\n doc = await loadingTask.promise\n const fragments: string[] = []\n let lastY: number | undefined = undefined\n\n for (let pageNum = 1; pageNum <= doc.numPages; pageNum++) {\n const page = await doc.getPage(pageNum)\n const { items } = await page.getTextContent()\n\n for (const item of items) {\n // Skip non-text items\n if (!isTextItem(item)) continue\n\n const currentY = item.transform[5]\n if (lastY !== undefined && currentY !== lastY) {\n fragments.push(options.newlineDelimiter)\n }\n\n fragments.push(item.str)\n lastY = currentY\n }\n page.cleanup()\n }\n\n const content = fragments.join('')\n if (ignorePdfBadFormat.has(content.charCodeAt(0))) {\n return ''\n }\n return content\n } catch (e) {\n if (options.outputErrorToConsole) {\n console.error('Error parsing PDF:', e)\n }\n throw e\n } finally {\n doc?.destroy().catch((e: Error) => console.error(e))\n }\n}\n"],"names":["parsePdf","GlobalWorkerOptions","workerSrc","require","resolve","pdfjsDistDir","path","dirname","standardFontsDir","join","isTextItem","item","str","Array","isArray","transform","ignorePdfBadFormat","Set","filePath","options","doc","loadingTask","getDocument","url","disableFontFace","standardFontDataUrl","promise","fragments","lastY","undefined","pageNum","numPages","page","getPage","items","getTextContent","currentY","push","newlineDelimiter","cleanup","content","has","charCodeAt","e","outputErrorToConsole","console","error","destroy","catch"],"mappings":"AAAA;;;;CAIC;;;;+BAkBqBA;;;eAAAA;;;iEAjBL;qBACkD;;;;;;AAGnE,yDAAyD;AACzDC,wBAAmB,CAACC,SAAS,GAAGC,QAAQC,OAAO,CAAC;AAChD,MAAMC,eAAeC,iBAAI,CAACC,OAAO,CAACJ,QAAQC,OAAO,CAAC;AAClD,MAAMI,mBAAmBF,iBAAI,CAACG,IAAI,CAACJ,cAAc,oBAAoB;AAErE,uCAAuC;AACvC,SAASK,WAAWC,IAAS;IAC3B,OAAO,OAAOA,KAAKC,GAAG,KAAK,YAAYC,MAAMC,OAAO,CAACH,KAAKI,SAAS;AACrE;AAEA,MAAMC,qBAAqB,IAAIC,IAAI;IAAC;IAAQ;CAAO;AAG5C,eAAejB,SAASkB,QAAgB,EAAEC,OAA0B;IACzE,IAAIC;IAEJ,IAAI;QACF,uDAAuD;QACvD,MAAMC,cAAcC,IAAAA,gBAAW,EAAC;YAAEC,KAAKL;YAAUM,iBAAiB;YAAMC,qBAAqBjB;QAAiB;QAC9GY,MAAM,MAAMC,YAAYK,OAAO;QAC/B,MAAMC,YAAsB,EAAE;QAC9B,IAAIC,QAA4BC;QAEhC,IAAK,IAAIC,UAAU,GAAGA,WAAWV,IAAIW,QAAQ,EAAED,UAAW;YACxD,MAAME,OAAO,MAAMZ,IAAIa,OAAO,CAACH;YAC/B,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAMF,KAAKG,cAAc;YAE3C,KAAK,MAAMxB,QAAQuB,MAAO;gBACxB,sBAAsB;gBACtB,IAAI,CAACxB,WAAWC,OAAO;gBAEvB,MAAMyB,WAAWzB,KAAKI,SAAS,CAAC,EAAE;gBAClC,IAAIa,UAAUC,aAAaO,aAAaR,OAAO;oBAC7CD,UAAUU,IAAI,CAAClB,QAAQmB,gBAAgB;gBACzC;gBAEAX,UAAUU,IAAI,CAAC1B,KAAKC,GAAG;gBACvBgB,QAAQQ;YACV;YACAJ,KAAKO,OAAO;QACd;QAEA,MAAMC,UAAUb,UAAUlB,IAAI,CAAC;QAC/B,IAAIO,mBAAmByB,GAAG,CAACD,QAAQE,UAAU,CAAC,KAAK;YACjD,OAAO;QACT;QACA,OAAOF;IACT,EAAE,OAAOG,GAAG;QACV,IAAIxB,QAAQyB,oBAAoB,EAAE;YAChCC,QAAQC,KAAK,CAAC,sBAAsBH;QACtC;QACA,MAAMA;IACR,SAAU;QACRvB,KAAK2B,UAAUC,MAAM,CAACL,IAAaE,QAAQC,KAAK,CAACH;IACnD;AACF"}
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ /*
6
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
7
+ * This file is part of Sync-in | The open source file sync and share solution
8
+ * See the LICENSE file for licensing details
9
+ */ "use strict";
10
+ Object.defineProperty(exports, "__esModule", {
11
+ value: true
12
+ });
13
+ Object.defineProperty(exports, "de", {
14
+ enumerable: true,
15
+ get: function() {
16
+ return de;
17
+ }
18
+ });
19
+ const de = {
20
+ 'If you no longer wish to receive notifications, change your preferences directly from your user space': 'Wenn Sie keine Benachrichtigungen mehr erhalten möchten, ändern Sie Ihre Einstellungen direkt in Ihrem Benutzerbereich',
21
+ 'Access it from': 'Öffnen Sie es über',
22
+ Comment: 'Kommentar',
23
+ commented: 'hat kommentiert',
24
+ 'You receive this notification if you are the owner of the file or if you have also commented on this file': 'Sie erhalten diese Benachrichtigung, wenn Sie der Eigentümer der Datei sind oder wenn Sie diese Datei ebenfalls kommentiert haben',
25
+ Space: 'Bereich',
26
+ 'from the space': 'aus dem Bereich',
27
+ 'to the space': 'zum Bereich',
28
+ 'Access your spaces from': 'Öffnen Sie Ihre Bereiche über',
29
+ 'Access this space from': 'Öffnen Sie diesen Bereich über',
30
+ 'You now have access to the space': 'Sie haben jetzt Zugriff auf den Bereich',
31
+ 'You no longer have access to the space': 'Sie haben keinen Zugriff mehr auf den Bereich',
32
+ 'This space has been permanently deleted': 'Dieser Bereich wurde dauerhaft gelöscht',
33
+ anchored: 'hat angeheftet',
34
+ unanchored: 'hat gelöst',
35
+ Share: 'Freigabe',
36
+ 'shared with you': 'hat mit Ihnen geteilt',
37
+ 'no longer share with you': 'teilt nicht mehr mit Ihnen',
38
+ 'You now have access to the share': 'Sie haben jetzt Zugriff auf die Freigabe',
39
+ 'You no longer have access to the share': 'Sie haben keinen Zugriff mehr auf die Freigabe',
40
+ 'You are no longer a member of the parent share, your child share has been deleted': 'Sie sind kein Mitglied der übergeordneten Freigabe mehr, Ihre untergeordnete Freigabe wurde gelöscht',
41
+ 'Access your shares from': 'Öffnen Sie Ihre Freigaben über',
42
+ 'Access password': 'Zugriffspasswort',
43
+ Sync: 'Synchronisierung',
44
+ 'Access your syncs from': 'Öffnen Sie Ihre Synchronisierungen über',
45
+ 'You are no longer synchronizing': 'Sie synchronisieren nicht mehr',
46
+ 'Security notification': 'Sicherheitsbenachrichtigung',
47
+ 'Your account has been locked after several unsuccessful authentication attempts': 'Ihr Konto wurde nach mehreren fehlgeschlagenen Anmeldeversuchen gesperrt',
48
+ 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.': 'Diese Sicherheitsbenachrichtigung betrifft Ihr Sync-in-Konto. Bitte wenden Sie sich an einen Administrator, damit er die Analyse durchführt und Ihr Konto entsperrt.',
49
+ 'Two-factor authentication (2FA) on your account has been disabled': 'Die Zwei-Faktor-Authentifizierung (2FA) für Ihr Konto wurde deaktiviert',
50
+ 'Two-factor authentication (2FA) on your account has been enabled': 'Die Zwei-Faktor-Authentifizierung (2FA) für Ihr Konto wurde aktiviert',
51
+ 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.': 'Sie erhalten diese Benachrichtigung, weil sich die Sicherheit Ihres Sync-in-Kontos geändert hat. Wenn Sie der Meinung sind, dass dies ein Fehler war, überprüfen Sie bitte Ihre Sicherheitseinstellungen oder kontaktieren Sie Ihren Administrator.',
52
+ 'Address IP': 'IP-Adresse',
53
+ Browser: 'Browser'
54
+ };
55
+
56
+ //# sourceMappingURL=de.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/i18n/de.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/*\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\nexport const de = {\n 'If you no longer wish to receive notifications, change your preferences directly from your user space':\n 'Wenn Sie keine Benachrichtigungen mehr erhalten möchten, ändern Sie Ihre Einstellungen direkt in Ihrem Benutzerbereich',\n 'Access it from': 'Öffnen Sie es über',\n Comment: 'Kommentar',\n commented: 'hat kommentiert',\n 'You receive this notification if you are the owner of the file or if you have also commented on this file':\n 'Sie erhalten diese Benachrichtigung, wenn Sie der Eigentümer der Datei sind oder wenn Sie diese Datei ebenfalls kommentiert haben',\n Space: 'Bereich',\n 'from the space': 'aus dem Bereich',\n 'to the space': 'zum Bereich',\n 'Access your spaces from': 'Öffnen Sie Ihre Bereiche über',\n 'Access this space from': 'Öffnen Sie diesen Bereich über',\n 'You now have access to the space': 'Sie haben jetzt Zugriff auf den Bereich',\n 'You no longer have access to the space': 'Sie haben keinen Zugriff mehr auf den Bereich',\n 'This space has been permanently deleted': 'Dieser Bereich wurde dauerhaft gelöscht',\n anchored: 'hat angeheftet',\n unanchored: 'hat gelöst',\n Share: 'Freigabe',\n 'shared with you': 'hat mit Ihnen geteilt',\n 'no longer share with you': 'teilt nicht mehr mit Ihnen',\n 'You now have access to the share': 'Sie haben jetzt Zugriff auf die Freigabe',\n 'You no longer have access to the share': 'Sie haben keinen Zugriff mehr auf die Freigabe',\n 'You are no longer a member of the parent share, your child share has been deleted':\n 'Sie sind kein Mitglied der übergeordneten Freigabe mehr, Ihre untergeordnete Freigabe wurde gelöscht',\n 'Access your shares from': 'Öffnen Sie Ihre Freigaben über',\n 'Access password': 'Zugriffspasswort',\n Sync: 'Synchronisierung',\n 'Access your syncs from': 'Öffnen Sie Ihre Synchronisierungen über',\n 'You are no longer synchronizing': 'Sie synchronisieren nicht mehr',\n 'Security notification': 'Sicherheitsbenachrichtigung',\n 'Your account has been locked after several unsuccessful authentication attempts':\n 'Ihr Konto wurde nach mehreren fehlgeschlagenen Anmeldeversuchen gesperrt',\n 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.':\n 'Diese Sicherheitsbenachrichtigung betrifft Ihr Sync-in-Konto. Bitte wenden Sie sich an einen Administrator, damit er die Analyse durchführt und Ihr Konto entsperrt.',\n 'Two-factor authentication (2FA) on your account has been disabled': 'Die Zwei-Faktor-Authentifizierung (2FA) für Ihr Konto wurde deaktiviert',\n 'Two-factor authentication (2FA) on your account has been enabled': 'Die Zwei-Faktor-Authentifizierung (2FA) für Ihr Konto wurde aktiviert',\n 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.':\n 'Sie erhalten diese Benachrichtigung, weil sich die Sicherheit Ihres Sync-in-Kontos geändert hat. Wenn Sie der Meinung sind, dass dies ein Fehler war, überprüfen Sie bitte Ihre Sicherheitseinstellungen oder kontaktieren Sie Ihren Administrator.',\n 'Address IP': 'IP-Adresse',\n Browser: 'Browser'\n} as const\n"],"names":["de","Comment","commented","Space","anchored","unanchored","Share","Sync","Browser"],"mappings":"AAAA;;;;CAIC,GACD;;;;CAIC;;;;+BAEYA;;;eAAAA;;;AAAN,MAAMA,KAAK;IAChB,yGACE;IACF,kBAAkB;IAClBC,SAAS;IACTC,WAAW;IACX,6GACE;IACFC,OAAO;IACP,kBAAkB;IAClB,gBAAgB;IAChB,2BAA2B;IAC3B,0BAA0B;IAC1B,oCAAoC;IACpC,0CAA0C;IAC1C,2CAA2C;IAC3CC,UAAU;IACVC,YAAY;IACZC,OAAO;IACP,mBAAmB;IACnB,4BAA4B;IAC5B,oCAAoC;IACpC,0CAA0C;IAC1C,qFACE;IACF,2BAA2B;IAC3B,mBAAmB;IACnBC,MAAM;IACN,0BAA0B;IAC1B,mCAAmC;IACnC,yBAAyB;IACzB,mFACE;IACF,8IACE;IACF,qEAAqE;IACrE,oEAAoE;IACpE,iMACE;IACF,cAAc;IACdC,SAAS;AACX"}
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "es", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return es;
13
+ }
14
+ });
15
+ const es = {
16
+ 'If you no longer wish to receive notifications, change your preferences directly from your user space': 'Si ya no desea recibir notificaciones, cambie sus preferencias directamente desde su espacio de usuario',
17
+ 'Access it from': 'Acceda a él desde',
18
+ Comment: 'Comentario',
19
+ commented: 'comentó',
20
+ 'You receive this notification if you are the owner of the file or if you have also commented on this file': 'Recibe esta notificación si es el propietario del archivo o si también ha comentado este archivo',
21
+ Space: 'Espacio',
22
+ 'from the space': 'del espacio',
23
+ 'to the space': 'al espacio',
24
+ 'Access your spaces from': 'Acceda a sus espacios desde',
25
+ 'Access this space from': 'Acceda a este espacio desde',
26
+ 'You now have access to the space': 'Ahora tiene acceso al espacio',
27
+ 'You no longer have access to the space': 'Ya no tiene acceso al espacio',
28
+ 'This space has been permanently deleted': 'Este espacio ha sido eliminado permanentemente',
29
+ anchored: 'ancló',
30
+ unanchored: 'desancló',
31
+ Share: 'Compartir',
32
+ 'shared with you': 'compartió con usted',
33
+ 'no longer share with you': 'ya no comparte con usted',
34
+ 'You now have access to the share': 'Ahora tiene acceso al recurso compartido',
35
+ 'You no longer have access to the share': 'Ya no tiene acceso al recurso compartido',
36
+ 'You are no longer a member of the parent share, your child share has been deleted': 'Ya no es miembro del recurso compartido principal; su recurso compartido hijo ha sido eliminado',
37
+ 'Access your shares from': 'Acceda a sus recursos compartidos desde',
38
+ 'Access password': 'Contraseña de acceso',
39
+ Sync: 'Sincronización',
40
+ 'Access your syncs from': 'Acceda a sus sincronizaciones desde',
41
+ 'You are no longer synchronizing': 'Ya no está sincronizando',
42
+ 'Security notification': 'Notificación de seguridad',
43
+ 'Your account has been locked after several unsuccessful authentication attempts': 'Su cuenta ha sido bloqueada tras varios intentos de autenticación fallidos',
44
+ 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.': 'Esta notificación de seguridad concierne a su cuenta de Sync-in. Póngase en contacto con un administrador para realizar el análisis y desbloquear su cuenta.',
45
+ 'Two-factor authentication (2FA) on your account has been disabled': 'La autenticación de dos factores (2FA) de su cuenta ha sido desactivada',
46
+ 'Two-factor authentication (2FA) on your account has been enabled': 'La autenticación de dos factores (2FA) de su cuenta ha sido activada',
47
+ 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.': 'Ha recibido esta notificación porque la seguridad de su cuenta de Sync-in ha cambiado. Si cree que se trata de un error, revise su configuración de seguridad o contacte a su administrador.',
48
+ 'Address IP': 'Dirección IP',
49
+ Browser: 'Navegador'
50
+ };
51
+
52
+ //# sourceMappingURL=es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/i18n/es.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\nexport const es = {\n 'If you no longer wish to receive notifications, change your preferences directly from your user space':\n 'Si ya no desea recibir notificaciones, cambie sus preferencias directamente desde su espacio de usuario',\n 'Access it from': 'Acceda a él desde',\n Comment: 'Comentario',\n commented: 'comentó',\n 'You receive this notification if you are the owner of the file or if you have also commented on this file':\n 'Recibe esta notificación si es el propietario del archivo o si también ha comentado este archivo',\n Space: 'Espacio',\n 'from the space': 'del espacio',\n 'to the space': 'al espacio',\n 'Access your spaces from': 'Acceda a sus espacios desde',\n 'Access this space from': 'Acceda a este espacio desde',\n 'You now have access to the space': 'Ahora tiene acceso al espacio',\n 'You no longer have access to the space': 'Ya no tiene acceso al espacio',\n 'This space has been permanently deleted': 'Este espacio ha sido eliminado permanentemente',\n anchored: 'ancló',\n unanchored: 'desancló',\n Share: 'Compartir',\n 'shared with you': 'compartió con usted',\n 'no longer share with you': 'ya no comparte con usted',\n 'You now have access to the share': 'Ahora tiene acceso al recurso compartido',\n 'You no longer have access to the share': 'Ya no tiene acceso al recurso compartido',\n 'You are no longer a member of the parent share, your child share has been deleted':\n 'Ya no es miembro del recurso compartido principal; su recurso compartido hijo ha sido eliminado',\n 'Access your shares from': 'Acceda a sus recursos compartidos desde',\n 'Access password': 'Contraseña de acceso',\n Sync: 'Sincronización',\n 'Access your syncs from': 'Acceda a sus sincronizaciones desde',\n 'You are no longer synchronizing': 'Ya no está sincronizando',\n 'Security notification': 'Notificación de seguridad',\n 'Your account has been locked after several unsuccessful authentication attempts':\n 'Su cuenta ha sido bloqueada tras varios intentos de autenticación fallidos',\n 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.':\n 'Esta notificación de seguridad concierne a su cuenta de Sync-in. Póngase en contacto con un administrador para realizar el análisis y desbloquear su cuenta.',\n 'Two-factor authentication (2FA) on your account has been disabled': 'La autenticación de dos factores (2FA) de su cuenta ha sido desactivada',\n 'Two-factor authentication (2FA) on your account has been enabled': 'La autenticación de dos factores (2FA) de su cuenta ha sido activada',\n 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.':\n 'Ha recibido esta notificación porque la seguridad de su cuenta de Sync-in ha cambiado. Si cree que se trata de un error, revise su configuración de seguridad o contacte a su administrador.',\n 'Address IP': 'Dirección IP',\n Browser: 'Navegador'\n} as const\n"],"names":["es","Comment","commented","Space","anchored","unanchored","Share","Sync","Browser"],"mappings":"AAAA;;;;CAIC;;;;+BAEYA;;;eAAAA;;;AAAN,MAAMA,KAAK;IAChB,yGACE;IACF,kBAAkB;IAClBC,SAAS;IACTC,WAAW;IACX,6GACE;IACFC,OAAO;IACP,kBAAkB;IAClB,gBAAgB;IAChB,2BAA2B;IAC3B,0BAA0B;IAC1B,oCAAoC;IACpC,0CAA0C;IAC1C,2CAA2C;IAC3CC,UAAU;IACVC,YAAY;IACZC,OAAO;IACP,mBAAmB;IACnB,4BAA4B;IAC5B,oCAAoC;IACpC,0CAA0C;IAC1C,qFACE;IACF,2BAA2B;IAC3B,mBAAmB;IACnBC,MAAM;IACN,0BAA0B;IAC1B,mCAAmC;IACnC,yBAAyB;IACzB,mFACE;IACF,8IACE;IACF,qEAAqE;IACrE,oEAAoE;IACpE,iMACE;IACF,cAAc;IACdC,SAAS;AACX"}
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "hi", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return hi;
13
+ }
14
+ });
15
+ const hi = {
16
+ 'If you no longer wish to receive notifications, change your preferences directly from your user space': 'यदि आप अब सूचनाएँ प्राप्त नहीं करना चाहते हैं, तो अपने उपयोगकर्ता क्षेत्र से सीधे अपनी प्राथमिकताएँ बदलें',
17
+ 'Access it from': 'इसे यहाँ से एक्सेस करें',
18
+ Comment: 'टिप्पणी',
19
+ commented: 'ने टिप्पणी की',
20
+ 'You receive this notification if you are the owner of the file or if you have also commented on this file': 'यदि आप फ़ाइल के मालिक हैं या आपने भी इस फ़ाइल पर टिप्पणी की है, तो आपको यह सूचना प्राप्त होती है',
21
+ Space: 'स्पेस',
22
+ 'from the space': 'स्पेस से',
23
+ 'to the space': 'स्पेस में',
24
+ 'Access your spaces from': 'अपने स्पेस यहाँ से एक्सेस करें',
25
+ 'Access this space from': 'इस स्पेस को यहाँ से एक्सेस करें',
26
+ 'You now have access to the space': 'अब आपको स्पेस तक पहुंच प्राप्त है',
27
+ 'You no longer have access to the space': 'अब आपको स्पेस तक पहुंच नहीं है',
28
+ 'This space has been permanently deleted': 'यह स्पेस स्थायी रूप से हटा दिया गया है',
29
+ anchored: 'एंकर किया',
30
+ unanchored: 'अनएंकर किया',
31
+ Share: 'साझा',
32
+ 'shared with you': 'आपके साथ साझा किया',
33
+ 'no longer share with you': 'अब आपके साथ साझा नहीं किया',
34
+ 'You now have access to the share': 'अब आपको साझा सामग्री तक पहुंच प्राप्त है',
35
+ 'You no longer have access to the share': 'अब आपको साझा सामग्री तक पहुंच नहीं है',
36
+ 'You are no longer a member of the parent share, your child share has been deleted': 'आप अब पैरेंट शेयर के सदस्य नहीं हैं; आपका चाइल्ड शेयर हटा दिया गया है',
37
+ 'Access your shares from': 'अपने शेयर यहाँ से एक्सेस करें',
38
+ 'Access password': 'एक्सेस पासवर्ड',
39
+ Sync: 'समन्वयन',
40
+ 'Access your syncs from': 'अपने समन्वयन यहाँ से एक्सेस करें',
41
+ 'You are no longer synchronizing': 'आप अब समन्वयन नहीं कर रहे हैं',
42
+ 'Security notification': 'सुरक्षा सूचना',
43
+ 'Your account has been locked after several unsuccessful authentication attempts': 'कई असफल प्रमाणीकरण प्रयासों के बाद आपका खाता लॉक कर दिया गया है',
44
+ 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.': 'यह सुरक्षा सूचना आपके Sync-in खाते से संबंधित है। कृपया विश्लेषण करने और अपना खाता अनलॉक करने के लिए किसी प्रशासक से संपर्क करें।',
45
+ 'Two-factor authentication (2FA) on your account has been disabled': 'आपके खाते पर दो‑कारक प्रमाणीकरण (2FA) अक्षम कर दिया गया है',
46
+ 'Two-factor authentication (2FA) on your account has been enabled': 'आपके खाते पर दो‑कारक प्रमाणीकरण (2FA) सक्षम कर दिया गया है',
47
+ 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.': 'आपको यह सूचना इसलिए मिली है क्योंकि आपके Sync-in खाते की सुरक्षा बदल गई है। यदि आपको लगता है कि यह गलती से हुआ है, तो कृपया अपनी सुरक्षा सेटिंग्स की समीक्षा करें या अपने प्रशासक से संपर्क करें।',
48
+ 'Address IP': 'IP पता',
49
+ Browser: 'ब्राउज़र'
50
+ };
51
+
52
+ //# sourceMappingURL=hi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/applications/notifications/i18n/hi.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\nexport const hi = {\n 'If you no longer wish to receive notifications, change your preferences directly from your user space':\n 'यदि आप अब सूचनाएँ प्राप्त नहीं करना चाहते हैं, तो अपने उपयोगकर्ता क्षेत्र से सीधे अपनी प्राथमिकताएँ बदलें',\n 'Access it from': 'इसे यहाँ से एक्सेस करें',\n Comment: 'टिप्पणी',\n commented: 'ने टिप्पणी की',\n 'You receive this notification if you are the owner of the file or if you have also commented on this file':\n 'यदि आप फ़ाइल के मालिक हैं या आपने भी इस फ़ाइल पर टिप्पणी की है, तो आपको यह सूचना प्राप्त होती है',\n Space: 'स्पेस',\n 'from the space': 'स्पेस से',\n 'to the space': 'स्पेस में',\n 'Access your spaces from': 'अपने स्पेस यहाँ से एक्सेस करें',\n 'Access this space from': 'इस स्पेस को यहाँ से एक्सेस करें',\n 'You now have access to the space': 'अब आपको स्पेस तक पहुंच प्राप्त है',\n 'You no longer have access to the space': 'अब आपको स्पेस तक पहुंच नहीं है',\n 'This space has been permanently deleted': 'यह स्पेस स्थायी रूप से हटा दिया गया है',\n anchored: 'एंकर किया',\n unanchored: 'अनएंकर किया',\n Share: 'साझा',\n 'shared with you': 'आपके साथ साझा किया',\n 'no longer share with you': 'अब आपके साथ साझा नहीं किया',\n 'You now have access to the share': 'अब आपको साझा सामग्री तक पहुंच प्राप्त है',\n 'You no longer have access to the share': 'अब आपको साझा सामग्री तक पहुंच नहीं है',\n 'You are no longer a member of the parent share, your child share has been deleted':\n 'आप अब पैरेंट शेयर के सदस्य नहीं हैं; आपका चाइल्ड शेयर हटा दिया गया है',\n 'Access your shares from': 'अपने शेयर यहाँ से एक्सेस करें',\n 'Access password': 'एक्सेस पासवर्ड',\n Sync: 'समन्वयन',\n 'Access your syncs from': 'अपने समन्वयन यहाँ से एक्सेस करें',\n 'You are no longer synchronizing': 'आप अब समन्वयन नहीं कर रहे हैं',\n 'Security notification': 'सुरक्षा सूचना',\n 'Your account has been locked after several unsuccessful authentication attempts':\n 'कई असफल प्रमाणीकरण प्रयासों के बाद आपका खाता लॉक कर दिया गया है',\n 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.':\n 'यह सुरक्षा सूचना आपके Sync-in खाते से संबंधित है। कृपया विश्लेषण करने और अपना खाता अनलॉक करने के लिए किसी प्रशासक से संपर्क करें।',\n 'Two-factor authentication (2FA) on your account has been disabled': 'आपके खाते पर दो‑कारक प्रमाणीकरण (2FA) अक्षम कर दिया गया है',\n 'Two-factor authentication (2FA) on your account has been enabled': 'आपके खाते पर दो‑कारक प्रमाणीकरण (2FA) सक्षम कर दिया गया है',\n 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.':\n 'आपको यह सूचना इसलिए मिली है क्योंकि आपके Sync-in खाते की सुरक्षा बदल गई है। यदि आपको लगता है कि यह गलती से हुआ है, तो कृपया अपनी सुरक्षा सेटिंग्स की समीक्षा करें या अपने प्रशासक से संपर्क करें।',\n 'Address IP': 'IP पता',\n Browser: 'ब्राउज़र'\n} as const\n"],"names":["hi","Comment","commented","Space","anchored","unanchored","Share","Sync","Browser"],"mappings":"AAAA;;;;CAIC;;;;+BAEYA;;;eAAAA;;;AAAN,MAAMA,KAAK;IAChB,yGACE;IACF,kBAAkB;IAClBC,SAAS;IACTC,WAAW;IACX,6GACE;IACFC,OAAO;IACP,kBAAkB;IAClB,gBAAgB;IAChB,2BAA2B;IAC3B,0BAA0B;IAC1B,oCAAoC;IACpC,0CAA0C;IAC1C,2CAA2C;IAC3CC,UAAU;IACVC,YAAY;IACZC,OAAO;IACP,mBAAmB;IACnB,4BAA4B;IAC5B,oCAAoC;IACpC,0CAA0C;IAC1C,qFACE;IACF,2BAA2B;IAC3B,mBAAmB;IACnBC,MAAM;IACN,0BAA0B;IAC1B,mCAAmC;IACnC,yBAAyB;IACzB,mFACE;IACF,8IACE;IACF,qEAAqE;IACrE,oEAAoE;IACpE,iMACE;IACF,cAAc;IACdC,SAAS;AACX"}