@sync-in/server 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +173 -58
- package/environment/environment.dist.yaml +6 -3
- package/migrations/0003_giant_luckman.sql +6 -0
- package/migrations/meta/0003_snapshot.json +2463 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +19 -17
- package/server/app.bootstrap.js +5 -2
- package/server/app.bootstrap.js.map +1 -1
- package/server/app.constants.js +0 -4
- package/server/app.constants.js.map +1 -1
- package/server/app.service.js +7 -6
- package/server/app.service.js.map +1 -1
- package/server/applications/files/constants/only-office.js +12 -0
- package/server/applications/files/constants/only-office.js.map +1 -1
- package/server/applications/files/files.config.js +5 -0
- package/server/applications/files/files.config.js.map +1 -1
- package/server/applications/files/files.controller.js +12 -4
- package/server/applications/files/files.controller.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +18 -4
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/services/files-content-manager.service.js +6 -6
- package/server/applications/files/services/files-content-manager.service.js.map +1 -1
- package/server/applications/files/services/files-manager.service.js +4 -4
- package/server/applications/files/services/files-manager.service.js.map +1 -1
- package/server/applications/files/services/files-methods.service.js +4 -7
- package/server/applications/files/services/files-methods.service.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +2 -2
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/files/services/files-parser.service.js +6 -3
- package/server/applications/files/services/files-parser.service.js.map +1 -1
- package/server/applications/files/services/files-scheduler.service.js +51 -3
- package/server/applications/files/services/files-scheduler.service.js.map +1 -1
- package/server/applications/files/services/files-search-manager.service.js +4 -0
- package/server/applications/files/services/files-search-manager.service.js.map +1 -1
- package/server/applications/files/utils/doc-textify/adapters/pdf.js +6 -8
- package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
- package/server/applications/notifications/i18n/de.js +56 -0
- package/server/applications/notifications/i18n/de.js.map +1 -0
- package/server/applications/notifications/i18n/es.js +52 -0
- package/server/applications/notifications/i18n/es.js.map +1 -0
- package/server/applications/notifications/i18n/hi.js +52 -0
- package/server/applications/notifications/i18n/hi.js.map +1 -0
- package/server/applications/notifications/i18n/index.js +73 -8
- package/server/applications/notifications/i18n/index.js.map +1 -1
- package/server/applications/notifications/i18n/it.js +52 -0
- package/server/applications/notifications/i18n/it.js.map +1 -0
- package/server/applications/notifications/i18n/ja.js +52 -0
- package/server/applications/notifications/i18n/ja.js.map +1 -0
- package/server/applications/notifications/i18n/ko.js +52 -0
- package/server/applications/notifications/i18n/ko.js.map +1 -0
- package/server/applications/notifications/i18n/pl.js +52 -0
- package/server/applications/notifications/i18n/pl.js.map +1 -0
- package/server/applications/notifications/i18n/pt.js +52 -0
- package/server/applications/notifications/i18n/pt.js.map +1 -0
- package/server/applications/notifications/i18n/pt_br.js +52 -0
- package/server/applications/notifications/i18n/pt_br.js.map +1 -0
- package/server/applications/notifications/i18n/ru.js +52 -0
- package/server/applications/notifications/i18n/ru.js.map +1 -0
- package/server/applications/notifications/i18n/tr.js +52 -0
- package/server/applications/notifications/i18n/tr.js.map +1 -0
- package/server/applications/notifications/i18n/zh.js +52 -0
- package/server/applications/notifications/i18n/zh.js.map +1 -0
- package/server/applications/notifications/mails/models.js +6 -7
- package/server/applications/notifications/mails/models.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
- package/server/applications/shares/dto/create-or-update-share.dto.js +11 -0
- package/server/applications/shares/dto/create-or-update-share.dto.js.map +1 -1
- package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
- package/server/applications/shares/schemas/share.interface.js.map +1 -1
- package/server/applications/shares/schemas/shares.schema.js +9 -0
- package/server/applications/shares/schemas/shares.schema.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.js +46 -17
- package/server/applications/shares/services/shares-manager.service.js.map +1 -1
- package/server/applications/shares/services/shares-queries.service.js +24 -5
- package/server/applications/shares/services/shares-queries.service.js.map +1 -1
- package/server/applications/spaces/constants/cache.js +4 -0
- package/server/applications/spaces/constants/cache.js.map +1 -1
- package/server/applications/spaces/dto/create-or-update-space.dto.js +5 -0
- package/server/applications/spaces/dto/create-or-update-space.dto.js.map +1 -1
- package/server/applications/spaces/guards/space.guard.js +3 -3
- package/server/applications/spaces/guards/space.guard.js.map +1 -1
- package/server/applications/spaces/models/space-props.model.js.map +1 -1
- package/server/applications/spaces/models/space.model.js.map +1 -1
- package/server/applications/spaces/schemas/space.interface.js.map +1 -1
- package/server/applications/spaces/schemas/spaces.schema.js +1 -0
- package/server/applications/spaces/schemas/spaces.schema.js.map +1 -1
- package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-manager.service.js +34 -31
- package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-queries.service.js +23 -7
- package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
- package/server/applications/spaces/services/spaces-scheduler.service.js +21 -20
- package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
- package/server/applications/spaces/spaces.controller.js +4 -2
- package/server/applications/spaces/spaces.controller.js.map +1 -1
- package/server/applications/spaces/utils/paths.js +14 -16
- package/server/applications/spaces/utils/paths.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.js +4 -3
- package/server/applications/sync/services/sync-manager.service.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/sync/sync.controller.js +2 -1
- package/server/applications/sync/sync.controller.js.map +1 -1
- package/server/applications/users/constants/routes.js +5 -0
- package/server/applications/users/constants/routes.js.map +1 -1
- package/server/applications/users/constants/user.js +0 -16
- package/server/applications/users/constants/user.js.map +1 -1
- package/server/applications/users/dto/user-properties.dto.js +10 -0
- package/server/applications/users/dto/user-properties.dto.js.map +1 -1
- package/server/applications/users/models/user.model.js.map +1 -1
- package/server/applications/users/schemas/user.interface.js.map +1 -1
- package/server/applications/users/schemas/users.schema.js +3 -2
- package/server/applications/users/schemas/users.schema.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +1 -0
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +2 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +7 -2
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +1 -0
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-queries.service.js +18 -4
- package/server/applications/users/services/users-queries.service.js.map +1 -1
- package/server/applications/users/users.controller.js +15 -0
- package/server/applications/users/users.controller.js.map +1 -1
- package/server/applications/users/users.gateway.js +6 -0
- package/server/applications/users/users.gateway.js.map +1 -1
- package/server/applications/users/utils/test.js +2 -2
- package/server/applications/users/utils/test.js.map +1 -1
- package/server/applications/webdav/constants/routes.js +2 -2
- package/server/applications/webdav/constants/routes.js.map +1 -1
- package/server/applications/webdav/constants/webdav.js +2 -2
- package/server/applications/webdav/constants/webdav.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.js +2 -2
- package/server/applications/webdav/filters/webdav.filter.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +2 -2
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-methods.service.js +3 -2
- package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
- package/server/applications/webdav/utils/webdav.js +1 -2
- package/server/applications/webdav/utils/webdav.js.map +1 -1
- package/server/authentication/auth.config.js +2 -2
- package/server/authentication/auth.config.js.map +1 -1
- package/server/authentication/guards/auth-basic.strategy.js +2 -2
- package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
- package/server/common/i18n.js +52 -0
- package/server/common/i18n.js.map +1 -0
- package/server/common/image.js +63 -43
- package/server/common/image.js.map +1 -1
- package/server/common/interfaces.js.map +1 -1
- package/server/common/shared.js +5 -2
- package/server/common/shared.js.map +1 -1
- package/server/configuration/config.validation.js +3 -3
- package/server/configuration/config.validation.js.map +1 -1
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +8 -6
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
- package/server/infrastructure/cache/adapters/redis-cache.adapter.js +22 -17
- package/server/infrastructure/cache/adapters/redis-cache.adapter.js.map +1 -1
- package/server/infrastructure/cache/cache.e2e-spec.js +1 -0
- package/server/infrastructure/cache/cache.e2e-spec.js.map +1 -1
- package/server/infrastructure/cache/cache.module.js +1 -14
- package/server/infrastructure/cache/cache.module.js.map +1 -1
- package/server/infrastructure/cache/services/cache.service.js.map +1 -1
- package/server/infrastructure/database/database.module.js +20 -1
- package/server/infrastructure/database/database.module.js.map +1 -1
- package/server/infrastructure/database/utils.js +48 -0
- package/server/infrastructure/database/utils.js.map +1 -1
- package/server/infrastructure/scheduler/scheduler.module.js +1 -1
- package/server/infrastructure/scheduler/scheduler.module.js.map +1 -1
- package/server/infrastructure/websocket/adapters/cluster.adapter.js +1 -3
- package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
- package/static/3rdpartylicenses.txt +137 -163
- package/static/chunk-2KLC4T2Z.js +1 -0
- package/static/chunk-2VMSXRCB.js +12 -0
- package/static/chunk-3GMLWAFZ.js +1 -0
- package/static/chunk-3OHSRRKH.js +4 -0
- package/static/chunk-3R4WKOHQ.js +1 -0
- package/static/{chunk-7ITZXYYJ.js → chunk-3R74L4UU.js} +1 -1
- package/static/chunk-3XVM35O2.js +1 -0
- package/static/chunk-3YVRP3VM.js +2 -0
- package/static/chunk-5NMSIIQB.js +1 -0
- package/static/chunk-5UKZLU5H.js +1 -0
- package/static/chunk-AF24EYXU.js +1 -0
- package/static/chunk-AKQVEHO6.js +2 -0
- package/static/chunk-BCVX464U.js +2 -0
- package/static/chunk-BQV4FRM6.js +1 -0
- package/static/{chunk-EVIE5F2U.js → chunk-CETH7UYS.js} +1 -1
- package/static/chunk-CHJ64RJM.js +1 -0
- package/static/chunk-DIT6W7VM.js +562 -0
- package/static/chunk-DKSEQTMX.js +1 -0
- package/static/chunk-DM4NXKEP.js +1 -0
- package/static/chunk-DPUVSXRB.js +1 -0
- package/static/chunk-DSWEWLXJ.js +1 -0
- package/static/chunk-FJE6BOFL.js +1 -0
- package/static/chunk-FZ3JPGYZ.js +1 -0
- package/static/chunk-IQSKQXC3.js +1 -0
- package/static/chunk-ITUFI2BJ.js +1 -0
- package/static/chunk-JPT5WEAT.js +1 -0
- package/static/chunk-LCTZJ537.js +1 -0
- package/static/chunk-LK2UCQJ6.js +1 -0
- package/static/chunk-LNTUR3GU.js +1 -0
- package/static/chunk-LP5TBXEN.js +7 -0
- package/static/{chunk-IPAC4VAF.js → chunk-LVSNIS5P.js} +1 -1
- package/static/{chunk-SIPE37PA.js → chunk-MTVSJTIW.js} +1 -1
- package/static/chunk-N3U6637P.js +1 -0
- package/static/chunk-NNV4OXSB.js +1 -0
- package/static/chunk-O6FYXVHI.js +1 -0
- package/static/chunk-OOGP4WSH.js +2 -0
- package/static/chunk-PB4AIT7O.js +1 -0
- package/static/chunk-PCWDQPOM.js +2 -0
- package/static/chunk-PNR6M34W.js +1 -0
- package/static/chunk-PVDHBQRM.js +1 -0
- package/static/chunk-Q5KM7LTX.js +1 -0
- package/static/chunk-QHC6ZPQ4.js +1 -0
- package/static/chunk-QMRBZHE4.js +1 -0
- package/static/chunk-QO6BTONN.js +1 -0
- package/static/chunk-QSJRY3TF.js +1 -0
- package/static/chunk-QUUIRSYT.js +1 -0
- package/static/chunk-RFH46UW3.js +1 -0
- package/static/{chunk-PTGDOWV3.js → chunk-RSXHRKM5.js} +1 -1
- package/static/chunk-RV3VZJPZ.js +1 -0
- package/static/{chunk-QNJFQVYI.js → chunk-S7HNXVRB.js} +1 -1
- package/static/chunk-SBZ572Q4.js +2 -0
- package/static/chunk-SJR5R3Y4.js +1 -0
- package/static/chunk-SLHTEGRU.js +1 -0
- package/static/{chunk-SH5EVL4E.js → chunk-SSFF27P2.js} +1 -1
- package/static/chunk-UNCPXHHT.js +1 -0
- package/static/chunk-URHTCJ7G.js +1 -0
- package/static/chunk-V3LHHZYN.js +1 -0
- package/static/{chunk-DJYJ66UF.js → chunk-VJTXJ43D.js} +1 -1
- package/static/chunk-VQQKMY2C.js +1 -0
- package/static/{chunk-IQOALFYU.js → chunk-WSSU2HXE.js} +1 -1
- package/static/chunk-XDZGW64M.js +3 -0
- package/static/chunk-XTRDKGKG.js +1 -0
- package/static/chunk-YLWTEC3X.js +1 -0
- package/static/chunk-Z5J5F5SX.js +1 -0
- package/static/chunk-ZIJQRARU.js +1 -0
- package/static/index.html +2 -2
- package/static/main-4H5BJY3J.js +9 -0
- package/static/scripts-WRDOQIU5.js +24 -0
- package/static/{styles-A5VYX3CE.css → styles-2C2UNCNB.css} +1 -1
- package/server/applications/spaces/interfaces/space-quota.interface.js +0 -10
- package/server/applications/spaces/interfaces/space-quota.interface.js.map +0 -1
- package/static/chunk-22EANI6R.js +0 -1
- package/static/chunk-3GFGJYMK.js +0 -1
- package/static/chunk-4YGJGZZZ.js +0 -1
- package/static/chunk-5K7HEX3C.js +0 -27
- package/static/chunk-5KLMS6A4.js +0 -1
- package/static/chunk-ATP3BFHV.js +0 -562
- package/static/chunk-BB4G55KE.js +0 -1
- package/static/chunk-EWKSX76T.js +0 -1
- package/static/chunk-FHLACA7V.js +0 -1
- package/static/chunk-GCATNU55.js +0 -1
- package/static/chunk-GYODPCIE.js +0 -1
- package/static/chunk-HZTFYLM5.js +0 -1
- package/static/chunk-JSUKJT6Z.js +0 -1
- package/static/chunk-JXZCNFW7.js +0 -1
- package/static/chunk-LTGFCQR7.js +0 -1
- package/static/chunk-LV3PYKWO.js +0 -1
- package/static/chunk-N2WFNW6M.js +0 -7
- package/static/chunk-ORMRCEGT.js +0 -1
- package/static/chunk-OUTBJSMW.js +0 -1
- package/static/chunk-RS2PX32L.js +0 -1
- package/static/chunk-RSSWH3S2.js +0 -1
- package/static/chunk-RTRJ3KFH.js +0 -1
- package/static/chunk-TKTCBDOG.js +0 -1
- package/static/chunk-V6K2N46L.js +0 -1
- package/static/chunk-XLCCZSQL.js +0 -4
- package/static/chunk-YPEH66GG.js +0 -1
- package/static/chunk-YPOIUQ57.js +0 -1
- package/static/chunk-ZKCFO2OA.js +0 -4
- package/static/main-MZ7HWZXO.js +0 -9
- package/static/scripts-VZVAP2P4.js +0 -30
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-paths-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { getProps, isPathExists, isPathIsDir } from '../../files/utils/files'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { getEnvPermissions } from '../../spaces/utils/permissions'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { SyncPathsManager } from './sync-paths-manager.service'\nimport { SyncQueries } from './sync-queries.service'\n\n// Mock modules used directly inside SyncPathsManager\njest.mock('../../../common/shared', () => ({\n currentTimeStamp: jest.fn(() => 1000)\n}))\njest.mock('../../files/utils/files', () => ({\n isPathExists: jest.fn(),\n isPathIsDir: jest.fn(),\n getProps: jest.fn(),\n sanitizePath: jest.fn((p: string) => p)\n}))\njest.mock('../../spaces/utils/permissions', () => ({\n getEnvPermissions: jest.fn(() => 'server-perms')\n}))\njest.mock('../constants/sync', () => ({\n SYNC_PATH_REPOSITORY: {\n SPACES: ['spaces'],\n PERSONAL: ['personal'],\n SHARES: ['shares']\n }\n}))\njest.mock('../../notifications/constants/notifications', () => ({\n NOTIFICATION_APP: { SYNC: 'SYNC' },\n NOTIFICATION_APP_EVENT: { SYNC: { DELETE: 'DELETE', CREATE: 'CREATE', UPDATE: 'UPDATE' } }\n}))\n\ndescribe(SyncPathsManager.name, () => {\n let service: SyncPathsManager\n let contextManager: { get: jest.Mock }\n let spacesManager: { spaceEnv: jest.Mock }\n let usersQueries: Record<string, jest.Mock>\n let filesQueries: { getSpaceFileId: jest.Mock; getOrCreateSpaceFile: jest.Mock }\n let notificationsManager: { create: jest.Mock }\n let syncQueries: {\n getClient: jest.Mock\n clientExistsForOwner: jest.Mock\n createPath: jest.Mock\n deletePath: jest.Mock\n getPaths: jest.Mock\n getPathSettings: jest.Mock\n updatePathSettings: jest.Mock\n clearCachePathSettings: jest.Mock\n }\n\n const userWith = (clientId?: string) => ({ id: 1, clientId })\n const flush = () => new Promise((r) => setImmediate(r))\n\n beforeEach(async () => {\n contextManager = { get: jest.fn(() => 'http://origin.local') }\n spacesManager = { spaceEnv: jest.fn() }\n usersQueries = {}\n filesQueries = {\n getSpaceFileId: jest.fn(),\n getOrCreateSpaceFile: jest.fn()\n }\n notificationsManager = {\n create: jest.fn().mockResolvedValue(undefined)\n }\n syncQueries = {\n getClient: jest.fn(),\n clientExistsForOwner: jest.fn(),\n createPath: jest.fn(),\n deletePath: jest.fn(),\n getPaths: jest.fn(),\n getPathSettings: jest.fn(),\n updatePathSettings: jest.fn().mockResolvedValue(undefined),\n clearCachePathSettings: jest.fn()\n }\n ;(isPathExists as jest.Mock).mockReset()\n ;(isPathIsDir as jest.Mock).mockReset()\n ;(getProps as jest.Mock).mockReset()\n ;(getEnvPermissions as jest.Mock).mockReset().mockReturnValue('server-perms')\n ;(currentTimeStamp as jest.Mock).mockReset().mockReturnValue(1000)\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n SyncPathsManager,\n { provide: ContextManager, useValue: contextManager },\n { provide: SpacesManager, useValue: spacesManager },\n { provide: UsersQueries, useValue: usersQueries },\n { provide: FilesQueries, useValue: filesQueries },\n { provide: NotificationsManager, useValue: notificationsManager },\n { provide: SyncQueries, useValue: syncQueries }\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<SyncPathsManager>(SyncPathsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('createPath', () => {\n const baseReq = () =>\n ({\n user: { id: 1, clientId: 'client-1' },\n params: { '*': 'SPACES/alias/sub' },\n space: {\n realPath: '/real/path',\n quotaIsExceeded: false,\n root: { id: 1, alias: 'alias' },\n inFilesRepository: true,\n paths: ['sub'],\n dbFile: { ownerId: 1, path: '.' },\n id: 10\n }\n }) as any\n\n it('should throw BAD_REQUEST when client id is missing', async () => {\n const req = baseReq()\n req.user.clientId = undefined\n await expect(service.createPath(req, { remotePath: 'x' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Client id is missing'\n })\n })\n\n it('should throw INSUFFICIENT_STORAGE when space quota is exceeded', async () => {\n const req = baseReq()\n req.space.quotaIsExceeded = true\n await expect(service.createPath(req, { remotePath: 'x' } as any)).rejects.toMatchObject({\n status: HttpStatus.INSUFFICIENT_STORAGE\n })\n })\n\n it.each([\n {\n title: 'NOT_FOUND when remote path does not exist',\n setup: () => (isPathExists as jest.Mock).mockResolvedValue(false),\n expected: { status: HttpStatus.NOT_FOUND, message: 'Remote path not found : client/remote' }\n },\n {\n title: 'BAD_REQUEST when remote path is not a directory',\n setup: () => ((isPathExists as jest.Mock).mockResolvedValue(true), (isPathIsDir as jest.Mock).mockResolvedValue(false)),\n expected: { status: HttpStatus.BAD_REQUEST, message: 'Remote path must be a directory' }\n },\n {\n title: 'NOT_FOUND when client is not found',\n setup: () => (\n (isPathExists as jest.Mock).mockResolvedValue(true),\n (isPathIsDir as jest.Mock).mockResolvedValue(true),\n syncQueries.getClient.mockResolvedValue(null)\n ),\n expected: { status: HttpStatus.NOT_FOUND, message: 'Client not found' }\n }\n ])('should throw $title', async ({ setup, expected }) => {\n const req = baseReq()\n setup()\n await expect(service.createPath(req, { remotePath: 'client/remote' } as any)).rejects.toMatchObject(expected)\n })\n\n it('should create path and return id and permissions, overriding remotePath and permissions', async () => {\n const req = baseReq()\n ;(isPathExists as jest.Mock).mockResolvedValue(true)\n ;(isPathIsDir as jest.Mock).mockResolvedValue(true)\n ;(getEnvPermissions as jest.Mock).mockReturnValue('env-perms')\n syncQueries.getClient.mockResolvedValue({ id: 'client-1' })\n // Spy on private getDBProps to simplify\n const getDBPropsSpy = jest.spyOn<any, any>(service as any, 'getDBProps').mockResolvedValue({ ownerId: 1 })\n syncQueries.createPath.mockResolvedValue(123)\n\n const res = await service.createPath(req, { remotePath: 'client/remote', permissions: 'client-perms' } as any)\n expect(res).toEqual({ id: 123, permissions: 'env-perms' })\n expect(syncQueries.createPath).toHaveBeenCalledWith(\n 'client-1',\n { ownerId: 1 },\n expect.objectContaining({ remotePath: 'SPACES/alias/sub', permissions: 'env-perms' })\n )\n\n getDBPropsSpy.mockRestore()\n })\n })\n\n describe('deletePath', () => {\n it.each([\n { user: { id: 1, clientId: undefined } as any, id: 10, status: HttpStatus.BAD_REQUEST, msg: 'Client id is missing' },\n { user: { id: 1, clientId: 'c1' } as any, id: 10, status: HttpStatus.FORBIDDEN }\n ])('should handle errors (status=$status)', async ({ user, id, status, msg }) => {\n if (status === HttpStatus.FORBIDDEN) syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.deletePath(user, id)).rejects.toMatchObject(msg ? { status, message: msg } : { status })\n })\n\n it('should catch errors from deletePath and throw BAD_REQUEST', async () => {\n const user: any = { id: 1, clientId: 'c1' }\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.deletePath.mockRejectedValue(new Error('db'))\n await expect(service.deletePath(user, 10)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Unable to remove path'\n })\n expect(syncQueries.deletePath).toHaveBeenCalledWith('c1', 10)\n })\n\n it('should delete path successfully when allowed', async () => {\n const user: any = { id: 1, clientId: undefined }\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.deletePath.mockResolvedValue(undefined)\n await expect(service.deletePath(user, 10, 'cX')).resolves.toBeUndefined()\n expect(syncQueries.deletePath).toHaveBeenCalledWith('cX', 10)\n })\n })\n\n describe('updatePath', () => {\n it('should throw FORBIDDEN when client does not belong to owner', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.FORBIDDEN\n })\n })\n\n it('should throw NOT_FOUND when path settings do not exist', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue(null)\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.NOT_FOUND,\n message: 'Sync path not found'\n })\n })\n\n it('should update path settings, set new timestamp, clear cache and return updated settings', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue({ id: 5, timestamp: 500, lastSync: 1, remotePath: '/a', permissions: 'p' })\n syncQueries.updatePathSettings.mockResolvedValue(undefined)\n ;(currentTimeStamp as jest.Mock).mockReturnValue(4242)\n\n const out = await service.updatePath({ id: 1 } as any, 'c1', 5, { id: 666, lastSync: 3, permissions: 'new' } as any)\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith(\n 'c1',\n 5,\n expect.objectContaining({ id: 5, lastSync: 3, timestamp: 4242, permissions: 'new' })\n )\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', 5)\n expect(out).toEqual(expect.objectContaining({ id: 5, lastSync: 3, timestamp: 4242, permissions: 'new' }))\n })\n\n it('should clear cache and throw INTERNAL_SERVER_ERROR when update fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue({ id: 5, timestamp: 500, lastSync: 1 })\n syncQueries.updatePathSettings.mockRejectedValue(new Error('db'))\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.INTERNAL_SERVER_ERROR,\n message: 'Unable to update path'\n })\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', 5)\n })\n })\n\n describe('updatePaths', () => {\n beforeEach(() => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n })\n\n it('should throw when client id is missing', async () => {\n await expect(service.updatePaths(userWith(undefined) as any, [])).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Client id is missing'\n })\n })\n\n it('should throw FORBIDDEN when client does not belong to owner', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.updatePaths(userWith('c1') as any, [])).rejects.toMatchObject({\n status: HttpStatus.FORBIDDEN\n })\n })\n\n it('should mark client paths as deleted and notify when no corresponding server paths (server remotePath undefined)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 2, settings: { timestamp: 1, lastSync: 1 }, remotePath: undefined }])\n const clientPaths = [{ id: 1, remotePath: 'SPACES/a', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n\n const res = await service.updatePaths(userWith('c1') as any, clientPaths)\n expect(res.delete).toEqual([1])\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n })\n\n it('should propagate spaceEnv errors as BAD_REQUEST', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 1, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockRejectedValue(new Error('boom'))\n await expect(\n service.updatePaths(userWith('c1') as any, [{ id: 1, remotePath: 'SPACES/x', timestamp: 1, lastSync: 1, permissions: 'p' } as any])\n ).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'boom'\n })\n })\n\n it('should skip server path when space is null and mark client item as deleted', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 2, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue(null)\n const res = await service.updatePaths(userWith('c1') as any, [\n { id: 2, remotePath: 'SPACES/x', timestamp: 1, lastSync: 1, permissions: 'p' } as any\n ])\n expect(res.delete).toEqual([2])\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n })\n\n it('should add server-only path to client with server permissions', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 3, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'perm-xyz' })\n const res = await service.updatePaths(userWith('c1') as any, [])\n expect(res.add).toHaveLength(1)\n expect(res.add[0]).toEqual(expect.objectContaining({ id: 3, remotePath: 'SPACES/x', permissions: 'perm-xyz' }))\n })\n\n it('should update server settings from client when client is newer (no hasUpdates)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 5, settings: { timestamp: 1, lastSync: 1, foo: 'server' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 5, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p', foo: 'client' } as any]\n await service.updatePaths(userWith('c1') as any, client)\n\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 5, expect.objectContaining({ foo: 'client', lastSync: 2 }))\n // No client update instructions because hasUpdates=false and serverNewer=false\n })\n\n it('should push server-newer updates to client and also remotePath/permissions corrections', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 7, settings: { timestamp: 20, lastSync: 5, srv: true }, remotePath: 'SPACES/correct' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'permX' })\n\n const client = [{ id: 7, timestamp: 10, lastSync: 5, remotePath: 'SPACES/wrong', permissions: 'old' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n // Should have two client updates: one full server settings + corrections, and one corrections-only\n expect(res.update).toEqual(\n expect.arrayContaining([\n expect.objectContaining({ id: 7, srv: true, remotePath: 'SPACES/correct', permissions: 'permX' }),\n expect.objectContaining({ id: 7, remotePath: 'SPACES/correct', permissions: 'permX' })\n ])\n )\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 7, expect.objectContaining({ lastSync: 5 }))\n // clear cache called for each update instruction\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledTimes(res.update.length)\n for (const u of res.update) {\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', u.id)\n }\n })\n\n it('should trigger update when lastSync differs even if timestamps and settings match', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 9, settings: { timestamp: 10, lastSync: 1, flag: 'S' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 9, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p', flag: 'S' } as any]\n await service.updatePaths(userWith('c1') as any, client)\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 9, expect.objectContaining({ lastSync: 2 }))\n })\n\n it('should perform no changes when client and server are identical (no-op branch)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 12, settings: { timestamp: 5, lastSync: 7, flag: 'A' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 12, timestamp: 5, lastSync: 7, remotePath: 'SPACES/x', permissions: 'p', flag: 'A' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n expect(res).toEqual({ add: [], update: [], delete: [] })\n expect(syncQueries.updatePathSettings).not.toHaveBeenCalled()\n })\n\n it('should correct client info while keeping server settings when timestamps are equal (hasUpdates=true)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n // Server has srv='S', client has wrong remotePath/permissions and extra clientOnly flag\n syncQueries.getPaths.mockResolvedValue([{ id: 13, settings: { timestamp: 5, lastSync: 1, srv: 'S' }, remotePath: 'SPACES/correct' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'permX' })\n\n const client = [{ id: 13, timestamp: 5, lastSync: 1, remotePath: 'SPACES/wrong', permissions: 'old', clientOnly: 'C' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n // Server uses its own settings base (srv: 'S') with corrections applied\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith(\n 'c1',\n 13,\n expect.objectContaining({ srv: 'S', lastSync: 1, remotePath: 'SPACES/correct', permissions: 'permX' })\n )\n // Client should receive corrections for remotePath and permissions\n expect(res.update).toEqual(expect.arrayContaining([expect.objectContaining({ id: 13, remotePath: 'SPACES/correct', permissions: 'permX' })]))\n })\n\n it('should log error when updatePathSettings rejects inside updatePaths', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 11, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n // Force client newer to trigger updatePathSettings\n const client = [{ id: 11, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p' } as any]\n syncQueries.updatePathSettings.mockRejectedValueOnce(new Error('db-fail'))\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n\n await service.updatePaths(userWith('c1') as any, client)\n // wait for microtasks to ensure .catch executed\n await flush()\n\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('updatePaths'))).toBe(true)\n })\n\n it('should catch notify failure at updatePaths level when building notification fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n // No server paths: will mark client path as deleted and call notify\n syncQueries.getPaths.mockResolvedValue([])\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n // BAD first segment to make notify fail while building URL (before notificationsManager.create)\n const client = [{ id: 1, remotePath: 'BAD/a/b', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n\n const res = await service.updatePaths(userWith('c1') as any, client)\n await flush()\n\n expect(res.delete).toEqual([1])\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('updatePaths'))).toBe(true)\n // create not called because we failed before reaching it\n expect(notificationsManager.create).not.toHaveBeenCalled()\n })\n\n it('should catch error inside notify when notifications creation fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([])\n // Valid remotePath to build URL correctly\n const client = [{ id: 2, remotePath: 'SPACES/a', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n notificationsManager.create.mockRejectedValueOnce(new Error('notify-fail'))\n\n const res = await service.updatePaths(userWith('c1') as any, client)\n await flush()\n\n expect(res.delete).toEqual([2])\n expect(loggerSpy).toHaveBeenCalled()\n // error comes from notify() catch\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('notify'))).toBe(true)\n })\n })\n\n describe('getDBProps (private) branches', () => {\n it('should throw BAD_REQUEST for shares list selection', async () => {\n await expect((service as any).getDBProps({ inSharesList: true } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Sync all shares is not supported, you must select a sub-directory'\n })\n })\n\n it('should return ownerId only for personal space at root', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: true,\n paths: [],\n dbFile: { ownerId: 42 }\n } as any)\n expect(res).toEqual({ ownerId: 42 })\n })\n\n it('should return ownerId and fileId for personal space subdir', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(77)\n const res = await (service as any).getDBProps({\n inPersonalSpace: true,\n paths: ['sub'],\n dbFile: { ownerId: 42 }\n } as any)\n expect(res).toEqual({ ownerId: 42, fileId: 77 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should throw BAD_REQUEST for whole files repository without alias', async () => {\n await expect((service as any).getDBProps({ inFilesRepository: true, root: { alias: null }, paths: [] } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Sync all space is not yet supported, you must select a sub-directory'\n })\n })\n\n it('should return spaceId and rootId for files repository root selection', async () => {\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 5,\n root: { id: 3, alias: 'x' },\n paths: []\n } as any)\n expect(res).toEqual({ spaceId: 5, spaceRootId: 3 })\n })\n\n it('should return spaceId, rootId and fileId for files repository subdir or null root', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(88)\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 5,\n root: { id: 3, alias: 'x' },\n paths: ['sub']\n } as any)\n expect(res).toEqual({ spaceId: 5, spaceRootId: 3, fileId: 88 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return spaceId and null spaceRootId plus fileId when files repository root has no id', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(90)\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 6,\n root: { id: undefined, alias: 'x' },\n paths: []\n } as any)\n expect(res).toEqual({ spaceId: 6, spaceRootId: null, fileId: 90 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return shareId only for shares repository root', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: true,\n id: 9,\n paths: []\n } as any)\n expect(res).toEqual({ shareId: 9 })\n })\n\n it('should return shareId and fileId for shares repository subdir', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(55)\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: true,\n id: 9,\n paths: ['sub']\n } as any)\n expect(res).toEqual({ shareId: 9, fileId: 55 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return undefined when no space flags match (no branch taken)', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: false,\n paths: []\n } as any)\n expect(res).toBeUndefined()\n })\n })\n\n describe('getOrCreateFileId (private) branches', () => {\n it('should return existing file id without creation', async () => {\n ;(getProps as jest.Mock).mockResolvedValue({ name: 'file' })\n filesQueries.getSpaceFileId.mockResolvedValue(101)\n const id = await (service as any).getOrCreateFileId({\n realPath: '/rp',\n dbFile: { path: '.' }\n })\n expect(id).toBe(101)\n expect(filesQueries.getOrCreateSpaceFile).not.toHaveBeenCalled()\n })\n\n it('should create file when not exists and return its id', async () => {\n ;(getProps as jest.Mock).mockResolvedValue({ id: 999, name: 'file' })\n filesQueries.getSpaceFileId.mockResolvedValue(0)\n filesQueries.getOrCreateSpaceFile.mockResolvedValue(202)\n const id = await (service as any).getOrCreateFileId({\n realPath: '/rp',\n dbFile: { path: '.' }\n })\n expect(id).toBe(202)\n expect(filesQueries.getOrCreateSpaceFile).toHaveBeenCalledWith(0, expect.objectContaining({ id: undefined }), { path: '.' })\n })\n })\n})\n"],"names":["jest","mock","currentTimeStamp","fn","isPathExists","isPathIsDir","getProps","sanitizePath","p","getEnvPermissions","SYNC_PATH_REPOSITORY","SPACES","PERSONAL","SHARES","NOTIFICATION_APP","SYNC","NOTIFICATION_APP_EVENT","DELETE","CREATE","UPDATE","describe","SyncPathsManager","name","service","contextManager","spacesManager","usersQueries","filesQueries","notificationsManager","syncQueries","userWith","clientId","id","flush","Promise","r","setImmediate","beforeEach","get","spaceEnv","getSpaceFileId","getOrCreateSpaceFile","create","mockResolvedValue","undefined","getClient","clientExistsForOwner","createPath","deletePath","getPaths","getPathSettings","updatePathSettings","clearCachePathSettings","mockReset","mockReturnValue","module","Test","createTestingModule","providers","provide","ContextManager","useValue","SpacesManager","UsersQueries","FilesQueries","NotificationsManager","SyncQueries","compile","useLogger","it","expect","toBeDefined","baseReq","user","params","space","realPath","quotaIsExceeded","root","alias","inFilesRepository","paths","dbFile","ownerId","path","req","remotePath","rejects","toMatchObject","status","HttpStatus","BAD_REQUEST","message","INSUFFICIENT_STORAGE","each","title","setup","expected","NOT_FOUND","getDBPropsSpy","spyOn","res","permissions","toEqual","toHaveBeenCalledWith","objectContaining","mockRestore","msg","FORBIDDEN","mockRejectedValue","Error","resolves","toBeUndefined","updatePath","timestamp","lastSync","out","INTERNAL_SERVER_ERROR","envPermissions","updatePaths","settings","clientPaths","delete","toHaveBeenCalledTimes","add","toHaveLength","foo","client","srv","update","arrayContaining","length","u","flag","not","toHaveBeenCalled","clientOnly","mockRejectedValueOnce","loggerSpy","logger","mockImplementation","calls","some","String","includes","toBe","getDBProps","inSharesList","inPersonalSpace","getOrCreateFileIdSpy","fileId","spaceId","spaceRootId","inSharesRepository","shareId","getOrCreateFileId"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/sync/services/sync-paths-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { currentTimeStamp } from '../../../common/shared'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { getProps, isPathExists, isPathIsDir } from '../../files/utils/files'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { getEnvPermissions } from '../../spaces/utils/permissions'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { SyncPathsManager } from './sync-paths-manager.service'\nimport { SyncQueries } from './sync-queries.service'\n\n// Mock modules used directly inside SyncPathsManager\njest.mock('../../../common/shared', () => ({\n currentTimeStamp: jest.fn(() => 1000)\n}))\njest.mock('../../files/utils/files', () => ({\n isPathExists: jest.fn(),\n isPathIsDir: jest.fn(),\n getProps: jest.fn(),\n sanitizePath: jest.fn((p: string) => p)\n}))\njest.mock('../../spaces/utils/permissions', () => ({\n getEnvPermissions: jest.fn(() => 'server-perms')\n}))\njest.mock('../constants/sync', () => ({\n SYNC_PATH_REPOSITORY: {\n SPACES: ['spaces'],\n PERSONAL: ['personal'],\n SHARES: ['shares']\n }\n}))\njest.mock('../../notifications/constants/notifications', () => ({\n NOTIFICATION_APP: { SYNC: 'SYNC' },\n NOTIFICATION_APP_EVENT: { SYNC: { DELETE: 'DELETE', CREATE: 'CREATE', UPDATE: 'UPDATE' } }\n}))\n\ndescribe(SyncPathsManager.name, () => {\n let service: SyncPathsManager\n let contextManager: { get: jest.Mock }\n let spacesManager: { spaceEnv: jest.Mock }\n let usersQueries: Record<string, jest.Mock>\n let filesQueries: { getSpaceFileId: jest.Mock; getOrCreateSpaceFile: jest.Mock }\n let notificationsManager: { create: jest.Mock }\n let syncQueries: {\n getClient: jest.Mock\n clientExistsForOwner: jest.Mock\n createPath: jest.Mock\n deletePath: jest.Mock\n getPaths: jest.Mock\n getPathSettings: jest.Mock\n updatePathSettings: jest.Mock\n clearCachePathSettings: jest.Mock\n }\n\n const userWith = (clientId?: string) => ({ id: 1, clientId })\n const flush = () => new Promise((r) => setImmediate(r))\n\n beforeEach(async () => {\n contextManager = { get: jest.fn(() => 'http://origin.local') }\n spacesManager = { spaceEnv: jest.fn() }\n usersQueries = {}\n filesQueries = {\n getSpaceFileId: jest.fn(),\n getOrCreateSpaceFile: jest.fn()\n }\n notificationsManager = {\n create: jest.fn().mockResolvedValue(undefined)\n }\n syncQueries = {\n getClient: jest.fn(),\n clientExistsForOwner: jest.fn(),\n createPath: jest.fn(),\n deletePath: jest.fn(),\n getPaths: jest.fn(),\n getPathSettings: jest.fn(),\n updatePathSettings: jest.fn().mockResolvedValue(undefined),\n clearCachePathSettings: jest.fn()\n }\n ;(isPathExists as jest.Mock).mockReset()\n ;(isPathIsDir as jest.Mock).mockReset()\n ;(getProps as jest.Mock).mockReset()\n ;(getEnvPermissions as jest.Mock).mockReset().mockReturnValue('server-perms')\n ;(currentTimeStamp as jest.Mock).mockReset().mockReturnValue(1000)\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n SyncPathsManager,\n { provide: ContextManager, useValue: contextManager },\n { provide: SpacesManager, useValue: spacesManager },\n { provide: UsersQueries, useValue: usersQueries },\n { provide: FilesQueries, useValue: filesQueries },\n { provide: NotificationsManager, useValue: notificationsManager },\n { provide: SyncQueries, useValue: syncQueries }\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<SyncPathsManager>(SyncPathsManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('createPath', () => {\n const baseReq = () =>\n ({\n user: { id: 1, clientId: 'client-1' },\n params: { '*': 'SPACES/alias/sub' },\n space: {\n realPath: '/real/path',\n quotaIsExceeded: false,\n root: { id: 1, alias: 'alias' },\n inFilesRepository: true,\n paths: ['sub'],\n dbFile: { ownerId: 1, path: '.' },\n id: 10\n }\n }) as any\n\n it('should throw BAD_REQUEST when client id is missing', async () => {\n const req = baseReq()\n req.user.clientId = undefined\n await expect(service.createPath(req, { remotePath: 'x' } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Client id is missing'\n })\n })\n\n it('should throw INSUFFICIENT_STORAGE when storage quota is exceeded', async () => {\n const req = baseReq()\n req.space.quotaIsExceeded = true\n await expect(service.createPath(req, { remotePath: 'x' } as any)).rejects.toMatchObject({\n status: HttpStatus.INSUFFICIENT_STORAGE\n })\n })\n\n it.each([\n {\n title: 'NOT_FOUND when remote path does not exist',\n setup: () => (isPathExists as jest.Mock).mockResolvedValue(false),\n expected: { status: HttpStatus.NOT_FOUND, message: 'Remote path not found : client/remote' }\n },\n {\n title: 'BAD_REQUEST when remote path is not a directory',\n setup: () => ((isPathExists as jest.Mock).mockResolvedValue(true), (isPathIsDir as jest.Mock).mockResolvedValue(false)),\n expected: { status: HttpStatus.BAD_REQUEST, message: 'Remote path must be a directory' }\n },\n {\n title: 'NOT_FOUND when client is not found',\n setup: () => (\n (isPathExists as jest.Mock).mockResolvedValue(true),\n (isPathIsDir as jest.Mock).mockResolvedValue(true),\n syncQueries.getClient.mockResolvedValue(null)\n ),\n expected: { status: HttpStatus.NOT_FOUND, message: 'Client not found' }\n }\n ])('should throw $title', async ({ setup, expected }) => {\n const req = baseReq()\n setup()\n await expect(service.createPath(req, { remotePath: 'client/remote' } as any)).rejects.toMatchObject(expected)\n })\n\n it('should create path and return id and permissions, overriding remotePath and permissions', async () => {\n const req = baseReq()\n ;(isPathExists as jest.Mock).mockResolvedValue(true)\n ;(isPathIsDir as jest.Mock).mockResolvedValue(true)\n ;(getEnvPermissions as jest.Mock).mockReturnValue('env-perms')\n syncQueries.getClient.mockResolvedValue({ id: 'client-1' })\n // Spy on private getDBProps to simplify\n const getDBPropsSpy = jest.spyOn<any, any>(service as any, 'getDBProps').mockResolvedValue({ ownerId: 1 })\n syncQueries.createPath.mockResolvedValue(123)\n\n const res = await service.createPath(req, { remotePath: 'client/remote', permissions: 'client-perms' } as any)\n expect(res).toEqual({ id: 123, permissions: 'env-perms' })\n expect(syncQueries.createPath).toHaveBeenCalledWith(\n 'client-1',\n { ownerId: 1 },\n expect.objectContaining({ remotePath: 'SPACES/alias/sub', permissions: 'env-perms' })\n )\n\n getDBPropsSpy.mockRestore()\n })\n })\n\n describe('deletePath', () => {\n it.each([\n { user: { id: 1, clientId: undefined } as any, id: 10, status: HttpStatus.BAD_REQUEST, msg: 'Client id is missing' },\n { user: { id: 1, clientId: 'c1' } as any, id: 10, status: HttpStatus.FORBIDDEN }\n ])('should handle errors (status=$status)', async ({ user, id, status, msg }) => {\n if (status === HttpStatus.FORBIDDEN) syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.deletePath(user, id)).rejects.toMatchObject(msg ? { status, message: msg } : { status })\n })\n\n it('should catch errors from deletePath and throw BAD_REQUEST', async () => {\n const user: any = { id: 1, clientId: 'c1' }\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.deletePath.mockRejectedValue(new Error('db'))\n await expect(service.deletePath(user, 10)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Unable to remove path'\n })\n expect(syncQueries.deletePath).toHaveBeenCalledWith('c1', 10)\n })\n\n it('should delete path successfully when allowed', async () => {\n const user: any = { id: 1, clientId: undefined }\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.deletePath.mockResolvedValue(undefined)\n await expect(service.deletePath(user, 10, 'cX')).resolves.toBeUndefined()\n expect(syncQueries.deletePath).toHaveBeenCalledWith('cX', 10)\n })\n })\n\n describe('updatePath', () => {\n it('should throw FORBIDDEN when client does not belong to owner', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.FORBIDDEN\n })\n })\n\n it('should throw NOT_FOUND when path settings do not exist', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue(null)\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.NOT_FOUND,\n message: 'Sync path not found'\n })\n })\n\n it('should update path settings, set new timestamp, clear cache and return updated settings', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue({ id: 5, timestamp: 500, lastSync: 1, remotePath: '/a', permissions: 'p' })\n syncQueries.updatePathSettings.mockResolvedValue(undefined)\n ;(currentTimeStamp as jest.Mock).mockReturnValue(4242)\n\n const out = await service.updatePath({ id: 1 } as any, 'c1', 5, { id: 666, lastSync: 3, permissions: 'new' } as any)\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith(\n 'c1',\n 5,\n expect.objectContaining({ id: 5, lastSync: 3, timestamp: 4242, permissions: 'new' })\n )\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', 5)\n expect(out).toEqual(expect.objectContaining({ id: 5, lastSync: 3, timestamp: 4242, permissions: 'new' }))\n })\n\n it('should clear cache and throw INTERNAL_SERVER_ERROR when update fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPathSettings.mockResolvedValue({ id: 5, timestamp: 500, lastSync: 1 })\n syncQueries.updatePathSettings.mockRejectedValue(new Error('db'))\n await expect(service.updatePath({ id: 1 } as any, 'c1', 5, {} as any)).rejects.toMatchObject({\n status: HttpStatus.INTERNAL_SERVER_ERROR,\n message: 'Unable to update path'\n })\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', 5)\n })\n })\n\n describe('updatePaths', () => {\n beforeEach(() => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n })\n\n it('should throw when client id is missing', async () => {\n await expect(service.updatePaths(userWith(undefined) as any, [])).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Client id is missing'\n })\n })\n\n it('should throw FORBIDDEN when client does not belong to owner', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(false)\n await expect(service.updatePaths(userWith('c1') as any, [])).rejects.toMatchObject({\n status: HttpStatus.FORBIDDEN\n })\n })\n\n it('should mark client paths as deleted and notify when no corresponding server paths (server remotePath undefined)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 2, settings: { timestamp: 1, lastSync: 1 }, remotePath: undefined }])\n const clientPaths = [{ id: 1, remotePath: 'SPACES/a', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n\n const res = await service.updatePaths(userWith('c1') as any, clientPaths)\n expect(res.delete).toEqual([1])\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n })\n\n it('should propagate spaceEnv errors as BAD_REQUEST', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 1, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockRejectedValue(new Error('boom'))\n await expect(\n service.updatePaths(userWith('c1') as any, [{ id: 1, remotePath: 'SPACES/x', timestamp: 1, lastSync: 1, permissions: 'p' } as any])\n ).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'boom'\n })\n })\n\n it('should skip server path when space is null and mark client item as deleted', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 2, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue(null)\n const res = await service.updatePaths(userWith('c1') as any, [\n { id: 2, remotePath: 'SPACES/x', timestamp: 1, lastSync: 1, permissions: 'p' } as any\n ])\n expect(res.delete).toEqual([2])\n expect(notificationsManager.create).toHaveBeenCalledTimes(1)\n })\n\n it('should add server-only path to client with server permissions', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 3, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'perm-xyz' })\n const res = await service.updatePaths(userWith('c1') as any, [])\n expect(res.add).toHaveLength(1)\n expect(res.add[0]).toEqual(expect.objectContaining({ id: 3, remotePath: 'SPACES/x', permissions: 'perm-xyz' }))\n })\n\n it('should update server settings from client when client is newer (no hasUpdates)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 5, settings: { timestamp: 1, lastSync: 1, foo: 'server' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 5, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p', foo: 'client' } as any]\n await service.updatePaths(userWith('c1') as any, client)\n\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 5, expect.objectContaining({ foo: 'client', lastSync: 2 }))\n // No client update instructions because hasUpdates=false and serverNewer=false\n })\n\n it('should push server-newer updates to client and also remotePath/permissions corrections', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 7, settings: { timestamp: 20, lastSync: 5, srv: true }, remotePath: 'SPACES/correct' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'permX' })\n\n const client = [{ id: 7, timestamp: 10, lastSync: 5, remotePath: 'SPACES/wrong', permissions: 'old' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n // Should have two client updates: one full server settings + corrections, and one corrections-only\n expect(res.update).toEqual(\n expect.arrayContaining([\n expect.objectContaining({ id: 7, srv: true, remotePath: 'SPACES/correct', permissions: 'permX' }),\n expect.objectContaining({ id: 7, remotePath: 'SPACES/correct', permissions: 'permX' })\n ])\n )\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 7, expect.objectContaining({ lastSync: 5 }))\n // clear cache called for each update instruction\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledTimes(res.update.length)\n for (const u of res.update) {\n expect(syncQueries.clearCachePathSettings).toHaveBeenCalledWith('c1', u.id)\n }\n })\n\n it('should trigger update when lastSync differs even if timestamps and settings match', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 9, settings: { timestamp: 10, lastSync: 1, flag: 'S' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 9, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p', flag: 'S' } as any]\n await service.updatePaths(userWith('c1') as any, client)\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith('c1', 9, expect.objectContaining({ lastSync: 2 }))\n })\n\n it('should perform no changes when client and server are identical (no-op branch)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 12, settings: { timestamp: 5, lastSync: 7, flag: 'A' }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n\n const client = [{ id: 12, timestamp: 5, lastSync: 7, remotePath: 'SPACES/x', permissions: 'p', flag: 'A' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n expect(res).toEqual({ add: [], update: [], delete: [] })\n expect(syncQueries.updatePathSettings).not.toHaveBeenCalled()\n })\n\n it('should correct client info while keeping server settings when timestamps are equal (hasUpdates=true)', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n // Server has srv='S', client has wrong remotePath/permissions and extra clientOnly flag\n syncQueries.getPaths.mockResolvedValue([{ id: 13, settings: { timestamp: 5, lastSync: 1, srv: 'S' }, remotePath: 'SPACES/correct' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'permX' })\n\n const client = [{ id: 13, timestamp: 5, lastSync: 1, remotePath: 'SPACES/wrong', permissions: 'old', clientOnly: 'C' } as any]\n const res = await service.updatePaths(userWith('c1') as any, client)\n\n // Server uses its own settings base (srv: 'S') with corrections applied\n expect(syncQueries.updatePathSettings).toHaveBeenCalledWith(\n 'c1',\n 13,\n expect.objectContaining({ srv: 'S', lastSync: 1, remotePath: 'SPACES/correct', permissions: 'permX' })\n )\n // Client should receive corrections for remotePath and permissions\n expect(res.update).toEqual(expect.arrayContaining([expect.objectContaining({ id: 13, remotePath: 'SPACES/correct', permissions: 'permX' })]))\n })\n\n it('should log error when updatePathSettings rejects inside updatePaths', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([{ id: 11, settings: { timestamp: 1, lastSync: 1 }, remotePath: 'SPACES/x' }])\n spacesManager.spaceEnv.mockResolvedValue({ envPermissions: 'p' })\n // Force client newer to trigger updatePathSettings\n const client = [{ id: 11, timestamp: 10, lastSync: 2, remotePath: 'SPACES/x', permissions: 'p' } as any]\n syncQueries.updatePathSettings.mockRejectedValueOnce(new Error('db-fail'))\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n\n await service.updatePaths(userWith('c1') as any, client)\n // wait for microtasks to ensure .catch executed\n await flush()\n\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('updatePaths'))).toBe(true)\n })\n\n it('should catch notify failure at updatePaths level when building notification fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n // No server paths: will mark client path as deleted and call notify\n syncQueries.getPaths.mockResolvedValue([])\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n // BAD first segment to make notify fail while building URL (before notificationsManager.create)\n const client = [{ id: 1, remotePath: 'BAD/a/b', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n\n const res = await service.updatePaths(userWith('c1') as any, client)\n await flush()\n\n expect(res.delete).toEqual([1])\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('updatePaths'))).toBe(true)\n // create not called because we failed before reaching it\n expect(notificationsManager.create).not.toHaveBeenCalled()\n })\n\n it('should catch error inside notify when notifications creation fails', async () => {\n syncQueries.clientExistsForOwner.mockResolvedValue(true)\n syncQueries.getPaths.mockResolvedValue([])\n // Valid remotePath to build URL correctly\n const client = [{ id: 2, remotePath: 'SPACES/a', timestamp: 1, lastSync: 1, permissions: 'p' } as any]\n const loggerSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined)\n notificationsManager.create.mockRejectedValueOnce(new Error('notify-fail'))\n\n const res = await service.updatePaths(userWith('c1') as any, client)\n await flush()\n\n expect(res.delete).toEqual([2])\n expect(loggerSpy).toHaveBeenCalled()\n // error comes from notify() catch\n expect(loggerSpy.mock.calls.some(([msg]) => String(msg).includes('notify'))).toBe(true)\n })\n })\n\n describe('getDBProps (private) branches', () => {\n it('should throw BAD_REQUEST for shares list selection', async () => {\n await expect((service as any).getDBProps({ inSharesList: true } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Sync all shares is not supported, you must select a sub-directory'\n })\n })\n\n it('should return ownerId only for personal space at root', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: true,\n paths: [],\n dbFile: { ownerId: 42 }\n } as any)\n expect(res).toEqual({ ownerId: 42 })\n })\n\n it('should return ownerId and fileId for personal space subdir', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(77)\n const res = await (service as any).getDBProps({\n inPersonalSpace: true,\n paths: ['sub'],\n dbFile: { ownerId: 42 }\n } as any)\n expect(res).toEqual({ ownerId: 42, fileId: 77 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should throw BAD_REQUEST for whole files repository without alias', async () => {\n await expect((service as any).getDBProps({ inFilesRepository: true, root: { alias: null }, paths: [] } as any)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Sync all space is not yet supported, you must select a sub-directory'\n })\n })\n\n it('should return spaceId and rootId for files repository root selection', async () => {\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 5,\n root: { id: 3, alias: 'x' },\n paths: []\n } as any)\n expect(res).toEqual({ spaceId: 5, spaceRootId: 3 })\n })\n\n it('should return spaceId, rootId and fileId for files repository subdir or null root', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(88)\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 5,\n root: { id: 3, alias: 'x' },\n paths: ['sub']\n } as any)\n expect(res).toEqual({ spaceId: 5, spaceRootId: 3, fileId: 88 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return spaceId and null spaceRootId plus fileId when files repository root has no id', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(90)\n const res = await (service as any).getDBProps({\n inFilesRepository: true,\n id: 6,\n root: { id: undefined, alias: 'x' },\n paths: []\n } as any)\n expect(res).toEqual({ spaceId: 6, spaceRootId: null, fileId: 90 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return shareId only for shares repository root', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: true,\n id: 9,\n paths: []\n } as any)\n expect(res).toEqual({ shareId: 9 })\n })\n\n it('should return shareId and fileId for shares repository subdir', async () => {\n const getOrCreateFileIdSpy = jest.spyOn<any, any>(service as any, 'getOrCreateFileId').mockResolvedValue(55)\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: true,\n id: 9,\n paths: ['sub']\n } as any)\n expect(res).toEqual({ shareId: 9, fileId: 55 })\n getOrCreateFileIdSpy.mockRestore()\n })\n\n it('should return undefined when no space flags match (no branch taken)', async () => {\n const res = await (service as any).getDBProps({\n inSharesList: false,\n inPersonalSpace: false,\n inFilesRepository: false,\n inSharesRepository: false,\n paths: []\n } as any)\n expect(res).toBeUndefined()\n })\n })\n\n describe('getOrCreateFileId (private) branches', () => {\n it('should return existing file id without creation', async () => {\n ;(getProps as jest.Mock).mockResolvedValue({ name: 'file' })\n filesQueries.getSpaceFileId.mockResolvedValue(101)\n const id = await (service as any).getOrCreateFileId({\n realPath: '/rp',\n dbFile: { path: '.' }\n })\n expect(id).toBe(101)\n expect(filesQueries.getOrCreateSpaceFile).not.toHaveBeenCalled()\n })\n\n it('should create file when not exists and return its id', async () => {\n ;(getProps as jest.Mock).mockResolvedValue({ id: 999, name: 'file' })\n filesQueries.getSpaceFileId.mockResolvedValue(0)\n filesQueries.getOrCreateSpaceFile.mockResolvedValue(202)\n const id = await (service as any).getOrCreateFileId({\n realPath: '/rp',\n dbFile: { path: '.' }\n })\n expect(id).toBe(202)\n expect(filesQueries.getOrCreateSpaceFile).toHaveBeenCalledWith(0, expect.objectContaining({ id: undefined }), { path: '.' })\n })\n })\n})\n"],"names":["jest","mock","currentTimeStamp","fn","isPathExists","isPathIsDir","getProps","sanitizePath","p","getEnvPermissions","SYNC_PATH_REPOSITORY","SPACES","PERSONAL","SHARES","NOTIFICATION_APP","SYNC","NOTIFICATION_APP_EVENT","DELETE","CREATE","UPDATE","describe","SyncPathsManager","name","service","contextManager","spacesManager","usersQueries","filesQueries","notificationsManager","syncQueries","userWith","clientId","id","flush","Promise","r","setImmediate","beforeEach","get","spaceEnv","getSpaceFileId","getOrCreateSpaceFile","create","mockResolvedValue","undefined","getClient","clientExistsForOwner","createPath","deletePath","getPaths","getPathSettings","updatePathSettings","clearCachePathSettings","mockReset","mockReturnValue","module","Test","createTestingModule","providers","provide","ContextManager","useValue","SpacesManager","UsersQueries","FilesQueries","NotificationsManager","SyncQueries","compile","useLogger","it","expect","toBeDefined","baseReq","user","params","space","realPath","quotaIsExceeded","root","alias","inFilesRepository","paths","dbFile","ownerId","path","req","remotePath","rejects","toMatchObject","status","HttpStatus","BAD_REQUEST","message","INSUFFICIENT_STORAGE","each","title","setup","expected","NOT_FOUND","getDBPropsSpy","spyOn","res","permissions","toEqual","toHaveBeenCalledWith","objectContaining","mockRestore","msg","FORBIDDEN","mockRejectedValue","Error","resolves","toBeUndefined","updatePath","timestamp","lastSync","out","INTERNAL_SERVER_ERROR","envPermissions","updatePaths","settings","clientPaths","delete","toHaveBeenCalledTimes","add","toHaveLength","foo","client","srv","update","arrayContaining","length","u","flag","not","toHaveBeenCalled","clientOnly","mockRejectedValueOnce","loggerSpy","logger","mockImplementation","calls","some","String","includes","toBe","getDBProps","inSharesList","inPersonalSpace","getOrCreateFileIdSpy","fileId","spaceId","spaceRootId","inSharesRepository","shareId","getOrCreateFileId"],"mappings":"AAAA;;;;CAIC;;;;wBAE0B;yBACS;wBACH;uCACF;qCACF;uBACuB;6CACf;sCACP;6BACI;qCACL;yCACI;oCACL;AAE5B,qDAAqD;AACrDA,KAAKC,IAAI,CAAC,0BAA0B,IAAO,CAAA;QACzCC,kBAAkBF,KAAKG,EAAE,CAAC,IAAM;IAClC,CAAA;AACAH,KAAKC,IAAI,CAAC,2BAA2B,IAAO,CAAA;QAC1CG,cAAcJ,KAAKG,EAAE;QACrBE,aAAaL,KAAKG,EAAE;QACpBG,UAAUN,KAAKG,EAAE;QACjBI,cAAcP,KAAKG,EAAE,CAAC,CAACK,IAAcA;IACvC,CAAA;AACAR,KAAKC,IAAI,CAAC,kCAAkC,IAAO,CAAA;QACjDQ,mBAAmBT,KAAKG,EAAE,CAAC,IAAM;IACnC,CAAA;AACAH,KAAKC,IAAI,CAAC,qBAAqB,IAAO,CAAA;QACpCS,sBAAsB;YACpBC,QAAQ;gBAAC;aAAS;YAClBC,UAAU;gBAAC;aAAW;YACtBC,QAAQ;gBAAC;aAAS;QACpB;IACF,CAAA;AACAb,KAAKC,IAAI,CAAC,+CAA+C,IAAO,CAAA;QAC9Da,kBAAkB;YAAEC,MAAM;QAAO;QACjCC,wBAAwB;YAAED,MAAM;gBAAEE,QAAQ;gBAAUC,QAAQ;gBAAUC,QAAQ;YAAS;QAAE;IAC3F,CAAA;AAEAC,SAASC,yCAAgB,CAACC,IAAI,EAAE;IAC9B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAWJ,MAAMC,WAAW,CAACC,WAAuB,CAAA;YAAEC,IAAI;YAAGD;QAAS,CAAA;IAC3D,MAAME,QAAQ,IAAM,IAAIC,QAAQ,CAACC,IAAMC,aAAaD;IAEpDE,WAAW;QACTb,iBAAiB;YAAEc,KAAKtC,KAAKG,EAAE,CAAC,IAAM;QAAuB;QAC7DsB,gBAAgB;YAAEc,UAAUvC,KAAKG,EAAE;QAAG;QACtCuB,eAAe,CAAC;QAChBC,eAAe;YACba,gBAAgBxC,KAAKG,EAAE;YACvBsC,sBAAsBzC,KAAKG,EAAE;QAC/B;QACAyB,uBAAuB;YACrBc,QAAQ1C,KAAKG,EAAE,GAAGwC,iBAAiB,CAACC;QACtC;QACAf,cAAc;YACZgB,WAAW7C,KAAKG,EAAE;YAClB2C,sBAAsB9C,KAAKG,EAAE;YAC7B4C,YAAY/C,KAAKG,EAAE;YACnB6C,YAAYhD,KAAKG,EAAE;YACnB8C,UAAUjD,KAAKG,EAAE;YACjB+C,iBAAiBlD,KAAKG,EAAE;YACxBgD,oBAAoBnD,KAAKG,EAAE,GAAGwC,iBAAiB,CAACC;YAChDQ,wBAAwBpD,KAAKG,EAAE;QACjC;QACEC,mBAAY,CAAeiD,SAAS;QACpChD,kBAAW,CAAegD,SAAS;QACnC/C,eAAQ,CAAe+C,SAAS;QAChC5C,8BAAiB,CAAe4C,SAAS,GAAGC,eAAe,CAAC;QAC5DpD,wBAAgB,CAAemD,SAAS,GAAGC,eAAe,CAAC;QAE7D,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTrC,yCAAgB;gBAChB;oBAAEsC,SAASC,qCAAc;oBAAEC,UAAUrC;gBAAe;gBACpD;oBAAEmC,SAASG,mCAAa;oBAAED,UAAUpC;gBAAc;gBAClD;oBAAEkC,SAASI,iCAAY;oBAAEF,UAAUnC;gBAAa;gBAChD;oBAAEiC,SAASK,iCAAY;oBAAEH,UAAUlC;gBAAa;gBAChD;oBAAEgC,SAASM,iDAAoB;oBAAEJ,UAAUjC;gBAAqB;gBAChE;oBAAE+B,SAASO,+BAAW;oBAAEL,UAAUhC;gBAAY;aAC/C;QACH,GAAGsC,OAAO;QAEVZ,OAAOa,SAAS,CAAC;YAAC;SAAQ;QAC1B7C,UAAUgC,OAAOjB,GAAG,CAAmBjB,yCAAgB;IACzD;IAEAgD,GAAG,qBAAqB;QACtBC,OAAO/C,SAASgD,WAAW;IAC7B;IAEAnD,SAAS,cAAc;QACrB,MAAMoD,UAAU,IACb,CAAA;gBACCC,MAAM;oBAAEzC,IAAI;oBAAGD,UAAU;gBAAW;gBACpC2C,QAAQ;oBAAE,KAAK;gBAAmB;gBAClCC,OAAO;oBACLC,UAAU;oBACVC,iBAAiB;oBACjBC,MAAM;wBAAE9C,IAAI;wBAAG+C,OAAO;oBAAQ;oBAC9BC,mBAAmB;oBACnBC,OAAO;wBAAC;qBAAM;oBACdC,QAAQ;wBAAEC,SAAS;wBAAGC,MAAM;oBAAI;oBAChCpD,IAAI;gBACN;YACF,CAAA;QAEFqC,GAAG,sDAAsD;YACvD,MAAMgB,MAAMb;YACZa,IAAIZ,IAAI,CAAC1C,QAAQ,GAAGa;YACpB,MAAM0B,OAAO/C,QAAQwB,UAAU,CAACsC,KAAK;gBAAEC,YAAY;YAAI,IAAWC,OAAO,CAACC,aAAa,CAAC;gBACtFC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;QACF;QAEAvB,GAAG,oEAAoE;YACrE,MAAMgB,MAAMb;YACZa,IAAIV,KAAK,CAACE,eAAe,GAAG;YAC5B,MAAMP,OAAO/C,QAAQwB,UAAU,CAACsC,KAAK;gBAAEC,YAAY;YAAI,IAAWC,OAAO,CAACC,aAAa,CAAC;gBACtFC,QAAQC,kBAAU,CAACG,oBAAoB;YACzC;QACF;QAEAxB,GAAGyB,IAAI,CAAC;YACN;gBACEC,OAAO;gBACPC,OAAO,IAAM,AAAC5F,mBAAY,CAAeuC,iBAAiB,CAAC;gBAC3DsD,UAAU;oBAAER,QAAQC,kBAAU,CAACQ,SAAS;oBAAEN,SAAS;gBAAwC;YAC7F;YACA;gBACEG,OAAO;gBACPC,OAAO,IAAO,CAAA,AAAC5F,mBAAY,CAAeuC,iBAAiB,CAAC,OAAO,AAACtC,kBAAW,CAAesC,iBAAiB,CAAC,MAAK;gBACrHsD,UAAU;oBAAER,QAAQC,kBAAU,CAACC,WAAW;oBAAEC,SAAS;gBAAkC;YACzF;YACA;gBACEG,OAAO;gBACPC,OAAO,IACL,CAAA,AAAC5F,mBAAY,CAAeuC,iBAAiB,CAAC,OAC9C,AAACtC,kBAAW,CAAesC,iBAAiB,CAAC,OAC7Cd,YAAYgB,SAAS,CAACF,iBAAiB,CAAC,KAAI;gBAE9CsD,UAAU;oBAAER,QAAQC,kBAAU,CAACQ,SAAS;oBAAEN,SAAS;gBAAmB;YACxE;SACD,EAAE,uBAAuB,OAAO,EAAEI,KAAK,EAAEC,QAAQ,EAAE;YAClD,MAAMZ,MAAMb;YACZwB;YACA,MAAM1B,OAAO/C,QAAQwB,UAAU,CAACsC,KAAK;gBAAEC,YAAY;YAAgB,IAAWC,OAAO,CAACC,aAAa,CAACS;QACtG;QAEA5B,GAAG,2FAA2F;YAC5F,MAAMgB,MAAMb;YACVpE,mBAAY,CAAeuC,iBAAiB,CAAC;YAC7CtC,kBAAW,CAAesC,iBAAiB,CAAC;YAC5ClC,8BAAiB,CAAe6C,eAAe,CAAC;YAClDzB,YAAYgB,SAAS,CAACF,iBAAiB,CAAC;gBAAEX,IAAI;YAAW;YACzD,wCAAwC;YACxC,MAAMmE,gBAAgBnG,KAAKoG,KAAK,CAAW7E,SAAgB,cAAcoB,iBAAiB,CAAC;gBAAEwC,SAAS;YAAE;YACxGtD,YAAYkB,UAAU,CAACJ,iBAAiB,CAAC;YAEzC,MAAM0D,MAAM,MAAM9E,QAAQwB,UAAU,CAACsC,KAAK;gBAAEC,YAAY;gBAAiBgB,aAAa;YAAe;YACrGhC,OAAO+B,KAAKE,OAAO,CAAC;gBAAEvE,IAAI;gBAAKsE,aAAa;YAAY;YACxDhC,OAAOzC,YAAYkB,UAAU,EAAEyD,oBAAoB,CACjD,YACA;gBAAErB,SAAS;YAAE,GACbb,OAAOmC,gBAAgB,CAAC;gBAAEnB,YAAY;gBAAoBgB,aAAa;YAAY;YAGrFH,cAAcO,WAAW;QAC3B;IACF;IAEAtF,SAAS,cAAc;QACrBiD,GAAGyB,IAAI,CAAC;YACN;gBAAErB,MAAM;oBAAEzC,IAAI;oBAAGD,UAAUa;gBAAU;gBAAUZ,IAAI;gBAAIyD,QAAQC,kBAAU,CAACC,WAAW;gBAAEgB,KAAK;YAAuB;YACnH;gBAAElC,MAAM;oBAAEzC,IAAI;oBAAGD,UAAU;gBAAK;gBAAUC,IAAI;gBAAIyD,QAAQC,kBAAU,CAACkB,SAAS;YAAC;SAChF,EAAE,yCAAyC,OAAO,EAAEnC,IAAI,EAAEzC,EAAE,EAAEyD,MAAM,EAAEkB,GAAG,EAAE;YAC1E,IAAIlB,WAAWC,kBAAU,CAACkB,SAAS,EAAE/E,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACxF,MAAM2B,OAAO/C,QAAQyB,UAAU,CAACyB,MAAMzC,KAAKuD,OAAO,CAACC,aAAa,CAACmB,MAAM;gBAAElB;gBAAQG,SAASe;YAAI,IAAI;gBAAElB;YAAO;QAC7G;QAEApB,GAAG,6DAA6D;YAC9D,MAAMI,OAAY;gBAAEzC,IAAI;gBAAGD,UAAU;YAAK;YAC1CF,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYmB,UAAU,CAAC6D,iBAAiB,CAAC,IAAIC,MAAM;YACnD,MAAMxC,OAAO/C,QAAQyB,UAAU,CAACyB,MAAM,KAAKc,OAAO,CAACC,aAAa,CAAC;gBAC/DC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;YACAtB,OAAOzC,YAAYmB,UAAU,EAAEwD,oBAAoB,CAAC,MAAM;QAC5D;QAEAnC,GAAG,gDAAgD;YACjD,MAAMI,OAAY;gBAAEzC,IAAI;gBAAGD,UAAUa;YAAU;YAC/Cf,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYmB,UAAU,CAACL,iBAAiB,CAACC;YACzC,MAAM0B,OAAO/C,QAAQyB,UAAU,CAACyB,MAAM,IAAI,OAAOsC,QAAQ,CAACC,aAAa;YACvE1C,OAAOzC,YAAYmB,UAAU,EAAEwD,oBAAoB,CAAC,MAAM;QAC5D;IACF;IAEApF,SAAS,cAAc;QACrBiD,GAAG,+DAA+D;YAChExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnD,MAAM2B,OAAO/C,QAAQ0F,UAAU,CAAC;gBAAEjF,IAAI;YAAE,GAAU,MAAM,GAAG,CAAC,IAAWuD,OAAO,CAACC,aAAa,CAAC;gBAC3FC,QAAQC,kBAAU,CAACkB,SAAS;YAC9B;QACF;QAEAvC,GAAG,0DAA0D;YAC3DxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYqB,eAAe,CAACP,iBAAiB,CAAC;YAC9C,MAAM2B,OAAO/C,QAAQ0F,UAAU,CAAC;gBAAEjF,IAAI;YAAE,GAAU,MAAM,GAAG,CAAC,IAAWuD,OAAO,CAACC,aAAa,CAAC;gBAC3FC,QAAQC,kBAAU,CAACQ,SAAS;gBAC5BN,SAAS;YACX;QACF;QAEAvB,GAAG,2FAA2F;YAC5FxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYqB,eAAe,CAACP,iBAAiB,CAAC;gBAAEX,IAAI;gBAAGkF,WAAW;gBAAKC,UAAU;gBAAG7B,YAAY;gBAAMgB,aAAa;YAAI;YACvHzE,YAAYsB,kBAAkB,CAACR,iBAAiB,CAACC;YAC/C1C,wBAAgB,CAAeoD,eAAe,CAAC;YAEjD,MAAM8D,MAAM,MAAM7F,QAAQ0F,UAAU,CAAC;gBAAEjF,IAAI;YAAE,GAAU,MAAM,GAAG;gBAAEA,IAAI;gBAAKmF,UAAU;gBAAGb,aAAa;YAAM;YAC3GhC,OAAOzC,YAAYsB,kBAAkB,EAAEqD,oBAAoB,CACzD,MACA,GACAlC,OAAOmC,gBAAgB,CAAC;gBAAEzE,IAAI;gBAAGmF,UAAU;gBAAGD,WAAW;gBAAMZ,aAAa;YAAM;YAEpFhC,OAAOzC,YAAYuB,sBAAsB,EAAEoD,oBAAoB,CAAC,MAAM;YACtElC,OAAO8C,KAAKb,OAAO,CAACjC,OAAOmC,gBAAgB,CAAC;gBAAEzE,IAAI;gBAAGmF,UAAU;gBAAGD,WAAW;gBAAMZ,aAAa;YAAM;QACxG;QAEAjC,GAAG,wEAAwE;YACzExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYqB,eAAe,CAACP,iBAAiB,CAAC;gBAAEX,IAAI;gBAAGkF,WAAW;gBAAKC,UAAU;YAAE;YACnFtF,YAAYsB,kBAAkB,CAAC0D,iBAAiB,CAAC,IAAIC,MAAM;YAC3D,MAAMxC,OAAO/C,QAAQ0F,UAAU,CAAC;gBAAEjF,IAAI;YAAE,GAAU,MAAM,GAAG,CAAC,IAAWuD,OAAO,CAACC,aAAa,CAAC;gBAC3FC,QAAQC,kBAAU,CAAC2B,qBAAqB;gBACxCzB,SAAS;YACX;YACAtB,OAAOzC,YAAYuB,sBAAsB,EAAEoD,oBAAoB,CAAC,MAAM;QACxE;IACF;IAEApF,SAAS,eAAe;QACtBiB,WAAW;YACTR,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDlB,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAI;QACjE;QAEAjD,GAAG,0CAA0C;YAC3C,MAAMC,OAAO/C,QAAQgG,WAAW,CAACzF,SAASc,YAAmB,EAAE,GAAG2C,OAAO,CAACC,aAAa,CAAC;gBACtFC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;QACF;QAEAvB,GAAG,+DAA+D;YAChExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnD,MAAM2B,OAAO/C,QAAQgG,WAAW,CAACzF,SAAS,OAAc,EAAE,GAAGyD,OAAO,CAACC,aAAa,CAAC;gBACjFC,QAAQC,kBAAU,CAACkB,SAAS;YAC9B;QACF;QAEAvC,GAAG,mHAAmH;YACpHxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;oBAAE;oBAAG7B,YAAY1C;gBAAU;aAAE;YAClH,MAAM6E,cAAc;gBAAC;oBAAEzF,IAAI;oBAAGsD,YAAY;oBAAY4B,WAAW;oBAAGC,UAAU;oBAAGb,aAAa;gBAAI;aAAS;YAE3G,MAAMD,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAc2F;YAC7DnD,OAAO+B,IAAIqB,MAAM,EAAEnB,OAAO,CAAC;gBAAC;aAAE;YAC9BjC,OAAO1C,qBAAqBc,MAAM,EAAEiF,qBAAqB,CAAC;QAC5D;QAEAtD,GAAG,mDAAmD;YACpDxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;oBAAE;oBAAG7B,YAAY;gBAAW;aAAE;YACnH7D,cAAcc,QAAQ,CAACsE,iBAAiB,CAAC,IAAIC,MAAM;YACnD,MAAMxC,OACJ/C,QAAQgG,WAAW,CAACzF,SAAS,OAAc;gBAAC;oBAAEE,IAAI;oBAAGsD,YAAY;oBAAY4B,WAAW;oBAAGC,UAAU;oBAAGb,aAAa;gBAAI;aAAS,GAClIf,OAAO,CAACC,aAAa,CAAC;gBACtBC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;QACF;QAEAvB,GAAG,8EAA8E;YAC/ExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;oBAAE;oBAAG7B,YAAY;gBAAW;aAAE;YACnH7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;YACzC,MAAM0D,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAc;gBAC3D;oBAAEE,IAAI;oBAAGsD,YAAY;oBAAY4B,WAAW;oBAAGC,UAAU;oBAAGb,aAAa;gBAAI;aAC9E;YACDhC,OAAO+B,IAAIqB,MAAM,EAAEnB,OAAO,CAAC;gBAAC;aAAE;YAC9BjC,OAAO1C,qBAAqBc,MAAM,EAAEiF,qBAAqB,CAAC;QAC5D;QAEAtD,GAAG,iEAAiE;YAClExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;oBAAE;oBAAG7B,YAAY;gBAAW;aAAE;YACnH7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAW;YACtE,MAAMjB,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAc,EAAE;YAC/DwC,OAAO+B,IAAIuB,GAAG,EAAEC,YAAY,CAAC;YAC7BvD,OAAO+B,IAAIuB,GAAG,CAAC,EAAE,EAAErB,OAAO,CAACjC,OAAOmC,gBAAgB,CAAC;gBAAEzE,IAAI;gBAAGsD,YAAY;gBAAYgB,aAAa;YAAW;QAC9G;QAEAjC,GAAG,kFAAkF;YACnFxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;wBAAGW,KAAK;oBAAS;oBAAGxC,YAAY;gBAAW;aAAE;YAClI7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAI;YAE/D,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAGkF,WAAW;oBAAIC,UAAU;oBAAG7B,YAAY;oBAAYgB,aAAa;oBAAKwB,KAAK;gBAAS;aAAS;YACtH,MAAMvG,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAEjDzD,OAAOzC,YAAYsB,kBAAkB,EAAEqD,oBAAoB,CAAC,MAAM,GAAGlC,OAAOmC,gBAAgB,CAAC;gBAAEqB,KAAK;gBAAUX,UAAU;YAAE;QAC1H,+EAA+E;QACjF;QAEA9C,GAAG,0FAA0F;YAC3FxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAIC,UAAU;wBAAGa,KAAK;oBAAK;oBAAG1C,YAAY;gBAAiB;aAAE;YACrI7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAQ;YAEnE,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAGkF,WAAW;oBAAIC,UAAU;oBAAG7B,YAAY;oBAAgBgB,aAAa;gBAAM;aAAS;YAC7G,MAAMD,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAE7D,mGAAmG;YACnGzD,OAAO+B,IAAI4B,MAAM,EAAE1B,OAAO,CACxBjC,OAAO4D,eAAe,CAAC;gBACrB5D,OAAOmC,gBAAgB,CAAC;oBAAEzE,IAAI;oBAAGgG,KAAK;oBAAM1C,YAAY;oBAAkBgB,aAAa;gBAAQ;gBAC/FhC,OAAOmC,gBAAgB,CAAC;oBAAEzE,IAAI;oBAAGsD,YAAY;oBAAkBgB,aAAa;gBAAQ;aACrF;YAEHhC,OAAOzC,YAAYsB,kBAAkB,EAAEqD,oBAAoB,CAAC,MAAM,GAAGlC,OAAOmC,gBAAgB,CAAC;gBAAEU,UAAU;YAAE;YAC3G,iDAAiD;YACjD7C,OAAOzC,YAAYuB,sBAAsB,EAAEuE,qBAAqB,CAACtB,IAAI4B,MAAM,CAACE,MAAM;YAClF,KAAK,MAAMC,KAAK/B,IAAI4B,MAAM,CAAE;gBAC1B3D,OAAOzC,YAAYuB,sBAAsB,EAAEoD,oBAAoB,CAAC,MAAM4B,EAAEpG,EAAE;YAC5E;QACF;QAEAqC,GAAG,qFAAqF;YACtFxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAGwF,UAAU;wBAAEN,WAAW;wBAAIC,UAAU;wBAAGkB,MAAM;oBAAI;oBAAG/C,YAAY;gBAAW;aAAE;YAC/H7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAI;YAE/D,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAGkF,WAAW;oBAAIC,UAAU;oBAAG7B,YAAY;oBAAYgB,aAAa;oBAAK+B,MAAM;gBAAI;aAAS;YAClH,MAAM9G,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YACjDzD,OAAOzC,YAAYsB,kBAAkB,EAAEqD,oBAAoB,CAAC,MAAM,GAAGlC,OAAOmC,gBAAgB,CAAC;gBAAEU,UAAU;YAAE;QAC7G;QAEA9C,GAAG,iFAAiF;YAClFxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAIwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;wBAAGkB,MAAM;oBAAI;oBAAG/C,YAAY;gBAAW;aAAE;YAC/H7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAI;YAE/D,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAIkF,WAAW;oBAAGC,UAAU;oBAAG7B,YAAY;oBAAYgB,aAAa;oBAAK+B,MAAM;gBAAI;aAAS;YAClH,MAAMhC,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAE7DzD,OAAO+B,KAAKE,OAAO,CAAC;gBAAEqB,KAAK,EAAE;gBAAEK,QAAQ,EAAE;gBAAEP,QAAQ,EAAE;YAAC;YACtDpD,OAAOzC,YAAYsB,kBAAkB,EAAEmF,GAAG,CAACC,gBAAgB;QAC7D;QAEAlE,GAAG,wGAAwG;YACzGxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnD,wFAAwF;YACxFd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAIwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;wBAAGa,KAAK;oBAAI;oBAAG1C,YAAY;gBAAiB;aAAE;YACpI7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAQ;YAEnE,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAIkF,WAAW;oBAAGC,UAAU;oBAAG7B,YAAY;oBAAgBgB,aAAa;oBAAOkC,YAAY;gBAAI;aAAS;YAC9H,MAAMnC,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAE7D,wEAAwE;YACxEzD,OAAOzC,YAAYsB,kBAAkB,EAAEqD,oBAAoB,CACzD,MACA,IACAlC,OAAOmC,gBAAgB,CAAC;gBAAEuB,KAAK;gBAAKb,UAAU;gBAAG7B,YAAY;gBAAkBgB,aAAa;YAAQ;YAEtG,mEAAmE;YACnEhC,OAAO+B,IAAI4B,MAAM,EAAE1B,OAAO,CAACjC,OAAO4D,eAAe,CAAC;gBAAC5D,OAAOmC,gBAAgB,CAAC;oBAAEzE,IAAI;oBAAIsD,YAAY;oBAAkBgB,aAAa;gBAAQ;aAAG;QAC7I;QAEAjC,GAAG,uEAAuE;YACxExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC;gBAAC;oBAAEX,IAAI;oBAAIwF,UAAU;wBAAEN,WAAW;wBAAGC,UAAU;oBAAE;oBAAG7B,YAAY;gBAAW;aAAE;YACpH7D,cAAcc,QAAQ,CAACI,iBAAiB,CAAC;gBAAE2E,gBAAgB;YAAI;YAC/D,mDAAmD;YACnD,MAAMS,SAAS;gBAAC;oBAAE/F,IAAI;oBAAIkF,WAAW;oBAAIC,UAAU;oBAAG7B,YAAY;oBAAYgB,aAAa;gBAAI;aAAS;YACxGzE,YAAYsB,kBAAkB,CAACsF,qBAAqB,CAAC,IAAI3B,MAAM;YAC/D,MAAM4B,YAAY1I,KAAKoG,KAAK,CAAC,AAAC7E,QAAgBoH,MAAM,EAAE,SAASC,kBAAkB,CAAC,IAAMhG;YAExF,MAAMrB,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YACjD,gDAAgD;YAChD,MAAM9F;YAENqC,OAAOoE,WAAWH,gBAAgB;YAClCjE,OAAOoE,UAAUzI,IAAI,CAAC4I,KAAK,CAACC,IAAI,CAAC,CAAC,CAACnC,IAAI,GAAKoC,OAAOpC,KAAKqC,QAAQ,CAAC,iBAAiBC,IAAI,CAAC;QACzF;QAEA5E,GAAG,qFAAqF;YACtFxC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnD,oEAAoE;YACpEd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC,EAAE;YACzC,MAAM+F,YAAY1I,KAAKoG,KAAK,CAAC,AAAC7E,QAAgBoH,MAAM,EAAE,SAASC,kBAAkB,CAAC,IAAMhG;YACxF,gGAAgG;YAChG,MAAMmF,SAAS;gBAAC;oBAAE/F,IAAI;oBAAGsD,YAAY;oBAAW4B,WAAW;oBAAGC,UAAU;oBAAGb,aAAa;gBAAI;aAAS;YAErG,MAAMD,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAC7D,MAAM9F;YAENqC,OAAO+B,IAAIqB,MAAM,EAAEnB,OAAO,CAAC;gBAAC;aAAE;YAC9BjC,OAAOoE,WAAWH,gBAAgB;YAClCjE,OAAOoE,UAAUzI,IAAI,CAAC4I,KAAK,CAACC,IAAI,CAAC,CAAC,CAACnC,IAAI,GAAKoC,OAAOpC,KAAKqC,QAAQ,CAAC,iBAAiBC,IAAI,CAAC;YACvF,yDAAyD;YACzD3E,OAAO1C,qBAAqBc,MAAM,EAAE4F,GAAG,CAACC,gBAAgB;QAC1D;QAEAlE,GAAG,sEAAsE;YACvExC,YAAYiB,oBAAoB,CAACH,iBAAiB,CAAC;YACnDd,YAAYoB,QAAQ,CAACN,iBAAiB,CAAC,EAAE;YACzC,0CAA0C;YAC1C,MAAMoF,SAAS;gBAAC;oBAAE/F,IAAI;oBAAGsD,YAAY;oBAAY4B,WAAW;oBAAGC,UAAU;oBAAGb,aAAa;gBAAI;aAAS;YACtG,MAAMoC,YAAY1I,KAAKoG,KAAK,CAAC,AAAC7E,QAAgBoH,MAAM,EAAE,SAASC,kBAAkB,CAAC,IAAMhG;YACxFhB,qBAAqBc,MAAM,CAAC+F,qBAAqB,CAAC,IAAI3B,MAAM;YAE5D,MAAMT,MAAM,MAAM9E,QAAQgG,WAAW,CAACzF,SAAS,OAAciG;YAC7D,MAAM9F;YAENqC,OAAO+B,IAAIqB,MAAM,EAAEnB,OAAO,CAAC;gBAAC;aAAE;YAC9BjC,OAAOoE,WAAWH,gBAAgB;YAClC,kCAAkC;YAClCjE,OAAOoE,UAAUzI,IAAI,CAAC4I,KAAK,CAACC,IAAI,CAAC,CAAC,CAACnC,IAAI,GAAKoC,OAAOpC,KAAKqC,QAAQ,CAAC,YAAYC,IAAI,CAAC;QACpF;IACF;IAEA7H,SAAS,iCAAiC;QACxCiD,GAAG,sDAAsD;YACvD,MAAMC,OAAO,AAAC/C,QAAgB2H,UAAU,CAAC;gBAAEC,cAAc;YAAK,IAAW5D,OAAO,CAACC,aAAa,CAAC;gBAC7FC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;QACF;QAEAvB,GAAG,yDAAyD;YAC1D,MAAMgC,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5CC,cAAc;gBACdC,iBAAiB;gBACjBnE,OAAO,EAAE;gBACTC,QAAQ;oBAAEC,SAAS;gBAAG;YACxB;YACAb,OAAO+B,KAAKE,OAAO,CAAC;gBAAEpB,SAAS;YAAG;QACpC;QAEAd,GAAG,8DAA8D;YAC/D,MAAMgF,uBAAuBrJ,KAAKoG,KAAK,CAAW7E,SAAgB,qBAAqBoB,iBAAiB,CAAC;YACzG,MAAM0D,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5CE,iBAAiB;gBACjBnE,OAAO;oBAAC;iBAAM;gBACdC,QAAQ;oBAAEC,SAAS;gBAAG;YACxB;YACAb,OAAO+B,KAAKE,OAAO,CAAC;gBAAEpB,SAAS;gBAAImE,QAAQ;YAAG;YAC9CD,qBAAqB3C,WAAW;QAClC;QAEArC,GAAG,qEAAqE;YACtE,MAAMC,OAAO,AAAC/C,QAAgB2H,UAAU,CAAC;gBAAElE,mBAAmB;gBAAMF,MAAM;oBAAEC,OAAO;gBAAK;gBAAGE,OAAO,EAAE;YAAC,IAAWM,OAAO,CAACC,aAAa,CAAC;gBACpIC,QAAQC,kBAAU,CAACC,WAAW;gBAC9BC,SAAS;YACX;QACF;QAEAvB,GAAG,wEAAwE;YACzE,MAAMgC,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5ClE,mBAAmB;gBACnBhD,IAAI;gBACJ8C,MAAM;oBAAE9C,IAAI;oBAAG+C,OAAO;gBAAI;gBAC1BE,OAAO,EAAE;YACX;YACAX,OAAO+B,KAAKE,OAAO,CAAC;gBAAEgD,SAAS;gBAAGC,aAAa;YAAE;QACnD;QAEAnF,GAAG,qFAAqF;YACtF,MAAMgF,uBAAuBrJ,KAAKoG,KAAK,CAAW7E,SAAgB,qBAAqBoB,iBAAiB,CAAC;YACzG,MAAM0D,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5ClE,mBAAmB;gBACnBhD,IAAI;gBACJ8C,MAAM;oBAAE9C,IAAI;oBAAG+C,OAAO;gBAAI;gBAC1BE,OAAO;oBAAC;iBAAM;YAChB;YACAX,OAAO+B,KAAKE,OAAO,CAAC;gBAAEgD,SAAS;gBAAGC,aAAa;gBAAGF,QAAQ;YAAG;YAC7DD,qBAAqB3C,WAAW;QAClC;QAEArC,GAAG,+FAA+F;YAChG,MAAMgF,uBAAuBrJ,KAAKoG,KAAK,CAAW7E,SAAgB,qBAAqBoB,iBAAiB,CAAC;YACzG,MAAM0D,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5ClE,mBAAmB;gBACnBhD,IAAI;gBACJ8C,MAAM;oBAAE9C,IAAIY;oBAAWmC,OAAO;gBAAI;gBAClCE,OAAO,EAAE;YACX;YACAX,OAAO+B,KAAKE,OAAO,CAAC;gBAAEgD,SAAS;gBAAGC,aAAa;gBAAMF,QAAQ;YAAG;YAChED,qBAAqB3C,WAAW;QAClC;QAEArC,GAAG,yDAAyD;YAC1D,MAAMgC,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5CC,cAAc;gBACdC,iBAAiB;gBACjBpE,mBAAmB;gBACnByE,oBAAoB;gBACpBzH,IAAI;gBACJiD,OAAO,EAAE;YACX;YACAX,OAAO+B,KAAKE,OAAO,CAAC;gBAAEmD,SAAS;YAAE;QACnC;QAEArF,GAAG,iEAAiE;YAClE,MAAMgF,uBAAuBrJ,KAAKoG,KAAK,CAAW7E,SAAgB,qBAAqBoB,iBAAiB,CAAC;YACzG,MAAM0D,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5CC,cAAc;gBACdC,iBAAiB;gBACjBpE,mBAAmB;gBACnByE,oBAAoB;gBACpBzH,IAAI;gBACJiD,OAAO;oBAAC;iBAAM;YAChB;YACAX,OAAO+B,KAAKE,OAAO,CAAC;gBAAEmD,SAAS;gBAAGJ,QAAQ;YAAG;YAC7CD,qBAAqB3C,WAAW;QAClC;QAEArC,GAAG,uEAAuE;YACxE,MAAMgC,MAAM,MAAM,AAAC9E,QAAgB2H,UAAU,CAAC;gBAC5CC,cAAc;gBACdC,iBAAiB;gBACjBpE,mBAAmB;gBACnByE,oBAAoB;gBACpBxE,OAAO,EAAE;YACX;YACAX,OAAO+B,KAAKW,aAAa;QAC3B;IACF;IAEA5F,SAAS,wCAAwC;QAC/CiD,GAAG,mDAAmD;;YAClD/D,eAAQ,CAAeqC,iBAAiB,CAAC;gBAAErB,MAAM;YAAO;YAC1DK,aAAaa,cAAc,CAACG,iBAAiB,CAAC;YAC9C,MAAMX,KAAK,MAAM,AAACT,QAAgBoI,iBAAiB,CAAC;gBAClD/E,UAAU;gBACVM,QAAQ;oBAAEE,MAAM;gBAAI;YACtB;YACAd,OAAOtC,IAAIiH,IAAI,CAAC;YAChB3E,OAAO3C,aAAac,oBAAoB,EAAE6F,GAAG,CAACC,gBAAgB;QAChE;QAEAlE,GAAG,wDAAwD;;YACvD/D,eAAQ,CAAeqC,iBAAiB,CAAC;gBAAEX,IAAI;gBAAKV,MAAM;YAAO;YACnEK,aAAaa,cAAc,CAACG,iBAAiB,CAAC;YAC9ChB,aAAac,oBAAoB,CAACE,iBAAiB,CAAC;YACpD,MAAMX,KAAK,MAAM,AAACT,QAAgBoI,iBAAiB,CAAC;gBAClD/E,UAAU;gBACVM,QAAQ;oBAAEE,MAAM;gBAAI;YACtB;YACAd,OAAOtC,IAAIiH,IAAI,CAAC;YAChB3E,OAAO3C,aAAac,oBAAoB,EAAE+D,oBAAoB,CAAC,GAAGlC,OAAOmC,gBAAgB,CAAC;gBAAEzE,IAAIY;YAAU,IAAI;gBAAEwC,MAAM;YAAI;QAC5H;IACF;AACF"}
|
|
@@ -269,7 +269,8 @@ _ts_decorate([
|
|
|
269
269
|
(0, _common.UseInterceptors)(_contextinterceptor.ContextInterceptor),
|
|
270
270
|
_ts_param(0, (0, _userdecorator.GetUser)()),
|
|
271
271
|
_ts_param(1, (0, _common.Body)(new _common.ParseArrayPipe({
|
|
272
|
-
items: _syncpathdto.SyncPathDto
|
|
272
|
+
items: _syncpathdto.SyncPathDto,
|
|
273
|
+
whitelist: true
|
|
273
274
|
}))),
|
|
274
275
|
_ts_metadata("design:type", Function),
|
|
275
276
|
_ts_metadata("design:paramtypes", [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/sync/sync.controller.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 {\n Body,\n Controller,\n Copy,\n Delete,\n Get,\n HttpException,\n HttpStatus,\n Move,\n Param,\n ParseArrayPipe,\n ParseIntPipe,\n Post,\n Proppatch,\n Put,\n Query,\n Req,\n Res,\n StreamableFile,\n UseGuards,\n UseInterceptors\n} from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { AuthTokenSkip } from '../../authentication/decorators/auth-token-skip.decorator'\nimport { ContextInterceptor } from '../../infrastructure/context/interceptors/context.interceptor'\nimport { SkipSpacePermissionsCheck } from '../spaces/decorators/space-skip-permissions.decorator'\nimport { FastifySpaceRequest } from '../spaces/interfaces/space-request.interface'\nimport { USER_PERMISSION } from '../users/constants/user'\nimport { UserHavePermission } from '../users/decorators/permissions.decorator'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserPermissionsGuard } from '../users/guards/permissions.guard'\nimport { UserModel } from '../users/models/user.model'\nimport { CLIENT_AUTH_TYPE } from './constants/auth'\nimport { SYNC_ROUTE } from './constants/routes'\nimport { CHECK_SERVER_RESP, SYNC_IN_SERVER_AGENT } from './constants/sync'\nimport { SyncEnvironment } from './decorators/sync-environment.decorator'\nimport { SyncClientAuthDto } from './dtos/sync-client-auth.dto'\nimport type { SyncClientRegistrationDto } from './dtos/sync-client-registration.dto'\nimport { SyncCopyMoveDto, SyncDiffDto, SyncMakeDto, SyncPropsDto } from './dtos/sync-operations.dto'\nimport { SyncPathDto, SyncPathUpdateDto } from './dtos/sync-path.dto'\nimport { SyncUploadDto } from './dtos/sync-upload.dto'\nimport { SyncDiffGzipBodyInterceptor } from './interceptors/sync-diff-gzip-body.interceptor'\nimport { AppStoreManifest } from './interfaces/store-manifest.interface'\nimport { ClientAuthCookieDto, ClientAuthTokenDto } from './interfaces/sync-client-auth.interface'\nimport { SyncClientPaths } from './interfaces/sync-client-paths.interface'\nimport { SyncPathSettings } from './interfaces/sync-path.interface'\nimport { SyncClientsManager } from './services/sync-clients-manager.service'\nimport { SyncManager } from './services/sync-manager.service'\nimport { SyncPathsManager } from './services/sync-paths-manager.service'\n\n@Controller(SYNC_ROUTE.BASE)\nexport class SyncController {\n constructor(\n private readonly syncManager: SyncManager,\n private readonly syncClientsManager: SyncClientsManager,\n private readonly syncPathsManager: SyncPathsManager\n ) {}\n\n /* CLIENT */\n\n @Get(SYNC_ROUTE.HANDSHAKE)\n @AuthTokenSkip()\n handshake(@Req() req: FastifyRequest) {\n if ('user-agent' in req.headers && req.headers['user-agent'].startsWith(SYNC_IN_SERVER_AGENT)) {\n return CHECK_SERVER_RESP\n }\n throw new HttpException('Server not found', HttpStatus.NOT_FOUND)\n }\n\n @Post(SYNC_ROUTE.REGISTER)\n @AuthTokenSkip()\n register(@Body() syncClientRegistrationDto: SyncClientRegistrationDto, @Req() req: FastifyRequest): Promise<{ clientToken: string }> {\n return this.syncClientsManager.register(syncClientRegistrationDto, req.ip)\n }\n\n @Post(SYNC_ROUTE.UNREGISTER)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n unregister(@GetUser() user: UserModel): Promise<void> {\n return this.syncClientsManager.unregister(user)\n }\n\n @Get(SYNC_ROUTE.APP_STORE)\n @AuthTokenSkip()\n checkAppStore(): Promise<AppStoreManifest> {\n return this.syncClientsManager.checkAppStore()\n }\n\n @Post(`${SYNC_ROUTE.AUTH}/:type`)\n @AuthTokenSkip()\n authenticate(\n @Param('type') type: CLIENT_AUTH_TYPE,\n @Body() clientAuthDto: SyncClientAuthDto,\n @Req() req: FastifyRequest,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<ClientAuthCookieDto | ClientAuthTokenDto> {\n return this.syncClientsManager.authenticate(type, clientAuthDto, req.ip, res)\n }\n\n @Get(SYNC_ROUTE.CLIENTS)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n getClients(@GetUser() user: UserModel): Promise<SyncClientPaths[]> {\n return this.syncClientsManager.getClients(user)\n }\n\n @Delete(`${SYNC_ROUTE.CLIENTS}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n deleteClient(@GetUser() user: UserModel, @Param('id') clientId: string): Promise<void> {\n return this.syncClientsManager.deleteClient(user, clientId)\n }\n\n /* PATHS */\n\n @Delete(`${SYNC_ROUTE.CLIENTS}/:id/${SYNC_ROUTE.PATHS}/:pathId`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n deleteClientPath(@GetUser() user: UserModel, @Param('id') clientId: string, @Param('pathId', ParseIntPipe) pathId: number): Promise<void> {\n return this.syncPathsManager.deletePath(user, pathId, clientId)\n }\n\n @Put(`${SYNC_ROUTE.CLIENTS}/:id/${SYNC_ROUTE.PATHS}/:pathId`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n updatePath(\n @GetUser() user: UserModel,\n @Param('id') clientId: string,\n @Param('pathId', ParseIntPipe) pathId: number,\n @Body() syncPathUpdateDto: SyncPathUpdateDto\n ): Promise<SyncPathSettings> {\n return this.syncPathsManager.updatePath(user, clientId, pathId, syncPathUpdateDto)\n }\n\n @Post(`${SYNC_ROUTE.PATHS}/*`)\n @SkipSpacePermissionsCheck()\n @SyncEnvironment()\n createPath(\n @Req() req: FastifySpaceRequest,\n @Body() syncPathDto: SyncPathDto\n ): Promise<{\n id: number\n permissions: string\n }> {\n return this.syncPathsManager.createPath(req, syncPathDto)\n }\n\n @Delete(`${SYNC_ROUTE.PATHS}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n deletePath(@GetUser() user: UserModel, @Param('id', ParseIntPipe) pathId: number): Promise<void> {\n return this.syncPathsManager.deletePath(user, pathId)\n }\n\n @Put(SYNC_ROUTE.PATHS)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n @UseInterceptors(ContextInterceptor)\n updatePaths(\n @GetUser() user: UserModel,\n @Body(new ParseArrayPipe({ items: SyncPathDto })) syncPathsDto: SyncPathDto[]\n ): Promise<{\n add: SyncPathSettings[]\n update: Partial<Record<keyof SyncPathSettings, any>>[]\n delete: number[]\n }> {\n return this.syncPathsManager.updatePaths(user, syncPathsDto)\n }\n\n /* OPERATIONS */\n\n @Post(`${SYNC_ROUTE.OPERATION}/${SYNC_ROUTE.DIFF}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n @UseInterceptors(SyncDiffGzipBodyInterceptor)\n diff(\n @GetUser() user: UserModel,\n @Param('id', ParseIntPipe) pathId: number,\n @Body() syncDiffDto: SyncDiffDto,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<void> {\n return this.syncManager.diff(user, pathId, syncDiffDto, res)\n }\n\n @Get(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n download(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.syncManager.download(req, res)\n }\n\n @Post(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n uploadCreate(@Req() req: FastifySpaceRequest, @Query() syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n return this.syncManager.upload(req, syncUploadDto)\n }\n\n @Put(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n uploadOverwrite(@Req() req: FastifySpaceRequest, @Query() syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n return this.syncManager.upload(req, syncUploadDto)\n }\n\n @Post(`${SYNC_ROUTE.OPERATION}/${SYNC_ROUTE.MAKE}/*`)\n @SyncEnvironment()\n make(@Req() req: FastifySpaceRequest, @Body() syncMakeDto: SyncMakeDto): Promise<{ ino: number }> {\n return this.syncManager.make(req, syncMakeDto)\n }\n\n @Proppatch(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n props(@Req() req: FastifySpaceRequest, @Body() syncPropsDto: SyncPropsDto): Promise<void> {\n return this.syncManager.props(req, syncPropsDto)\n }\n\n @Move(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n move(@Req() req: FastifySpaceRequest, @Body() syncCopyMoveDto: SyncCopyMoveDto): Promise<void> {\n return this.syncManager.copyMove(req, syncCopyMoveDto, true)\n }\n\n @Copy(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n copy(@Req() req: FastifySpaceRequest, @Body() syncCopyMoveDto: SyncCopyMoveDto): Promise<{ ino: number; mtime: number }> {\n return this.syncManager.copyMove(req, syncCopyMoveDto, false)\n }\n\n @Delete(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n delete(@Req() req: FastifySpaceRequest): Promise<void> {\n return this.syncManager.delete(req)\n }\n}\n"],"names":["SyncController","handshake","req","headers","startsWith","SYNC_IN_SERVER_AGENT","CHECK_SERVER_RESP","HttpException","HttpStatus","NOT_FOUND","register","syncClientRegistrationDto","syncClientsManager","ip","unregister","user","checkAppStore","authenticate","type","clientAuthDto","res","getClients","deleteClient","clientId","deleteClientPath","pathId","syncPathsManager","deletePath","updatePath","syncPathUpdateDto","createPath","syncPathDto","updatePaths","syncPathsDto","diff","syncDiffDto","syncManager","download","uploadCreate","syncUploadDto","upload","uploadOverwrite","make","syncMakeDto","props","syncPropsDto","move","syncCopyMoveDto","copyMove","copy","delete","HANDSHAKE","REGISTER","UNREGISTER","DESKTOP_APP","APP_STORE","SYNC_ROUTE","AUTH","passthrough","CLIENTS","PATHS","DESKTOP_APP_SYNC","ParseArrayPipe","items","SyncPathDto","OPERATION","DIFF","MAKE","BASE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/sync/sync.controller.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 {\n Body,\n Controller,\n Copy,\n Delete,\n Get,\n HttpException,\n HttpStatus,\n Move,\n Param,\n ParseArrayPipe,\n ParseIntPipe,\n Post,\n Proppatch,\n Put,\n Query,\n Req,\n Res,\n StreamableFile,\n UseGuards,\n UseInterceptors\n} from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { AuthTokenSkip } from '../../authentication/decorators/auth-token-skip.decorator'\nimport { ContextInterceptor } from '../../infrastructure/context/interceptors/context.interceptor'\nimport { SkipSpacePermissionsCheck } from '../spaces/decorators/space-skip-permissions.decorator'\nimport { FastifySpaceRequest } from '../spaces/interfaces/space-request.interface'\nimport { USER_PERMISSION } from '../users/constants/user'\nimport { UserHavePermission } from '../users/decorators/permissions.decorator'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserPermissionsGuard } from '../users/guards/permissions.guard'\nimport { UserModel } from '../users/models/user.model'\nimport { CLIENT_AUTH_TYPE } from './constants/auth'\nimport { SYNC_ROUTE } from './constants/routes'\nimport { CHECK_SERVER_RESP, SYNC_IN_SERVER_AGENT } from './constants/sync'\nimport { SyncEnvironment } from './decorators/sync-environment.decorator'\nimport { SyncClientAuthDto } from './dtos/sync-client-auth.dto'\nimport type { SyncClientRegistrationDto } from './dtos/sync-client-registration.dto'\nimport { SyncCopyMoveDto, SyncDiffDto, SyncMakeDto, SyncPropsDto } from './dtos/sync-operations.dto'\nimport { SyncPathDto, SyncPathUpdateDto } from './dtos/sync-path.dto'\nimport { SyncUploadDto } from './dtos/sync-upload.dto'\nimport { SyncDiffGzipBodyInterceptor } from './interceptors/sync-diff-gzip-body.interceptor'\nimport { AppStoreManifest } from './interfaces/store-manifest.interface'\nimport { ClientAuthCookieDto, ClientAuthTokenDto } from './interfaces/sync-client-auth.interface'\nimport { SyncClientPaths } from './interfaces/sync-client-paths.interface'\nimport { SyncPathSettings } from './interfaces/sync-path.interface'\nimport { SyncClientsManager } from './services/sync-clients-manager.service'\nimport { SyncManager } from './services/sync-manager.service'\nimport { SyncPathsManager } from './services/sync-paths-manager.service'\n\n@Controller(SYNC_ROUTE.BASE)\nexport class SyncController {\n constructor(\n private readonly syncManager: SyncManager,\n private readonly syncClientsManager: SyncClientsManager,\n private readonly syncPathsManager: SyncPathsManager\n ) {}\n\n /* CLIENT */\n\n @Get(SYNC_ROUTE.HANDSHAKE)\n @AuthTokenSkip()\n handshake(@Req() req: FastifyRequest) {\n if ('user-agent' in req.headers && req.headers['user-agent'].startsWith(SYNC_IN_SERVER_AGENT)) {\n return CHECK_SERVER_RESP\n }\n throw new HttpException('Server not found', HttpStatus.NOT_FOUND)\n }\n\n @Post(SYNC_ROUTE.REGISTER)\n @AuthTokenSkip()\n register(@Body() syncClientRegistrationDto: SyncClientRegistrationDto, @Req() req: FastifyRequest): Promise<{ clientToken: string }> {\n return this.syncClientsManager.register(syncClientRegistrationDto, req.ip)\n }\n\n @Post(SYNC_ROUTE.UNREGISTER)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n unregister(@GetUser() user: UserModel): Promise<void> {\n return this.syncClientsManager.unregister(user)\n }\n\n @Get(SYNC_ROUTE.APP_STORE)\n @AuthTokenSkip()\n checkAppStore(): Promise<AppStoreManifest> {\n return this.syncClientsManager.checkAppStore()\n }\n\n @Post(`${SYNC_ROUTE.AUTH}/:type`)\n @AuthTokenSkip()\n authenticate(\n @Param('type') type: CLIENT_AUTH_TYPE,\n @Body() clientAuthDto: SyncClientAuthDto,\n @Req() req: FastifyRequest,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<ClientAuthCookieDto | ClientAuthTokenDto> {\n return this.syncClientsManager.authenticate(type, clientAuthDto, req.ip, res)\n }\n\n @Get(SYNC_ROUTE.CLIENTS)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n getClients(@GetUser() user: UserModel): Promise<SyncClientPaths[]> {\n return this.syncClientsManager.getClients(user)\n }\n\n @Delete(`${SYNC_ROUTE.CLIENTS}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP)\n @UseGuards(UserPermissionsGuard)\n deleteClient(@GetUser() user: UserModel, @Param('id') clientId: string): Promise<void> {\n return this.syncClientsManager.deleteClient(user, clientId)\n }\n\n /* PATHS */\n\n @Delete(`${SYNC_ROUTE.CLIENTS}/:id/${SYNC_ROUTE.PATHS}/:pathId`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n deleteClientPath(@GetUser() user: UserModel, @Param('id') clientId: string, @Param('pathId', ParseIntPipe) pathId: number): Promise<void> {\n return this.syncPathsManager.deletePath(user, pathId, clientId)\n }\n\n @Put(`${SYNC_ROUTE.CLIENTS}/:id/${SYNC_ROUTE.PATHS}/:pathId`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n updatePath(\n @GetUser() user: UserModel,\n @Param('id') clientId: string,\n @Param('pathId', ParseIntPipe) pathId: number,\n @Body() syncPathUpdateDto: SyncPathUpdateDto\n ): Promise<SyncPathSettings> {\n return this.syncPathsManager.updatePath(user, clientId, pathId, syncPathUpdateDto)\n }\n\n @Post(`${SYNC_ROUTE.PATHS}/*`)\n @SkipSpacePermissionsCheck()\n @SyncEnvironment()\n createPath(\n @Req() req: FastifySpaceRequest,\n @Body() syncPathDto: SyncPathDto\n ): Promise<{\n id: number\n permissions: string\n }> {\n return this.syncPathsManager.createPath(req, syncPathDto)\n }\n\n @Delete(`${SYNC_ROUTE.PATHS}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n deletePath(@GetUser() user: UserModel, @Param('id', ParseIntPipe) pathId: number): Promise<void> {\n return this.syncPathsManager.deletePath(user, pathId)\n }\n\n @Put(SYNC_ROUTE.PATHS)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n @UseInterceptors(ContextInterceptor)\n updatePaths(\n @GetUser() user: UserModel,\n @Body(new ParseArrayPipe({ items: SyncPathDto, whitelist: true })) syncPathsDto: SyncPathDto[]\n ): Promise<{\n add: SyncPathSettings[]\n update: Partial<Record<keyof SyncPathSettings, any>>[]\n delete: number[]\n }> {\n return this.syncPathsManager.updatePaths(user, syncPathsDto)\n }\n\n /* OPERATIONS */\n\n @Post(`${SYNC_ROUTE.OPERATION}/${SYNC_ROUTE.DIFF}/:id`)\n @UserHavePermission(USER_PERMISSION.DESKTOP_APP_SYNC)\n @UseGuards(UserPermissionsGuard)\n @UseInterceptors(SyncDiffGzipBodyInterceptor)\n diff(\n @GetUser() user: UserModel,\n @Param('id', ParseIntPipe) pathId: number,\n @Body() syncDiffDto: SyncDiffDto,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<void> {\n return this.syncManager.diff(user, pathId, syncDiffDto, res)\n }\n\n @Get(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n download(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.syncManager.download(req, res)\n }\n\n @Post(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n uploadCreate(@Req() req: FastifySpaceRequest, @Query() syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n return this.syncManager.upload(req, syncUploadDto)\n }\n\n @Put(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n uploadOverwrite(@Req() req: FastifySpaceRequest, @Query() syncUploadDto: SyncUploadDto): Promise<{ ino: number }> {\n return this.syncManager.upload(req, syncUploadDto)\n }\n\n @Post(`${SYNC_ROUTE.OPERATION}/${SYNC_ROUTE.MAKE}/*`)\n @SyncEnvironment()\n make(@Req() req: FastifySpaceRequest, @Body() syncMakeDto: SyncMakeDto): Promise<{ ino: number }> {\n return this.syncManager.make(req, syncMakeDto)\n }\n\n @Proppatch(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n props(@Req() req: FastifySpaceRequest, @Body() syncPropsDto: SyncPropsDto): Promise<void> {\n return this.syncManager.props(req, syncPropsDto)\n }\n\n @Move(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n move(@Req() req: FastifySpaceRequest, @Body() syncCopyMoveDto: SyncCopyMoveDto): Promise<void> {\n return this.syncManager.copyMove(req, syncCopyMoveDto, true)\n }\n\n @Copy(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n copy(@Req() req: FastifySpaceRequest, @Body() syncCopyMoveDto: SyncCopyMoveDto): Promise<{ ino: number; mtime: number }> {\n return this.syncManager.copyMove(req, syncCopyMoveDto, false)\n }\n\n @Delete(`${SYNC_ROUTE.OPERATION}/*`)\n @SyncEnvironment()\n delete(@Req() req: FastifySpaceRequest): Promise<void> {\n return this.syncManager.delete(req)\n }\n}\n"],"names":["SyncController","handshake","req","headers","startsWith","SYNC_IN_SERVER_AGENT","CHECK_SERVER_RESP","HttpException","HttpStatus","NOT_FOUND","register","syncClientRegistrationDto","syncClientsManager","ip","unregister","user","checkAppStore","authenticate","type","clientAuthDto","res","getClients","deleteClient","clientId","deleteClientPath","pathId","syncPathsManager","deletePath","updatePath","syncPathUpdateDto","createPath","syncPathDto","updatePaths","syncPathsDto","diff","syncDiffDto","syncManager","download","uploadCreate","syncUploadDto","upload","uploadOverwrite","make","syncMakeDto","props","syncPropsDto","move","syncCopyMoveDto","copyMove","copy","delete","HANDSHAKE","REGISTER","UNREGISTER","DESKTOP_APP","APP_STORE","SYNC_ROUTE","AUTH","passthrough","CLIENTS","PATHS","DESKTOP_APP_SYNC","ParseArrayPipe","items","SyncPathDto","whitelist","OPERATION","DIFF","MAKE","BASE"],"mappings":"AAAA;;;;CAIC;;;;+BAqDYA;;;eAAAA;;;wBA9BN;yBACsC;wCACf;oCACK;+CACO;uCACN;sBACJ;sCACG;+BACX;kCACa;2BACX;sBACO;wBACN;sBAC6B;0CACxB;mCACE;mCAEsC;6BACzB;+BACjB;6CACc;2CAKT;oCACP;yCACK;;;;;;;;;;;;;;;AAG1B,IAAA,AAAMA,iBAAN,MAAMA;IAOX,UAAU,GAEV,AAEAC,UAAU,AAAOC,GAAmB,EAAE;QACpC,IAAI,gBAAgBA,IAAIC,OAAO,IAAID,IAAIC,OAAO,CAAC,aAAa,CAACC,UAAU,CAACC,0BAAoB,GAAG;YAC7F,OAAOC,uBAAiB;QAC1B;QACA,MAAM,IAAIC,qBAAa,CAAC,oBAAoBC,kBAAU,CAACC,SAAS;IAClE;IAIAC,SAAS,AAAQC,yBAAoD,EAAE,AAAOT,GAAmB,EAAoC;QACnI,OAAO,IAAI,CAACU,kBAAkB,CAACF,QAAQ,CAACC,2BAA2BT,IAAIW,EAAE;IAC3E;IAKAC,WAAW,AAAWC,IAAe,EAAiB;QACpD,OAAO,IAAI,CAACH,kBAAkB,CAACE,UAAU,CAACC;IAC5C;IAIAC,gBAA2C;QACzC,OAAO,IAAI,CAACJ,kBAAkB,CAACI,aAAa;IAC9C;IAIAC,aACE,AAAeC,IAAsB,EACrC,AAAQC,aAAgC,EACxC,AAAOjB,GAAmB,EAC1B,AAA4BkB,GAAiB,EACM;QACnD,OAAO,IAAI,CAACR,kBAAkB,CAACK,YAAY,CAACC,MAAMC,eAAejB,IAAIW,EAAE,EAAEO;IAC3E;IAKAC,WAAW,AAAWN,IAAe,EAA8B;QACjE,OAAO,IAAI,CAACH,kBAAkB,CAACS,UAAU,CAACN;IAC5C;IAKAO,aAAa,AAAWP,IAAe,EAAE,AAAaQ,QAAgB,EAAiB;QACrF,OAAO,IAAI,CAACX,kBAAkB,CAACU,YAAY,CAACP,MAAMQ;IACpD;IAEA,SAAS,GAET,AAGAC,iBAAiB,AAAWT,IAAe,EAAE,AAAaQ,QAAgB,EAAE,AAA+BE,MAAc,EAAiB;QACxI,OAAO,IAAI,CAACC,gBAAgB,CAACC,UAAU,CAACZ,MAAMU,QAAQF;IACxD;IAKAK,WACE,AAAWb,IAAe,EAC1B,AAAaQ,QAAgB,EAC7B,AAA+BE,MAAc,EAC7C,AAAQI,iBAAoC,EACjB;QAC3B,OAAO,IAAI,CAACH,gBAAgB,CAACE,UAAU,CAACb,MAAMQ,UAAUE,QAAQI;IAClE;IAKAC,WACE,AAAO5B,GAAwB,EAC/B,AAAQ6B,WAAwB,EAI/B;QACD,OAAO,IAAI,CAACL,gBAAgB,CAACI,UAAU,CAAC5B,KAAK6B;IAC/C;IAKAJ,WAAW,AAAWZ,IAAe,EAAE,AAA2BU,MAAc,EAAiB;QAC/F,OAAO,IAAI,CAACC,gBAAgB,CAACC,UAAU,CAACZ,MAAMU;IAChD;IAMAO,YACE,AAAWjB,IAAe,EAC1B,AAAmEkB,YAA2B,EAK7F;QACD,OAAO,IAAI,CAACP,gBAAgB,CAACM,WAAW,CAACjB,MAAMkB;IACjD;IAEA,cAAc,GAEd,AAIAC,KACE,AAAWnB,IAAe,EAC1B,AAA2BU,MAAc,EACzC,AAAQU,WAAwB,EAChC,AAA4Bf,GAAiB,EAC9B;QACf,OAAO,IAAI,CAACgB,WAAW,CAACF,IAAI,CAACnB,MAAMU,QAAQU,aAAaf;IAC1D;IAIAiB,SAAS,AAAOnC,GAAwB,EAAE,AAA4BkB,GAAiB,EAA2B;QAChH,OAAO,IAAI,CAACgB,WAAW,CAACC,QAAQ,CAACnC,KAAKkB;IACxC;IAIAkB,aAAa,AAAOpC,GAAwB,EAAE,AAASqC,aAA4B,EAA4B;QAC7G,OAAO,IAAI,CAACH,WAAW,CAACI,MAAM,CAACtC,KAAKqC;IACtC;IAIAE,gBAAgB,AAAOvC,GAAwB,EAAE,AAASqC,aAA4B,EAA4B;QAChH,OAAO,IAAI,CAACH,WAAW,CAACI,MAAM,CAACtC,KAAKqC;IACtC;IAIAG,KAAK,AAAOxC,GAAwB,EAAE,AAAQyC,WAAwB,EAA4B;QAChG,OAAO,IAAI,CAACP,WAAW,CAACM,IAAI,CAACxC,KAAKyC;IACpC;IAIAC,MAAM,AAAO1C,GAAwB,EAAE,AAAQ2C,YAA0B,EAAiB;QACxF,OAAO,IAAI,CAACT,WAAW,CAACQ,KAAK,CAAC1C,KAAK2C;IACrC;IAIAC,KAAK,AAAO5C,GAAwB,EAAE,AAAQ6C,eAAgC,EAAiB;QAC7F,OAAO,IAAI,CAACX,WAAW,CAACY,QAAQ,CAAC9C,KAAK6C,iBAAiB;IACzD;IAIAE,KAAK,AAAO/C,GAAwB,EAAE,AAAQ6C,eAAgC,EAA2C;QACvH,OAAO,IAAI,CAACX,WAAW,CAACY,QAAQ,CAAC9C,KAAK6C,iBAAiB;IACzD;IAIAG,OAAO,AAAOhD,GAAwB,EAAiB;QACrD,OAAO,IAAI,CAACkC,WAAW,CAACc,MAAM,CAAChD;IACjC;IAlLA,YACE,AAAiBkC,WAAwB,EACzC,AAAiBxB,kBAAsC,EACvD,AAAiBc,gBAAkC,CACnD;aAHiBU,cAAAA;aACAxB,qBAAAA;aACAc,mBAAAA;IAChB;AA+KL;;wCA3KkByB;;;;;;;;;;yCASCC;;;;;;;;;;;;yCAMAC;wEACmBC;;;;;;;;;;wCAMpBC;;;;;;;yBAMPC,kBAAU,CAACC,IAAI,CAAC,MAAM;;;;;;QAMtBC,aAAa;;;;;;;;;;;;wCAKNC;wEACoBL;;;;;;;;;;2BAMzBE,kBAAU,CAACG,OAAO,CAAC,IAAI;wEACEL;;;;;;;;;;;;2BAQzBE,kBAAU,CAACG,OAAO,CAAC,KAAK,EAAEH,kBAAU,CAACI,KAAK,CAAC,QAAQ;wEAC1BC;;;;;;;;;;;;;;wBAM5BL,kBAAU,CAACG,OAAO,CAAC,KAAK,EAAEH,kBAAU,CAACI,KAAK,CAAC,QAAQ;wEACvBC;;;;;;;;;;;;;;;;yBAW3BL,kBAAU,CAACI,KAAK,CAAC,EAAE;;;;;;;;;;;;;2BAajBJ,kBAAU,CAACI,KAAK,CAAC,IAAI;wEACIC;;;;;;;;;;;;wCAMpBD;wEACoBC;;;;uCAKxBC,sBAAc,CAAC;QAAEC,OAAOC,wBAAW;QAAEC,WAAW;IAAK;;;;;;;;;yBAWxDT,kBAAU,CAACU,SAAS,CAAC,CAAC,EAAEV,kBAAU,CAACW,IAAI,CAAC,IAAI;wEACjBN;;;;;;;QAO3BH,aAAa;;;;;;;;;;;;wBAKdF,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;QAEkBR,aAAa;;;;;;;;;;yBAIrDF,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;;;wBAMxBV,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;;;yBAMtBV,kBAAU,CAACU,SAAS,CAAC,CAAC,EAAEV,kBAAU,CAACY,IAAI,CAAC,EAAE;;;;;;;;;;;;8BAMrCZ,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;;;yBAM5BV,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;;;yBAMvBV,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;;;2BAMrBV,kBAAU,CAACU,SAAS,CAAC,EAAE;;;;;;;;;;+CAhLbG"}
|
|
@@ -82,6 +82,9 @@ _export(exports, {
|
|
|
82
82
|
get API_USERS_MY_PASSWORD () {
|
|
83
83
|
return API_USERS_MY_PASSWORD;
|
|
84
84
|
},
|
|
85
|
+
get API_USERS_MY_STORAGE_INDEXING () {
|
|
86
|
+
return API_USERS_MY_STORAGE_INDEXING;
|
|
87
|
+
},
|
|
85
88
|
get USERS_ROUTE () {
|
|
86
89
|
return USERS_ROUTE;
|
|
87
90
|
}
|
|
@@ -94,6 +97,7 @@ const USERS_ROUTE = {
|
|
|
94
97
|
PASSWORD: 'password',
|
|
95
98
|
APP_PASSWORDS: 'app_passwords',
|
|
96
99
|
NOTIFICATION: 'notification',
|
|
100
|
+
STORAGE_INDEXING: 'storage_indexing',
|
|
97
101
|
AVATAR: 'avatar',
|
|
98
102
|
GROUPS: 'groups',
|
|
99
103
|
USERS: 'users',
|
|
@@ -106,6 +110,7 @@ const API_USERS_MY_LANGUAGE = `${API_USERS_ME}/${USERS_ROUTE.LANGUAGE}`;
|
|
|
106
110
|
const API_USERS_MY_PASSWORD = `${API_USERS_ME}/${USERS_ROUTE.PASSWORD}`;
|
|
107
111
|
const API_USERS_MY_APP_PASSWORDS = `${API_USERS_ME}/${USERS_ROUTE.APP_PASSWORDS}`;
|
|
108
112
|
const API_USERS_MY_NOTIFICATION = `${API_USERS_ME}/${USERS_ROUTE.NOTIFICATION}`;
|
|
113
|
+
const API_USERS_MY_STORAGE_INDEXING = `${API_USERS_ME}/${USERS_ROUTE.STORAGE_INDEXING}`;
|
|
109
114
|
const API_USERS_MY_AVATAR = `${API_USERS_ME}/${USERS_ROUTE.AVATAR}`;
|
|
110
115
|
const API_USERS_MY_GROUPS = `${API_USERS_ME}/${USERS_ROUTE.GROUPS}`;
|
|
111
116
|
const API_USERS_MY_GROUPS_BROWSE = `${API_USERS_MY_GROUPS}/${USERS_ROUTE.BROWSE}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/users/constants/routes.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 { ADMIN_ROUTE } from '../../admin/constants/routes'\n\nexport const USERS_ROUTE = {\n BASE: '/api/users',\n ME: 'me',\n LANGUAGE: 'language',\n PASSWORD: 'password',\n APP_PASSWORDS: 'app_passwords',\n NOTIFICATION: 'notification',\n AVATAR: 'avatar',\n GROUPS: 'groups',\n USERS: 'users',\n GUESTS: 'guests',\n BROWSE: 'browse',\n GROUPS_LEAVE: 'leave'\n} as const\n\nexport const API_USERS_ME = `${USERS_ROUTE.BASE}/${USERS_ROUTE.ME}`\nexport const API_USERS_MY_LANGUAGE = `${API_USERS_ME}/${USERS_ROUTE.LANGUAGE}`\nexport const API_USERS_MY_PASSWORD = `${API_USERS_ME}/${USERS_ROUTE.PASSWORD}`\nexport const API_USERS_MY_APP_PASSWORDS = `${API_USERS_ME}/${USERS_ROUTE.APP_PASSWORDS}`\nexport const API_USERS_MY_NOTIFICATION = `${API_USERS_ME}/${USERS_ROUTE.NOTIFICATION}`\nexport const API_USERS_MY_AVATAR = `${API_USERS_ME}/${USERS_ROUTE.AVATAR}`\nexport const API_USERS_MY_GROUPS = `${API_USERS_ME}/${USERS_ROUTE.GROUPS}`\nexport const API_USERS_MY_GROUPS_BROWSE = `${API_USERS_MY_GROUPS}/${USERS_ROUTE.BROWSE}`\nexport const API_USERS_MY_GROUPS_LEAVE = `${API_USERS_MY_GROUPS}/${USERS_ROUTE.GROUPS_LEAVE}`\nexport const API_USERS_MY_GUESTS = `${API_USERS_ME}/${USERS_ROUTE.GUESTS}`\nexport const API_USERS_AVATAR = `${USERS_ROUTE.BASE}/${USERS_ROUTE.AVATAR}`\n\nexport const ADMIN_USERS_ROUTE = {\n BASE: ADMIN_ROUTE.BASE,\n LIST: 'list',\n USERS: 'users',\n GUESTS: 'guests',\n GROUPS: 'groups',\n PGROUPS: 'personal_groups',\n MEMBERS: 'members',\n IMPERSONATE: 'impersonate',\n LOGOUT: 'logout',\n BROWSE: 'browse'\n} as const\nexport const API_ADMIN_USERS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.USERS}`\nexport const API_ADMIN_USERS_LIST = `${API_ADMIN_USERS}/${ADMIN_USERS_ROUTE.LIST}`\nexport const API_ADMIN_GUESTS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.GUESTS}`\nexport const API_ADMIN_GUESTS_LIST = `${API_ADMIN_GUESTS}/${ADMIN_USERS_ROUTE.LIST}`\nexport const API_ADMIN_GROUPS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.GROUPS}`\nexport const API_ADMIN_PGROUPS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.PGROUPS}`\nexport const API_ADMIN_GROUPS_BROWSE = `${API_ADMIN_GROUPS}/${ADMIN_USERS_ROUTE.BROWSE}`\nexport const API_ADMIN_PERSONAL_GROUPS_BROWSE = `${API_ADMIN_PGROUPS}/${ADMIN_USERS_ROUTE.BROWSE}`\nexport const API_ADMIN_MEMBERS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.MEMBERS}`\nexport const API_ADMIN_IMPERSONATE = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.IMPERSONATE}`\nexport const API_ADMIN_IMPERSONATE_LOGOUT = `${API_ADMIN_IMPERSONATE}/${ADMIN_USERS_ROUTE.LOGOUT}`\n"],"names":["ADMIN_USERS_ROUTE","API_ADMIN_GROUPS","API_ADMIN_GROUPS_BROWSE","API_ADMIN_GUESTS","API_ADMIN_GUESTS_LIST","API_ADMIN_IMPERSONATE","API_ADMIN_IMPERSONATE_LOGOUT","API_ADMIN_MEMBERS","API_ADMIN_PERSONAL_GROUPS_BROWSE","API_ADMIN_PGROUPS","API_ADMIN_USERS","API_ADMIN_USERS_LIST","API_USERS_AVATAR","API_USERS_ME","API_USERS_MY_APP_PASSWORDS","API_USERS_MY_AVATAR","API_USERS_MY_GROUPS","API_USERS_MY_GROUPS_BROWSE","API_USERS_MY_GROUPS_LEAVE","API_USERS_MY_GUESTS","API_USERS_MY_LANGUAGE","API_USERS_MY_NOTIFICATION","API_USERS_MY_PASSWORD","USERS_ROUTE","BASE","ME","LANGUAGE","PASSWORD","APP_PASSWORDS","NOTIFICATION","AVATAR","GROUPS","USERS","GUESTS","BROWSE","GROUPS_LEAVE","ADMIN_ROUTE","LIST","PGROUPS","MEMBERS","IMPERSONATE","LOGOUT"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/users/constants/routes.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 { ADMIN_ROUTE } from '../../admin/constants/routes'\n\nexport const USERS_ROUTE = {\n BASE: '/api/users',\n ME: 'me',\n LANGUAGE: 'language',\n PASSWORD: 'password',\n APP_PASSWORDS: 'app_passwords',\n NOTIFICATION: 'notification',\n STORAGE_INDEXING: 'storage_indexing',\n AVATAR: 'avatar',\n GROUPS: 'groups',\n USERS: 'users',\n GUESTS: 'guests',\n BROWSE: 'browse',\n GROUPS_LEAVE: 'leave'\n} as const\n\nexport const API_USERS_ME = `${USERS_ROUTE.BASE}/${USERS_ROUTE.ME}`\nexport const API_USERS_MY_LANGUAGE = `${API_USERS_ME}/${USERS_ROUTE.LANGUAGE}`\nexport const API_USERS_MY_PASSWORD = `${API_USERS_ME}/${USERS_ROUTE.PASSWORD}`\nexport const API_USERS_MY_APP_PASSWORDS = `${API_USERS_ME}/${USERS_ROUTE.APP_PASSWORDS}`\nexport const API_USERS_MY_NOTIFICATION = `${API_USERS_ME}/${USERS_ROUTE.NOTIFICATION}`\nexport const API_USERS_MY_STORAGE_INDEXING = `${API_USERS_ME}/${USERS_ROUTE.STORAGE_INDEXING}`\nexport const API_USERS_MY_AVATAR = `${API_USERS_ME}/${USERS_ROUTE.AVATAR}`\nexport const API_USERS_MY_GROUPS = `${API_USERS_ME}/${USERS_ROUTE.GROUPS}`\nexport const API_USERS_MY_GROUPS_BROWSE = `${API_USERS_MY_GROUPS}/${USERS_ROUTE.BROWSE}`\nexport const API_USERS_MY_GROUPS_LEAVE = `${API_USERS_MY_GROUPS}/${USERS_ROUTE.GROUPS_LEAVE}`\nexport const API_USERS_MY_GUESTS = `${API_USERS_ME}/${USERS_ROUTE.GUESTS}`\nexport const API_USERS_AVATAR = `${USERS_ROUTE.BASE}/${USERS_ROUTE.AVATAR}`\n\nexport const ADMIN_USERS_ROUTE = {\n BASE: ADMIN_ROUTE.BASE,\n LIST: 'list',\n USERS: 'users',\n GUESTS: 'guests',\n GROUPS: 'groups',\n PGROUPS: 'personal_groups',\n MEMBERS: 'members',\n IMPERSONATE: 'impersonate',\n LOGOUT: 'logout',\n BROWSE: 'browse'\n} as const\nexport const API_ADMIN_USERS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.USERS}`\nexport const API_ADMIN_USERS_LIST = `${API_ADMIN_USERS}/${ADMIN_USERS_ROUTE.LIST}`\nexport const API_ADMIN_GUESTS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.GUESTS}`\nexport const API_ADMIN_GUESTS_LIST = `${API_ADMIN_GUESTS}/${ADMIN_USERS_ROUTE.LIST}`\nexport const API_ADMIN_GROUPS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.GROUPS}`\nexport const API_ADMIN_PGROUPS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.PGROUPS}`\nexport const API_ADMIN_GROUPS_BROWSE = `${API_ADMIN_GROUPS}/${ADMIN_USERS_ROUTE.BROWSE}`\nexport const API_ADMIN_PERSONAL_GROUPS_BROWSE = `${API_ADMIN_PGROUPS}/${ADMIN_USERS_ROUTE.BROWSE}`\nexport const API_ADMIN_MEMBERS = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.MEMBERS}`\nexport const API_ADMIN_IMPERSONATE = `${ADMIN_USERS_ROUTE.BASE}/${ADMIN_USERS_ROUTE.IMPERSONATE}`\nexport const API_ADMIN_IMPERSONATE_LOGOUT = `${API_ADMIN_IMPERSONATE}/${ADMIN_USERS_ROUTE.LOGOUT}`\n"],"names":["ADMIN_USERS_ROUTE","API_ADMIN_GROUPS","API_ADMIN_GROUPS_BROWSE","API_ADMIN_GUESTS","API_ADMIN_GUESTS_LIST","API_ADMIN_IMPERSONATE","API_ADMIN_IMPERSONATE_LOGOUT","API_ADMIN_MEMBERS","API_ADMIN_PERSONAL_GROUPS_BROWSE","API_ADMIN_PGROUPS","API_ADMIN_USERS","API_ADMIN_USERS_LIST","API_USERS_AVATAR","API_USERS_ME","API_USERS_MY_APP_PASSWORDS","API_USERS_MY_AVATAR","API_USERS_MY_GROUPS","API_USERS_MY_GROUPS_BROWSE","API_USERS_MY_GROUPS_LEAVE","API_USERS_MY_GUESTS","API_USERS_MY_LANGUAGE","API_USERS_MY_NOTIFICATION","API_USERS_MY_PASSWORD","API_USERS_MY_STORAGE_INDEXING","USERS_ROUTE","BASE","ME","LANGUAGE","PASSWORD","APP_PASSWORDS","NOTIFICATION","STORAGE_INDEXING","AVATAR","GROUPS","USERS","GUESTS","BROWSE","GROUPS_LEAVE","ADMIN_ROUTE","LIST","PGROUPS","MEMBERS","IMPERSONATE","LOGOUT"],"mappings":"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"}
|
|
@@ -28,15 +28,9 @@ _export(exports, {
|
|
|
28
28
|
get USER_NOTIFICATION () {
|
|
29
29
|
return USER_NOTIFICATION;
|
|
30
30
|
},
|
|
31
|
-
get USER_NOTIFICATION_TEXT () {
|
|
32
|
-
return USER_NOTIFICATION_TEXT;
|
|
33
|
-
},
|
|
34
31
|
get USER_ONLINE_STATUS () {
|
|
35
32
|
return USER_ONLINE_STATUS;
|
|
36
33
|
},
|
|
37
|
-
get USER_ONLINE_STATUS_LIST () {
|
|
38
|
-
return USER_ONLINE_STATUS_LIST;
|
|
39
|
-
},
|
|
40
34
|
get USER_PASSWORD_MIN_LENGTH () {
|
|
41
35
|
return USER_PASSWORD_MIN_LENGTH;
|
|
42
36
|
},
|
|
@@ -102,21 +96,11 @@ var USER_ONLINE_STATUS = /*#__PURE__*/ function(USER_ONLINE_STATUS) {
|
|
|
102
96
|
USER_ONLINE_STATUS[USER_ONLINE_STATUS["OFFLINE"] = 3] = "OFFLINE";
|
|
103
97
|
return USER_ONLINE_STATUS;
|
|
104
98
|
}({});
|
|
105
|
-
const USER_ONLINE_STATUS_LIST = [
|
|
106
|
-
'available',
|
|
107
|
-
'busy',
|
|
108
|
-
'absent',
|
|
109
|
-
'offline'
|
|
110
|
-
];
|
|
111
99
|
var USER_NOTIFICATION = /*#__PURE__*/ function(USER_NOTIFICATION) {
|
|
112
100
|
USER_NOTIFICATION[USER_NOTIFICATION["APPLICATION"] = 0] = "APPLICATION";
|
|
113
101
|
USER_NOTIFICATION[USER_NOTIFICATION["APPLICATION_EMAIL"] = 1] = "APPLICATION_EMAIL";
|
|
114
102
|
return USER_NOTIFICATION;
|
|
115
103
|
}({});
|
|
116
|
-
const USER_NOTIFICATION_TEXT = {
|
|
117
|
-
APPLICATION: 'application',
|
|
118
|
-
APPLICATION_EMAIL: 'application & email'
|
|
119
|
-
};
|
|
120
104
|
const USER_SECRET = {
|
|
121
105
|
TWO_FA_SECRET: 'twoFaSecret',
|
|
122
106
|
RECOVERY_CODES: 'recoveryCodes',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/users/constants/user.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 USER_PASSWORD_MIN_LENGTH = 8\nexport const USER_MAX_PASSWORD_ATTEMPTS = 10\nexport const USER_LOGIN_VALIDATION = /^[a-zA-Z0-9\\-\\\\._]{2,255}$/\n\nexport const USER_PATH = {\n TMP: 'tmp',\n TASKS: 'tasks'\n} as const\n\nexport enum USER_ROLE {\n ADMINISTRATOR,\n USER,\n GUEST,\n LINK\n}\n\nexport enum USER_GROUP_ROLE {\n MEMBER,\n MANAGER\n}\n\nexport const USER_PERMS_SEP = ','\n\nexport enum USER_PERMISSION {\n PERSONAL_SPACE = 'personal_space',\n SPACES = 'spaces_access',\n SPACES_ADMIN = 'spaces_admin',\n SHARES = 'shares_access',\n SHARES_ADMIN = 'shares_admin',\n GUESTS_ADMIN = 'guests_admin',\n PERSONAL_GROUPS_ADMIN = 'personal_groups_admin',\n DESKTOP_APP = 'desktop_app_access',\n DESKTOP_APP_SYNC = 'desktop_app_sync',\n WEBDAV = 'webdav_access'\n}\n\nexport enum GUEST_PERMISSION {\n SPACES = USER_PERMISSION.SPACES,\n SHARES = USER_PERMISSION.SHARES,\n WEBDAV = USER_PERMISSION.WEBDAV\n}\n\nexport enum USER_ONLINE_STATUS {\n AVAILABLE,\n BUSY,\n ABSENT,\n OFFLINE\n}\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/users/constants/user.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 USER_PASSWORD_MIN_LENGTH = 8\nexport const USER_MAX_PASSWORD_ATTEMPTS = 10\nexport const USER_LOGIN_VALIDATION = /^[a-zA-Z0-9\\-\\\\._]{2,255}$/\n\nexport const USER_PATH = {\n TMP: 'tmp',\n TASKS: 'tasks'\n} as const\n\nexport enum USER_ROLE {\n ADMINISTRATOR,\n USER,\n GUEST,\n LINK\n}\n\nexport enum USER_GROUP_ROLE {\n MEMBER,\n MANAGER\n}\n\nexport const USER_PERMS_SEP = ','\n\nexport enum USER_PERMISSION {\n PERSONAL_SPACE = 'personal_space',\n SPACES = 'spaces_access',\n SPACES_ADMIN = 'spaces_admin',\n SHARES = 'shares_access',\n SHARES_ADMIN = 'shares_admin',\n GUESTS_ADMIN = 'guests_admin',\n PERSONAL_GROUPS_ADMIN = 'personal_groups_admin',\n DESKTOP_APP = 'desktop_app_access',\n DESKTOP_APP_SYNC = 'desktop_app_sync',\n WEBDAV = 'webdav_access'\n}\n\nexport enum GUEST_PERMISSION {\n SPACES = USER_PERMISSION.SPACES,\n SHARES = USER_PERMISSION.SHARES,\n WEBDAV = USER_PERMISSION.WEBDAV\n}\n\nexport enum USER_ONLINE_STATUS {\n AVAILABLE,\n BUSY,\n ABSENT,\n OFFLINE\n}\n\nexport enum USER_NOTIFICATION {\n APPLICATION,\n APPLICATION_EMAIL\n}\n\nexport const USER_SECRET = {\n TWO_FA_SECRET: 'twoFaSecret',\n RECOVERY_CODES: 'recoveryCodes',\n APP_PASSWORDS: 'appPasswords'\n} as const\n"],"names":["GUEST_PERMISSION","USER_GROUP_ROLE","USER_LOGIN_VALIDATION","USER_MAX_PASSWORD_ATTEMPTS","USER_NOTIFICATION","USER_ONLINE_STATUS","USER_PASSWORD_MIN_LENGTH","USER_PATH","USER_PERMISSION","USER_PERMS_SEP","USER_ROLE","USER_SECRET","TMP","TASKS","TWO_FA_SECRET","RECOVERY_CODES","APP_PASSWORDS"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAsCWA;eAAAA;;QApBAC;eAAAA;;QAdCC;eAAAA;;QADAC;eAAAA;;QAgDDC;eAAAA;;QAPAC;eAAAA;;QA1CCC;eAAAA;;QAIAC;eAAAA;;QAmBDC;eAAAA;;QAFCC;eAAAA;;QAZDC;eAAAA;;QA6CCC;eAAAA;;;AAtDN,MAAML,2BAA2B;AACjC,MAAMH,6BAA6B;AACnC,MAAMD,wBAAwB;AAE9B,MAAMK,YAAY;IACvBK,KAAK;IACLC,OAAO;AACT;AAEO,IAAA,AAAKH,mCAAAA;;;;;WAAAA;;AAOL,IAAA,AAAKT,yCAAAA;;;WAAAA;;AAKL,MAAMQ,iBAAiB;AAEvB,IAAA,AAAKD,yCAAAA;;;;;;;;;;;WAAAA;;AAaL,IAAA,AAAKR,0CAAAA;;;;WAAAA;;AAML,IAAA,AAAKK,4CAAAA;;;;;WAAAA;;AAOL,IAAA,AAAKD,2CAAAA;;;WAAAA;;AAKL,MAAMO,cAAc;IACzBG,eAAe;IACfC,gBAAgB;IAChBC,eAAe;AACjB"}
|
|
@@ -25,6 +25,9 @@ _export(exports, {
|
|
|
25
25
|
get UserPasswordDto () {
|
|
26
26
|
return UserPasswordDto;
|
|
27
27
|
},
|
|
28
|
+
get UserStorageIndexingDto () {
|
|
29
|
+
return UserStorageIndexingDto;
|
|
30
|
+
},
|
|
28
31
|
get UserUpdatePasswordDto () {
|
|
29
32
|
return UserUpdatePasswordDto;
|
|
30
33
|
}
|
|
@@ -56,6 +59,13 @@ _ts_decorate([
|
|
|
56
59
|
(0, _classvalidator.IsInt)(),
|
|
57
60
|
_ts_metadata("design:type", Number)
|
|
58
61
|
], UserNotificationDto.prototype, "notification", void 0);
|
|
62
|
+
let UserStorageIndexingDto = class UserStorageIndexingDto {
|
|
63
|
+
};
|
|
64
|
+
_ts_decorate([
|
|
65
|
+
(0, _classvalidator.IsDefined)(),
|
|
66
|
+
(0, _classvalidator.IsBoolean)(),
|
|
67
|
+
_ts_metadata("design:type", Boolean)
|
|
68
|
+
], UserStorageIndexingDto.prototype, "storageIndexing", void 0);
|
|
59
69
|
let UserUpdatePasswordDto = class UserUpdatePasswordDto {
|
|
60
70
|
};
|
|
61
71
|
_ts_decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/users/dto/user-properties.dto.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 { Transform } from 'class-transformer'\nimport { IsDate, IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, MinLength, ValidateIf } from 'class-validator'\nimport { AUTH_SCOPE } from '../../../authentication/constants/scope'\nimport { currentDate } from '../../../common/shared'\nimport { USER_PASSWORD_MIN_LENGTH } from '../constants/user'\n\nexport class UserLanguageDto {\n @ValidateIf((_, language) => language === null || typeof language === 'string')\n language: string | null\n}\n\nexport class UserNotificationDto {\n @IsNotEmpty()\n @IsInt()\n notification: number\n}\n\nexport class UserUpdatePasswordDto {\n @IsNotEmpty()\n @IsString()\n oldPassword: string\n\n @IsNotEmpty()\n @IsString()\n @MinLength(USER_PASSWORD_MIN_LENGTH)\n newPassword: string\n}\n\nexport class UserPasswordDto {\n @IsNotEmpty()\n @IsString()\n @MinLength(USER_PASSWORD_MIN_LENGTH)\n password: string\n}\n\nexport class UserAppPasswordDto {\n @IsNotEmpty()\n @IsString()\n name: string\n\n @Transform(({ value }) => value.toLowerCase())\n @IsEnum(AUTH_SCOPE)\n app: AUTH_SCOPE\n\n @IsOptional()\n @Transform(({ value }) => (value ? currentDate(value) : null))\n @IsDate()\n expiration?: Date\n}\n"],"names":["UserAppPasswordDto","UserLanguageDto","UserNotificationDto","UserPasswordDto","UserUpdatePasswordDto","_","language","value","toLowerCase","currentDate"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/users/dto/user-properties.dto.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 { Transform } from 'class-transformer'\nimport { IsBoolean, IsDate, IsDefined, IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, MinLength, ValidateIf } from 'class-validator'\nimport { AUTH_SCOPE } from '../../../authentication/constants/scope'\nimport { currentDate } from '../../../common/shared'\nimport { USER_PASSWORD_MIN_LENGTH } from '../constants/user'\n\nexport class UserLanguageDto {\n @ValidateIf((_, language) => language === null || typeof language === 'string')\n language: string | null\n}\n\nexport class UserNotificationDto {\n @IsNotEmpty()\n @IsInt()\n notification: number\n}\n\nexport class UserStorageIndexingDto {\n @IsDefined()\n @IsBoolean()\n storageIndexing: boolean\n}\n\nexport class UserUpdatePasswordDto {\n @IsNotEmpty()\n @IsString()\n oldPassword: string\n\n @IsNotEmpty()\n @IsString()\n @MinLength(USER_PASSWORD_MIN_LENGTH)\n newPassword: string\n}\n\nexport class UserPasswordDto {\n @IsNotEmpty()\n @IsString()\n @MinLength(USER_PASSWORD_MIN_LENGTH)\n password: string\n}\n\nexport class UserAppPasswordDto {\n @IsNotEmpty()\n @IsString()\n name: string\n\n @Transform(({ value }) => value.toLowerCase())\n @IsEnum(AUTH_SCOPE)\n app: AUTH_SCOPE\n\n @IsOptional()\n @Transform(({ value }) => (value ? currentDate(value) : null))\n @IsDate()\n expiration?: Date\n}\n"],"names":["UserAppPasswordDto","UserLanguageDto","UserNotificationDto","UserPasswordDto","UserStorageIndexingDto","UserUpdatePasswordDto","_","language","value","toLowerCase","currentDate"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QA2CYA;eAAAA;;QAnCAC;eAAAA;;QAKAC;eAAAA;;QAuBAC;eAAAA;;QAjBAC;eAAAA;;QAMAC;eAAAA;;;kCAvBa;gCAC2F;uBAC1F;wBACC;sBACa;;;;;;;;;;AAElC,IAAA,AAAMJ,kBAAN,MAAMA;AAGb;;qCAFeK,GAAGC,WAAaA,aAAa,QAAQ,OAAOA,aAAa;;;AAIjE,IAAA,AAAML,sBAAN,MAAMA;AAIb;;;;;;AAEO,IAAA,AAAME,yBAAN,MAAMA;AAIb;;;;;;AAEO,IAAA,AAAMC,wBAAN,MAAMA;AASb;;;;;;;;;;;;AAEO,IAAA,AAAMF,kBAAN,MAAMA;AAKb;;;;;;;AAEO,IAAA,AAAMH,qBAAN,MAAMA;AAab;;;;;;;sCARc,EAAEQ,KAAK,EAAE,GAAKA,MAAMC,WAAW;;;;;;sCAK/B,EAAED,KAAK,EAAE,GAAMA,QAAQE,IAAAA,mBAAW,EAACF,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/users/models/user.model.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 { Exclude, Expose } from 'class-transformer'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { popFromObject } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { GUEST_PERMISSION, USER_PATH, USER_PERMISSION, USER_PERMS_SEP, USER_ROLE } from '../constants/user'\nimport type { Owner } from '../interfaces/owner.interface'\nimport type { UserSecrets } from '../interfaces/user-secrets.interface'\nimport type { User } from '../schemas/user.interface'\n\nexport class UserModel implements User {\n id: number\n login: string\n email: string\n firstName: string\n lastName: string\n role: number\n language: string\n isActive: boolean\n notification: number\n onlineStatus: number\n permissions: string\n storageUsage: number\n storageQuota: number\n passwordAttempts: number\n currentIp: string\n lastIp: string\n currentAccess: Date\n lastAccess: Date\n createdAt: Date\n // exclusions\n @Exclude()\n password: string\n @Exclude()\n secrets: UserSecrets\n @Exclude()\n // only used on backend\n impersonatedFromId?: number\n impersonatedClientId?: string\n // used for desktop|cmd app\n clientId?: string\n\n // outside db schema\n fullName: string\n impersonated?: boolean\n avatarBase64?: string\n // permissions as a list\n applications: string[] = []\n @Exclude({ toPlainOnly: true })\n exp?: number // refresh token expiration needed to refresh\n\n constructor(props: Partial<User> & { exp?: number; twoFaEnabled?: boolean }, removePassword = true) {\n // User model can be instantiated with data from the database or from a token payload\n this.initSecrets(props)\n Object.assign(this, props)\n if (removePassword) {\n // always remove the password field from model for obvious security reasons\n // do not remove it from `props` to not mutate the object\n this.removePassword()\n }\n this.setFullName()\n this.setApplications()\n this.setProfile()\n }\n\n private _homePath: string\n\n get homePath(): string {\n if (this.isLink || this.isGuest) {\n return (this._homePath ||= path.join(configuration.applications.files.tmpPath, this.isGuest ? 'guests' : 'links', this.login))\n }\n return (this._homePath ||= path.join(configuration.applications.files.usersPath, this.login))\n }\n\n private _filesPath: string\n\n get filesPath(): string {\n return (this._filesPath ||= path.join(this.homePath, SPACE_REPOSITORY.FILES))\n }\n\n private _trashPath: string\n\n get trashPath(): string {\n return (this._trashPath ||= path.join(this.homePath, SPACE_REPOSITORY.TRASH))\n }\n\n private _tmpPath: string\n\n get tmpPath(): string {\n return (this._tmpPath ||= path.join(this.homePath, USER_PATH.TMP))\n }\n\n private _tasksPath: string\n\n get tasksPath(): string {\n return (this._tasksPath ||= path.join(this.tmpPath, USER_PATH.TASKS))\n }\n\n @Expose()\n get isAdmin(): boolean {\n return this.role === USER_ROLE.ADMINISTRATOR\n }\n\n @Expose()\n get isUser(): boolean {\n return this.role === USER_ROLE.USER || this.role === USER_ROLE.ADMINISTRATOR\n }\n\n @Expose()\n get isGuest(): boolean {\n return this.role === USER_ROLE.GUEST\n }\n\n @Expose()\n get isLink(): boolean {\n return this.role === USER_ROLE.LINK\n }\n\n @Expose()\n get quotaIsExceeded(): boolean {\n return this.storageQuota !== null && this.storageUsage >= this.storageQuota\n }\n\n @Expose()\n get twoFaEnabled(): boolean {\n return !!this.secrets?.twoFaSecret\n }\n\n @Expose()\n get appPasswords(): number {\n return this.secrets?.appPasswords?.length || 0\n }\n\n static getHomePath(userLogin: string, isGuest = false, isLink = false): string {\n if (isGuest || isLink) {\n return path.join(configuration.applications.files.tmpPath, isGuest ? 'guests' : 'links', userLogin)\n }\n return path.join(configuration.applications.files.usersPath, userLogin)\n }\n\n static getFilesPath(userLogin: string): string {\n return path.join(UserModel.getHomePath(userLogin), SPACE_REPOSITORY.FILES)\n }\n\n static getTrashPath(userLogin: string): string {\n return path.join(UserModel.getHomePath(userLogin), SPACE_REPOSITORY.TRASH)\n }\n\n static getTasksPath(userLogin: string, isGuest = false, isLink = false): string {\n return path.join(UserModel.getHomePath(userLogin, isGuest, isLink), USER_PATH.TMP, USER_PATH.TASKS)\n }\n\n static getRepositoryPath(userLogin: string, inTrash = false): string {\n if (inTrash) return UserModel.getTrashPath(userLogin)\n return UserModel.getFilesPath(userLogin)\n }\n\n toString(): string {\n return `*User <${this.login}> (${this.id})*`\n }\n\n removePassword() {\n delete this.password\n }\n\n setFullName(force = false) {\n if (!this.fullName || force) {\n this.fullName = `${this.firstName || ''} ${this.lastName || ''}`.trim()\n }\n }\n\n async makePaths(): Promise<void> {\n if (this.isGuest || this.isLink) {\n await fs.mkdir(this.tasksPath, { recursive: true })\n } else {\n for (const p of [this.filesPath, this.trashPath, this.tasksPath]) {\n await fs.mkdir(p, { recursive: true })\n }\n }\n }\n\n asOwner(): Owner {\n return { id: this.id, login: this.login, email: this.email, fullName: this.fullName }\n }\n\n getInitials(): string {\n let initials: { f: string; l: string }\n if (this.firstName) {\n if (this.lastName) {\n initials = { f: this.firstName.charAt(0), l: this.lastName.charAt(0) }\n }\n initials = { f: this.firstName.charAt(0), l: this.firstName.charAt(1) }\n } else {\n initials = { f: this.login.charAt(0), l: this.login.charAt(1) }\n }\n return `${initials.f.toUpperCase()}${initials.l.toLowerCase()}`\n }\n\n havePermission(permission: string): boolean {\n if (this.isAdmin) {\n return true\n }\n if (permission === USER_PERMISSION.PERSONAL_SPACE && this.isGuest) {\n return false\n }\n return this.applications.indexOf(permission) !== -1\n }\n\n haveRole(role: number): boolean {\n return this.role <= role\n }\n\n private initSecrets(props: Partial<UserModel>) {\n // Remove the `twoFaEnabled` property to avoid conflicts with the current getter when using `plainToClass` with `class-validator`\n // The `props` variable may be empty when the class is instantiated using `plainToClass`\n if (props && 'twoFaEnabled' in props) {\n // Only used when the User model is instantiated from a token payload\n // Set a `twoFaSecret` property (boolean) on the `secrets` property so that the `twoFaEnabled` getter returns `true`\n this.secrets = { twoFaSecret: popFromObject('twoFaEnabled', props) }\n }\n }\n\n private setProfile() {\n if (this.isLink) {\n this.login = `Link (${this.id})`\n this.email = 'guest-link@sync-in'\n }\n }\n\n private setApplications() {\n if (this.isGuest) {\n // dynamically set the permissions\n this.applications = Object.values(GUEST_PERMISSION)\n } else if (this.permissions) {\n this.applications = this.permissions.split(USER_PERMS_SEP)\n }\n delete this.permissions\n }\n}\n"],"names":["UserModel","homePath","isLink","isGuest","_homePath","path","join","configuration","applications","files","tmpPath","login","usersPath","filesPath","_filesPath","SPACE_REPOSITORY","FILES","trashPath","_trashPath","TRASH","_tmpPath","USER_PATH","TMP","tasksPath","_tasksPath","TASKS","isAdmin","role","USER_ROLE","ADMINISTRATOR","isUser","USER","GUEST","LINK","quotaIsExceeded","storageQuota","storageUsage","twoFaEnabled","secrets","twoFaSecret","appPasswords","length","getHomePath","userLogin","getFilesPath","getTrashPath","getTasksPath","getRepositoryPath","inTrash","toString","id","removePassword","password","setFullName","force","fullName","firstName","lastName","trim","makePaths","fs","mkdir","recursive","p","asOwner","email","getInitials","initials","f","charAt","l","toUpperCase","toLowerCase","havePermission","permission","USER_PERMISSION","PERSONAL_SPACE","indexOf","haveRole","initSecrets","props","popFromObject","setProfile","setApplications","Object","values","GUEST_PERMISSION","permissions","split","USER_PERMS_SEP","assign","toPlainOnly"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/users/models/user.model.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 { Exclude, Expose } from 'class-transformer'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { popFromObject } from '../../../common/shared'\nimport { configuration } from '../../../configuration/config.environment'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { GUEST_PERMISSION, USER_PATH, USER_PERMISSION, USER_PERMS_SEP, USER_ROLE } from '../constants/user'\nimport type { Owner } from '../interfaces/owner.interface'\nimport type { UserSecrets } from '../interfaces/user-secrets.interface'\nimport type { User } from '../schemas/user.interface'\n\nexport class UserModel implements User {\n id: number\n login: string\n email: string\n firstName: string\n lastName: string\n role: number\n language: string\n isActive: boolean\n notification: number\n onlineStatus: number\n permissions: string\n storageUsage: number\n storageQuota: number\n storageIndexing: boolean\n passwordAttempts: number\n currentIp: string\n lastIp: string\n currentAccess: Date\n lastAccess: Date\n createdAt: Date\n // exclusions\n @Exclude()\n password: string\n @Exclude()\n secrets: UserSecrets\n @Exclude()\n // only used on backend\n impersonatedFromId?: number\n impersonatedClientId?: string\n // used for desktop|cmd app\n clientId?: string\n\n // outside db schema\n fullName: string\n impersonated?: boolean\n avatarBase64?: string\n // permissions as a list\n applications: string[] = []\n @Exclude({ toPlainOnly: true })\n exp?: number // refresh token expiration needed to refresh\n\n constructor(props: Partial<User> & { exp?: number; twoFaEnabled?: boolean }, removePassword = true) {\n // User model can be instantiated with data from the database or from a token payload\n this.initSecrets(props)\n Object.assign(this, props)\n if (removePassword) {\n // always remove the password field from model for obvious security reasons\n // do not remove it from `props` to not mutate the object\n this.removePassword()\n }\n this.setFullName()\n this.setApplications()\n this.setProfile()\n }\n\n private _homePath: string\n\n get homePath(): string {\n if (this.isLink || this.isGuest) {\n return (this._homePath ||= path.join(configuration.applications.files.tmpPath, this.isGuest ? 'guests' : 'links', this.login))\n }\n return (this._homePath ||= path.join(configuration.applications.files.usersPath, this.login))\n }\n\n private _filesPath: string\n\n get filesPath(): string {\n return (this._filesPath ||= path.join(this.homePath, SPACE_REPOSITORY.FILES))\n }\n\n private _trashPath: string\n\n get trashPath(): string {\n return (this._trashPath ||= path.join(this.homePath, SPACE_REPOSITORY.TRASH))\n }\n\n private _tmpPath: string\n\n get tmpPath(): string {\n return (this._tmpPath ||= path.join(this.homePath, USER_PATH.TMP))\n }\n\n private _tasksPath: string\n\n get tasksPath(): string {\n return (this._tasksPath ||= path.join(this.tmpPath, USER_PATH.TASKS))\n }\n\n @Expose()\n get isAdmin(): boolean {\n return this.role === USER_ROLE.ADMINISTRATOR\n }\n\n @Expose()\n get isUser(): boolean {\n return this.role === USER_ROLE.USER || this.role === USER_ROLE.ADMINISTRATOR\n }\n\n @Expose()\n get isGuest(): boolean {\n return this.role === USER_ROLE.GUEST\n }\n\n @Expose()\n get isLink(): boolean {\n return this.role === USER_ROLE.LINK\n }\n\n @Expose()\n get quotaIsExceeded(): boolean {\n return this.storageQuota !== null && this.storageUsage >= this.storageQuota\n }\n\n @Expose()\n get twoFaEnabled(): boolean {\n return !!this.secrets?.twoFaSecret\n }\n\n @Expose()\n get appPasswords(): number {\n return this.secrets?.appPasswords?.length || 0\n }\n\n static getHomePath(userLogin: string, isGuest = false, isLink = false): string {\n if (isGuest || isLink) {\n return path.join(configuration.applications.files.tmpPath, isGuest ? 'guests' : 'links', userLogin)\n }\n return path.join(configuration.applications.files.usersPath, userLogin)\n }\n\n static getFilesPath(userLogin: string): string {\n return path.join(UserModel.getHomePath(userLogin), SPACE_REPOSITORY.FILES)\n }\n\n static getTrashPath(userLogin: string): string {\n return path.join(UserModel.getHomePath(userLogin), SPACE_REPOSITORY.TRASH)\n }\n\n static getTasksPath(userLogin: string, isGuest = false, isLink = false): string {\n return path.join(UserModel.getHomePath(userLogin, isGuest, isLink), USER_PATH.TMP, USER_PATH.TASKS)\n }\n\n static getRepositoryPath(userLogin: string, inTrash = false): string {\n if (inTrash) return UserModel.getTrashPath(userLogin)\n return UserModel.getFilesPath(userLogin)\n }\n\n toString(): string {\n return `*User <${this.login}> (${this.id})*`\n }\n\n removePassword() {\n delete this.password\n }\n\n setFullName(force = false) {\n if (!this.fullName || force) {\n this.fullName = `${this.firstName || ''} ${this.lastName || ''}`.trim()\n }\n }\n\n async makePaths(): Promise<void> {\n if (this.isGuest || this.isLink) {\n await fs.mkdir(this.tasksPath, { recursive: true })\n } else {\n for (const p of [this.filesPath, this.trashPath, this.tasksPath]) {\n await fs.mkdir(p, { recursive: true })\n }\n }\n }\n\n asOwner(): Owner {\n return { id: this.id, login: this.login, email: this.email, fullName: this.fullName }\n }\n\n getInitials(): string {\n let initials: { f: string; l: string }\n if (this.firstName) {\n if (this.lastName) {\n initials = { f: this.firstName.charAt(0), l: this.lastName.charAt(0) }\n }\n initials = { f: this.firstName.charAt(0), l: this.firstName.charAt(1) }\n } else {\n initials = { f: this.login.charAt(0), l: this.login.charAt(1) }\n }\n return `${initials.f.toUpperCase()}${initials.l.toLowerCase()}`\n }\n\n havePermission(permission: string): boolean {\n if (this.isAdmin) {\n return true\n }\n if (permission === USER_PERMISSION.PERSONAL_SPACE && this.isGuest) {\n return false\n }\n return this.applications.indexOf(permission) !== -1\n }\n\n haveRole(role: number): boolean {\n return this.role <= role\n }\n\n private initSecrets(props: Partial<UserModel>) {\n // Remove the `twoFaEnabled` property to avoid conflicts with the current getter when using `plainToClass` with `class-validator`\n // The `props` variable may be empty when the class is instantiated using `plainToClass`\n if (props && 'twoFaEnabled' in props) {\n // Only used when the User model is instantiated from a token payload\n // Set a `twoFaSecret` property (boolean) on the `secrets` property so that the `twoFaEnabled` getter returns `true`\n this.secrets = { twoFaSecret: popFromObject('twoFaEnabled', props) }\n }\n }\n\n private setProfile() {\n if (this.isLink) {\n this.login = `Link (${this.id})`\n this.email = 'guest-link@sync-in'\n }\n }\n\n private setApplications() {\n if (this.isGuest) {\n // dynamically set the permissions\n this.applications = Object.values(GUEST_PERMISSION)\n } else if (this.permissions) {\n this.applications = this.permissions.split(USER_PERMS_SEP)\n }\n delete this.permissions\n }\n}\n"],"names":["UserModel","homePath","isLink","isGuest","_homePath","path","join","configuration","applications","files","tmpPath","login","usersPath","filesPath","_filesPath","SPACE_REPOSITORY","FILES","trashPath","_trashPath","TRASH","_tmpPath","USER_PATH","TMP","tasksPath","_tasksPath","TASKS","isAdmin","role","USER_ROLE","ADMINISTRATOR","isUser","USER","GUEST","LINK","quotaIsExceeded","storageQuota","storageUsage","twoFaEnabled","secrets","twoFaSecret","appPasswords","length","getHomePath","userLogin","getFilesPath","getTrashPath","getTasksPath","getRepositoryPath","inTrash","toString","id","removePassword","password","setFullName","force","fullName","firstName","lastName","trim","makePaths","fs","mkdir","recursive","p","asOwner","email","getInitials","initials","f","charAt","l","toUpperCase","toLowerCase","havePermission","permission","USER_PERMISSION","PERSONAL_SPACE","indexOf","haveRole","initSecrets","props","popFromObject","setProfile","setApplications","Object","values","GUEST_PERMISSION","permissions","split","USER_PERMS_SEP","assign","toPlainOnly"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/users/schemas/user.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 type { UserSecrets } from '../interfaces/user-secrets.interface'\nimport type { users } from './users.schema'\n\ntype UserSchema = typeof users.$inferSelect\n\nexport class User implements UserSchema {\n id: number\n email: string\n login: string\n firstName: string\n lastName: string\n password: string\n role: number\n isActive: boolean\n secrets: UserSecrets\n language: string\n permissions: string\n storageUsage: number\n storageQuota: number\n notification: number\n onlineStatus: number\n passwordAttempts: number\n currentIp: string\n lastIp: string\n currentAccess: Date\n lastAccess: Date\n createdAt: Date\n}\n"],"names":["User"],"mappings":"AAAA;;;;CAIC;;;;+BAOYA;;;eAAAA;;;AAAN,IAAA,AAAMA,OAAN,MAAMA;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/users/schemas/user.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 type { UserSecrets } from '../interfaces/user-secrets.interface'\nimport type { users } from './users.schema'\n\ntype UserSchema = typeof users.$inferSelect\n\nexport class User implements UserSchema {\n id: number\n email: string\n login: string\n firstName: string\n lastName: string\n password: string\n role: number\n isActive: boolean\n secrets: UserSecrets\n language: string\n permissions: string\n storageUsage: number\n storageQuota: number\n storageIndexing: boolean\n notification: number\n onlineStatus: number\n passwordAttempts: number\n currentIp: string\n lastIp: string\n currentAccess: Date\n lastAccess: Date\n createdAt: Date\n}\n"],"names":["User"],"mappings":"AAAA;;;;CAIC;;;;+BAOYA;;;eAAAA;;;AAAN,IAAA,AAAMA,OAAN,MAAMA;AAuBb"}
|
|
@@ -51,8 +51,8 @@ const users = (0, _mysqlcore.mysqlTable)('users', {
|
|
|
51
51
|
}).default(1).notNull(),
|
|
52
52
|
isActive: (0, _mysqlcore.boolean)('isActive').default(true).notNull(),
|
|
53
53
|
secrets: (0, _columns.jsonColumn)()('secrets'),
|
|
54
|
-
language: (0, _mysqlcore.
|
|
55
|
-
length:
|
|
54
|
+
language: (0, _mysqlcore.varchar)('language', {
|
|
55
|
+
length: 10
|
|
56
56
|
}),
|
|
57
57
|
permissions: (0, _mysqlcore.varchar)('permissions', {
|
|
58
58
|
length: 255
|
|
@@ -65,6 +65,7 @@ const users = (0, _mysqlcore.mysqlTable)('users', {
|
|
|
65
65
|
mode: 'number',
|
|
66
66
|
unsigned: true
|
|
67
67
|
}),
|
|
68
|
+
storageIndexing: (0, _mysqlcore.boolean)('storageIndexing').default(true).notNull(),
|
|
68
69
|
notification: (0, _mysqlcore.tinyint)('notification', {
|
|
69
70
|
unsigned: true
|
|
70
71
|
}).default(1).notNull(),
|