@sync-in/server 1.9.3 → 1.9.6

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 (80) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +7 -7
  3. package/server/applications/files/interfaces/only-office-config.interface.js.map +1 -1
  4. package/server/applications/files/services/files-methods.service.spec.js +2 -4
  5. package/server/applications/files/services/files-methods.service.spec.js.map +1 -1
  6. package/server/applications/files/services/files-recents.service.js +4 -0
  7. package/server/applications/files/services/files-recents.service.js.map +1 -1
  8. package/server/applications/files/services/files-scheduler.service.js +23 -4
  9. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  10. package/server/applications/spaces/services/spaces-scheduler.service.js +9 -1
  11. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  12. package/static/{chunk-YXWF2DGF.js → chunk-2F42MZQ5.js} +1 -1
  13. package/static/{chunk-KBWK65KM.js → chunk-2U5VKTML.js} +1 -1
  14. package/static/{chunk-XAIOGRBO.js → chunk-3AR5VNJE.js} +1 -1
  15. package/static/chunk-3WS72A6C.js +1 -0
  16. package/static/{chunk-6VJI4X2A.js → chunk-4GBA6EJ4.js} +1 -1
  17. package/static/{chunk-O7UXVNR2.js → chunk-4ZKAVMB4.js} +1 -1
  18. package/static/{chunk-JEVBUJQ4.js → chunk-5ATJIR5S.js} +1 -1
  19. package/static/{chunk-MZBO5PAR.js → chunk-5GIWZKNS.js} +1 -1
  20. package/static/{chunk-4OV3SAUS.js → chunk-5KVI243T.js} +1 -1
  21. package/static/{chunk-4EUHBTWV.js → chunk-5NFH4E2B.js} +1 -1
  22. package/static/{chunk-PKU4IIIR.js → chunk-7HL5Z6PF.js} +1 -1
  23. package/static/{chunk-4DF2SQD4.js → chunk-7QYALK5T.js} +1 -1
  24. package/static/{chunk-ZC5ZDCDC.js → chunk-ANH4VNOS.js} +1 -1
  25. package/static/{chunk-CURVLK7L.js → chunk-AYYJZMBE.js} +1 -1
  26. package/static/{chunk-A7R246NW.js → chunk-B2A4HNDC.js} +1 -1
  27. package/static/{chunk-ZRBLCAOK.js → chunk-B4TDS6AQ.js} +1 -1
  28. package/static/{chunk-WJYVS27M.js → chunk-BVKDW5XO.js} +1 -1
  29. package/static/{chunk-GDPJRUVU.js → chunk-BX3QZ7IL.js} +1 -1
  30. package/static/{chunk-ZPI7RQ2S.js → chunk-C5T7RZSD.js} +1 -1
  31. package/static/{chunk-7NI353LS.js → chunk-CHMDM2ZW.js} +1 -1
  32. package/static/{chunk-IUJ4IK26.js → chunk-CUC7R6C2.js} +1 -1
  33. package/static/{chunk-A7DSX7VP.js → chunk-D6QWQHWE.js} +1 -1
  34. package/static/{chunk-U75PLYIJ.js → chunk-DK2LAJEL.js} +1 -1
  35. package/static/{chunk-TGHBDJZA.js → chunk-DQAQUSVW.js} +1 -1
  36. package/static/{chunk-QUSS6SUC.js → chunk-DU4Q4RWJ.js} +1 -1
  37. package/static/{chunk-MBFMTBVJ.js → chunk-E5C4QRNQ.js} +2 -2
  38. package/static/{chunk-R6VB3INJ.js → chunk-EPDWJEPD.js} +1 -1
  39. package/static/{chunk-L3PDWJZ3.js → chunk-FCR5AEHR.js} +1 -1
  40. package/static/{chunk-5NHB7SV3.js → chunk-FEQUP26G.js} +1 -1
  41. package/static/{chunk-FLPZB3OX.js → chunk-FSGT46LM.js} +1 -1
  42. package/static/{chunk-XXYMVRSH.js → chunk-GLPKRULI.js} +1 -1
  43. package/static/{chunk-SDR3UG2F.js → chunk-GRV44RYI.js} +1 -1
  44. package/static/{chunk-FXM7XXWA.js → chunk-GYYJ4FWN.js} +1 -1
  45. package/static/{chunk-33WFRCUP.js → chunk-HB5DC7RJ.js} +1 -1
  46. package/static/{chunk-NFIES7BC.js → chunk-HLKZCMKV.js} +1 -1
  47. package/static/{chunk-TVJQXN73.js → chunk-IBC7CFBQ.js} +1 -1
  48. package/static/{chunk-DDRGLHOP.js → chunk-IIKL33TV.js} +1 -1
  49. package/static/{chunk-A6J6SOM6.js → chunk-JYHTSSKW.js} +1 -1
  50. package/static/{chunk-CAZSNVMS.js → chunk-KAAFVHYE.js} +1 -1
  51. package/static/{chunk-H4RLHI3Y.js → chunk-KWKZN53T.js} +1 -1
  52. package/static/chunk-MGMDT4VN.js +1 -0
  53. package/static/chunk-MWUUM2NK.js +13 -0
  54. package/static/{chunk-Z6RJZIDG.js → chunk-NHMYAVJK.js} +1 -1
  55. package/static/{chunk-YTBSB2GE.js → chunk-NQCKX2AD.js} +1 -1
  56. package/static/{chunk-27XEAHMV.js → chunk-O233BXWK.js} +1 -1
  57. package/static/{chunk-RJOHDAPM.js → chunk-ODAQRAPO.js} +1 -1
  58. package/static/{chunk-2LHHXDD5.js → chunk-OVUMPMVM.js} +1 -1
  59. package/static/chunk-Q6B4OVER.js +5 -0
  60. package/static/{chunk-NK2NMAJI.js → chunk-QKMN3S4M.js} +1 -1
  61. package/static/{chunk-FRBTL2ER.js → chunk-QUUQOBTF.js} +1 -1
  62. package/static/chunk-QV5LQKTS.js +1 -0
  63. package/static/{chunk-XHQEF2IX.js → chunk-S4UTSOPV.js} +1 -1
  64. package/static/{chunk-5HCVWZMA.js → chunk-SF6Q6VRC.js} +1 -1
  65. package/static/{chunk-S6YKBWJE.js → chunk-TOCCCZP2.js} +1 -1
  66. package/static/{chunk-HE6EDXWI.js → chunk-UO7ATVQG.js} +1 -1
  67. package/static/{chunk-4KXJ6C4N.js → chunk-X5UDV4ZB.js} +1 -1
  68. package/static/{chunk-VO4WVT6K.js → chunk-XIQXRSZ2.js} +1 -1
  69. package/static/chunk-YYTDPI5S.js +1 -0
  70. package/static/{chunk-ASBPYTLT.js → chunk-Z2KBIZ5D.js} +1 -1
  71. package/static/{chunk-K3MOXDU5.js → chunk-ZCOEP4O2.js} +1 -1
  72. package/static/index.html +1 -1
  73. package/static/main-ODUA232E.js +11 -0
  74. package/static/chunk-2XY4PMI5.js +0 -1
  75. package/static/chunk-3LVFDMTN.js +0 -1
  76. package/static/chunk-UUX3M6DC.js +0 -1
  77. package/static/chunk-VJ2HWQRJ.js +0 -5
  78. package/static/chunk-W72JYHOH.js +0 -1
  79. package/static/chunk-ZERBTNFW.js +0 -13
  80. package/static/main-FE6GWZXU.js +0 -11
package/CHANGELOG.md CHANGED
@@ -1,4 +1,16 @@
1
1
 
