@sync-in/server 1.8.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 +11 -2
- package/package.json +10 -9
- package/server/app.bootstrap.js +4 -2
- package/server/app.bootstrap.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-manager.service.js.map +1 -1
- package/server/applications/files/services/files-methods.service.js +1 -6
- package/server/applications/files/services/files-methods.service.js.map +1 -1
- package/server/applications/files/utils/doc-textify/adapters/pdf.js +5 -16
- package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -2
- package/server/applications/users/services/users-manager.service.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/common/image.js +62 -58
- package/server/common/image.js.map +1 -1
- package/static/3rdpartylicenses.txt +0 -26
- package/static/chunk-2VMSXRCB.js +12 -0
- package/static/{chunk-X5XGK6T7.js → chunk-3OHSRRKH.js} +1 -1
- package/static/{chunk-H6NE33VX.js → chunk-3R4WKOHQ.js} +1 -1
- package/static/{chunk-WLMNXRBS.js → chunk-3R74L4UU.js} +1 -1
- package/static/{chunk-ZPF2DSQV.js → chunk-5UKZLU5H.js} +1 -1
- package/static/{chunk-KFJIQIGR.js → chunk-BQV4FRM6.js} +1 -1
- package/static/{chunk-MFLIJH6T.js → chunk-CETH7UYS.js} +1 -1
- package/static/{chunk-C36MW4ME.js → chunk-DIT6W7VM.js} +9 -9
- package/static/{chunk-YW57T2PF.js → chunk-IQSKQXC3.js} +1 -1
- package/static/{chunk-QZU2S5CV.js → chunk-ITUFI2BJ.js} +1 -1
- package/static/{chunk-PGZZP5W3.js → chunk-LCTZJ537.js} +1 -1
- package/static/{chunk-LVM4QB22.js → chunk-LK2UCQJ6.js} +1 -1
- package/static/{chunk-ZTCRGJ6Y.js → chunk-LP5TBXEN.js} +1 -1
- package/static/{chunk-BIKLW4YS.js → chunk-LVSNIS5P.js} +1 -1
- package/static/{chunk-VM4YX6Q7.js → chunk-MTVSJTIW.js} +1 -1
- package/static/{chunk-V3AT2BKP.js → chunk-O6FYXVHI.js} +1 -1
- package/static/{chunk-SHIVUDP3.js → chunk-PNR6M34W.js} +1 -1
- package/static/{chunk-M3XVNQZQ.js → chunk-QMRBZHE4.js} +1 -1
- package/static/{chunk-NO2LTNW3.js → chunk-QSJRY3TF.js} +1 -1
- package/static/{chunk-373XVRXW.js → chunk-QUUIRSYT.js} +1 -1
- package/static/{chunk-UEQCWMXD.js → chunk-RFH46UW3.js} +1 -1
- package/static/{chunk-AY2SZ3G6.js → chunk-RSXHRKM5.js} +1 -1
- package/static/{chunk-UJPPR4MX.js → chunk-RV3VZJPZ.js} +1 -1
- package/static/{chunk-JSWCNGXJ.js → chunk-S7HNXVRB.js} +1 -1
- package/static/{chunk-VKK5BSLX.js → chunk-SJR5R3Y4.js} +1 -1
- package/static/{chunk-UG5DMXYO.js → chunk-V3LHHZYN.js} +1 -1
- package/static/{chunk-HAS5ZOTR.js → chunk-VJTXJ43D.js} +1 -1
- package/static/{chunk-HNQRZALS.js → chunk-VQQKMY2C.js} +1 -1
- package/static/{chunk-MSUHTBB2.js → chunk-WSSU2HXE.js} +1 -1
- package/static/{chunk-GUGNR5TF.js → chunk-XDZGW64M.js} +2 -2
- package/static/{chunk-TPYBFZS5.js → chunk-XTRDKGKG.js} +1 -1
- package/static/{chunk-YEKR5OPO.js → chunk-YLWTEC3X.js} +1 -1
- package/static/index.html +1 -1
- package/static/{main-VOL6OMJ5.js → main-4H5BJY3J.js} +2 -2
- package/static/chunk-WJW7CT6G.js +0 -27
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
## [1.8.
|
|
1
|
+
## [1.8.1](https://github.com/Sync-in/server/compare/v1.8.0...v1.8.1) (2025-10-30)
|
|
2
2
|
|
|
3
3
|
### Highlights
|
|
4
4
|
|
|
5
5
|
* 🌍 **14 languages supported** — added 12 new ones: 🇩🇪 🇪🇸 🇵🇹 🇧🇷 🇮🇹 🇨🇳 🇮🇳 🇹🇷 🇯🇵 🇰🇷 🇵🇱 🇷🇺
|
|
6
6
|
* ⚡ **Better suited for small systems** – reduced the default number of backend workers from **2 to 1** to improve memory efficiency on lightweight
|
|
7
7
|
setups (e.g. Raspberry Pi).
|
|
8
|
+
* 😈 **FreeBSD support** – npm distribution is now compatible with FreeBSD
|
|
8
9
|
* 🔍 **Indexing & search controls** — new config to enable/disable indexing, per-space toggles, and full-text search preferences.
|
|
9
10
|
* 📊 **Quotas** — define storage quotas for external shares; storage from anchored external locations now counts toward the space’s total usage.
|
|
10
11
|
* 🖼️ **Thumbnails** — photo thumbnail generation is now **3× faster**.
|
|
11
|
-
* 🐳 **Docker** — minimized system dependencies for a **lighter and more efficient image
|
|
12
|
+
* 🐳 **Docker** — minimized system dependencies for a **lighter and more efficient image** (from 562MB to 357MB, saving 205MB!).
|
|
12
13
|
|
|
13
14
|
➡️ [More details](https://sync-in.com/news/sync-in-server-1-8)
|
|
14
15
|
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **backend:files:** lower PDF.js verbosity to reduce logging noise ([336fce8](https://github.com/Sync-in/server/commit/336fce8d6b9f2873c10bfaf3a7ca226eb3cb6069))
|
|
19
|
+
* **backend:users:** handle graceful shutdown in WebSocket gateway to prevent new connections during app termination ([0f02820](https://github.com/Sync-in/server/commit/0f02820a291fd5764e928a00cd540514ddfc5ad3))
|
|
20
|
+
* **backend:** update router options access to use `options.routerOptions` instead of deprecated `constraints` property (Fastify v6 compatibility) ([2d74512](https://github.com/Sync-in/server/commit/2d74512a800ba7d80e043679249ec98d3ab6f180))
|
|
21
|
+
|
|
22
|
+
## [1.8.0](https://github.com/Sync-in/server/compare/v1.7.0...v1.8.0) (2025-10-26)
|
|
23
|
+
|
|
15
24
|
### Features
|
|
16
25
|
|
|
17
26
|
* **backend:cache:** update Redis packages to latest versions supporting Redis 7.x and 8.x, adjust code and improve cache
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sync-in/server",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Johan Legrand",
|
|
@@ -74,24 +74,24 @@
|
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@fastify/cookie": "11.0.2",
|
|
76
76
|
"@fastify/helmet": "13.0.2",
|
|
77
|
-
"@fastify/multipart": "9.
|
|
77
|
+
"@fastify/multipart": "9.3.0",
|
|
78
78
|
"@fastify/send": "4.1.0",
|
|
79
79
|
"@fastify/static": "8.3.0",
|
|
80
80
|
"@knaadh/nestjs-drizzle-mysql2": "1.2.0",
|
|
81
81
|
"@lukeed/ms": "2.0.2",
|
|
82
82
|
"@nestjs/axios": "4.0.1",
|
|
83
|
-
"@nestjs/common": "11.1.
|
|
83
|
+
"@nestjs/common": "11.1.8",
|
|
84
84
|
"@nestjs/config": "4.0.2",
|
|
85
|
-
"@nestjs/core": "11.1.
|
|
85
|
+
"@nestjs/core": "11.1.8",
|
|
86
86
|
"@nestjs/jwt": "11.0.1",
|
|
87
87
|
"@nestjs/passport": "11.0.5",
|
|
88
|
-
"@nestjs/platform-fastify": "11.1.
|
|
89
|
-
"@nestjs/platform-socket.io": "11.1.
|
|
88
|
+
"@nestjs/platform-fastify": "11.1.8",
|
|
89
|
+
"@nestjs/platform-socket.io": "11.1.8",
|
|
90
90
|
"@nestjs/schedule": "6.0.1",
|
|
91
|
-
"@nestjs/websockets": "11.1.
|
|
92
|
-
"@resvg/resvg-js": "2.6.2",
|
|
91
|
+
"@nestjs/websockets": "11.1.8",
|
|
93
92
|
"@socket.io/cluster-adapter": "0.3.0",
|
|
94
93
|
"@socket.io/redis-adapter": "8.3.0",
|
|
94
|
+
"@types/text-to-svg": "3.1.4",
|
|
95
95
|
"archiver": "7.0.1",
|
|
96
96
|
"bcryptjs": "3.0.2",
|
|
97
97
|
"class-transformer": "0.5.1",
|
|
@@ -112,7 +112,6 @@
|
|
|
112
112
|
"passport-jwt": "4.0.1",
|
|
113
113
|
"passport-local": "1.0.0",
|
|
114
114
|
"passport": "0.7.0",
|
|
115
|
-
"pdfjs-dist": "5.4.296",
|
|
116
115
|
"pino-pretty": "13.1.2",
|
|
117
116
|
"qrcode-generator": "2.0.4",
|
|
118
117
|
"redis": "5.9.0",
|
|
@@ -120,7 +119,9 @@
|
|
|
120
119
|
"sharp": "0.34.4",
|
|
121
120
|
"socket.io": "4.8.1",
|
|
122
121
|
"tar": "7.5.1",
|
|
122
|
+
"text-to-svg": "3.1.5",
|
|
123
123
|
"time2fa": "1.4.2",
|
|
124
|
+
"unpdf": "1.3.2",
|
|
124
125
|
"yauzl": "3.2.0"
|
|
125
126
|
}
|
|
126
127
|
}
|
package/server/app.bootstrap.js
CHANGED
|
@@ -35,8 +35,10 @@ async function appBootstrap() {
|
|
|
35
35
|
/* APP */ const fastifyAdapter = new _platformfastify.FastifyAdapter({
|
|
36
36
|
logger: false,
|
|
37
37
|
trustProxy: _configenvironment.configuration.server.trustProxy,
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
routerOptions: {
|
|
39
|
+
ignoreTrailingSlash: true,
|
|
40
|
+
maxParamLength: 256
|
|
41
|
+
},
|
|
40
42
|
bodyLimit: 26214400 /* 25 MB */
|
|
41
43
|
});
|
|
42
44
|
const app = await _core.NestFactory.create(_appmodule.AppModule, fastifyAdapter, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { WEBDAV_NS, WEBDAV_SPACES } from './applications/webdav/constants/routes'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n ignoreTrailingSlash: true,\n
|
|
1
|
+
{"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { WEBDAV_NS, WEBDAV_SPACES } from './applications/webdav/constants/routes'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n routerOptions: {\n ignoreTrailingSlash: true,\n maxParamLength: 256\n },\n bodyLimit: 26214400 /* 25 MB */\n })\n const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter, {\n bufferLogs: true\n })\n\n /* NestJS starts listening for shutdown hooks */\n app.enableShutdownHooks()\n\n /* Fastify instance */\n const fastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* PARSER */\n // xml body parser is used for webdav methods\n app.useBodyParser(['application/xml', 'text/xml'])\n // add webdav methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n // '*' body parser allow binary data as stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n // Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)\n // This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.\n // todo: remove it when fixed on Joplin side\n fastifyInstance.addHook('onRequest', async (req, _reply) => {\n if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(WEBDAV_SPACES[WEBDAV_NS.WEBDAV].route)) {\n req.headers['content-type'] = 'application/octet-stream'\n }\n })\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\n )\n /* VALIDATION */\n app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))\n\n /* STATIC */\n app.useStaticAssets({ root: STATIC_PATH, prefixAvoidTrailingSlash: true })\n\n /* SECURITY */\n await app.register(fastifyHelmet, { contentSecurityPolicy: CONTENT_SECURITY_POLICY(configuration.applications.files.onlyoffice.externalServer) })\n\n /* COOKIES */\n // we use csrf secret to unsign csrf cookie\n await app.register(fastifyCookie, {\n secret: configuration.auth.token.csrf.secret,\n parseOptions: {\n secure: 'auto',\n sameSite: configuration.auth.cookieSameSite,\n httpOnly: true\n }\n })\n\n /* UPLOAD */\n await app.register(multipart, {\n preservePath: true,\n limits: { parts: Infinity, fileSize: configuration.applications.files.maxUploadSize }\n })\n\n /* WEBSOCKET */\n if (!IS_TEST_ENV) {\n const webSocketAdapter = new WebSocketAdapter(app)\n await webSocketAdapter.initAdapter()\n app.useWebSocketAdapter(webSocketAdapter)\n }\n\n return app\n}\n"],"names":["appBootstrap","fastifyAdapter","FastifyAdapter","logger","trustProxy","configuration","server","routerOptions","ignoreTrailingSlash","maxParamLength","bodyLimit","app","NestFactory","create","AppModule","bufferLogs","enableShutdownHooks","fastifyInstance","getInstance","useLogger","IS_TEST_ENV","get","Logger","useBodyParser","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addContentTypeParser","_req","_payload","done","addHook","req","_reply","headers","indexOf","originalUrl","startsWith","WEBDAV_SPACES","WEBDAV_NS","WEBDAV","route","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","cookieSameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "FilesController", {
|
|
|
14
14
|
});
|
|
15
15
|
const _common = require("@nestjs/common");
|
|
16
16
|
const _fastify = require("fastify");
|
|
17
|
+
const _image = require("../../common/image");
|
|
17
18
|
const _spaceskipguarddecorator = require("../spaces/decorators/space-skip-guard.decorator");
|
|
18
19
|
const _spaceskippermissionsdecorator = require("../spaces/decorators/space-skip-permissions.decorator");
|
|
19
20
|
const _spacedecorator = require("../spaces/decorators/space.decorator");
|
|
@@ -66,8 +67,11 @@ let FilesController = class FilesController {
|
|
|
66
67
|
async delete(user, space) {
|
|
67
68
|
return this.filesMethods.delete(user, space);
|
|
68
69
|
}
|
|
69
|
-
async genThumbnail(space, size = 256) {
|
|
70
|
-
|
|
70
|
+
async genThumbnail(space, size = 256, res) {
|
|
71
|
+
if (size > 1024) size = 1024;
|
|
72
|
+
const thumb = await this.filesMethods.genThumbnail(space, size);
|
|
73
|
+
res.type(_image.webpMimeType);
|
|
74
|
+
return res.send(thumb);
|
|
71
75
|
}
|
|
72
76
|
// TASKS OPERATIONS
|
|
73
77
|
async downloadFromUrlAsTask(user, space, downloadFileDto) {
|
|
@@ -199,11 +203,15 @@ _ts_decorate([
|
|
|
199
203
|
_ts_decorate([
|
|
200
204
|
(0, _common.Get)(`${_routes.FILES_ROUTE.OPERATION}/${_operations.FILE_OPERATION.THUMBNAIL}/*`),
|
|
201
205
|
_ts_param(0, (0, _spacedecorator.GetSpace)()),
|
|
202
|
-
_ts_param(1, (0, _common.Query)('size'
|
|
206
|
+
_ts_param(1, (0, _common.Query)('size', new _common.ParseIntPipe({
|
|
207
|
+
optional: true
|
|
208
|
+
}))),
|
|
209
|
+
_ts_param(2, (0, _common.Res)()),
|
|
203
210
|
_ts_metadata("design:type", Function),
|
|
204
211
|
_ts_metadata("design:paramtypes", [
|
|
205
212
|
typeof _spaceenvmodel.SpaceEnv === "undefined" ? Object : _spaceenvmodel.SpaceEnv,
|
|
206
|
-
|
|
213
|
+
void 0,
|
|
214
|
+
typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply
|
|
207
215
|
]),
|
|
208
216
|
_ts_metadata("design:returntype", Promise)
|
|
209
217
|
], FilesController.prototype, "genThumbnail", null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/files/files.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 { Body, Controller, Copy, Delete, Get, Head, Logger, Move, Post, Query, Req, Res, Search, StreamableFile, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { SkipSpaceGuard } from '../spaces/decorators/space-skip-guard.decorator'\nimport { SkipSpacePermissionsCheck } from '../spaces/decorators/space-skip-permissions.decorator'\nimport { GetSpace } from '../spaces/decorators/space.decorator'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { FastifySpaceRequest } from '../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../spaces/models/space-env.model'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserModel } from '../users/models/user.model'\nimport { FILE_OPERATION } from './constants/operations'\nimport { FILES_ROUTE } from './constants/routes'\nimport { CompressFileDto, CopyMoveFileDto, DownloadFileDto, MakeFileDto, SearchFilesDto } from './dto/file-operations.dto'\nimport { FileTask } from './models/file-task'\nimport { FileContent } from './schemas/file-content.interface'\nimport { FileRecent } from './schemas/file-recent.interface'\nimport { FilesMethods } from './services/files-methods.service'\nimport { FilesRecents } from './services/files-recents.service'\nimport { FilesSearchManager } from './services/files-search-manager.service'\nimport { FilesTasksManager } from './services/files-tasks-manager.service'\n\n@Controller(FILES_ROUTE.BASE)\n@UseGuards(SpaceGuard)\nexport class FilesController {\n private readonly logger = new Logger(FilesController.name)\n\n constructor(\n private readonly filesMethods: FilesMethods,\n private readonly filesTasksManager: FilesTasksManager,\n private readonly filesRecents: FilesRecents,\n private readonly filesSearch: FilesSearchManager\n ) {}\n\n // OPERATIONS\n\n @Head(`${FILES_ROUTE.OPERATION}/*`)\n async head(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.filesMethods.headOrGet(req, res)\n }\n\n @Get(`${FILES_ROUTE.OPERATION}/*`)\n async download(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.filesMethods.headOrGet(req, res)\n }\n\n @Post(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.MAKE}/*`)\n async make(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() makeFileDto: MakeFileDto): Promise<void> {\n return this.filesMethods.make(user, space, makeFileDto)\n }\n\n @Post(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.UPLOAD}/*`)\n async upload(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<void> {\n return this.filesMethods.upload(req, res)\n }\n\n @Copy(`${FILES_ROUTE.OPERATION}/*`)\n async copy(\n @GetUser() user: UserModel,\n @GetSpace() space: SpaceEnv,\n @Body() copyMoveFileDto: CopyMoveFileDto\n ): Promise<{\n path: string\n name: string\n }> {\n return this.filesMethods.copy(user, space, copyMoveFileDto)\n }\n\n @Move(`${FILES_ROUTE.OPERATION}/*`)\n async move(\n @GetUser() user: UserModel,\n @GetSpace() space: SpaceEnv,\n @Body() copyMoveFileDto: CopyMoveFileDto\n ): Promise<{\n path: string\n name: string\n }> {\n return this.filesMethods.move(user, space, copyMoveFileDto)\n }\n\n @Delete(`${FILES_ROUTE.OPERATION}/*`)\n async delete(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<void> {\n return this.filesMethods.delete(user, space)\n }\n\n @Get(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.THUMBNAIL}/*`)\n async genThumbnail(@GetSpace() space: SpaceEnv, @Query('size') size: number = 256): Promise<StreamableFile> {\n return this.filesMethods.genThumbnail(space, size)\n }\n\n // TASKS OPERATIONS\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.DOWNLOAD}/*`)\n async downloadFromUrlAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() downloadFileDto: DownloadFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DOWNLOAD, user, space, downloadFileDto, this.filesMethods.downloadFromUrl.name)\n }\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.COMPRESS}/*`)\n @SkipSpacePermissionsCheck()\n // Compression could be used to download files, permission is checked later\n async compressAsTask(@Req() req: FastifySpaceRequest, @Body() compressFileDto: CompressFileDto): Promise<FileTask> {\n if (compressFileDto.compressInDirectory) {\n SpaceGuard.checkPermissions(req, this.logger)\n }\n return this.filesTasksManager.createTask(FILE_OPERATION.COMPRESS, req.user, req.space, compressFileDto, this.filesMethods.compress.name)\n }\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.DECOMPRESS}/*`)\n async decompressAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DECOMPRESS, user, space, null, this.filesMethods.decompress.name)\n }\n\n @Copy(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async copyAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() copyMoveFileDto: CopyMoveFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.COPY, user, space, copyMoveFileDto, this.filesMethods.copy.name)\n }\n\n @Move(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async moveAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() copyMoveFileDto: CopyMoveFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.MOVE, user, space, copyMoveFileDto, this.filesMethods.move.name)\n }\n\n @Delete(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async deleteAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DELETE, user, space, null, this.filesMethods.delete.name)\n }\n\n // RECENT FILES\n\n @Get(FILES_ROUTE.RECENTS)\n @SkipSpaceGuard()\n getRecents(@GetUser() user: UserModel, @Query('limit') limit: number = 10): Promise<FileRecent[]> {\n return this.filesRecents.getRecents(user, limit)\n }\n\n // SEARCH FILES\n\n @Search(FILES_ROUTE.SEARCH)\n @SkipSpaceGuard()\n search(@GetUser() user: UserModel, @Body() search: SearchFilesDto): Promise<FileContent[]> {\n return this.filesSearch.search(user, search)\n }\n}\n"],"names":["FilesController","head","req","res","filesMethods","headOrGet","download","make","user","space","makeFileDto","upload","copy","copyMoveFileDto","move","delete","genThumbnail","size","downloadFromUrlAsTask","downloadFileDto","filesTasksManager","createTask","FILE_OPERATION","DOWNLOAD","downloadFromUrl","name","compressAsTask","compressFileDto","compressInDirectory","SpaceGuard","checkPermissions","logger","COMPRESS","compress","decompressAsTask","DECOMPRESS","decompress","copyAsTask","COPY","moveAsTask","MOVE","deleteAsTask","DELETE","getRecents","limit","filesRecents","search","filesSearch","Logger","FILES_ROUTE","OPERATION","passthrough","MAKE","UPLOAD","THUMBNAIL","TASK_OPERATION","RECENTS","SEARCH","BASE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/files/files.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 Head,\n Logger,\n Move,\n ParseIntPipe,\n Post,\n Query,\n Req,\n Res,\n Search,\n StreamableFile,\n UseGuards\n} from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { webpMimeType } from '../../common/image'\nimport { SkipSpaceGuard } from '../spaces/decorators/space-skip-guard.decorator'\nimport { SkipSpacePermissionsCheck } from '../spaces/decorators/space-skip-permissions.decorator'\nimport { GetSpace } from '../spaces/decorators/space.decorator'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { FastifySpaceRequest } from '../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../spaces/models/space-env.model'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserModel } from '../users/models/user.model'\nimport { FILE_OPERATION } from './constants/operations'\nimport { FILES_ROUTE } from './constants/routes'\nimport { CompressFileDto, CopyMoveFileDto, DownloadFileDto, MakeFileDto, SearchFilesDto } from './dto/file-operations.dto'\nimport { FileTask } from './models/file-task'\nimport { FileContent } from './schemas/file-content.interface'\nimport { FileRecent } from './schemas/file-recent.interface'\nimport { FilesMethods } from './services/files-methods.service'\nimport { FilesRecents } from './services/files-recents.service'\nimport { FilesSearchManager } from './services/files-search-manager.service'\nimport { FilesTasksManager } from './services/files-tasks-manager.service'\n\n@Controller(FILES_ROUTE.BASE)\n@UseGuards(SpaceGuard)\nexport class FilesController {\n private readonly logger = new Logger(FilesController.name)\n\n constructor(\n private readonly filesMethods: FilesMethods,\n private readonly filesTasksManager: FilesTasksManager,\n private readonly filesRecents: FilesRecents,\n private readonly filesSearch: FilesSearchManager\n ) {}\n\n // OPERATIONS\n\n @Head(`${FILES_ROUTE.OPERATION}/*`)\n async head(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.filesMethods.headOrGet(req, res)\n }\n\n @Get(`${FILES_ROUTE.OPERATION}/*`)\n async download(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<StreamableFile> {\n return this.filesMethods.headOrGet(req, res)\n }\n\n @Post(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.MAKE}/*`)\n async make(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() makeFileDto: MakeFileDto): Promise<void> {\n return this.filesMethods.make(user, space, makeFileDto)\n }\n\n @Post(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.UPLOAD}/*`)\n async upload(@Req() req: FastifySpaceRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<void> {\n return this.filesMethods.upload(req, res)\n }\n\n @Copy(`${FILES_ROUTE.OPERATION}/*`)\n async copy(\n @GetUser() user: UserModel,\n @GetSpace() space: SpaceEnv,\n @Body() copyMoveFileDto: CopyMoveFileDto\n ): Promise<{\n path: string\n name: string\n }> {\n return this.filesMethods.copy(user, space, copyMoveFileDto)\n }\n\n @Move(`${FILES_ROUTE.OPERATION}/*`)\n async move(\n @GetUser() user: UserModel,\n @GetSpace() space: SpaceEnv,\n @Body() copyMoveFileDto: CopyMoveFileDto\n ): Promise<{\n path: string\n name: string\n }> {\n return this.filesMethods.move(user, space, copyMoveFileDto)\n }\n\n @Delete(`${FILES_ROUTE.OPERATION}/*`)\n async delete(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<void> {\n return this.filesMethods.delete(user, space)\n }\n\n @Get(`${FILES_ROUTE.OPERATION}/${FILE_OPERATION.THUMBNAIL}/*`)\n async genThumbnail(\n @GetSpace() space: SpaceEnv,\n @Query('size', new ParseIntPipe({ optional: true })) size = 256,\n @Res() res: FastifyReply\n ): Promise<StreamableFile> {\n if (size > 1024) size = 1024\n const thumb = await this.filesMethods.genThumbnail(space, size)\n res.type(webpMimeType)\n return res.send(thumb)\n }\n\n // TASKS OPERATIONS\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.DOWNLOAD}/*`)\n async downloadFromUrlAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() downloadFileDto: DownloadFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DOWNLOAD, user, space, downloadFileDto, this.filesMethods.downloadFromUrl.name)\n }\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.COMPRESS}/*`)\n @SkipSpacePermissionsCheck()\n // Compression could be used to download files, permission is checked later\n async compressAsTask(@Req() req: FastifySpaceRequest, @Body() compressFileDto: CompressFileDto): Promise<FileTask> {\n if (compressFileDto.compressInDirectory) {\n SpaceGuard.checkPermissions(req, this.logger)\n }\n return this.filesTasksManager.createTask(FILE_OPERATION.COMPRESS, req.user, req.space, compressFileDto, this.filesMethods.compress.name)\n }\n\n @Post(`${FILES_ROUTE.TASK_OPERATION}/${FILE_OPERATION.DECOMPRESS}/*`)\n async decompressAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DECOMPRESS, user, space, null, this.filesMethods.decompress.name)\n }\n\n @Copy(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async copyAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() copyMoveFileDto: CopyMoveFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.COPY, user, space, copyMoveFileDto, this.filesMethods.copy.name)\n }\n\n @Move(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async moveAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv, @Body() copyMoveFileDto: CopyMoveFileDto): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.MOVE, user, space, copyMoveFileDto, this.filesMethods.move.name)\n }\n\n @Delete(`${FILES_ROUTE.TASK_OPERATION}/*`)\n async deleteAsTask(@GetUser() user: UserModel, @GetSpace() space: SpaceEnv): Promise<FileTask> {\n return this.filesTasksManager.createTask(FILE_OPERATION.DELETE, user, space, null, this.filesMethods.delete.name)\n }\n\n // RECENT FILES\n\n @Get(FILES_ROUTE.RECENTS)\n @SkipSpaceGuard()\n getRecents(@GetUser() user: UserModel, @Query('limit') limit: number = 10): Promise<FileRecent[]> {\n return this.filesRecents.getRecents(user, limit)\n }\n\n // SEARCH FILES\n\n @Search(FILES_ROUTE.SEARCH)\n @SkipSpaceGuard()\n search(@GetUser() user: UserModel, @Body() search: SearchFilesDto): Promise<FileContent[]> {\n return this.filesSearch.search(user, search)\n }\n}\n"],"names":["FilesController","head","req","res","filesMethods","headOrGet","download","make","user","space","makeFileDto","upload","copy","copyMoveFileDto","move","delete","genThumbnail","size","thumb","type","webpMimeType","send","downloadFromUrlAsTask","downloadFileDto","filesTasksManager","createTask","FILE_OPERATION","DOWNLOAD","downloadFromUrl","name","compressAsTask","compressFileDto","compressInDirectory","SpaceGuard","checkPermissions","logger","COMPRESS","compress","decompressAsTask","DECOMPRESS","decompress","copyAsTask","COPY","moveAsTask","MOVE","deleteAsTask","DELETE","getRecents","limit","filesRecents","search","filesSearch","Logger","FILES_ROUTE","OPERATION","passthrough","MAKE","UPLOAD","THUMBNAIL","ParseIntPipe","optional","TASK_OPERATION","RECENTS","SEARCH","BASE"],"mappings":"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"}
|
|
@@ -39,6 +39,7 @@ describe(_filescontroller.FilesController.name, ()=>{
|
|
|
39
39
|
const fakeRes = {
|
|
40
40
|
header: jest.fn().mockReturnThis(),
|
|
41
41
|
status: jest.fn().mockReturnThis(),
|
|
42
|
+
type: jest.fn().mockReturnThis(),
|
|
42
43
|
send: jest.fn()
|
|
43
44
|
};
|
|
44
45
|
// Mocks
|
|
@@ -164,16 +165,29 @@ describe(_filescontroller.FilesController.name, ()=>{
|
|
|
164
165
|
const stream = {};
|
|
165
166
|
filesMethodsMock.genThumbnail.mockResolvedValue(stream);
|
|
166
167
|
// pass undefined to exercise controller default parameter
|
|
167
|
-
const result = await filesController.genThumbnail(fakeSpace, undefined);
|
|
168
|
+
const result = await filesController.genThumbnail(fakeSpace, undefined, fakeRes);
|
|
168
169
|
expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 256);
|
|
169
|
-
expect(
|
|
170
|
+
expect(fakeRes.type).toHaveBeenCalled();
|
|
171
|
+
expect(fakeRes.send).toHaveBeenCalledWith(stream);
|
|
172
|
+
expect(result).toBeUndefined();
|
|
170
173
|
});
|
|
171
174
|
it('genThumbnail() should pass provided size', async ()=>{
|
|
172
175
|
const stream = {};
|
|
173
176
|
filesMethodsMock.genThumbnail.mockResolvedValue(stream);
|
|
174
|
-
const result = await filesController.genThumbnail(fakeSpace, 512);
|
|
177
|
+
const result = await filesController.genThumbnail(fakeSpace, 512, fakeRes);
|
|
175
178
|
expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 512);
|
|
176
|
-
expect(
|
|
179
|
+
expect(fakeRes.type).toHaveBeenCalled();
|
|
180
|
+
expect(fakeRes.send).toHaveBeenCalledWith(stream);
|
|
181
|
+
expect(result).toBeUndefined();
|
|
182
|
+
});
|
|
183
|
+
it('genThumbnail() should reduce size larger than 1024', async ()=>{
|
|
184
|
+
const stream = {};
|
|
185
|
+
filesMethodsMock.genThumbnail.mockResolvedValue(stream);
|
|
186
|
+
const result = await filesController.genThumbnail(fakeSpace, 2048, fakeRes);
|
|
187
|
+
expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 1024);
|
|
188
|
+
expect(fakeRes.type).toHaveBeenCalled();
|
|
189
|
+
expect(fakeRes.send).toHaveBeenCalledWith(stream);
|
|
190
|
+
expect(result).toBeUndefined();
|
|
177
191
|
});
|
|
178
192
|
});
|
|
179
193
|
describe('Tasks operations', ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/files/files.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { FILE_OPERATION } from './constants/operations'\nimport { FilesController } from './files.controller'\nimport { FilesMethods } from './services/files-methods.service'\nimport { FilesRecents } from './services/files-recents.service'\nimport { FilesSearchManager } from './services/files-search-manager.service'\nimport { FilesTasksManager } from './services/files-tasks-manager.service'\n\ndescribe(FilesController.name, () => {\n let filesController: FilesController\n\n // Reusable fakes\n const fakeUser: any = { id: 1, login: 'john', role: 1 }\n const fakeSpace: any = { id: 42, key: 'space-key', url: '/space/a', realPath: '/data/space/a', realBasePath: '/data/space' }\n const fakeReq: any = { user: fakeUser, space: fakeSpace, headers: {}, method: 'GET', ip: '127.0.0.1' }\n const fakeRes: any = { header: jest.fn().mockReturnThis(), status: jest.fn().mockReturnThis(), send: jest.fn() }\n\n // Mocks\n const filesMethodsMock = {\n headOrGet: jest.fn(),\n make: jest.fn(),\n upload: jest.fn(),\n copy: jest.fn(),\n move: jest.fn(),\n delete: jest.fn(),\n genThumbnail: jest.fn(),\n downloadFromUrl: jest.fn(),\n compress: jest.fn(),\n decompress: jest.fn()\n }\n\n const filesTasksManagerMock = {\n createTask: jest.fn()\n }\n\n const filesRecentsMock = {\n getRecents: jest.fn()\n }\n\n const filesSearchMock = {\n search: jest.fn()\n }\n\n beforeAll(async () => {\n const testingModuleBuilder = Test.createTestingModule({\n controllers: [FilesController],\n providers: [\n { provide: FilesMethods, useValue: filesMethodsMock },\n { provide: FilesTasksManager, useValue: filesTasksManagerMock },\n { provide: FilesRecents, useValue: filesRecentsMock },\n { provide: FilesSearchManager, useValue: filesSearchMock }\n ]\n })\n // IMPORTANT: override the guard referenced by @UseGuards to avoid resolving its dependencies\n testingModuleBuilder.overrideGuard(SpaceGuard).useValue({ canActivate: jest.fn().mockReturnValue(true) })\n\n const module: TestingModule = await testingModuleBuilder.compile()\n\n filesController = module.get<FilesController>(FilesController)\n })\n\n it('should be defined', () => {\n expect(filesController).toBeDefined()\n })\n\n describe('Operations', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('head() should delegate to filesMethods.headOrGet(req, res) and return its result', async () => {\n const stream = {} as any\n filesMethodsMock.headOrGet.mockResolvedValue(stream)\n\n const result = await filesController.head(fakeReq, fakeRes)\n\n expect(filesMethodsMock.headOrGet).toHaveBeenCalledWith(fakeReq, fakeRes)\n expect(result).toBe(stream)\n })\n\n it('download() should delegate to filesMethods.headOrGet(req, res) and return its result', async () => {\n const stream = {} as any\n filesMethodsMock.headOrGet.mockResolvedValue(stream)\n\n const result = await filesController.download(fakeReq, fakeRes)\n\n expect(filesMethodsMock.headOrGet).toHaveBeenCalledWith(fakeReq, fakeRes)\n expect(result).toBe(stream)\n })\n\n it('make() should call filesMethods.make(user, space, dto)', async () => {\n const dto = { path: '/a', name: 'b', type: 'directory' } as any\n\n await filesController.make(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.make).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n })\n\n it('upload() should call filesMethods.upload(req, res)', async () => {\n await filesController.upload(fakeReq, fakeRes)\n\n expect(filesMethodsMock.upload).toHaveBeenCalledWith(fakeReq, fakeRes)\n })\n\n it('copy() should call filesMethods.copy(user, space, dto) and return its result', async () => {\n const dto = { dstDirectory: '/dst', dstName: 'b' } as any\n const expected = { path: '/dst', name: 'b' }\n filesMethodsMock.copy.mockResolvedValue(expected)\n\n const result = await filesController.copy(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.copy).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n expect(result).toEqual(expected)\n })\n\n it('move() should call filesMethods.move(user, space, dto) and return its result', async () => {\n const dto = { dstDirectory: '/dst', dstName: 'c' } as any\n const expected = { path: '/dst', name: 'c' }\n filesMethodsMock.move.mockResolvedValue(expected)\n\n const result = await filesController.move(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.move).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n expect(result).toEqual(expected)\n })\n\n it('delete() should call filesMethods.delete(user, space)', async () => {\n await filesController.delete(fakeUser, fakeSpace)\n\n expect(filesMethodsMock.delete).toHaveBeenCalledWith(fakeUser, fakeSpace)\n })\n\n it('genThumbnail() should default size to 256 when not provided', async () => {\n const stream = {} as any\n filesMethodsMock.genThumbnail.mockResolvedValue(stream)\n\n // pass undefined to exercise controller default parameter\n const result = await filesController.genThumbnail(fakeSpace, undefined as unknown as number)\n\n expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 256)\n expect(result).toBe(stream)\n })\n\n it('genThumbnail() should pass provided size', async () => {\n const stream = {} as any\n filesMethodsMock.genThumbnail.mockResolvedValue(stream)\n\n const result = await filesController.genThumbnail(fakeSpace, 512)\n\n expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 512)\n expect(result).toBe(stream)\n })\n })\n\n describe('Tasks operations', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('downloadFromUrlAsTask() should create DOWNLOAD task using method name \"downloadFromUrl\"', async () => {\n const dto = { url: 'http://x', to: '/a' } as any\n const task = { id: 1 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.downloadFromUrlAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.DOWNLOAD,\n fakeUser,\n fakeSpace,\n dto,\n filesMethodsMock.downloadFromUrl.name\n )\n expect(result).toBe(task)\n })\n\n it('compressAsTask() should call SpaceGuard.checkPermissions when compressInDirectory is true', async () => {\n const dto = { compressInDirectory: true } as any\n const spy = jest.spyOn(SpaceGuard as any, 'checkPermissions').mockImplementation(() => undefined)\n\n filesTasksManagerMock.createTask.mockResolvedValue({} as any)\n await filesController.compressAsTask(fakeReq, dto)\n\n expect(spy).toHaveBeenCalled()\n spy.mockRestore()\n })\n\n it('compressAsTask() should create COMPRESS task with req.user and req.space and method name \"compress\"', async () => {\n const dto = { compressInDirectory: false } as any\n const task = { id: 2 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.compressAsTask(fakeReq, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.COMPRESS,\n fakeReq.user,\n fakeReq.space,\n dto,\n filesMethodsMock.compress.name\n )\n expect(result).toBe(task)\n })\n\n it('decompressAsTask() should create DECOMPRESS task with null dto and method name \"decompress\"', async () => {\n const task = { id: 3 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.decompressAsTask(fakeUser, fakeSpace)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.DECOMPRESS,\n fakeUser,\n fakeSpace,\n null,\n filesMethodsMock.decompress.name\n )\n expect(result).toBe(task)\n })\n\n it('copyAsTask() should create COPY task with method name \"copy\"', async () => {\n const dto = { from: '/a', to: '/b' } as any\n const task = { id: 4 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.copyAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.COPY, fakeUser, fakeSpace, dto, filesMethodsMock.copy.name)\n expect(result).toBe(task)\n })\n\n it('moveAsTask() should create MOVE task with method name \"move\"', async () => {\n const dto = { from: '/a', to: '/c' } as any\n const task = { id: 5 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.moveAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.MOVE, fakeUser, fakeSpace, dto, filesMethodsMock.move.name)\n expect(result).toBe(task)\n })\n\n it('deleteAsTask() should create DELETE task with null dto and method name \"delete\"', async () => {\n const task = { id: 6 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.deleteAsTask(fakeUser, fakeSpace)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.DELETE, fakeUser, fakeSpace, null, filesMethodsMock.delete.name)\n expect(result).toBe(task)\n })\n })\n\n describe('Recents & Search', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('getRecents() should use limit=10 by default', async () => {\n const recents = [{ path: '/a' }] as any\n filesRecentsMock.getRecents.mockResolvedValue(recents)\n\n const result = await filesController.getRecents(fakeUser, undefined as unknown as number)\n\n expect(filesRecentsMock.getRecents).toHaveBeenCalledWith(fakeUser, 10)\n expect(result).toBe(recents)\n })\n\n it('getRecents() should forward provided limit', async () => {\n const recents = [{ path: '/b' }] as any\n filesRecentsMock.getRecents.mockResolvedValue(recents)\n\n const result = await filesController.getRecents(fakeUser, 5)\n\n expect(filesRecentsMock.getRecents).toHaveBeenCalledWith(fakeUser, 5)\n expect(result).toBe(recents)\n })\n\n it('search() should delegate to filesSearch.search(user, dto)', async () => {\n const dto = { query: 'test' } as any\n const items = [{ name: 'file' }] as any\n filesSearchMock.search.mockResolvedValue(items)\n\n const result = await filesController.search(fakeUser, dto)\n\n expect(filesSearchMock.search).toHaveBeenCalledWith(fakeUser, dto)\n expect(result).toBe(items)\n })\n })\n})\n"],"names":["describe","FilesController","name","filesController","fakeUser","id","login","role","fakeSpace","key","url","realPath","realBasePath","fakeReq","user","space","headers","method","ip","fakeRes","header","jest","fn","mockReturnThis","status","send","filesMethodsMock","headOrGet","make","upload","copy","move","delete","genThumbnail","downloadFromUrl","compress","decompress","filesTasksManagerMock","createTask","filesRecentsMock","getRecents","filesSearchMock","search","beforeAll","testingModuleBuilder","Test","createTestingModule","controllers","providers","provide","FilesMethods","useValue","FilesTasksManager","FilesRecents","FilesSearchManager","overrideGuard","SpaceGuard","canActivate","mockReturnValue","module","compile","get","it","expect","toBeDefined","beforeEach","clearAllMocks","stream","mockResolvedValue","result","head","toHaveBeenCalledWith","toBe","download","dto","path","type","dstDirectory","dstName","expected","toEqual","undefined","to","task","downloadFromUrlAsTask","FILE_OPERATION","DOWNLOAD","compressInDirectory","spy","spyOn","mockImplementation","compressAsTask","toHaveBeenCalled","mockRestore","COMPRESS","decompressAsTask","DECOMPRESS","from","copyAsTask","COPY","moveAsTask","MOVE","deleteAsTask","DELETE","recents","query","items"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/files/files.controller.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { FILE_OPERATION } from './constants/operations'\nimport { FilesController } from './files.controller'\nimport { FilesMethods } from './services/files-methods.service'\nimport { FilesRecents } from './services/files-recents.service'\nimport { FilesSearchManager } from './services/files-search-manager.service'\nimport { FilesTasksManager } from './services/files-tasks-manager.service'\n\ndescribe(FilesController.name, () => {\n let filesController: FilesController\n\n // Reusable fakes\n const fakeUser: any = { id: 1, login: 'john', role: 1 }\n const fakeSpace: any = { id: 42, key: 'space-key', url: '/space/a', realPath: '/data/space/a', realBasePath: '/data/space' }\n const fakeReq: any = { user: fakeUser, space: fakeSpace, headers: {}, method: 'GET', ip: '127.0.0.1' }\n const fakeRes: any = { header: jest.fn().mockReturnThis(), status: jest.fn().mockReturnThis(), type: jest.fn().mockReturnThis(), send: jest.fn() }\n\n // Mocks\n const filesMethodsMock = {\n headOrGet: jest.fn(),\n make: jest.fn(),\n upload: jest.fn(),\n copy: jest.fn(),\n move: jest.fn(),\n delete: jest.fn(),\n genThumbnail: jest.fn(),\n downloadFromUrl: jest.fn(),\n compress: jest.fn(),\n decompress: jest.fn()\n }\n\n const filesTasksManagerMock = {\n createTask: jest.fn()\n }\n\n const filesRecentsMock = {\n getRecents: jest.fn()\n }\n\n const filesSearchMock = {\n search: jest.fn()\n }\n\n beforeAll(async () => {\n const testingModuleBuilder = Test.createTestingModule({\n controllers: [FilesController],\n providers: [\n { provide: FilesMethods, useValue: filesMethodsMock },\n { provide: FilesTasksManager, useValue: filesTasksManagerMock },\n { provide: FilesRecents, useValue: filesRecentsMock },\n { provide: FilesSearchManager, useValue: filesSearchMock }\n ]\n })\n // IMPORTANT: override the guard referenced by @UseGuards to avoid resolving its dependencies\n testingModuleBuilder.overrideGuard(SpaceGuard).useValue({ canActivate: jest.fn().mockReturnValue(true) })\n\n const module: TestingModule = await testingModuleBuilder.compile()\n\n filesController = module.get<FilesController>(FilesController)\n })\n\n it('should be defined', () => {\n expect(filesController).toBeDefined()\n })\n\n describe('Operations', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('head() should delegate to filesMethods.headOrGet(req, res) and return its result', async () => {\n const stream = {} as any\n filesMethodsMock.headOrGet.mockResolvedValue(stream)\n\n const result = await filesController.head(fakeReq, fakeRes)\n\n expect(filesMethodsMock.headOrGet).toHaveBeenCalledWith(fakeReq, fakeRes)\n expect(result).toBe(stream)\n })\n\n it('download() should delegate to filesMethods.headOrGet(req, res) and return its result', async () => {\n const stream = {} as any\n filesMethodsMock.headOrGet.mockResolvedValue(stream)\n\n const result = await filesController.download(fakeReq, fakeRes)\n\n expect(filesMethodsMock.headOrGet).toHaveBeenCalledWith(fakeReq, fakeRes)\n expect(result).toBe(stream)\n })\n\n it('make() should call filesMethods.make(user, space, dto)', async () => {\n const dto = { path: '/a', name: 'b', type: 'directory' } as any\n\n await filesController.make(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.make).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n })\n\n it('upload() should call filesMethods.upload(req, res)', async () => {\n await filesController.upload(fakeReq, fakeRes)\n\n expect(filesMethodsMock.upload).toHaveBeenCalledWith(fakeReq, fakeRes)\n })\n\n it('copy() should call filesMethods.copy(user, space, dto) and return its result', async () => {\n const dto = { dstDirectory: '/dst', dstName: 'b' } as any\n const expected = { path: '/dst', name: 'b' }\n filesMethodsMock.copy.mockResolvedValue(expected)\n\n const result = await filesController.copy(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.copy).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n expect(result).toEqual(expected)\n })\n\n it('move() should call filesMethods.move(user, space, dto) and return its result', async () => {\n const dto = { dstDirectory: '/dst', dstName: 'c' } as any\n const expected = { path: '/dst', name: 'c' }\n filesMethodsMock.move.mockResolvedValue(expected)\n\n const result = await filesController.move(fakeUser, fakeSpace, dto)\n\n expect(filesMethodsMock.move).toHaveBeenCalledWith(fakeUser, fakeSpace, dto)\n expect(result).toEqual(expected)\n })\n\n it('delete() should call filesMethods.delete(user, space)', async () => {\n await filesController.delete(fakeUser, fakeSpace)\n\n expect(filesMethodsMock.delete).toHaveBeenCalledWith(fakeUser, fakeSpace)\n })\n\n it('genThumbnail() should default size to 256 when not provided', async () => {\n const stream = {} as any\n filesMethodsMock.genThumbnail.mockResolvedValue(stream)\n\n // pass undefined to exercise controller default parameter\n const result = await filesController.genThumbnail(fakeSpace, undefined as unknown as number, fakeRes)\n\n expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 256)\n expect(fakeRes.type).toHaveBeenCalled()\n expect(fakeRes.send).toHaveBeenCalledWith(stream)\n expect(result).toBeUndefined()\n })\n\n it('genThumbnail() should pass provided size', async () => {\n const stream = {} as any\n filesMethodsMock.genThumbnail.mockResolvedValue(stream)\n\n const result = await filesController.genThumbnail(fakeSpace, 512, fakeRes)\n\n expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 512)\n expect(fakeRes.type).toHaveBeenCalled()\n expect(fakeRes.send).toHaveBeenCalledWith(stream)\n expect(result).toBeUndefined()\n })\n\n it('genThumbnail() should reduce size larger than 1024', async () => {\n const stream = {} as any\n filesMethodsMock.genThumbnail.mockResolvedValue(stream)\n\n const result = await filesController.genThumbnail(fakeSpace, 2048, fakeRes)\n\n expect(filesMethodsMock.genThumbnail).toHaveBeenCalledWith(fakeSpace, 1024)\n expect(fakeRes.type).toHaveBeenCalled()\n expect(fakeRes.send).toHaveBeenCalledWith(stream)\n expect(result).toBeUndefined()\n })\n })\n\n describe('Tasks operations', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('downloadFromUrlAsTask() should create DOWNLOAD task using method name \"downloadFromUrl\"', async () => {\n const dto = { url: 'http://x', to: '/a' } as any\n const task = { id: 1 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.downloadFromUrlAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.DOWNLOAD,\n fakeUser,\n fakeSpace,\n dto,\n filesMethodsMock.downloadFromUrl.name\n )\n expect(result).toBe(task)\n })\n\n it('compressAsTask() should call SpaceGuard.checkPermissions when compressInDirectory is true', async () => {\n const dto = { compressInDirectory: true } as any\n const spy = jest.spyOn(SpaceGuard as any, 'checkPermissions').mockImplementation(() => undefined)\n\n filesTasksManagerMock.createTask.mockResolvedValue({} as any)\n await filesController.compressAsTask(fakeReq, dto)\n\n expect(spy).toHaveBeenCalled()\n spy.mockRestore()\n })\n\n it('compressAsTask() should create COMPRESS task with req.user and req.space and method name \"compress\"', async () => {\n const dto = { compressInDirectory: false } as any\n const task = { id: 2 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.compressAsTask(fakeReq, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.COMPRESS,\n fakeReq.user,\n fakeReq.space,\n dto,\n filesMethodsMock.compress.name\n )\n expect(result).toBe(task)\n })\n\n it('decompressAsTask() should create DECOMPRESS task with null dto and method name \"decompress\"', async () => {\n const task = { id: 3 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.decompressAsTask(fakeUser, fakeSpace)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(\n FILE_OPERATION.DECOMPRESS,\n fakeUser,\n fakeSpace,\n null,\n filesMethodsMock.decompress.name\n )\n expect(result).toBe(task)\n })\n\n it('copyAsTask() should create COPY task with method name \"copy\"', async () => {\n const dto = { from: '/a', to: '/b' } as any\n const task = { id: 4 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.copyAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.COPY, fakeUser, fakeSpace, dto, filesMethodsMock.copy.name)\n expect(result).toBe(task)\n })\n\n it('moveAsTask() should create MOVE task with method name \"move\"', async () => {\n const dto = { from: '/a', to: '/c' } as any\n const task = { id: 5 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.moveAsTask(fakeUser, fakeSpace, dto)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.MOVE, fakeUser, fakeSpace, dto, filesMethodsMock.move.name)\n expect(result).toBe(task)\n })\n\n it('deleteAsTask() should create DELETE task with null dto and method name \"delete\"', async () => {\n const task = { id: 6 } as any\n filesTasksManagerMock.createTask.mockResolvedValue(task)\n\n const result = await filesController.deleteAsTask(fakeUser, fakeSpace)\n\n expect(filesTasksManagerMock.createTask).toHaveBeenCalledWith(FILE_OPERATION.DELETE, fakeUser, fakeSpace, null, filesMethodsMock.delete.name)\n expect(result).toBe(task)\n })\n })\n\n describe('Recents & Search', () => {\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('getRecents() should use limit=10 by default', async () => {\n const recents = [{ path: '/a' }] as any\n filesRecentsMock.getRecents.mockResolvedValue(recents)\n\n const result = await filesController.getRecents(fakeUser, undefined as unknown as number)\n\n expect(filesRecentsMock.getRecents).toHaveBeenCalledWith(fakeUser, 10)\n expect(result).toBe(recents)\n })\n\n it('getRecents() should forward provided limit', async () => {\n const recents = [{ path: '/b' }] as any\n filesRecentsMock.getRecents.mockResolvedValue(recents)\n\n const result = await filesController.getRecents(fakeUser, 5)\n\n expect(filesRecentsMock.getRecents).toHaveBeenCalledWith(fakeUser, 5)\n expect(result).toBe(recents)\n })\n\n it('search() should delegate to filesSearch.search(user, dto)', async () => {\n const dto = { query: 'test' } as any\n const items = [{ name: 'file' }] as any\n filesSearchMock.search.mockResolvedValue(items)\n\n const result = await filesController.search(fakeUser, dto)\n\n expect(filesSearchMock.search).toHaveBeenCalledWith(fakeUser, dto)\n expect(result).toBe(items)\n })\n })\n})\n"],"names":["describe","FilesController","name","filesController","fakeUser","id","login","role","fakeSpace","key","url","realPath","realBasePath","fakeReq","user","space","headers","method","ip","fakeRes","header","jest","fn","mockReturnThis","status","type","send","filesMethodsMock","headOrGet","make","upload","copy","move","delete","genThumbnail","downloadFromUrl","compress","decompress","filesTasksManagerMock","createTask","filesRecentsMock","getRecents","filesSearchMock","search","beforeAll","testingModuleBuilder","Test","createTestingModule","controllers","providers","provide","FilesMethods","useValue","FilesTasksManager","FilesRecents","FilesSearchManager","overrideGuard","SpaceGuard","canActivate","mockReturnValue","module","compile","get","it","expect","toBeDefined","beforeEach","clearAllMocks","stream","mockResolvedValue","result","head","toHaveBeenCalledWith","toBe","download","dto","path","dstDirectory","dstName","expected","toEqual","undefined","toHaveBeenCalled","toBeUndefined","to","task","downloadFromUrlAsTask","FILE_OPERATION","DOWNLOAD","compressInDirectory","spy","spyOn","mockImplementation","compressAsTask","mockRestore","COMPRESS","decompressAsTask","DECOMPRESS","from","copyAsTask","COPY","moveAsTask","MOVE","deleteAsTask","DELETE","recents","query","items"],"mappings":"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"}
|