2
+ ## [1.9.6](https://github.com/Sync-in/server/compare/v1.9.5...v1.9.6) (2025-12-16)
3
+
4
+ ### Bug Fixes
5
+
6
+ * **backend:files:** skip adding recents for trashed files ([c445196](https://github.com/Sync-in/server/commit/c445196914b2d351fba9218698a24496b1d6036c))
7
+ * **backend:schedulers:** resolve scheduled methods being skipped because of @Timeout decorator overlap ([50f4140](https://github.com/Sync-in/server/commit/50f4140a7b0b478e6b499ea8884b43f13595bb71))
8
+ * **frontend:files:** enable autoplay for video in media viewer component ([20fe25f](https://github.com/Sync-in/server/commit/20fe25fba00987994076d09489febd5593e08cef))
9
+ * **frontend:files:** remove hidden class from buttons for consistent visibility across breakpoints ([a60538a](https://github.com/Sync-in/server/commit/a60538ad01c675dacdac7ed4d80ca2bdf5f369ba))
10
+ * **frontend:files:** update file metadata timestamps on save and align OnlyOffice state change handlers ([db768e1](https://github.com/Sync-in/server/commit/db768e14452f4712df9f443350c214e0700b7270))
11
+ * **frontend:search:** improve search input layout and update filter button visibility for responsiveness ([09ebce6](https://github.com/Sync-in/server/commit/09ebce612fa2d72699a4d60bf9896f8e3c0fc4e4))
12
+ * **frontend:spaces:** show disabled space message to space managers ([f8bcdf7](https://github.com/Sync-in/server/commit/f8bcdf7fdd4b25abc2ba4b74715adbb0ae04a3e3))
13
+
2
14
  ## [1.9.3](https://github.com/Sync-in/server/compare/v1.9.1...v1.9.3) (2025-12-07)
3
15
 
4
16
  ### Security Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sync-in/server",
3
- "version": "1.9.3",
3
+ "version": "1.9.6",
4
4
  "description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
5
5
  "author": {
6
6
  "name": "Johan Legrand",
@@ -83,11 +83,11 @@
83
83
  "@nestjs/common": "11.1.9",
84
84
  "@nestjs/config": "4.0.2",
85
85
  "@nestjs/core": "11.1.9",
86
- "@nestjs/jwt": "11.0.1",
86
+ "@nestjs/jwt": "11.0.2",
87
87
  "@nestjs/passport": "11.0.5",
88
88
  "@nestjs/platform-fastify": "11.1.9",
89
89
  "@nestjs/platform-socket.io": "11.1.9",
90
- "@nestjs/schedule": "6.0.1",
90
+ "@nestjs/schedule": "6.1.0",
91
91
  "@nestjs/websockets": "11.1.9",
92
92
  "@socket.io/cluster-adapter": "0.3.0",
93
93
  "@socket.io/redis-adapter": "8.3.0",
@@ -97,15 +97,15 @@
97
97
  "class-transformer": "0.5.1",
98
98
  "class-validator": "0.14.3",
99
99
  "deepmerge": "4.3.1",
100
- "drizzle-kit": "0.31.7",
100
+ "drizzle-kit": "0.31.8",
101
101
  "drizzle-orm": "0.44.7",
102
- "fast-xml-parser": "5.3.2",
102
+ "fast-xml-parser": "5.3.3",
103
103
  "fs-extra": "11.3.2",
104
104
  "html-to-text": "9.0.5",
105
105
  "js-yaml": "4.1.1",
106
- "ldapts": "8.0.11",
106
+ "ldapts": "8.0.25",
107
107
  "mime-types": "3.0.2",
108
- "mysql2": "3.15.3",
108
+ "mysql2": "3.16.0",
109
109
  "nestjs-pino": "4.5.0",
110
110
  "nodemailer": "7.0.11",
111
111
  "passport-http": "0.3.0",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/only-office-config.interface.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 { FILE_MODE } from '../constants/operations'\n\nexport interface OnlyOfficeReqConfig {\n documentServerUrl: string\n config: OnlyOfficeConfig\n}\n\nexport interface OnlyOfficeConvertForm {\n key: string\n url: string\n outputtype: string\n filetype: string\n async: boolean\n token?: string\n}\n\nexport interface OnlyOfficeConfig {\n documentType?: string\n token?: string\n type?: 'mobile' | 'desktop'\n height?: string\n width?: string\n document?: {\n fileType: string\n key: string\n referenceData?: {\n fileKey: string\n instanceId: string\n }\n title: string\n url: string\n info?: {\n owner?: string\n uploaded?: string\n favorite?: boolean\n folder?: string\n sharingSettings?: any[]\n }\n permissions?: {\n /**\n * @deprecated Deprecated since version 5.5, please add the onRequestRestore field instead.\n */\n changeHistory?: boolean\n chat?: boolean\n comment?: boolean\n commentGroups?: any\n copy?: boolean\n deleteCommentAuthorOnly?: boolean\n download?: boolean\n edit?: boolean\n editCommentAuthorOnly?: boolean\n fillForms?: boolean\n modifyContentControl?: boolean\n modifyFilter?: boolean\n print?: boolean\n protect?: boolean\n review?: boolean\n reviewGroups?: string[]\n userInfoGroups?: string[]\n }\n }\n editorConfig?: {\n actionLink?: any\n callbackUrl?: string\n coEditing?: {\n mode: string\n change: boolean\n }\n createUrl?: string\n lang?: string\n mode?: FILE_MODE\n recent?: any[]\n region?: string\n templates?: any[]\n user?: {\n group?: string\n id?: string\n image?: string\n name?: string\n }\n customization?: {\n anonymous?: {\n request?: boolean\n label?: string\n }\n autosave?: boolean\n forcesave?: boolean\n close?: {\n visible: boolean\n text: string\n }\n comments?: boolean\n compactHeader?: boolean\n compactToolbar?: boolean\n compatibleFeatures?: boolean\n customer?: {\n address?: string\n info?: string\n logo?: string\n logoDark?: string\n mail?: string\n name?: string\n phone?: string\n www?: string\n }\n features?: any\n feedback?: any\n goback?: any\n help?: boolean\n hideNotes?: boolean\n hideRightMenu?: boolean\n hideRulers?: boolean\n integrationMode?: string\n logo?: {\n image?: string\n imageDark?: string\n imageLight?: string\n imageEmbedded?: string\n url?: string\n visible?: boolean\n }\n macros?: boolean\n macrosMode?: string\n mentionShare?: boolean\n mobileForceView?: boolean\n plugins?: boolean\n review?: {\n hideReviewDisplay?: boolean\n hoverMode?: boolean\n reviewDisplay?: string\n showReviewChanges?: boolean\n trackChanges?: boolean\n }\n submitForm?: boolean\n toolbarHideFileName?: boolean\n toolbarNoTabs?: boolean\n uiTheme?: string\n unit?: string\n zoom?: number\n about?: boolean\n }\n embedded?: {\n embedUrl?: string\n fullscreenUrl?: string\n saveUrl?: string\n shareUrl?: string\n toolbarDocked?: string\n }\n plugins?: {\n autostart?: string[]\n options?: {\n all?: any\n pluginGuid: any\n }\n pluginsData?: string[]\n }\n }\n events?: {\n onAppReady?: (event: object) => void\n onCollaborativeChanges?: (event: object) => void\n onDocumentReady?: (event: object) => void\n onDocumentStateChange?: (event: object) => void\n onDownloadAs?: (event: object) => void\n onError?: (event: object) => void\n onInfo?: (event: object) => void\n onMetaChange?: (event: object) => void\n onMakeActionLink?: (event: object) => void\n onRequestRefreshFile?: (event: object) => void\n onPluginsReady?: (event: object) => void\n onReady?: (event: object) => void\n onRequestClose?: (event: object) => void\n onRequestCreateNew?: (event: object) => void\n onRequestEditRights?: (event: object) => void\n onRequestHistory?: (event: object) => void\n onRequestHistoryClose?: (event: object) => void\n onRequestHistoryData?: (event: object) => void\n onRequestInsertImage?: (event: object) => void\n onRequestOpen?: (event: object) => void\n onRequestReferenceData?: (event: object) => void\n onRequestReferenceSource?: (event: object) => void\n onRequestRename?: (event: object) => void\n onRequestRestore?: (event: object) => void\n onRequestSaveAs?: (event: object) => void\n onRequestSelectDocument?: (event: object) => void\n onRequestSelectSpreadsheet?: (event: object) => void\n onRequestSendNotify?: (event: object) => void\n onRequestSharingSettings?: (event: object) => void\n onRequestStartFilling: (event: object) => void\n onRequestUsers?: (event: object) => void\n onSubmit?: (event: object) => void\n onWarning?: (event: object) => void\n }\n}\n\nexport interface OnlyOfficeCallBack {\n /* documentation : https://api.onlyoffice.com/docs/docs-api/usage-api/callback-handler/ */\n key: string // document key\n /*\n status:\n 1 - document is being edited\n 2 - document is ready for saving\n 3 - document saving error has occurred\n 4 - document is closed with no changes\n 6 - document is being edited, but the current document state is saved\n 7 - error has occurred while force saving the document\n */\n status: 1 | 2 | 3 | 4 | 6 | 7\n url?: string // link to download the modified version (for status: 2, 3, 6 or 7)\n notmodified?: boolean // only with status 2\n /*\n actions:\n 0 - the user disconnects from the document co-editing\n 1 - the new user connects to the document co-editing\n 2 - the user clicks the forcesave button.\n */\n actions?: { type: 0 | 1 | 2; userid: string }[]\n forcesavetype?: 0 | 1 | 2 | 3 // The type is present when the status value is equal to 6 or 7 only\n /*\n forcesavetype:\n 0 - to the command service\n 1 - each time the saving is done (e.g. the Save button is clicked), which is only available when the forcesave option is set to true\n 2 - by timer with the settings from the server config\n 3 - each time the form is submitted (e.g. the Complete & Submit button is clicked)\n */\n users?: string[] // when multiple users are editing the document\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/only-office-config.interface.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 { FILE_MODE } from '../constants/operations'\n\nexport interface OnlyOfficeReqConfig {\n documentServerUrl: string\n config: OnlyOfficeConfig\n}\n\nexport interface OnlyOfficeConvertForm {\n key: string\n url: string\n outputtype: string\n filetype: string\n async: boolean\n token?: string\n}\n\nexport interface OnlyOfficeConfig {\n documentType?: string\n token?: string\n type?: 'mobile' | 'desktop'\n height?: string\n width?: string\n document?: {\n fileType: string\n key: string\n referenceData?: {\n fileKey: string\n instanceId: string\n }\n title: string\n url: string\n info?: {\n owner?: string\n uploaded?: string\n favorite?: boolean\n folder?: string\n sharingSettings?: any[]\n }\n permissions?: {\n /**\n * @deprecated Deprecated since version 5.5, please add the onRequestRestore field instead.\n */\n changeHistory?: boolean\n chat?: boolean\n comment?: boolean\n commentGroups?: any\n copy?: boolean\n deleteCommentAuthorOnly?: boolean\n download?: boolean\n edit?: boolean\n editCommentAuthorOnly?: boolean\n fillForms?: boolean\n modifyContentControl?: boolean\n modifyFilter?: boolean\n print?: boolean\n protect?: boolean\n review?: boolean\n reviewGroups?: string[]\n userInfoGroups?: string[]\n }\n }\n editorConfig?: {\n actionLink?: any\n callbackUrl?: string\n coEditing?: {\n mode: string\n change: boolean\n }\n createUrl?: string\n lang?: string\n mode?: FILE_MODE\n recent?: any[]\n region?: string\n templates?: any[]\n user?: {\n group?: string\n id?: string\n image?: string\n name?: string\n }\n customization?: {\n anonymous?: {\n request?: boolean\n label?: string\n }\n autosave?: boolean\n forcesave?: boolean\n close?: {\n visible: boolean\n text: string\n }\n comments?: boolean\n compactHeader?: boolean\n compactToolbar?: boolean\n compatibleFeatures?: boolean\n customer?: {\n address?: string\n info?: string\n logo?: string\n logoDark?: string\n mail?: string\n name?: string\n phone?: string\n www?: string\n }\n features?: any\n feedback?: any\n goback?: any\n help?: boolean\n hideNotes?: boolean\n hideRightMenu?: boolean\n hideRulers?: boolean\n integrationMode?: string\n logo?: {\n image?: string\n imageDark?: string\n imageLight?: string\n imageEmbedded?: string\n url?: string\n visible?: boolean\n }\n macros?: boolean\n macrosMode?: string\n mentionShare?: boolean\n mobileForceView?: boolean\n plugins?: boolean\n review?: {\n hideReviewDisplay?: boolean\n hoverMode?: boolean\n reviewDisplay?: string\n showReviewChanges?: boolean\n trackChanges?: boolean\n }\n submitForm?: boolean\n toolbarHideFileName?: boolean\n toolbarNoTabs?: boolean\n uiTheme?: string\n unit?: string\n zoom?: number\n about?: boolean\n }\n embedded?: {\n embedUrl?: string\n fullscreenUrl?: string\n saveUrl?: string\n shareUrl?: string\n toolbarDocked?: string\n }\n plugins?: {\n autostart?: string[]\n options?: {\n all?: any\n pluginGuid: any\n }\n pluginsData?: string[]\n }\n }\n events?: {\n onAppReady?: (event: object) => void\n onCollaborativeChanges?: (event: object) => void\n onDocumentReady?: (event: object) => void\n onDocumentStateChange?: (event: { data: boolean }) => void\n onDownloadAs?: (event: object) => void\n onError?: (event: object) => void\n onInfo?: (event: object) => void\n onMetaChange?: (event: object) => void\n onMakeActionLink?: (event: object) => void\n onRequestRefreshFile?: (event: object) => void\n onPluginsReady?: (event: object) => void\n onReady?: (event: object) => void\n onRequestClose?: (event: object) => void\n onRequestCreateNew?: (event: object) => void\n onRequestEditRights?: (event: object) => void\n onRequestHistory?: (event: object) => void\n onRequestHistoryClose?: (event: object) => void\n onRequestHistoryData?: (event: object) => void\n onRequestInsertImage?: (event: object) => void\n onRequestOpen?: (event: object) => void\n onRequestReferenceData?: (event: object) => void\n onRequestReferenceSource?: (event: object) => void\n onRequestRename?: (event: object) => void\n onRequestRestore?: (event: object) => void\n onRequestSaveAs?: (event: object) => void\n onRequestSelectDocument?: (event: object) => void\n onRequestSelectSpreadsheet?: (event: object) => void\n onRequestSendNotify?: (event: object) => void\n onRequestSharingSettings?: (event: object) => void\n onRequestStartFilling?: (event: object) => void\n onRequestUsers?: (event: object) => void\n onSubmit?: (event: object) => void\n onWarning?: (event: object) => void\n }\n}\n\nexport interface OnlyOfficeCallBack {\n /* documentation : https://api.onlyoffice.com/docs/docs-api/usage-api/callback-handler/ */\n key: string // document key\n /*\n status:\n 1 - document is being edited\n 2 - document is ready for saving\n 3 - document saving error has occurred\n 4 - document is closed with no changes\n 6 - document is being edited, but the current document state is saved\n 7 - error has occurred while force saving the document\n */\n status: 1 | 2 | 3 | 4 | 6 | 7\n url?: string // link to download the modified version (for status: 2, 3, 6 or 7)\n notmodified?: boolean // only with status 2\n /*\n actions:\n 0 - the user disconnects from the document co-editing\n 1 - the new user connects to the document co-editing\n 2 - the user clicks the forcesave button.\n */\n actions?: { type: 0 | 1 | 2; userid: string }[]\n forcesavetype?: 0 | 1 | 2 | 3 // The type is present when the status value is equal to 6 or 7 only\n /*\n forcesavetype:\n 0 - to the command service\n 1 - each time the saving is done (e.g. the Save button is clicked), which is only available when the forcesave option is set to true\n 2 - by timer with the settings from the server config\n 3 - each time the form is submitted (e.g. the Complete & Submit button is clicked)\n */\n users?: string[] // when multiple users are editing the document\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
@@ -108,7 +108,7 @@ describe(_filesmethodsservice.FilesMethods.name, ()=>{
108
108
  dstDirectory: '../../../foo',
109
109
  dstName: '../bar/../'
110
110
  };
111
- expect(()=>(0, _functions.transformAndValidate)(_fileoperationsdto.CompressFileDto, copyMoveFileDto)).toThrow();
111
+ expect(()=>(0, _functions.transformAndValidate)(_fileoperationsdto.CopyMoveFileDto, copyMoveFileDto)).toThrow();
112
112
  await expect(filesMethods.copyMove(userTest, spaceEnv, copyMoveFileDto, false)).rejects.toThrow(/is not valid/i);
113
113
  });
114
114
  it('should avoid path traversal on Compress action', async ()=>{
@@ -124,9 +124,7 @@ describe(_filesmethodsservice.FilesMethods.name, ()=>{
124
124
  extension: _compress.tarExtension
125
125
  };
126
126
  expect(()=>(0, _functions.transformAndValidate)(_fileoperationsdto.CompressFileDto, compressFileDto)).toThrow();
127
- await expect(filesMethods.compress(userTest, spaceEnv, {
128
- ...compressFileDto
129
- })).rejects.toThrow(/does not exist/i);
127
+ await expect(filesMethods.compress(userTest, spaceEnv, compressFileDto)).rejects.toThrow(/does not exist/i);
130
128
  compressFileDto.files[0].path = '../../../bar/../';
131
129
  await expect(filesMethods.compress(userTest, spaceEnv, compressFileDto)).rejects.toThrow(/is not valid/i);
132
130
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-methods.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport path from 'node:path'\nimport { transformAndValidate } from '../../../common/functions'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpaceModel } from '../../spaces/models/space.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { generateUserTest } from '../../users/utils/test'\nimport { tarExtension } from '../constants/compress'\nimport { CompressFileDto, CopyMoveFileDto } from '../dto/file-operations.dto'\nimport { FilesManager } from './files-manager.service'\nimport { FilesMethods } from './files-methods.service'\n\ndescribe(FilesMethods.name, () => {\n let filesMethods: FilesMethods\n let spacesManager: SpacesManager\n let userTest: UserModel\n const spaceEnv: Partial<SpaceEnv> = {\n id: 1,\n alias: 'project',\n name: 'project',\n enabled: true,\n permissions: 'a:d:m:so',\n role: 0,\n realBasePath: SpaceModel.getFilesPath('project'),\n realPath: path.join(SpaceModel.getFilesPath('project'), 'foo'),\n url: `${SPACE_REPOSITORY.FILES}/project/foo`\n }\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [],\n providers: [\n FilesMethods,\n SpacesManager,\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n {\n provide: Cache,\n useValue: { get: () => null }\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: UsersQueries, useValue: {} },\n { provide: SharesManager, useValue: {} },\n {\n provide: SpacesQueries,\n useValue: {\n permissions: () => spaceEnv\n }\n },\n { provide: FilesManager, useValue: {} }\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n filesMethods = module.get<FilesMethods>(FilesMethods)\n spacesManager = module.get<SpacesManager>(SpacesManager)\n userTest = new UserModel(generateUserTest())\n // mock\n spacesManager.updateSpacesQuota = jest.fn().mockReturnValue(undefined)\n })\n\n it('should be defined', () => {\n expect(filesMethods).toBeDefined()\n expect(spacesManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should avoid path traversal on CopyMove action', async () => {\n const copyMoveFileDto = { dstDirectory: '../../../foo', dstName: '../bar/../' } satisfies CopyMoveFileDto\n expect(() => transformAndValidate(CompressFileDto, copyMoveFileDto satisfies CopyMoveFileDto)).toThrow()\n await expect((filesMethods as any).copyMove(userTest, spaceEnv as SpaceEnv, copyMoveFileDto satisfies CopyMoveFileDto, false)).rejects.toThrow(\n /is not valid/i\n )\n })\n\n it('should avoid path traversal on Compress action', async () => {\n const compressFileDto: CompressFileDto = {\n name: '../../archive',\n compressInDirectory: false,\n files: [{ name: '../../foo', rootAlias: undefined }],\n extension: tarExtension as typeof tarExtension\n }\n expect(() => transformAndValidate(CompressFileDto, compressFileDto satisfies CompressFileDto)).toThrow()\n await expect(filesMethods.compress(userTest, spaceEnv as SpaceEnv, { ...(compressFileDto as CompressFileDto) })).rejects.toThrow(\n /does not exist/i\n )\n compressFileDto.files[0].path = '../../../bar/../'\n await expect(filesMethods.compress(userTest, spaceEnv as SpaceEnv, compressFileDto as CompressFileDto)).rejects.toThrow(/is not valid/i)\n })\n})\n"],"names":["describe","FilesMethods","name","filesMethods","spacesManager","userTest","spaceEnv","id","alias","enabled","permissions","role","realBasePath","SpaceModel","getFilesPath","realPath","path","join","url","SPACE_REPOSITORY","FILES","beforeAll","module","Test","createTestingModule","imports","providers","SpacesManager","provide","DB_TOKEN_PROVIDER","useValue","Cache","get","ContextManager","NotificationsManager","UsersQueries","SharesManager","SpacesQueries","FilesManager","compile","useLogger","UserModel","generateUserTest","updateSpacesQuota","jest","fn","mockReturnValue","undefined","it","expect","toBeDefined","copyMoveFileDto","dstDirectory","dstName","transformAndValidate","CompressFileDto","toThrow","copyMove","rejects","compressFileDto","compressInDirectory","files","rootAlias","extension","tarExtension","compress"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-methods.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport path from 'node:path'\nimport { transformAndValidate } from '../../../common/functions'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpaceModel } from '../../spaces/models/space.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { generateUserTest } from '../../users/utils/test'\nimport { tarExtension } from '../constants/compress'\nimport { CompressFileDto, CopyMoveFileDto } from '../dto/file-operations.dto'\nimport { FilesManager } from './files-manager.service'\nimport { FilesMethods } from './files-methods.service'\n\ndescribe(FilesMethods.name, () => {\n let filesMethods: FilesMethods\n let spacesManager: SpacesManager\n let userTest: UserModel\n const spaceEnv = {\n id: 1,\n alias: 'project',\n name: 'project',\n enabled: true,\n permissions: 'a:d:m:so',\n role: 0,\n realBasePath: SpaceModel.getFilesPath('project'),\n realPath: path.join(SpaceModel.getFilesPath('project'), 'foo'),\n url: `${SPACE_REPOSITORY.FILES}/project/foo`\n } as SpaceEnv\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [],\n providers: [\n FilesMethods,\n SpacesManager,\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n {\n provide: Cache,\n useValue: { get: () => null }\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: UsersQueries, useValue: {} },\n { provide: SharesManager, useValue: {} },\n {\n provide: SpacesQueries,\n useValue: {\n permissions: () => spaceEnv\n }\n },\n { provide: FilesManager, useValue: {} }\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n filesMethods = module.get<FilesMethods>(FilesMethods)\n spacesManager = module.get<SpacesManager>(SpacesManager)\n userTest = new UserModel(generateUserTest())\n // mock\n spacesManager.updateSpacesQuota = jest.fn().mockReturnValue(undefined)\n })\n\n it('should be defined', () => {\n expect(filesMethods).toBeDefined()\n expect(spacesManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should avoid path traversal on CopyMove action', async () => {\n const copyMoveFileDto: CopyMoveFileDto = { dstDirectory: '../../../foo', dstName: '../bar/../' }\n expect(() => transformAndValidate(CopyMoveFileDto, copyMoveFileDto)).toThrow()\n await expect((filesMethods as any).copyMove(userTest, spaceEnv, copyMoveFileDto, false)).rejects.toThrow(/is not valid/i)\n })\n\n it('should avoid path traversal on Compress action', async () => {\n const compressFileDto: CompressFileDto = {\n name: '../../archive',\n compressInDirectory: false,\n files: [{ name: '../../foo', rootAlias: undefined }],\n extension: tarExtension\n }\n expect(() => transformAndValidate(CompressFileDto, compressFileDto)).toThrow()\n await expect(filesMethods.compress(userTest, spaceEnv, compressFileDto)).rejects.toThrow(/does not exist/i)\n compressFileDto.files[0].path = '../../../bar/../'\n await expect(filesMethods.compress(userTest, spaceEnv, compressFileDto)).rejects.toThrow(/is not valid/i)\n })\n})\n"],"names":["describe","FilesMethods","name","filesMethods","spacesManager","userTest","spaceEnv","id","alias","enabled","permissions","role","realBasePath","SpaceModel","getFilesPath","realPath","path","join","url","SPACE_REPOSITORY","FILES","beforeAll","module","Test","createTestingModule","imports","providers","SpacesManager","provide","DB_TOKEN_PROVIDER","useValue","Cache","get","ContextManager","NotificationsManager","UsersQueries","SharesManager","SpacesQueries","FilesManager","compile","useLogger","UserModel","generateUserTest","updateSpacesQuota","jest","fn","mockReturnValue","undefined","it","expect","toBeDefined","copyMoveFileDto","dstDirectory","dstName","transformAndValidate","CopyMoveFileDto","toThrow","copyMove","rejects","compressFileDto","compressInDirectory","files","rootAlias","extension","tarExtension","CompressFileDto","compress"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;iEACnB;2BACoB;8BACf;uCACS;2BACG;6CACG;sCACP;wBACG;4BAEN;sCACG;sCACA;2BACJ;qCACG;sBACI;0BACJ;mCACoB;qCACpB;qCACA;;;;;;AAE7BA,SAASC,iCAAY,CAACC,IAAI,EAAE;IAC1B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,MAAMC,WAAW;QACfC,IAAI;QACJC,OAAO;QACPN,MAAM;QACNO,SAAS;QACTC,aAAa;QACbC,MAAM;QACNC,cAAcC,sBAAU,CAACC,YAAY,CAAC;QACtCC,UAAUC,iBAAI,CAACC,IAAI,CAACJ,sBAAU,CAACC,YAAY,CAAC,YAAY;QACxDI,KAAK,GAAGC,wBAAgB,CAACC,KAAK,CAAC,YAAY,CAAC;IAC9C;IAEAC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,SAAS,EAAE;YACXC,WAAW;gBACTzB,iCAAY;gBACZ0B,mCAAa;gBACb;oBAAEC,SAASC,4BAAiB;oBAAEC,UAAU,CAAC;gBAAE;gBAC3C;oBACEF,SAASG,mBAAK;oBACdD,UAAU;wBAAEE,KAAK,IAAM;oBAAK;gBAC9B;gBACA;oBAAEJ,SAASK,qCAAc;oBAAEH,UAAU,CAAC;gBAAE;gBACxC;oBACEF,SAASM,iDAAoB;oBAC7BJ,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASO,iCAAY;oBAAEL,UAAU,CAAC;gBAAE;gBACtC;oBAAEF,SAASQ,mCAAa;oBAAEN,UAAU,CAAC;gBAAE;gBACvC;oBACEF,SAASS,mCAAa;oBACtBP,UAAU;wBACRpB,aAAa,IAAMJ;oBACrB;gBACF;gBACA;oBAAEsB,SAASU,iCAAY;oBAAER,UAAU,CAAC;gBAAE;aACvC;QACH,GAAGS,OAAO;QAEVjB,OAAOkB,SAAS,CAAC;YAAC;SAAQ;QAC1BrC,eAAemB,OAAOU,GAAG,CAAe/B,iCAAY;QACpDG,gBAAgBkB,OAAOU,GAAG,CAAgBL,mCAAa;QACvDtB,WAAW,IAAIoC,oBAAS,CAACC,IAAAA,sBAAgB;QACzC,OAAO;QACPtC,cAAcuC,iBAAiB,GAAGC,KAAKC,EAAE,GAAGC,eAAe,CAACC;IAC9D;IAEAC,GAAG,qBAAqB;QACtBC,OAAO9C,cAAc+C,WAAW;QAChCD,OAAO7C,eAAe8C,WAAW;QACjCD,OAAO5C,UAAU6C,WAAW;IAC9B;IAEAF,GAAG,kDAAkD;QACnD,MAAMG,kBAAmC;YAAEC,cAAc;YAAgBC,SAAS;QAAa;QAC/FJ,OAAO,IAAMK,IAAAA,+BAAoB,EAACC,kCAAe,EAAEJ,kBAAkBK,OAAO;QAC5E,MAAMP,OAAO,AAAC9C,aAAqBsD,QAAQ,CAACpD,UAAUC,UAAU6C,iBAAiB,QAAQO,OAAO,CAACF,OAAO,CAAC;IAC3G;IAEAR,GAAG,kDAAkD;QACnD,MAAMW,kBAAmC;YACvCzD,MAAM;YACN0D,qBAAqB;YACrBC,OAAO;gBAAC;oBAAE3D,MAAM;oBAAa4D,WAAWf;gBAAU;aAAE;YACpDgB,WAAWC,sBAAY;QACzB;QACAf,OAAO,IAAMK,IAAAA,+BAAoB,EAACW,kCAAe,EAAEN,kBAAkBH,OAAO;QAC5E,MAAMP,OAAO9C,aAAa+D,QAAQ,CAAC7D,UAAUC,UAAUqD,kBAAkBD,OAAO,CAACF,OAAO,CAAC;QACzFG,gBAAgBE,KAAK,CAAC,EAAE,CAAC7C,IAAI,GAAG;QAChC,MAAMiC,OAAO9C,aAAa+D,QAAQ,CAAC7D,UAAUC,UAAUqD,kBAAkBD,OAAO,CAACF,OAAO,CAAC;IAC3F;AACF"}
@@ -36,6 +36,10 @@ let FilesRecents = class FilesRecents {
36
36
  return this.filesQueries.getRecentsFromUser(user.id, spaceIds, shareIds, limit);
37
37
  }
38
38
  async updateRecents(user, space, files) {
39
+ if (space.inTrashRepository) {
40
+ // Ignore trashed files
41
+ return;
42
+ }
39
43
  const timestamp = (0, _shared.currentTimeStamp)(null, true) - (0, _functions.convertHumanTimeToMs)(this.keepTime);
40
44
  const location = this.getLocation(user, space, files);
41
45
  // only store files, ignore dirs
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-recents.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable } from '@nestjs/common'\nimport { convertDiffUpdate, convertHumanTimeToMs, diffCollection } from '../../../common/functions'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { FileProps } from '../interfaces/file-props.interface'\nimport { FileRecentLocation } from '../interfaces/file-recent-location.interface'\nimport { FileRecent } from '../schemas/file-recent.interface'\nimport { FilesQueries } from './files-queries.service'\n\n@Injectable()\nexport class FilesRecents {\n private readonly keepTime = '14d'\n\n constructor(\n private readonly filesQueries: FilesQueries,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n async getRecents(user: UserModel, limit: number): Promise<FileRecent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n return this.filesQueries.getRecentsFromUser(user.id, spaceIds, shareIds, limit)\n }\n\n async updateRecents(user: UserModel, space: SpaceEnv, files: FileProps[]): Promise<void> {\n const timestamp = currentTimeStamp(null, true) - convertHumanTimeToMs(this.keepTime)\n const location = this.getLocation(user, space, files)\n // only store files, ignore dirs\n const fsRecents = files.filter((f) => !f.isDir && f.size > 0 && f.mtime > timestamp)\n const dbRecents = await this.filesQueries.getRecentsFromLocation(location)\n if (!fsRecents.length && !dbRecents.length) {\n return\n }\n const [add, update, remove] = diffCollection(dbRecents as any, fsRecents as any, ['mtime', 'name'])\n const toAdd: Partial<FileRecent>[] = add.map(\n (f: FileProps): Partial<FileRecent> =>\n ({\n id: f.id,\n name: f.name,\n mtime: f.mtime,\n mime: f.mime,\n ...location,\n ...(space.inSharesList && { shareId: f.root.id })\n }) as FileRecent\n )\n const toUpdate: Record<string | 'object', Partial<FileProps> | FileProps>[] = convertDiffUpdate(update)\n const toRemove: number[] = remove.map((f: FileRecent) => f.id)\n await this.filesQueries.updateRecents(location, toAdd, toUpdate, toRemove)\n }\n\n private getLocation(user: UserModel, space: SpaceEnv, files: FileProps[]): FileRecentLocation {\n const location: FileRecentLocation = { path: space.url }\n if (space.inPersonalSpace) {\n location.ownerId = user.id\n } else if (space.inSharesList) {\n location.shareId = files.map((f) => f.root.id)\n } else if (space.inSharesRepository) {\n location.shareId = space.id\n } else {\n location.spaceId = space.id\n }\n return location\n }\n}\n"],"names":["FilesRecents","getRecents","user","limit","spaceIds","shareIds","Promise","all","spacesQueries","id","sharesQueries","isAdmin","filesQueries","getRecentsFromUser","updateRecents","space","files","timestamp","currentTimeStamp","convertHumanTimeToMs","keepTime","location","getLocation","fsRecents","filter","f","isDir","size","mtime","dbRecents","getRecentsFromLocation","length","add","update","remove","diffCollection","toAdd","map","name","mime","inSharesList","shareId","root","toUpdate","convertDiffUpdate","toRemove","path","url","inPersonalSpace","ownerId","inSharesRepository","spaceId"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbc;2BAC6C;wBACvC;sCACH;sCAEA;qCAKD;;;;;;;;;;AAGtB,IAAA,AAAMA,eAAN,MAAMA;IASX,MAAMC,WAAWC,IAAe,EAAEC,KAAa,EAAyB;QACtE,MAAM,CAACC,UAAUC,SAAS,GAAG,MAAMC,QAAQC,GAAG,CAAC;YAAC,IAAI,CAACC,aAAa,CAACJ,QAAQ,CAACF,KAAKO,EAAE;YAAG,IAAI,CAACC,aAAa,CAACL,QAAQ,CAACH,KAAKO,EAAE,EAAE,CAACP,KAAKS,OAAO;SAAE;QAC1I,OAAO,IAAI,CAACC,YAAY,CAACC,kBAAkB,CAACX,KAAKO,EAAE,EAAEL,UAAUC,UAAUF;IAC3E;IAEA,MAAMW,cAAcZ,IAAe,EAAEa,KAAe,EAAEC,KAAkB,EAAiB;QACvF,MAAMC,YAAYC,IAAAA,wBAAgB,EAAC,MAAM,QAAQC,IAAAA,+BAAoB,EAAC,IAAI,CAACC,QAAQ;QACnF,MAAMC,WAAW,IAAI,CAACC,WAAW,CAACpB,MAAMa,OAAOC;QAC/C,gCAAgC;QAChC,MAAMO,YAAYP,MAAMQ,MAAM,CAAC,CAACC,IAAM,CAACA,EAAEC,KAAK,IAAID,EAAEE,IAAI,GAAG,KAAKF,EAAEG,KAAK,GAAGX;QAC1E,MAAMY,YAAY,MAAM,IAAI,CAACjB,YAAY,CAACkB,sBAAsB,CAACT;QACjE,IAAI,CAACE,UAAUQ,MAAM,IAAI,CAACF,UAAUE,MAAM,EAAE;YAC1C;QACF;QACA,MAAM,CAACC,KAAKC,QAAQC,OAAO,GAAGC,IAAAA,yBAAc,EAACN,WAAkBN,WAAkB;YAAC;YAAS;SAAO;QAClG,MAAMa,QAA+BJ,IAAIK,GAAG,CAC1C,CAACZ,IACE,CAAA;gBACChB,IAAIgB,EAAEhB,EAAE;gBACR6B,MAAMb,EAAEa,IAAI;gBACZV,OAAOH,EAAEG,KAAK;gBACdW,MAAMd,EAAEc,IAAI;gBACZ,GAAGlB,QAAQ;gBACX,GAAIN,MAAMyB,YAAY,IAAI;oBAAEC,SAAShB,EAAEiB,IAAI,CAACjC,EAAE;gBAAC,CAAC;YAClD,CAAA;QAEJ,MAAMkC,WAAwEC,IAAAA,4BAAiB,EAACX;QAChG,MAAMY,WAAqBX,OAAOG,GAAG,CAAC,CAACZ,IAAkBA,EAAEhB,EAAE;QAC7D,MAAM,IAAI,CAACG,YAAY,CAACE,aAAa,CAACO,UAAUe,OAAOO,UAAUE;IACnE;IAEQvB,YAAYpB,IAAe,EAAEa,KAAe,EAAEC,KAAkB,EAAsB;QAC5F,MAAMK,WAA+B;YAAEyB,MAAM/B,MAAMgC,GAAG;QAAC;QACvD,IAAIhC,MAAMiC,eAAe,EAAE;YACzB3B,SAAS4B,OAAO,GAAG/C,KAAKO,EAAE;QAC5B,OAAO,IAAIM,MAAMyB,YAAY,EAAE;YAC7BnB,SAASoB,OAAO,GAAGzB,MAAMqB,GAAG,CAAC,CAACZ,IAAMA,EAAEiB,IAAI,CAACjC,EAAE;QAC/C,OAAO,IAAIM,MAAMmC,kBAAkB,EAAE;YACnC7B,SAASoB,OAAO,GAAG1B,MAAMN,EAAE;QAC7B,OAAO;YACLY,SAAS8B,OAAO,GAAGpC,MAAMN,EAAE;QAC7B;QACA,OAAOY;IACT;IAjDA,YACE,AAAiBT,YAA0B,EAC3C,AAAiBJ,aAA4B,EAC7C,AAAiBE,aAA4B,CAC7C;aAHiBE,eAAAA;aACAJ,gBAAAA;aACAE,gBAAAA;aALFU,WAAW;IAMzB;AA8CL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-recents.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Injectable } from '@nestjs/common'\nimport { convertDiffUpdate, convertHumanTimeToMs, diffCollection } from '../../../common/functions'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { FileProps } from '../interfaces/file-props.interface'\nimport { FileRecentLocation } from '../interfaces/file-recent-location.interface'\nimport { FileRecent } from '../schemas/file-recent.interface'\nimport { FilesQueries } from './files-queries.service'\n\n@Injectable()\nexport class FilesRecents {\n private readonly keepTime = '14d'\n\n constructor(\n private readonly filesQueries: FilesQueries,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n async getRecents(user: UserModel, limit: number): Promise<FileRecent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n return this.filesQueries.getRecentsFromUser(user.id, spaceIds, shareIds, limit)\n }\n\n async updateRecents(user: UserModel, space: SpaceEnv, files: FileProps[]): Promise<void> {\n if (space.inTrashRepository) {\n // Ignore trashed files\n return\n }\n const timestamp = currentTimeStamp(null, true) - convertHumanTimeToMs(this.keepTime)\n const location = this.getLocation(user, space, files)\n // only store files, ignore dirs\n const fsRecents = files.filter((f) => !f.isDir && f.size > 0 && f.mtime > timestamp)\n const dbRecents = await this.filesQueries.getRecentsFromLocation(location)\n if (!fsRecents.length && !dbRecents.length) {\n return\n }\n const [add, update, remove] = diffCollection(dbRecents as any, fsRecents as any, ['mtime', 'name'])\n const toAdd: Partial<FileRecent>[] = add.map(\n (f: FileProps): Partial<FileRecent> =>\n ({\n id: f.id,\n name: f.name,\n mtime: f.mtime,\n mime: f.mime,\n ...location,\n ...(space.inSharesList && { shareId: f.root.id })\n }) as FileRecent\n )\n const toUpdate: Record<string | 'object', Partial<FileProps> | FileProps>[] = convertDiffUpdate(update)\n const toRemove: number[] = remove.map((f: FileRecent) => f.id)\n await this.filesQueries.updateRecents(location, toAdd, toUpdate, toRemove)\n }\n\n private getLocation(user: UserModel, space: SpaceEnv, files: FileProps[]): FileRecentLocation {\n const location: FileRecentLocation = { path: space.url }\n if (space.inPersonalSpace) {\n location.ownerId = user.id\n } else if (space.inSharesList) {\n location.shareId = files.map((f) => f.root.id)\n } else if (space.inSharesRepository) {\n location.shareId = space.id\n } else {\n location.spaceId = space.id\n }\n return location\n }\n}\n"],"names":["FilesRecents","getRecents","user","limit","spaceIds","shareIds","Promise","all","spacesQueries","id","sharesQueries","isAdmin","filesQueries","getRecentsFromUser","updateRecents","space","files","inTrashRepository","timestamp","currentTimeStamp","convertHumanTimeToMs","keepTime","location","getLocation","fsRecents","filter","f","isDir","size","mtime","dbRecents","getRecentsFromLocation","length","add","update","remove","diffCollection","toAdd","map","name","mime","inSharesList","shareId","root","toUpdate","convertDiffUpdate","toRemove","path","url","inPersonalSpace","ownerId","inSharesRepository","spaceId"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbc;2BAC6C;wBACvC;sCACH;sCAEA;qCAKD;;;;;;;;;;AAGtB,IAAA,AAAMA,eAAN,MAAMA;IASX,MAAMC,WAAWC,IAAe,EAAEC,KAAa,EAAyB;QACtE,MAAM,CAACC,UAAUC,SAAS,GAAG,MAAMC,QAAQC,GAAG,CAAC;YAAC,IAAI,CAACC,aAAa,CAACJ,QAAQ,CAACF,KAAKO,EAAE;YAAG,IAAI,CAACC,aAAa,CAACL,QAAQ,CAACH,KAAKO,EAAE,EAAE,CAACP,KAAKS,OAAO;SAAE;QAC1I,OAAO,IAAI,CAACC,YAAY,CAACC,kBAAkB,CAACX,KAAKO,EAAE,EAAEL,UAAUC,UAAUF;IAC3E;IAEA,MAAMW,cAAcZ,IAAe,EAAEa,KAAe,EAAEC,KAAkB,EAAiB;QACvF,IAAID,MAAME,iBAAiB,EAAE;YAC3B,uBAAuB;YACvB;QACF;QACA,MAAMC,YAAYC,IAAAA,wBAAgB,EAAC,MAAM,QAAQC,IAAAA,+BAAoB,EAAC,IAAI,CAACC,QAAQ;QACnF,MAAMC,WAAW,IAAI,CAACC,WAAW,CAACrB,MAAMa,OAAOC;QAC/C,gCAAgC;QAChC,MAAMQ,YAAYR,MAAMS,MAAM,CAAC,CAACC,IAAM,CAACA,EAAEC,KAAK,IAAID,EAAEE,IAAI,GAAG,KAAKF,EAAEG,KAAK,GAAGX;QAC1E,MAAMY,YAAY,MAAM,IAAI,CAAClB,YAAY,CAACmB,sBAAsB,CAACT;QACjE,IAAI,CAACE,UAAUQ,MAAM,IAAI,CAACF,UAAUE,MAAM,EAAE;YAC1C;QACF;QACA,MAAM,CAACC,KAAKC,QAAQC,OAAO,GAAGC,IAAAA,yBAAc,EAACN,WAAkBN,WAAkB;YAAC;YAAS;SAAO;QAClG,MAAMa,QAA+BJ,IAAIK,GAAG,CAC1C,CAACZ,IACE,CAAA;gBACCjB,IAAIiB,EAAEjB,EAAE;gBACR8B,MAAMb,EAAEa,IAAI;gBACZV,OAAOH,EAAEG,KAAK;gBACdW,MAAMd,EAAEc,IAAI;gBACZ,GAAGlB,QAAQ;gBACX,GAAIP,MAAM0B,YAAY,IAAI;oBAAEC,SAAShB,EAAEiB,IAAI,CAAClC,EAAE;gBAAC,CAAC;YAClD,CAAA;QAEJ,MAAMmC,WAAwEC,IAAAA,4BAAiB,EAACX;QAChG,MAAMY,WAAqBX,OAAOG,GAAG,CAAC,CAACZ,IAAkBA,EAAEjB,EAAE;QAC7D,MAAM,IAAI,CAACG,YAAY,CAACE,aAAa,CAACQ,UAAUe,OAAOO,UAAUE;IACnE;IAEQvB,YAAYrB,IAAe,EAAEa,KAAe,EAAEC,KAAkB,EAAsB;QAC5F,MAAMM,WAA+B;YAAEyB,MAAMhC,MAAMiC,GAAG;QAAC;QACvD,IAAIjC,MAAMkC,eAAe,EAAE;YACzB3B,SAAS4B,OAAO,GAAGhD,KAAKO,EAAE;QAC5B,OAAO,IAAIM,MAAM0B,YAAY,EAAE;YAC7BnB,SAASoB,OAAO,GAAG1B,MAAMsB,GAAG,CAAC,CAACZ,IAAMA,EAAEiB,IAAI,CAAClC,EAAE;QAC/C,OAAO,IAAIM,MAAMoC,kBAAkB,EAAE;YACnC7B,SAASoB,OAAO,GAAG3B,MAAMN,EAAE;QAC7B,OAAO;YACLa,SAAS8B,OAAO,GAAGrC,MAAMN,EAAE;QAC7B;QACA,OAAOa;IACT;IArDA,YACE,AAAiBV,YAA0B,EAC3C,AAAiBJ,aAA4B,EAC7C,AAAiBE,aAA4B,CAC7C;aAHiBE,eAAAA;aACAJ,gBAAAA;aACAE,gBAAAA;aALFW,WAAW;IAMzB;AAkDL"}
@@ -53,6 +53,21 @@ function _ts_param(paramIndex, decorator) {
53
53
  };
54
54
  }
55
55
  let FilesScheduler = class FilesScheduler {
56
+ async onStartup() {
57
+ try {
58
+ await this.cleanupInterruptedTasks();
59
+ await this.clearRecentFiles();
60
+ } catch (e) {
61
+ this.logger.error(e);
62
+ }
63
+ }
64
+ async afterStartup() {
65
+ try {
66
+ await this.indexContentFiles();
67
+ } catch (e) {
68
+ this.logger.error(e);
69
+ }
70
+ }
56
71
  async cleanupInterruptedTasks() {
57
72
  this.logger.log(`${this.cleanupInterruptedTasks.name} - START`);
58
73
  try {
@@ -182,11 +197,17 @@ let FilesScheduler = class FilesScheduler {
182
197
  }
183
198
  };
184
199
  _ts_decorate([
185
- (0, _schedule.Timeout)(30000),
200
+ (0, _schedule.Timeout)(30_000),
201
+ _ts_metadata("design:type", Function),
202
+ _ts_metadata("design:paramtypes", []),
203
+ _ts_metadata("design:returntype", Promise)
204
+ ], FilesScheduler.prototype, "onStartup", null);
205
+ _ts_decorate([
206
+ (0, _schedule.Timeout)(180_000),
186
207
  _ts_metadata("design:type", Function),
187
208
  _ts_metadata("design:paramtypes", []),
188
209
  _ts_metadata("design:returntype", Promise)
189
- ], FilesScheduler.prototype, "cleanupInterruptedTasks", null);
210
+ ], FilesScheduler.prototype, "afterStartup", null);
190
211
  _ts_decorate([
191
212
  (0, _schedule.Cron)(_schedule.CronExpression.EVERY_DAY_AT_MIDNIGHT),
192
213
  _ts_metadata("design:type", Function),
@@ -194,14 +215,12 @@ _ts_decorate([
194
215
  _ts_metadata("design:returntype", Promise)
195
216
  ], FilesScheduler.prototype, "cleanupUserTaskFiles", null);
196
217
  _ts_decorate([
197
- (0, _schedule.Timeout)(30000),
198
218
  (0, _schedule.Cron)(_schedule.CronExpression.EVERY_8_HOURS),
199
219
  _ts_metadata("design:type", Function),
200
220
  _ts_metadata("design:paramtypes", []),
201
221
  _ts_metadata("design:returntype", Promise)
202
222
  ], FilesScheduler.prototype, "clearRecentFiles", null);
203
223
  _ts_decorate([
204
- (0, _schedule.Timeout)(120000),
205
224
  (0, _schedule.Cron)(_schedule.CronExpression.EVERY_4_HOURS),
206
225
  _ts_metadata("design:type", Function),
207
226
  _ts_metadata("design:paramtypes", []),
@@ -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 { 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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"}
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(30_000)\n async onStartup(): Promise<void> {\n try {\n await this.cleanupInterruptedTasks()\n await this.clearRecentFiles()\n } catch (e) {\n this.logger.error(e)\n }\n }\n\n @Timeout(180_000)\n async afterStartup(): Promise<void> {\n try {\n await this.indexContentFiles()\n } catch (e) {\n this.logger.error(e)\n }\n }\n\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 @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 @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","onStartup","cleanupInterruptedTasks","clearRecentFiles","e","logger","error","afterStartup","indexContentFiles","log","name","nb","keys","cache","CACHE_TASK_PREFIX","key","task","get","status","FileTaskStatus","PENDING","ERROR","result","set","catch","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","keepNumber","nbCleared","fk","filesRecents","ownerId","spaceId","shareId","r","execute","sql","mtime","affectedRows","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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"}
@@ -26,6 +26,9 @@ function _ts_metadata(k, v) {
26
26
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
27
27
  }
28
28
  let SpacesScheduler = class SpacesScheduler {
29
+ async onStartup() {
30
+ await this.updateQuotas();
31
+ }
29
32
  async updateQuotas() {
30
33
  this.logger.log('Update Personal Quotas - START');
31
34
  try {
@@ -65,7 +68,12 @@ let SpacesScheduler = class SpacesScheduler {
65
68
  }
66
69
  };
67
70
  _ts_decorate([
68
- (0, _schedule.Timeout)(60000),
71
+ (0, _schedule.Timeout)(60_000),
72
+ _ts_metadata("design:type", Function),
73
+ _ts_metadata("design:paramtypes", []),
74
+ _ts_metadata("design:returntype", Promise)
75
+ ], SpacesScheduler.prototype, "onStartup", null);
76
+ _ts_decorate([
69
77
  (0, _schedule.Cron)(_schedule.CronExpression.EVERY_HOUR),
70
78
  _ts_metadata("design:type", Function),
71
79
  _ts_metadata("design:paramtypes", []),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/spaces/services/spaces-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 { Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SpacesManager } from './spaces-manager.service'\n\n@Injectable()\nexport class SpacesScheduler {\n private readonly logger = new Logger(SpacesScheduler.name)\n\n constructor(\n private readonly spacesManager: SpacesManager,\n private readonly sharesManager: SharesManager\n ) {}\n\n @Timeout(60000)\n @Cron(CronExpression.EVERY_HOUR)\n async updateQuotas() {\n this.logger.log('Update Personal Quotas - START')\n try {\n await this.spacesManager.updatePersonalSpacesQuota()\n } catch (e) {\n this.logger.error(`Update Personal Quotas} - ${e}`)\n }\n this.logger.log('Update Personal Quotas - END')\n this.logger.log('Update Space Quotas - START')\n try {\n await this.spacesManager.updateSpacesQuota()\n } catch (e) {\n this.logger.error(`Update Space Quotas - ${e}`)\n }\n this.logger.log('Update Space Quotas - END')\n this.logger.log('Update Share External Path Quotas - START')\n try {\n await this.sharesManager.updateSharesExternalPathQuota()\n } catch (e) {\n this.logger.error(`Update Share External Path Quotas - ${e}`)\n }\n this.logger.log('Update Share External Path Quotas - END')\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_2AM)\n async deleteExpiredSpaces() {\n /* Removes spaces that have been disabled for more than 30 days */\n this.logger.log(`${this.deleteExpiredSpaces.name} - START`)\n try {\n await this.spacesManager.deleteExpiredSpaces()\n } catch (e) {\n this.logger.error(`${this.deleteExpiredSpaces.name} - ${e}`)\n }\n this.logger.log(`${this.deleteExpiredSpaces.name} - DONE`)\n }\n}\n"],"names":["SpacesScheduler","updateQuotas","logger","log","spacesManager","updatePersonalSpacesQuota","e","error","updateSpacesQuota","sharesManager","updateSharesExternalPathQuota","deleteExpiredSpaces","name","Logger","EVERY_HOUR","EVERY_DAY_AT_2AM"],"mappings":"AAAA;;;;CAIC;;;;+BAQYA;;;eAAAA;;;wBANsB;0BACW;sCAChB;sCACA;;;;;;;;;;AAGvB,IAAA,AAAMA,kBAAN,MAAMA;IAQX,MAEMC,eAAe;QACnB,IAAI,CAACC,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACC,aAAa,CAACC,yBAAyB;QACpD,EAAE,OAAOC,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,0BAA0B,EAAED,GAAG;QACpD;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI,CAACD,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACC,aAAa,CAACI,iBAAiB;QAC5C,EAAE,OAAOF,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,sBAAsB,EAAED,GAAG;QAChD;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI,CAACD,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACM,aAAa,CAACC,6BAA6B;QACxD,EAAE,OAAOJ,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,oCAAoC,EAAED,GAAG;QAC9D;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;IAClB;IAEA,MACMQ,sBAAsB;QAC1B,gEAAgE,GAChE,IAAI,CAACT,MAAM,CAACC,GAAG,CAAC,GAAG,IAAI,CAACQ,mBAAmB,CAACC,IAAI,CAAC,QAAQ,CAAC;QAC1D,IAAI;YACF,MAAM,IAAI,CAACR,aAAa,CAACO,mBAAmB;QAC9C,EAAE,OAAOL,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,GAAG,IAAI,CAACI,mBAAmB,CAACC,IAAI,CAAC,GAAG,EAAEN,GAAG;QAC7D;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC,GAAG,IAAI,CAACQ,mBAAmB,CAACC,IAAI,CAAC,OAAO,CAAC;IAC3D;IAzCA,YACE,AAAiBR,aAA4B,EAC7C,AAAiBK,aAA4B,CAC7C;aAFiBL,gBAAAA;aACAK,gBAAAA;aAJFP,SAAS,IAAIW,cAAM,CAACb,gBAAgBY,IAAI;IAKtD;AAuCL;;;iDApCuBE;;;;;;iDAyBAC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/spaces/services/spaces-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 { Injectable, Logger } from '@nestjs/common'\nimport { Cron, CronExpression, Timeout } from '@nestjs/schedule'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SpacesManager } from './spaces-manager.service'\n\n@Injectable()\nexport class SpacesScheduler {\n private readonly logger = new Logger(SpacesScheduler.name)\n\n constructor(\n private readonly spacesManager: SpacesManager,\n private readonly sharesManager: SharesManager\n ) {}\n\n @Timeout(60_000)\n async onStartup() {\n await this.updateQuotas()\n }\n\n @Cron(CronExpression.EVERY_HOUR)\n async updateQuotas() {\n this.logger.log('Update Personal Quotas - START')\n try {\n await this.spacesManager.updatePersonalSpacesQuota()\n } catch (e) {\n this.logger.error(`Update Personal Quotas} - ${e}`)\n }\n this.logger.log('Update Personal Quotas - END')\n this.logger.log('Update Space Quotas - START')\n try {\n await this.spacesManager.updateSpacesQuota()\n } catch (e) {\n this.logger.error(`Update Space Quotas - ${e}`)\n }\n this.logger.log('Update Space Quotas - END')\n this.logger.log('Update Share External Path Quotas - START')\n try {\n await this.sharesManager.updateSharesExternalPathQuota()\n } catch (e) {\n this.logger.error(`Update Share External Path Quotas - ${e}`)\n }\n this.logger.log('Update Share External Path Quotas - END')\n }\n\n @Cron(CronExpression.EVERY_DAY_AT_2AM)\n async deleteExpiredSpaces() {\n /* Removes spaces that have been disabled for more than 30 days */\n this.logger.log(`${this.deleteExpiredSpaces.name} - START`)\n try {\n await this.spacesManager.deleteExpiredSpaces()\n } catch (e) {\n this.logger.error(`${this.deleteExpiredSpaces.name} - ${e}`)\n }\n this.logger.log(`${this.deleteExpiredSpaces.name} - DONE`)\n }\n}\n"],"names":["SpacesScheduler","onStartup","updateQuotas","logger","log","spacesManager","updatePersonalSpacesQuota","e","error","updateSpacesQuota","sharesManager","updateSharesExternalPathQuota","deleteExpiredSpaces","name","Logger","EVERY_HOUR","EVERY_DAY_AT_2AM"],"mappings":"AAAA;;;;CAIC;;;;+BAQYA;;;eAAAA;;;wBANsB;0BACW;sCAChB;sCACA;;;;;;;;;;AAGvB,IAAA,AAAMA,kBAAN,MAAMA;IAQX,MACMC,YAAY;QAChB,MAAM,IAAI,CAACC,YAAY;IACzB;IAEA,MACMA,eAAe;QACnB,IAAI,CAACC,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACC,aAAa,CAACC,yBAAyB;QACpD,EAAE,OAAOC,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,0BAA0B,EAAED,GAAG;QACpD;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI,CAACD,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACC,aAAa,CAACI,iBAAiB;QAC5C,EAAE,OAAOF,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,sBAAsB,EAAED,GAAG;QAChD;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI,CAACD,MAAM,CAACC,GAAG,CAAC;QAChB,IAAI;YACF,MAAM,IAAI,CAACM,aAAa,CAACC,6BAA6B;QACxD,EAAE,OAAOJ,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,CAAC,oCAAoC,EAAED,GAAG;QAC9D;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC;IAClB;IAEA,MACMQ,sBAAsB;QAC1B,gEAAgE,GAChE,IAAI,CAACT,MAAM,CAACC,GAAG,CAAC,GAAG,IAAI,CAACQ,mBAAmB,CAACC,IAAI,CAAC,QAAQ,CAAC;QAC1D,IAAI;YACF,MAAM,IAAI,CAACR,aAAa,CAACO,mBAAmB;QAC9C,EAAE,OAAOL,GAAG;YACV,IAAI,CAACJ,MAAM,CAACK,KAAK,CAAC,GAAG,IAAI,CAACI,mBAAmB,CAACC,IAAI,CAAC,GAAG,EAAEN,GAAG;QAC7D;QACA,IAAI,CAACJ,MAAM,CAACC,GAAG,CAAC,GAAG,IAAI,CAACQ,mBAAmB,CAACC,IAAI,CAAC,OAAO,CAAC;IAC3D;IA7CA,YACE,AAAiBR,aAA4B,EAC7C,AAAiBK,aAA4B,CAC7C;aAFiBL,gBAAAA;aACAK,gBAAAA;aAJFP,SAAS,IAAIW,cAAM,CAACd,gBAAgBa,IAAI;IAKtD;AA2CL;;;;;;;;iDApCuBE;;;;;;iDAyBAC"}
@@ -1 +1 @@
1
- import{a as ie,b as ne,c as ae}from"./chunk-2CAAJBRO.js";import{Ab as te,qb as I,s as q,xb as D,yb as $,zb as ee}from"./chunk-L3PDWJZ3.js";import{Ae as T,Cd as B,Ed as j,Gb as _,Jd as k,Jf as Z,Kd as G,Ld as x,Oa as t,Rb as P,Sb as s,Tb as r,Ub as M,Vb as R,Wd as J,Xb as g,Yb as y,Ye as X,Zb as h,Zf as N,ab as u,cc as d,fd as H,ja as O,jd as w,kc as L,lb as C,mb as f,mc as Y,od as F,og as v,qd as z,qe as K,rb as a,sb as i,se as Q,tb as l,ub as m,ud as b,vd as W,wd as U,xd as V}from"./chunk-BJARRIS6.js";function se(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltDown)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function ce(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.LOCAL]),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.LOCAL])}}function re(o,p){if(o&1&&C(0,se,1,2,"fa-icon",1)(1,ce,1,3,"fa-icon",2),o&2){let n=_();f(n.small?0:1)}}function de(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltUp)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function pe(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.REMOTE]),P("ms-1",n.syncPath.settings.mode===n.SYNC_PATH_MODE.BOTH),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.REMOTE])}}function me(o,p){if(o&1&&C(0,de,1,2,"fa-icon",1)(1,pe,1,5,"fa-icon",4),o&2){let n=_();f(n.small?0:1)}}var oe=(()=>{let p=class p{constructor(){this.small=!1,this.SYNC_PATH_MODE=D,this.SYNC_TRANSFER_SIDE_ICON=ae,this.icons={faLongArrowAltDown:N,faLongArrowAltUp:T},this.SYNC_TRANSFER_SIDE=ie,this.SYNC_TRANSFER_SIDE_CLASS=ne}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-direction-icon"]],inputs:{syncPath:"syncPath",small:"small"},decls:3,vars:2,consts:[[1,"d-flex","justify-content-center"],[3,"icon","fixedWidth"],[3,"icon","class"],[3,"icon"],[3,"icon","ms-1","class"]],template:function(S,e){S&1&&(i(0,"span",0),C(1,re,2,1),C(2,me,2,1),l()),S&2&&(t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.DOWNLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?1:-1),t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.UPLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?2:-1))},dependencies:[v],encapsulation:2});let o=p;return o})();function _e(o,p){if(o&1&&(i(0,"div")(1,"div"),m(2,"fa-icon",0),i(3,"span",1),r(4,"Client"),l()(),i(5,"div",10)(6,"span",11),r(7),l()()(),i(8,"div")(9,"div"),m(10,"fa-icon",0),i(11,"span",1),r(12,"Server"),l()(),i(13,"div",10)(14,"span",11)(15,"div",12),m(16,"fa-icon",13),r(17),l()()()()),o&2){let n=_();s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.CLIENT),t(5),M(n.syncPath.settings.localPath),t(),s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.SERVER),t(6),a("icon",n.syncPath.icon),t(),R(" ",n.syncPath.showedPath," ")}}function Se(o,p){if(o&1&&(i(0,"span",4),m(1,"fa-icon",14),L(2,"translate"),l()),o&2){let n=_();t(),a("icon",n.icons.faExclamationCircle)("tooltip",Y(2,2,"You must have permission to modify the server folder to choose a different sync mode",n.locale.language))}}var Le=(()=>{let p=class p{constructor(){this.direction="center",this.showPaths=!1,this.size="small",this.locale=O(j),this.icons={CLIENT:I.CLIENT,SERVER:I.SERVER,faExclamationCircle:X,faLongArrowAltDown:N,faLongArrowAltUp:T,faGauge:J,faClock:Q,faRotate:x,faEdit:K,faBug:Z},this.colSize={small:[2,5],large:[3,6]},this.SYNC_PATH_CONFLICT_MODE=ee,this.SYNC_PATH_MODE=D,this.SYNC_PATH_DIFF_MODE=$,this.SYNC_PATH_SCHEDULER_UNIT=te}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-settings"]],inputs:{syncPath:"syncPath",direction:"direction",showPaths:"showPaths",size:"size"},decls:74,vars:98,consts:[[3,"icon"],["l10nTranslate","",1,"ms-2"],["type","text",3,"ngModelChange","ngModel"],[3,"syncPath","small"],[1,"ms-2","fs-lg","cursor-pointer"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel"],["l10nTranslate","",3,"disabled","ngValue"],["l10nTranslate","",3,"ngValue"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel","disabled"],["min","1","type","number",1,"form-control","form-select-sm","pe-1","me-2",2,"width","70px",3,"ngModelChange","ngModel","disabled"],[1,"col-8"],[1,"form-control-sm","form-control-plaintext"],[1,"d-flex","align-items-center"],[1,"me-1",3,"icon"],[1,"text-warning",3,"icon","tooltip"]],template:function(S,e){S&1&&(i(0,"div"),C(1,_e,18,17),i(2,"div")(3,"div"),m(4,"fa-icon",0),i(5,"span",1),r(6,"Name"),l()(),i(7,"div")(8,"input",2),h("ngModelChange",function(c){return y(e.syncPath.settings.name,c)||(e.syncPath.settings.name=c),c}),l()()(),i(9,"div")(10,"div"),m(11,"app-sync-path-direction-icon",3),i(12,"span",1),r(13,"Direction"),l(),C(14,Se,3,5,"span",4),l(),i(15,"div")(16,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.mode,c)||(e.syncPath.settings.mode=c),c}),i(17,"option",6),r(18,"upload only"),l(),i(19,"option",7),r(20,"download only"),l(),i(21,"option",6),r(22,"both"),l()()()(),i(23,"div")(24,"div"),m(25,"fa-icon",0),i(26,"span",1),r(27,"Conflict"),l()(),i(28,"div")(29,"select",8),h("ngModelChange",function(c){return y(e.syncPath.settings.conflictMode,c)||(e.syncPath.settings.conflictMode=c),c}),i(30,"option",7),r(31,"the client\u2019s files take precedence"),l(),i(32,"option",7),r(33,"the server\u2019s files take precedence"),l(),i(34,"option",7),r(35,"the most recent files will be kept"),l()()()(),i(36,"div")(37,"div"),m(38,"fa-icon",0),i(39,"span",1),r(40,"Mode"),l()(),i(41,"div")(42,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.diffMode,c)||(e.syncPath.settings.diffMode=c),c}),i(43,"option",7),r(44),l(),i(45,"option",7),r(46),l()()()(),i(47,"div")(48,"div"),m(49,"fa-icon",0),i(50,"span",1),r(51,"Scheduler"),l()(),i(52,"div")(53,"input",9),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.value,c)||(e.syncPath.settings.scheduler.value=c),c}),l(),i(54,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.unit,c)||(e.syncPath.settings.scheduler.unit=c),c}),i(55,"option",7),r(56,"disabled"),l(),i(57,"option",7),r(58,"scheduler_unit_minute"),l(),i(59,"option",7),r(60,"scheduler_unit_hour"),l(),i(61,"option",7),r(62,"scheduler_unit_day"),l()()()(),i(63,"div")(64,"div"),m(65,"fa-icon",0),i(66,"span",1),r(67,"Status"),l()(),i(68,"div")(69,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.enabled,c)||(e.syncPath.settings.enabled=c),c}),i(70,"option",7),r(71,"enabled"),l(),i(72,"option",7),r(73,"disabled"),l()()()()()),S&2&&(s(d("d-flex flex-column justify-content-",e.direction)),t(),f(e.showPaths?1:-1),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faEdit),t(3),s(d("col-",e.colSize[e.size][1])),t(),s(d("form-control form-select-sm ",e.syncPath.settings.name?"":"is-invalid")),g("ngModel",e.syncPath.settings.name),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("d-flex align-items-center col-",e.colSize[e.size][0])),t(),a("syncPath",e.syncPath)("small",!0),t(3),f(e.syncPath.isWriteable?-1:14),t(),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.mode),t(),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.UPLOAD),t(2),a("ngValue",e.SYNC_PATH_MODE.DOWNLOAD),t(2),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.BOTH),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faBug),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.conflictMode),a("disabled",e.syncPath.settings.mode!=="both"),t(),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.LOCAL),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.REMOTE),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.RECENT),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faGauge),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.diffMode),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.FAST),t(),M(e.SYNC_PATH_DIFF_MODE.FAST),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.SECURE),t(),M(e.SYNC_PATH_DIFF_MODE.SECURE),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faClock),t(3),s(d("d-flex flex-row col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.scheduler.value),a("disabled",e.syncPath.settings.scheduler.unit===e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(),g("ngModel",e.syncPath.settings.scheduler.unit),t(),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.MINUTE),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.HOUR),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DAY),t(2),s(d("d-flex justify-content-",e.direction," align-items-center")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faRotate),t(3),s(d("col-",e.colSize[e.size][1])),t(),P("text-danger",!e.syncPath.settings.enabled),g("ngModel",e.syncPath.settings.enabled),t(),a("ngValue",!0),t(2),a("ngValue",!1))},dependencies:[G,v,B,W,U,H,z,b,w,V,F,q,oe,k],encapsulation:2});let o=p;return o})();export{oe as a,Le as b};
1
+ import{a as ie,b as ne,c as ae}from"./chunk-2CAAJBRO.js";import{Ab as te,qb as I,s as q,xb as D,yb as $,zb as ee}from"./chunk-FCR5AEHR.js";import{Ae as T,Cd as B,Ed as j,Gb as _,Jd as k,Jf as Z,Kd as G,Ld as x,Oa as t,Rb as P,Sb as s,Tb as r,Ub as M,Vb as R,Wd as J,Xb as g,Yb as y,Ye as X,Zb as h,Zf as N,ab as u,cc as d,fd as H,ja as O,jd as w,kc as L,lb as C,mb as f,mc as Y,od as F,og as v,qd as z,qe as K,rb as a,sb as i,se as Q,tb as l,ub as m,ud as b,vd as W,wd as U,xd as V}from"./chunk-BJARRIS6.js";function se(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltDown)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function ce(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.LOCAL]),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.LOCAL])}}function re(o,p){if(o&1&&C(0,se,1,2,"fa-icon",1)(1,ce,1,3,"fa-icon",2),o&2){let n=_();f(n.small?0:1)}}function de(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltUp)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function pe(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.REMOTE]),P("ms-1",n.syncPath.settings.mode===n.SYNC_PATH_MODE.BOTH),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.REMOTE])}}function me(o,p){if(o&1&&C(0,de,1,2,"fa-icon",1)(1,pe,1,5,"fa-icon",4),o&2){let n=_();f(n.small?0:1)}}var oe=(()=>{let p=class p{constructor(){this.small=!1,this.SYNC_PATH_MODE=D,this.SYNC_TRANSFER_SIDE_ICON=ae,this.icons={faLongArrowAltDown:N,faLongArrowAltUp:T},this.SYNC_TRANSFER_SIDE=ie,this.SYNC_TRANSFER_SIDE_CLASS=ne}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-direction-icon"]],inputs:{syncPath:"syncPath",small:"small"},decls:3,vars:2,consts:[[1,"d-flex","justify-content-center"],[3,"icon","fixedWidth"],[3,"icon","class"],[3,"icon"],[3,"icon","ms-1","class"]],template:function(S,e){S&1&&(i(0,"span",0),C(1,re,2,1),C(2,me,2,1),l()),S&2&&(t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.DOWNLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?1:-1),t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.UPLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?2:-1))},dependencies:[v],encapsulation:2});let o=p;return o})();function _e(o,p){if(o&1&&(i(0,"div")(1,"div"),m(2,"fa-icon",0),i(3,"span",1),r(4,"Client"),l()(),i(5,"div",10)(6,"span",11),r(7),l()()(),i(8,"div")(9,"div"),m(10,"fa-icon",0),i(11,"span",1),r(12,"Server"),l()(),i(13,"div",10)(14,"span",11)(15,"div",12),m(16,"fa-icon",13),r(17),l()()()()),o&2){let n=_();s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.CLIENT),t(5),M(n.syncPath.settings.localPath),t(),s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.SERVER),t(6),a("icon",n.syncPath.icon),t(),R(" ",n.syncPath.showedPath," ")}}function Se(o,p){if(o&1&&(i(0,"span",4),m(1,"fa-icon",14),L(2,"translate"),l()),o&2){let n=_();t(),a("icon",n.icons.faExclamationCircle)("tooltip",Y(2,2,"You must have permission to modify the server folder to choose a different sync mode",n.locale.language))}}var Le=(()=>{let p=class p{constructor(){this.direction="center",this.showPaths=!1,this.size="small",this.locale=O(j),this.icons={CLIENT:I.CLIENT,SERVER:I.SERVER,faExclamationCircle:X,faLongArrowAltDown:N,faLongArrowAltUp:T,faGauge:J,faClock:Q,faRotate:x,faEdit:K,faBug:Z},this.colSize={small:[2,5],large:[3,6]},this.SYNC_PATH_CONFLICT_MODE=ee,this.SYNC_PATH_MODE=D,this.SYNC_PATH_DIFF_MODE=$,this.SYNC_PATH_SCHEDULER_UNIT=te}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-settings"]],inputs:{syncPath:"syncPath",direction:"direction",showPaths:"showPaths",size:"size"},decls:74,vars:98,consts:[[3,"icon"],["l10nTranslate","",1,"ms-2"],["type","text",3,"ngModelChange","ngModel"],[3,"syncPath","small"],[1,"ms-2","fs-lg","cursor-pointer"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel"],["l10nTranslate","",3,"disabled","ngValue"],["l10nTranslate","",3,"ngValue"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel","disabled"],["min","1","type","number",1,"form-control","form-select-sm","pe-1","me-2",2,"width","70px",3,"ngModelChange","ngModel","disabled"],[1,"col-8"],[1,"form-control-sm","form-control-plaintext"],[1,"d-flex","align-items-center"],[1,"me-1",3,"icon"],[1,"text-warning",3,"icon","tooltip"]],template:function(S,e){S&1&&(i(0,"div"),C(1,_e,18,17),i(2,"div")(3,"div"),m(4,"fa-icon",0),i(5,"span",1),r(6,"Name"),l()(),i(7,"div")(8,"input",2),h("ngModelChange",function(c){return y(e.syncPath.settings.name,c)||(e.syncPath.settings.name=c),c}),l()()(),i(9,"div")(10,"div"),m(11,"app-sync-path-direction-icon",3),i(12,"span",1),r(13,"Direction"),l(),C(14,Se,3,5,"span",4),l(),i(15,"div")(16,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.mode,c)||(e.syncPath.settings.mode=c),c}),i(17,"option",6),r(18,"upload only"),l(),i(19,"option",7),r(20,"download only"),l(),i(21,"option",6),r(22,"both"),l()()()(),i(23,"div")(24,"div"),m(25,"fa-icon",0),i(26,"span",1),r(27,"Conflict"),l()(),i(28,"div")(29,"select",8),h("ngModelChange",function(c){return y(e.syncPath.settings.conflictMode,c)||(e.syncPath.settings.conflictMode=c),c}),i(30,"option",7),r(31,"the client\u2019s files take precedence"),l(),i(32,"option",7),r(33,"the server\u2019s files take precedence"),l(),i(34,"option",7),r(35,"the most recent files will be kept"),l()()()(),i(36,"div")(37,"div"),m(38,"fa-icon",0),i(39,"span",1),r(40,"Mode"),l()(),i(41,"div")(42,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.diffMode,c)||(e.syncPath.settings.diffMode=c),c}),i(43,"option",7),r(44),l(),i(45,"option",7),r(46),l()()()(),i(47,"div")(48,"div"),m(49,"fa-icon",0),i(50,"span",1),r(51,"Scheduler"),l()(),i(52,"div")(53,"input",9),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.value,c)||(e.syncPath.settings.scheduler.value=c),c}),l(),i(54,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.unit,c)||(e.syncPath.settings.scheduler.unit=c),c}),i(55,"option",7),r(56,"disabled"),l(),i(57,"option",7),r(58,"scheduler_unit_minute"),l(),i(59,"option",7),r(60,"scheduler_unit_hour"),l(),i(61,"option",7),r(62,"scheduler_unit_day"),l()()()(),i(63,"div")(64,"div"),m(65,"fa-icon",0),i(66,"span",1),r(67,"Status"),l()(),i(68,"div")(69,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.enabled,c)||(e.syncPath.settings.enabled=c),c}),i(70,"option",7),r(71,"enabled"),l(),i(72,"option",7),r(73,"disabled"),l()()()()()),S&2&&(s(d("d-flex flex-column justify-content-",e.direction)),t(),f(e.showPaths?1:-1),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faEdit),t(3),s(d("col-",e.colSize[e.size][1])),t(),s(d("form-control form-select-sm ",e.syncPath.settings.name?"":"is-invalid")),g("ngModel",e.syncPath.settings.name),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("d-flex align-items-center col-",e.colSize[e.size][0])),t(),a("syncPath",e.syncPath)("small",!0),t(3),f(e.syncPath.isWriteable?-1:14),t(),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.mode),t(),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.UPLOAD),t(2),a("ngValue",e.SYNC_PATH_MODE.DOWNLOAD),t(2),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.BOTH),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faBug),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.conflictMode),a("disabled",e.syncPath.settings.mode!=="both"),t(),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.LOCAL),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.REMOTE),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.RECENT),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faGauge),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.diffMode),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.FAST),t(),M(e.SYNC_PATH_DIFF_MODE.FAST),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.SECURE),t(),M(e.SYNC_PATH_DIFF_MODE.SECURE),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faClock),t(3),s(d("d-flex flex-row col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.scheduler.value),a("disabled",e.syncPath.settings.scheduler.unit===e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(),g("ngModel",e.syncPath.settings.scheduler.unit),t(),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.MINUTE),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.HOUR),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DAY),t(2),s(d("d-flex justify-content-",e.direction," align-items-center")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faRotate),t(3),s(d("col-",e.colSize[e.size][1])),t(),P("text-danger",!e.syncPath.settings.enabled),g("ngModel",e.syncPath.settings.enabled),t(),a("ngValue",!0),t(2),a("ngValue",!1))},dependencies:[G,v,B,W,U,H,z,b,w,V,F,q,oe,k],encapsulation:2});let o=p;return o})();export{oe as a,Le as b};