@sync-in/server 1.10.0 → 1.10.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -2
  3. package/package.json +2 -3
  4. package/server/app.bootstrap.js +3 -22
  5. package/server/app.bootstrap.js.map +1 -1
  6. package/server/applications/comments/services/comments-queries.service.js +5 -9
  7. package/server/applications/comments/services/comments-queries.service.js.map +1 -1
  8. package/server/applications/users/users.e2e-spec.js +0 -1
  9. package/server/applications/users/users.e2e-spec.js.map +1 -1
  10. package/server/applications/webdav/constants/webdav.js +7 -0
  11. package/server/applications/webdav/constants/webdav.js.map +1 -1
  12. package/server/applications/webdav/utils/bootstrap.js +45 -0
  13. package/server/applications/webdav/utils/bootstrap.js.map +1 -0
  14. package/server/applications/webdav/webdav.controller.js +1 -1
  15. package/server/applications/webdav/webdav.controller.js.map +1 -1
  16. package/server/applications/webdav/webdav.e2e-spec.js +131 -2
  17. package/server/applications/webdav/webdav.e2e-spec.js.map +1 -1
  18. package/server/authentication/auth.e2e-spec.js +12 -6
  19. package/server/authentication/auth.e2e-spec.js.map +1 -1
  20. package/server/authentication/guards/auth-basic.guard.spec.js +23 -0
  21. package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
  22. package/server/authentication/guards/auth-basic.strategy.js +3 -3
  23. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  24. package/server/authentication/guards/auth-digest.strategy.js +32 -11
  25. package/server/authentication/guards/auth-digest.strategy.js.map +1 -1
  26. package/server/authentication/guards/implementations/http-basic.strategy.js +76 -0
  27. package/server/authentication/guards/implementations/http-basic.strategy.js.map +1 -0
  28. package/server/authentication/guards/implementations/http-digest.strategy.js +155 -0
  29. package/server/authentication/guards/implementations/http-digest.strategy.js.map +1 -0
  30. package/server/authentication/services/auth-manager.service.js +1 -2
  31. package/server/authentication/services/auth-manager.service.js.map +1 -1
  32. package/static/{chunk-XBKCQCBI.js → chunk-2GXOVGTD.js} +1 -1
  33. package/static/{chunk-QHJT5H4M.js → chunk-3MVPXC3U.js} +1 -1
  34. package/static/{chunk-I5SPA4G2.js → chunk-3VRUIWQG.js} +1 -1
  35. package/static/{chunk-L3BIP4AA.js → chunk-3ZBAQTHJ.js} +1 -1
  36. package/static/{chunk-D55YR5X7.js → chunk-76M3BMK6.js} +11 -11
  37. package/static/{chunk-GXWGB7WO.js → chunk-76REYAEA.js} +1 -1
  38. package/static/{chunk-CCZWPM7Q.js → chunk-7HJFIMNF.js} +1 -1
  39. package/static/{chunk-NIR4YE2E.js → chunk-7KAYOR3A.js} +1 -1
  40. package/static/{chunk-O3YLAEVE.js → chunk-AALPWGPB.js} +2 -2
  41. package/static/{chunk-KWFELZTM.js → chunk-CN5YVRFT.js} +1 -1
  42. package/static/{chunk-B6HQYQYG.js → chunk-CVXLHSO5.js} +1 -1
  43. package/static/{chunk-R7PLNX75.js → chunk-D2MLAO5N.js} +1 -1
  44. package/static/{chunk-HGODIZTV.js → chunk-EKWB5W72.js} +1 -1
  45. package/static/{chunk-PQZLR4P3.js → chunk-FTFEQDWH.js} +1 -1
  46. package/static/{chunk-3WZ6F3LC.js → chunk-FWQJ4ZCD.js} +1 -1
  47. package/static/{chunk-FIUF2JM4.js → chunk-IHS5LSJJ.js} +1 -1
  48. package/static/{chunk-G3PL6YX3.js → chunk-J7474P3L.js} +1 -1
  49. package/static/{chunk-LGIVVJDD.js → chunk-JAJ7VXMB.js} +1 -1
  50. package/static/{chunk-T42BV6TR.js → chunk-KEZNIIFH.js} +1 -1
  51. package/static/{chunk-OUHCDDT6.js → chunk-LWSCODLD.js} +1 -1
  52. package/static/{chunk-6WMXMIE4.js → chunk-NIKNG2FX.js} +1 -1
  53. package/static/{chunk-KPOQLDWF.js → chunk-QGHNJVJ6.js} +1 -1
  54. package/static/{chunk-GWRAGN3M.js → chunk-QJ22N76V.js} +1 -1
  55. package/static/{chunk-NJJURHX4.js → chunk-QTPIEEZW.js} +1 -1
  56. package/static/{chunk-ZHOE5VEY.js → chunk-R4VYKZVJ.js} +1 -1
  57. package/static/{chunk-7VRYTDX4.js → chunk-RBTLSPYJ.js} +1 -1
  58. package/static/{chunk-GQHXYX6Z.js → chunk-S44QIK3G.js} +1 -1
  59. package/static/{chunk-45AZ6ZML.js → chunk-S6H2ELRY.js} +1 -1
  60. package/static/{chunk-E32J777S.js → chunk-SPQH3ATC.js} +1 -1
  61. package/static/{chunk-DGCVA6BM.js → chunk-TTWMFWEC.js} +1 -1
  62. package/static/{chunk-ULSPQ3HP.js → chunk-U5E5H2DD.js} +1 -1
  63. package/static/{chunk-LNLBIJZD.js → chunk-VBTZDHZ3.js} +1 -1
  64. package/static/{chunk-I3FR3A45.js → chunk-VZFZUI6D.js} +1 -1
  65. package/static/{chunk-S3TTWPQA.js → chunk-WFMEUST4.js} +1 -1
  66. package/static/{chunk-27Z3SYRL.js → chunk-WRK2FTKU.js} +1 -1
  67. package/static/{chunk-4TPFERL6.js → chunk-WZPF4LS2.js} +1 -1
  68. package/static/{chunk-POUWUMC4.js → chunk-X7NHX5C7.js} +1 -1
  69. package/static/{chunk-XTVNHFKX.js → chunk-XSURUW7C.js} +1 -1
  70. package/static/{chunk-5O66CLTD.js → chunk-XX3JPJUM.js} +1 -1
  71. package/static/{chunk-3RPUQ22U.js → chunk-XZHWESIY.js} +1 -1
  72. package/static/{chunk-3JYMJQYT.js → chunk-ZHUBWKA2.js} +1 -1
  73. package/static/{chunk-XEWLBWFF.js → chunk-ZU5MQTFN.js} +1 -1
  74. package/static/index.html +1 -1
  75. package/static/{main-YKDNJ7LK.js → main-5O3KLGIR.js} +3 -3
package/CHANGELOG.md CHANGED
@@ -1,4 +1,13 @@
1
1
 
2
+ ## [1.10.1](https://github.com/Sync-in/server/compare/v1.10.0...v1.10.1) (2026-01-12)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * **auth:** WebDAV basic auth fails with ":" in password ([#104](https://github.com/Sync-in/server/issues/104)) ([9671b71](https://github.com/Sync-in/server/commit/9671b71e5a4fcbfb659b5eb1e2818f55f3df7976))
8
+ * **backend:comments:** refine file path query for better handling of space roots ([5b0c8ff](https://github.com/Sync-in/server/commit/5b0c8fff0aa3eba9d3e0308e2ae012992f1fa91b))
9
+ * **backend:webdav:** treat PUT requests as binary streams to avoid body parsing ([edc291c](https://github.com/Sync-in/server/commit/edc291ccc634e03843c4db9f7000969e6fc9946f))
10
+
2
11
  ## [1.10.0](https://github.com/Sync-in/server/compare/v1.9.6...v1.10.0) (2026-01-07)
3
12
 
4
13
  🔥🚀 Collabora Online integration
package/README.md CHANGED
@@ -45,8 +45,8 @@ Sync-in fits seamlessly into any environment — from small teams to large enter
45
45
  - 🔑 Advanced User Access Control
46
46
  - **Spaces & Shares**: Organize files with fine-grained access permissions
47
47
  - Role-based permission system ensuring secure file management
48
- - 🤝 Collaboration & Integration
49
- - **OnlyOffice Integration**: Edit and collaborate on documents in real-time
48
+ - 🤝 Collaboration
49
+ - **Collabora Online & OnlyOffice Integration**: Real-time document editing and collaboration
50
50
  - **Activity Tracking**: Commenting, notifications, and file history for seamless teamwork
51
51
  - 🔎 Powerful Full-Text Search
52
52
  - **Deep content search** for easy retrieval of files and documents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sync-in/server",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
5
5
  "author": {
6
6
  "name": "Johan Legrand",
@@ -107,14 +107,13 @@
107
107
  "mysql2": "3.16.0",
108
108
  "nestjs-pino": "4.5.0",
109
109
  "nodemailer": "7.0.12",
110
- "passport-http": "0.3.0",
111
110
  "passport-jwt": "4.0.1",
112
111
  "passport-local": "1.0.0",
113
112
  "passport": "0.7.0",
114
113
  "pino-pretty": "13.1.3",
115
114
  "qrcode-generator": "2.0.4",
116
115
  "redis": "5.10.0",
117
- "sax": "1.4.3",
116
+ "sax": "1.4.4",
118
117
  "sharp": "0.34.5",
119
118
  "socket.io": "4.8.3",
120
119
  "tar": "7.5.2",
@@ -21,8 +21,7 @@ const _platformfastify = require("@nestjs/platform-fastify");
21
21
  const _nestjspino = require("nestjs-pino");
22
22
  const _appconstants = require("./app.constants");
23
23
  const _appmodule = require("./app.module");
24
- const _applicationsconstants = require("./applications/applications.constants");
25
- const _routes = require("./applications/webdav/constants/routes");
24
+ const _bootstrap = require("./applications/webdav/utils/bootstrap");
26
25
  const _configconstants = require("./configuration/config.constants");
27
26
  const _configenvironment = require("./configuration/config.environment");
28
27
  const _websocketadapter = require("./infrastructure/websocket/adapters/web-socket.adapter");
@@ -49,29 +48,11 @@ async function appBootstrap() {
49
48
  /* LOGGER */ app.useLogger(_configconstants.IS_TEST_ENV ? [
50
49
  'fatal'
51
50
  ] : app.get(_nestjspino.Logger));
52
- /* PARSER */ // xml body parser is used for webdav methods
53
- app.useBodyParser([
54
- 'application/xml',
55
- 'text/xml'
56
- ]);
57
- // add webdav methods
58
- for (const method of Object.values(_applicationsconstants.HTTP_WEBDAV_METHOD)){
59
- fastifyInstance.addHttpMethod(method, {
60
- hasBody: true
61
- });
62
- }
63
- // '*' body parser allow binary data as stream (unlimited body size)
51
+ /* WEBDAV BOOTSTRAP RULES */ (0, _bootstrap.bootstrapWebDAV)(app, fastifyInstance);
52
+ /* PARSER */ // '*' body parser allow binary data as a stream (unlimited body size)
64
53
  fastifyInstance.addContentTypeParser('*', {
65
54
  bodyLimit: 0
66
55
  }, (_req, _payload, done)=>done(null));
67
- // Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)
68
- // This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.
69
- // todo: remove it when fixed on Joplin side
70
- fastifyInstance.addHook('onRequest', async (req, _reply)=>{
71
- if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(_routes.WEBDAV_SPACES[_routes.WEBDAV_NS.WEBDAV].route)) {
72
- req.headers['content-type'] = 'application/octet-stream';
73
- }
74
- });
75
56
  /* INTERCEPTORS */ app.useGlobalInterceptors(new _nestjspino.LoggerErrorInterceptor(), new _common.ClassSerializerInterceptor(app.get(_core.Reflector), {
76
57
  excludePrefixes: [
77
58
  '_'
@@ -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 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, {\n contentSecurityPolicy: CONTENT_SECURITY_POLICY(\n configuration.applications.files.onlyoffice.externalServer,\n configuration.applications.files.collabora.externalServer\n )\n })\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","collabora","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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"}
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 { FastifyInstance, FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { bootstrapWebDAV } from './applications/webdav/utils/bootstrap'\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: FastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* WEBDAV BOOTSTRAP RULES */\n bootstrapWebDAV(app, fastifyInstance)\n\n /* PARSER */\n // '*' body parser allow binary data as a stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\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, {\n contentSecurityPolicy: CONTENT_SECURITY_POLICY(\n configuration.applications.files.onlyoffice.externalServer,\n configuration.applications.files.collabora.externalServer\n )\n })\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","bootstrapWebDAV","addContentTypeParser","_req","_payload","done","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","collabora","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","cookieSameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"AAAA;;;;CAIC;;;;+BAiBqBA;;;eAAAA;;;+DAfI;+DACA;kEACJ;wBACqC;sBACpB;iCACgB;4BAER;8BACP;2BACd;2BACM;iCACS;mCACX;kCACG;;;;;;AAE1B,eAAeA;IACpB,OAAO,GACP,MAAMC,iBAAiB,IAAIC,+BAAc,CAAC;QACxCC,QAAQ;QACRC,YAAYC,gCAAa,CAACC,MAAM,CAACF,UAAU;QAC3CG,eAAe;YACbC,qBAAqB;YACrBC,gBAAgB;QAClB;QACAC,WAAW,SAAS,SAAS;IAC/B;IACA,MAAMC,MAA8B,MAAMC,iBAAW,CAACC,MAAM,CAAyBC,oBAAS,EAAEb,gBAAgB;QAC9Gc,YAAY;IACd;IAEA,8CAA8C,GAC9CJ,IAAIK,mBAAmB;IAEvB,oBAAoB,GACpB,MAAMC,kBAAmChB,eAAeiB,WAAW;IAEnE,UAAU,GACVP,IAAIQ,SAAS,CAACC,4BAAW,GAAG;QAAC;KAAQ,GAAGT,IAAIU,GAAG,CAACC,kBAAM;IAEtD,0BAA0B,GAC1BC,IAAAA,0BAAe,EAACZ,KAAKM;IAErB,UAAU,GACV,sEAAsE;IACtEA,gBAAgBO,oBAAoB,CAAC,KAAK;QAAEd,WAAW;IAAE,GAAG,CAACe,MAAsBC,UAAiCC,OAASA,KAAK;IAElI,gBAAgB,GAChBhB,IAAIiB,qBAAqB,CACvB,IAAIC,kCAAsB,IAC1B,IAAIC,kCAA0B,CAACnB,IAAIU,GAAG,CAACU,eAAS,GAAG;QACjDC,iBAAiB;YAAC;SAAI;IACxB;IAGF,cAAc,GACdrB,IAAIsB,cAAc,CAAC,IAAIC,sBAAc,CAAC;QAAEC,WAAW;QAAMC,WAAW;IAAK;IAEzE,UAAU,GACVzB,IAAI0B,eAAe,CAAC;QAAEC,MAAMC,4BAAW;QAAEC,0BAA0B;IAAK;IAExE,YAAY,GACZ,MAAM7B,IAAI8B,QAAQ,CAACC,eAAa,EAAE;QAChCC,uBAAuBC,IAAAA,qCAAuB,EAC5CvC,gCAAa,CAACwC,YAAY,CAACC,KAAK,CAACC,UAAU,CAACC,cAAc,EAC1D3C,gCAAa,CAACwC,YAAY,CAACC,KAAK,CAACG,SAAS,CAACD,cAAc;IAE7D;IAEA,WAAW,GACX,2CAA2C;IAC3C,MAAMrC,IAAI8B,QAAQ,CAACS,eAAa,EAAE;QAChCC,QAAQ9C,gCAAa,CAAC+C,IAAI,CAACC,KAAK,CAACC,IAAI,CAACH,MAAM;QAC5CI,cAAc;YACZC,QAAQ;YACRC,UAAUpD,gCAAa,CAAC+C,IAAI,CAACM,cAAc;YAC3CC,UAAU;QACZ;IACF;IAEA,UAAU,GACV,MAAMhD,IAAI8B,QAAQ,CAACmB,kBAAS,EAAE;QAC5BC,cAAc;QACdC,QAAQ;YAAEC,OAAOC;YAAUC,UAAU5D,gCAAa,CAACwC,YAAY,CAACC,KAAK,CAACoB,aAAa;QAAC;IACtF;IAEA,aAAa,GACb,IAAI,CAAC9C,4BAAW,EAAE;QAChB,MAAM+C,mBAAmB,IAAIC,kCAAgB,CAACzD;QAC9C,MAAMwD,iBAAiBE,WAAW;QAClC1D,IAAI2D,mBAAmB,CAACH;IAC1B;IAEA,OAAOxD;AACT"}
@@ -132,16 +132,12 @@ let CommentsQueries = class CommentsQueries {
132
132
  file: {
133
133
  name: (0, _drizzleorm.sql)`IF (${_filesschema.files.id} = ${_spacesrootsschema.spacesRoots.fileId}, ${_spacesrootsschema.spacesRoots.name}, ${_filesschema.files.name})`.as('name'),
134
134
  path: (0, _drizzleorm.sql)`
135
- CONCAT_WS('/', IF (${_filesschema.files.inTrash} = 0, '${_drizzleorm.sql.raw(_spaces.SPACE_REPOSITORY.FILES)}', '${_drizzleorm.sql.raw(_spaces.SPACE_REPOSITORY.TRASH)}'),
136
- IF (${_filesschema.files.ownerId} = ${userId}, '${_drizzleorm.sql.raw(_spaces.SPACE_ALIAS.PERSONAL)}', ${_spacesschema.spaces.alias}),
135
+ CONCAT_WS('/',
136
+ IF (${_filesschema.files.inTrash} = 0, '${_drizzleorm.sql.raw(_spaces.SPACE_REPOSITORY.FILES)}', '${_drizzleorm.sql.raw(_spaces.SPACE_REPOSITORY.TRASH)}'),
137
+ IF (${_filesschema.files.ownerId} = ${userId}, '${_drizzleorm.sql.raw(_spaces.SPACE_ALIAS.PERSONAL)}', ${_spacesschema.spaces.alias}),
137
138
  IF (${spaceRootFile.id} IS NOT NULL,
138
- IF (${_filesschema.files.id} = ${spaceRootFile.id}, NULL, REGEXP_REPLACE(${_filesschema.files.path}, ${(0, _filesschema.filePathSQL)(spaceRootFile)}, ${_spacesrootsschema.spacesRoots.alias})),
139
- NULLIF(
140
- CONCAT_WS('/',
141
- IF (${_filesschema.files.spaceExternalRootId} = ${_spacesrootsschema.spacesRoots.id}, ${_spacesrootsschema.spacesRoots.alias}, NULL),
142
- IF (${_filesschema.files.path} = '.', NULL, ${_filesschema.files.path})
143
- )
144
- , '')
139
+ IF (${_filesschema.files.id} = ${spaceRootFile.id}, NULL, IF (${_filesschema.files.path} = '.', NULL, REGEXP_REPLACE(${_filesschema.files.path}, ${(0, _filesschema.filePathSQL)(spaceRootFile)}, ${_spacesrootsschema.spacesRoots.alias}))),
140
+ NULLIF(CONCAT_WS('/', IF (${_filesschema.files.spaceExternalRootId} = ${_spacesrootsschema.spacesRoots.id}, ${_spacesrootsschema.spacesRoots.alias}, NULL), IF (${_filesschema.files.path} = '.', NULL, ${_filesschema.files.path})), '')
145
141
  )
146
142
  )`.as('path'),
147
143
  mime: _filesschema.files.mime,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/comments/services/comments-queries.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable } from '@nestjs/common'\nimport { and, desc, eq, getTableColumns, inArray, isNotNull, isNull, ne, or, SelectedFields, SQL, sql } from 'drizzle-orm'\nimport { alias, union } from 'drizzle-orm/mysql-core'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport type { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbCheckAffectedRows, dbGetInsertedId } from '../../../infrastructure/database/utils'\nimport { filePathSQL, files } from '../../files/schemas/files.schema'\nimport { UserMailNotification } from '../../notifications/interfaces/user-mail-notification.interface'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SPACE_ALIAS, SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport { CommentRecent } from '../interfaces/comment-recent.interface'\nimport { Comment } from '../schemas/comment.interface'\nimport { comments } from '../schemas/comments.schema'\n\n@Injectable()\nexport class CommentsQueries {\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n getComments(userId: number, isFileOwner: boolean, fromFileId?: number, fromCommentId?: number, limit: number = undefined): Promise<Comment[]> {\n let where: SQL\n if (fromFileId) {\n where = eq(comments.fileId, fromFileId)\n } else if (fromCommentId) {\n where = eq(comments.id, fromCommentId)\n limit = 1\n } else {\n throw Error('fromFileId or fromCommentId must be provided')\n }\n return this.db\n .select({\n ...getTableColumns(comments),\n author: { login: users.login, fullName: userFullNameSQL(users), email: users.email, isAuthor: sql`${users.id} = ${userId}`.mapWith(Boolean) },\n isFileOwner: sql`${+isFileOwner}`.mapWith(Boolean)\n })\n .from(comments)\n .leftJoin(users, eq(users.id, comments.userId))\n .where(where)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n async createComment(userId: number, fileId: number, content: string): Promise<Comment['id']> {\n return dbGetInsertedId(await this.db.insert(comments).values({ userId: userId, fileId: fileId, content: content } as Comment))\n }\n\n async updateComment(userId: number, commentId: number, fileId: number, content: string): Promise<boolean> {\n return dbCheckAffectedRows(\n await this.db\n .update(comments)\n .set({ content: content } as Comment)\n .where(and(eq(comments.userId, userId), eq(comments.id, commentId), eq(comments.fileId, fileId)))\n .limit(1),\n 1,\n false\n )\n }\n\n async deleteComment(userId: number, commentId: number, fileId: number, isFileOwner: boolean): Promise<boolean> {\n return dbCheckAffectedRows(\n await this.db\n .delete(comments)\n .where(and(or(eq(sql`${+isFileOwner}`, 1), eq(comments.userId, userId)), eq(comments.id, commentId), eq(comments.fileId, fileId)))\n .limit(1),\n 1,\n false\n )\n }\n\n membersToNotify(fromUserId: number, fileId: number): Promise<UserMailNotification[]> {\n /* lists the owner of the file and the users who have commented on it */\n const select: UserMailNotification | SelectedFields<any, any> = {\n id: users.id,\n email: users.email,\n language: users.language,\n notification: users.notification\n }\n const fromComments = this.db\n .select(select)\n .from(comments)\n .innerJoin(users, and(eq(users.id, comments.userId), ne(users.id, fromUserId)))\n .where(eq(comments.fileId, fileId))\n const fromFile = this.db\n .select(select)\n .from(files)\n .innerJoin(users, and(eq(users.id, files.ownerId), ne(users.id, fromUserId)))\n .where(eq(files.id, fileId))\n return union(fromComments, fromFile) as any\n }\n\n getRecentsFromShares(userId: number, shareIds: number[], limit: number) {\n const shareFile: any = alias(files, 'shareFile')\n return this.db\n .select({\n id: comments.id,\n content: comments.content,\n modifiedAt: comments.modifiedAt,\n author: { login: users.login, fullName: userFullNameSQL(users).as('fullName'), email: users.email },\n file: {\n name: sql<string>`IF (${files.id} = ${shareFile.id}, ${shares.name}, ${files.name})`.as('name'),\n path: sql<string>`\n CONCAT_WS('/', '${sql.raw(SPACE_REPOSITORY.SHARES)}',\n IF (${shareFile.id} IS NOT NULL,\n IF (${files.id} = ${shareFile.id}, NULL, REGEXP_REPLACE(${files.path}, ${filePathSQL(shareFile)}, ${shares.alias})),\n CONCAT_WS('/', ${shares.alias}, IF (${files.path} = '.', NULL, ${files.path}))\n )\n )`.as('path'),\n mime: files.mime,\n inTrash: sql<number>`0`.as('inTrash'),\n fromSpace: sql<number>`0`.as('fromSpace'),\n fromShare: sql<number>`1`.as('fromShare')\n }\n } satisfies CommentRecent | SelectedFields<any, any>)\n .from(shares)\n .leftJoin(shareFile, eq(shareFile.id, shares.fileId))\n .leftJoin(spaces, eq(spaces.id, shareFile.spaceId))\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(\n files,\n or(\n // file linked to the share\n eq(files.id, shareFile.id),\n // all files with an external share id\n and(isNull(shareFile.id), eq(files.shareExternalId, shares.id)),\n // all files under the share\n and(\n isNotNull(shareFile.id),\n eq(shareFile.isDir, true),\n sql`${files.spaceId} <=> ${shareFile.spaceId}`,\n sql`${files.ownerId} <=> ${shareFile.ownerId}`,\n sql`${files.spaceExternalRootId} <=> ${shareFile.spaceExternalRootId}`,\n sql`${files.shareExternalId} <=> ${shareFile.shareExternalId}`,\n sql`${files.path} REGEXP CONCAT('^', IF(${shareFile.path} = '.', CONCAT(${shareFile.name}, '(/.*|)$'), CONCAT(${shareFile.path}, '/')))`\n )\n )\n )\n .innerJoin(comments, and(eq(comments.fileId, files.id), ne(comments.userId, userId)))\n .innerJoin(users, eq(users.id, comments.userId))\n .where(inArray(shares.id, shareIds))\n .groupBy(comments.id)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n getRecentsFromSpaces(userId: number, spaceIds: number[], limit: number) {\n const spaceRootFile: any = alias(files, 'spaceRootFile')\n return this.db\n .select({\n id: comments.id,\n content: comments.content,\n modifiedAt: comments.modifiedAt,\n author: { login: users.login, fullName: userFullNameSQL(users).as('fullName'), email: users.email },\n file: {\n name: sql<string>`IF (${files.id} = ${spacesRoots.fileId}, ${spacesRoots.name}, ${files.name})`.as('name'),\n path: sql<string>`\n CONCAT_WS('/', IF (${files.inTrash} = 0, '${sql.raw(SPACE_REPOSITORY.FILES)}', '${sql.raw(SPACE_REPOSITORY.TRASH)}'), \n IF (${files.ownerId} = ${userId}, '${sql.raw(SPACE_ALIAS.PERSONAL)}', ${spaces.alias}),\n IF (${spaceRootFile.id} IS NOT NULL,\n IF (${files.id} = ${spaceRootFile.id}, NULL, REGEXP_REPLACE(${files.path}, ${filePathSQL(spaceRootFile)}, ${spacesRoots.alias})),\n NULLIF(\n CONCAT_WS('/', \n IF (${files.spaceExternalRootId} = ${spacesRoots.id}, ${spacesRoots.alias}, NULL), \n IF (${files.path} = '.', NULL, ${files.path})\n )\n , '')\n )\n )`.as('path'),\n mime: files.mime,\n inTrash: sql<number>`${files.inTrash}`.as('inTrash'),\n fromSpace: sql<number>`IF (${files.ownerId} = ${userId}, 0, 1)`.as('fromSpace'),\n fromShare: sql<number>`0`.as('fromShare')\n }\n } satisfies CommentRecent | SelectedFields<any, any>)\n .from(spaces)\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(spaceRootFile, eq(spaceRootFile.id, spacesRoots.fileId))\n .leftJoin(\n files,\n or(\n // all files from user\n eq(files.ownerId, userId),\n // all files from spaces\n eq(files.spaceId, spaces.id),\n // all files from space roots\n eq(files.id, spacesRoots.fileId),\n // all files under the space roots\n and(\n isNotNull(spaceRootFile.id),\n eq(spaceRootFile.isDir, true),\n sql`${files.ownerId} <=> ${spaceRootFile.ownerId}`,\n sql`${files.path} REGEXP CONCAT('^', IF(${spaceRootFile.path} = '.', CONCAT(${spaceRootFile.name}, '(/.*|)$'), CONCAT(${spaceRootFile.path}, '/')))`\n )\n )\n )\n .innerJoin(comments, and(eq(comments.fileId, files.id), ne(comments.userId, userId)))\n .innerJoin(users, eq(users.id, comments.userId))\n .where(inArray(spaces.id, spaceIds))\n .groupBy(comments.id)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n async getRecentsFromUser(user: UserModel, limit = 10): Promise<CommentRecent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n const fromSpaces = this.getRecentsFromSpaces(user.id, spaceIds, limit * 2)\n const fromShares = this.getRecentsFromShares(user.id, shareIds, limit * 2)\n const unionAlias = union(fromSpaces, fromShares).as('unionAlias')\n return this.db.select().from(unionAlias).groupBy(unionAlias.id).orderBy(desc(unionAlias.id)).limit(limit)\n }\n}\n"],"names":["CommentsQueries","getComments","userId","isFileOwner","fromFileId","fromCommentId","limit","undefined","where","eq","comments","fileId","id","Error","db","select","getTableColumns","author","login","users","fullName","userFullNameSQL","email","isAuthor","sql","mapWith","Boolean","from","leftJoin","orderBy","desc","createComment","content","dbGetInsertedId","insert","values","updateComment","commentId","dbCheckAffectedRows","update","set","and","deleteComment","delete","or","membersToNotify","fromUserId","language","notification","fromComments","innerJoin","ne","fromFile","files","ownerId","union","getRecentsFromShares","shareIds","shareFile","alias","modifiedAt","as","file","name","shares","path","raw","SPACE_REPOSITORY","SHARES","filePathSQL","mime","inTrash","fromSpace","fromShare","spaces","spaceId","spacesRoots","isNull","shareExternalId","isNotNull","isDir","spaceExternalRootId","inArray","groupBy","getRecentsFromSpaces","spaceIds","spaceRootFile","FILES","TRASH","SPACE_ALIAS","PERSONAL","getRecentsFromUser","user","Promise","all","spacesQueries","sharesQueries","isAdmin","fromSpaces","fromShares","unionAlias"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/comments/services/comments-queries.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Inject, Injectable } from '@nestjs/common'\nimport { and, desc, eq, getTableColumns, inArray, isNotNull, isNull, ne, or, SelectedFields, SQL, sql } from 'drizzle-orm'\nimport { alias, union } from 'drizzle-orm/mysql-core'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport type { DBSchema } from '../../../infrastructure/database/interfaces/database.interface'\nimport { dbCheckAffectedRows, dbGetInsertedId } from '../../../infrastructure/database/utils'\nimport { filePathSQL, files } from '../../files/schemas/files.schema'\nimport { UserMailNotification } from '../../notifications/interfaces/user-mail-notification.interface'\nimport { shares } from '../../shares/schemas/shares.schema'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SPACE_ALIAS, SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { spacesRoots } from '../../spaces/schemas/spaces-roots.schema'\nimport { spaces } from '../../spaces/schemas/spaces.schema'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { userFullNameSQL, users } from '../../users/schemas/users.schema'\nimport { CommentRecent } from '../interfaces/comment-recent.interface'\nimport { Comment } from '../schemas/comment.interface'\nimport { comments } from '../schemas/comments.schema'\n\n@Injectable()\nexport class CommentsQueries {\n constructor(\n @Inject(DB_TOKEN_PROVIDER) private readonly db: DBSchema,\n private readonly spacesQueries: SpacesQueries,\n private readonly sharesQueries: SharesQueries\n ) {}\n\n getComments(userId: number, isFileOwner: boolean, fromFileId?: number, fromCommentId?: number, limit: number = undefined): Promise<Comment[]> {\n let where: SQL\n if (fromFileId) {\n where = eq(comments.fileId, fromFileId)\n } else if (fromCommentId) {\n where = eq(comments.id, fromCommentId)\n limit = 1\n } else {\n throw Error('fromFileId or fromCommentId must be provided')\n }\n return this.db\n .select({\n ...getTableColumns(comments),\n author: { login: users.login, fullName: userFullNameSQL(users), email: users.email, isAuthor: sql`${users.id} = ${userId}`.mapWith(Boolean) },\n isFileOwner: sql`${+isFileOwner}`.mapWith(Boolean)\n })\n .from(comments)\n .leftJoin(users, eq(users.id, comments.userId))\n .where(where)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n async createComment(userId: number, fileId: number, content: string): Promise<Comment['id']> {\n return dbGetInsertedId(await this.db.insert(comments).values({ userId: userId, fileId: fileId, content: content } as Comment))\n }\n\n async updateComment(userId: number, commentId: number, fileId: number, content: string): Promise<boolean> {\n return dbCheckAffectedRows(\n await this.db\n .update(comments)\n .set({ content: content } as Comment)\n .where(and(eq(comments.userId, userId), eq(comments.id, commentId), eq(comments.fileId, fileId)))\n .limit(1),\n 1,\n false\n )\n }\n\n async deleteComment(userId: number, commentId: number, fileId: number, isFileOwner: boolean): Promise<boolean> {\n return dbCheckAffectedRows(\n await this.db\n .delete(comments)\n .where(and(or(eq(sql`${+isFileOwner}`, 1), eq(comments.userId, userId)), eq(comments.id, commentId), eq(comments.fileId, fileId)))\n .limit(1),\n 1,\n false\n )\n }\n\n membersToNotify(fromUserId: number, fileId: number): Promise<UserMailNotification[]> {\n /* lists the owner of the file and the users who have commented on it */\n const select: UserMailNotification | SelectedFields<any, any> = {\n id: users.id,\n email: users.email,\n language: users.language,\n notification: users.notification\n }\n const fromComments = this.db\n .select(select)\n .from(comments)\n .innerJoin(users, and(eq(users.id, comments.userId), ne(users.id, fromUserId)))\n .where(eq(comments.fileId, fileId))\n const fromFile = this.db\n .select(select)\n .from(files)\n .innerJoin(users, and(eq(users.id, files.ownerId), ne(users.id, fromUserId)))\n .where(eq(files.id, fileId))\n return union(fromComments, fromFile) as any\n }\n\n getRecentsFromShares(userId: number, shareIds: number[], limit: number) {\n const shareFile: any = alias(files, 'shareFile')\n return this.db\n .select({\n id: comments.id,\n content: comments.content,\n modifiedAt: comments.modifiedAt,\n author: { login: users.login, fullName: userFullNameSQL(users).as('fullName'), email: users.email },\n file: {\n name: sql<string>`IF (${files.id} = ${shareFile.id}, ${shares.name}, ${files.name})`.as('name'),\n path: sql<string>`\n CONCAT_WS('/', '${sql.raw(SPACE_REPOSITORY.SHARES)}',\n IF (${shareFile.id} IS NOT NULL,\n IF (${files.id} = ${shareFile.id}, NULL, REGEXP_REPLACE(${files.path}, ${filePathSQL(shareFile)}, ${shares.alias})),\n CONCAT_WS('/', ${shares.alias}, IF (${files.path} = '.', NULL, ${files.path}))\n )\n )`.as('path'),\n mime: files.mime,\n inTrash: sql<number>`0`.as('inTrash'),\n fromSpace: sql<number>`0`.as('fromSpace'),\n fromShare: sql<number>`1`.as('fromShare')\n }\n } satisfies CommentRecent | SelectedFields<any, any>)\n .from(shares)\n .leftJoin(shareFile, eq(shareFile.id, shares.fileId))\n .leftJoin(spaces, eq(spaces.id, shareFile.spaceId))\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(\n files,\n or(\n // file linked to the share\n eq(files.id, shareFile.id),\n // all files with an external share id\n and(isNull(shareFile.id), eq(files.shareExternalId, shares.id)),\n // all files under the share\n and(\n isNotNull(shareFile.id),\n eq(shareFile.isDir, true),\n sql`${files.spaceId} <=> ${shareFile.spaceId}`,\n sql`${files.ownerId} <=> ${shareFile.ownerId}`,\n sql`${files.spaceExternalRootId} <=> ${shareFile.spaceExternalRootId}`,\n sql`${files.shareExternalId} <=> ${shareFile.shareExternalId}`,\n sql`${files.path} REGEXP CONCAT('^', IF(${shareFile.path} = '.', CONCAT(${shareFile.name}, '(/.*|)$'), CONCAT(${shareFile.path}, '/')))`\n )\n )\n )\n .innerJoin(comments, and(eq(comments.fileId, files.id), ne(comments.userId, userId)))\n .innerJoin(users, eq(users.id, comments.userId))\n .where(inArray(shares.id, shareIds))\n .groupBy(comments.id)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n getRecentsFromSpaces(userId: number, spaceIds: number[], limit: number) {\n const spaceRootFile: any = alias(files, 'spaceRootFile')\n return this.db\n .select({\n id: comments.id,\n content: comments.content,\n modifiedAt: comments.modifiedAt,\n author: { login: users.login, fullName: userFullNameSQL(users).as('fullName'), email: users.email },\n file: {\n name: sql<string>`IF (${files.id} = ${spacesRoots.fileId}, ${spacesRoots.name}, ${files.name})`.as('name'),\n path: sql<string>`\n CONCAT_WS('/', \n IF (${files.inTrash} = 0, '${sql.raw(SPACE_REPOSITORY.FILES)}', '${sql.raw(SPACE_REPOSITORY.TRASH)}'), \n IF (${files.ownerId} = ${userId}, '${sql.raw(SPACE_ALIAS.PERSONAL)}', ${spaces.alias}),\n IF (${spaceRootFile.id} IS NOT NULL,\n IF (${files.id} = ${spaceRootFile.id}, NULL, IF (${files.path} = '.', NULL, REGEXP_REPLACE(${files.path}, ${filePathSQL(spaceRootFile)}, ${spacesRoots.alias}))),\n NULLIF(CONCAT_WS('/', IF (${files.spaceExternalRootId} = ${spacesRoots.id}, ${spacesRoots.alias}, NULL), IF (${files.path} = '.', NULL, ${files.path})), '')\n )\n )`.as('path'),\n mime: files.mime,\n inTrash: sql<number>`${files.inTrash}`.as('inTrash'),\n fromSpace: sql<number>`IF (${files.ownerId} = ${userId}, 0, 1)`.as('fromSpace'),\n fromShare: sql<number>`0`.as('fromShare')\n }\n } satisfies CommentRecent | SelectedFields<any, any>)\n .from(spaces)\n .leftJoin(spacesRoots, eq(spacesRoots.spaceId, spaces.id))\n .leftJoin(spaceRootFile, eq(spaceRootFile.id, spacesRoots.fileId))\n .leftJoin(\n files,\n or(\n // all files from user\n eq(files.ownerId, userId),\n // all files from spaces\n eq(files.spaceId, spaces.id),\n // all files from space roots\n eq(files.id, spacesRoots.fileId),\n // all files under the space roots\n and(\n isNotNull(spaceRootFile.id),\n eq(spaceRootFile.isDir, true),\n sql`${files.ownerId} <=> ${spaceRootFile.ownerId}`,\n sql`${files.path} REGEXP CONCAT('^', IF(${spaceRootFile.path} = '.', CONCAT(${spaceRootFile.name}, '(/.*|)$'), CONCAT(${spaceRootFile.path}, '/')))`\n )\n )\n )\n .innerJoin(comments, and(eq(comments.fileId, files.id), ne(comments.userId, userId)))\n .innerJoin(users, eq(users.id, comments.userId))\n .where(inArray(spaces.id, spaceIds))\n .groupBy(comments.id)\n .orderBy(desc(comments.id))\n .limit(limit)\n }\n\n async getRecentsFromUser(user: UserModel, limit = 10): Promise<CommentRecent[]> {\n const [spaceIds, shareIds] = await Promise.all([this.spacesQueries.spaceIds(user.id), this.sharesQueries.shareIds(user.id, +user.isAdmin)])\n const fromSpaces = this.getRecentsFromSpaces(user.id, spaceIds, limit * 2)\n const fromShares = this.getRecentsFromShares(user.id, shareIds, limit * 2)\n const unionAlias = union(fromSpaces, fromShares).as('unionAlias')\n return this.db.select().from(unionAlias).groupBy(unionAlias.id).orderBy(desc(unionAlias.id)).limit(limit)\n }\n}\n"],"names":["CommentsQueries","getComments","userId","isFileOwner","fromFileId","fromCommentId","limit","undefined","where","eq","comments","fileId","id","Error","db","select","getTableColumns","author","login","users","fullName","userFullNameSQL","email","isAuthor","sql","mapWith","Boolean","from","leftJoin","orderBy","desc","createComment","content","dbGetInsertedId","insert","values","updateComment","commentId","dbCheckAffectedRows","update","set","and","deleteComment","delete","or","membersToNotify","fromUserId","language","notification","fromComments","innerJoin","ne","fromFile","files","ownerId","union","getRecentsFromShares","shareIds","shareFile","alias","modifiedAt","as","file","name","shares","path","raw","SPACE_REPOSITORY","SHARES","filePathSQL","mime","inTrash","fromSpace","fromShare","spaces","spaceId","spacesRoots","isNull","shareExternalId","isNotNull","isDir","spaceExternalRootId","inArray","groupBy","getRecentsFromSpaces","spaceIds","spaceRootFile","FILES","TRASH","SPACE_ALIAS","PERSONAL","getRecentsFromUser","user","Promise","all","spacesQueries","sharesQueries","isAdmin","fromSpaces","fromShares","unionAlias"],"mappings":"AAAA;;;;CAIC;;;;+BAuBYA;;;eAAAA;;;wBArBsB;4BAC0E;2BAChF;2BACK;uBAEmB;6BAClB;8BAEZ;sCACO;wBACgB;mCAClB;8BACL;sCACO;6BAES;gCAGd;;;;;;;;;;;;;;;AAGlB,IAAA,AAAMA,kBAAN,MAAMA;IAOXC,YAAYC,MAAc,EAAEC,WAAoB,EAAEC,UAAmB,EAAEC,aAAsB,EAAEC,QAAgBC,SAAS,EAAsB;QAC5I,IAAIC;QACJ,IAAIJ,YAAY;YACdI,QAAQC,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAEP;QAC9B,OAAO,IAAIC,eAAe;YACxBG,QAAQC,IAAAA,cAAE,EAACC,wBAAQ,CAACE,EAAE,EAAEP;YACxBC,QAAQ;QACV,OAAO;YACL,MAAMO,MAAM;QACd;QACA,OAAO,IAAI,CAACC,EAAE,CACXC,MAAM,CAAC;YACN,GAAGC,IAAAA,2BAAe,EAACN,wBAAQ,CAAC;YAC5BO,QAAQ;gBAAEC,OAAOC,kBAAK,CAACD,KAAK;gBAAEE,UAAUC,IAAAA,4BAAe,EAACF,kBAAK;gBAAGG,OAAOH,kBAAK,CAACG,KAAK;gBAAEC,UAAUC,IAAAA,eAAG,CAAA,CAAC,EAAEL,kBAAK,CAACP,EAAE,CAAC,GAAG,EAAEV,OAAO,CAAC,CAACuB,OAAO,CAACC;YAAS;YAC5IvB,aAAaqB,IAAAA,eAAG,CAAA,CAAC,EAAE,CAACrB,YAAY,CAAC,CAACsB,OAAO,CAACC;QAC5C,GACCC,IAAI,CAACjB,wBAAQ,EACbkB,QAAQ,CAACT,kBAAK,EAAEV,IAAAA,cAAE,EAACU,kBAAK,CAACP,EAAE,EAAEF,wBAAQ,CAACR,MAAM,GAC5CM,KAAK,CAACA,OACNqB,OAAO,CAACC,IAAAA,gBAAI,EAACpB,wBAAQ,CAACE,EAAE,GACxBN,KAAK,CAACA;IACX;IAEA,MAAMyB,cAAc7B,MAAc,EAAES,MAAc,EAAEqB,OAAe,EAA0B;QAC3F,OAAOC,IAAAA,sBAAe,EAAC,MAAM,IAAI,CAACnB,EAAE,CAACoB,MAAM,CAACxB,wBAAQ,EAAEyB,MAAM,CAAC;YAAEjC,QAAQA;YAAQS,QAAQA;YAAQqB,SAASA;QAAQ;IAClH;IAEA,MAAMI,cAAclC,MAAc,EAAEmC,SAAiB,EAAE1B,MAAc,EAAEqB,OAAe,EAAoB;QACxG,OAAOM,IAAAA,0BAAmB,EACxB,MAAM,IAAI,CAACxB,EAAE,CACVyB,MAAM,CAAC7B,wBAAQ,EACf8B,GAAG,CAAC;YAAER,SAASA;QAAQ,GACvBxB,KAAK,CAACiC,IAAAA,eAAG,EAAChC,IAAAA,cAAE,EAACC,wBAAQ,CAACR,MAAM,EAAEA,SAASO,IAAAA,cAAE,EAACC,wBAAQ,CAACE,EAAE,EAAEyB,YAAY5B,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAEA,UACvFL,KAAK,CAAC,IACT,GACA;IAEJ;IAEA,MAAMoC,cAAcxC,MAAc,EAAEmC,SAAiB,EAAE1B,MAAc,EAAER,WAAoB,EAAoB;QAC7G,OAAOmC,IAAAA,0BAAmB,EACxB,MAAM,IAAI,CAACxB,EAAE,CACV6B,MAAM,CAACjC,wBAAQ,EACfF,KAAK,CAACiC,IAAAA,eAAG,EAACG,IAAAA,cAAE,EAACnC,IAAAA,cAAE,EAACe,IAAAA,eAAG,CAAA,CAAC,EAAE,CAACrB,YAAY,CAAC,EAAE,IAAIM,IAAAA,cAAE,EAACC,wBAAQ,CAACR,MAAM,EAAEA,UAAUO,IAAAA,cAAE,EAACC,wBAAQ,CAACE,EAAE,EAAEyB,YAAY5B,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAEA,UACxHL,KAAK,CAAC,IACT,GACA;IAEJ;IAEAuC,gBAAgBC,UAAkB,EAAEnC,MAAc,EAAmC;QACnF,sEAAsE,GACtE,MAAMI,SAA0D;YAC9DH,IAAIO,kBAAK,CAACP,EAAE;YACZU,OAAOH,kBAAK,CAACG,KAAK;YAClByB,UAAU5B,kBAAK,CAAC4B,QAAQ;YACxBC,cAAc7B,kBAAK,CAAC6B,YAAY;QAClC;QACA,MAAMC,eAAe,IAAI,CAACnC,EAAE,CACzBC,MAAM,CAACA,QACPY,IAAI,CAACjB,wBAAQ,EACbwC,SAAS,CAAC/B,kBAAK,EAAEsB,IAAAA,eAAG,EAAChC,IAAAA,cAAE,EAACU,kBAAK,CAACP,EAAE,EAAEF,wBAAQ,CAACR,MAAM,GAAGiD,IAAAA,cAAE,EAAChC,kBAAK,CAACP,EAAE,EAAEkC,cACjEtC,KAAK,CAACC,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAEA;QAC7B,MAAMyC,WAAW,IAAI,CAACtC,EAAE,CACrBC,MAAM,CAACA,QACPY,IAAI,CAAC0B,kBAAK,EACVH,SAAS,CAAC/B,kBAAK,EAAEsB,IAAAA,eAAG,EAAChC,IAAAA,cAAE,EAACU,kBAAK,CAACP,EAAE,EAAEyC,kBAAK,CAACC,OAAO,GAAGH,IAAAA,cAAE,EAAChC,kBAAK,CAACP,EAAE,EAAEkC,cAC/DtC,KAAK,CAACC,IAAAA,cAAE,EAAC4C,kBAAK,CAACzC,EAAE,EAAED;QACtB,OAAO4C,IAAAA,gBAAK,EAACN,cAAcG;IAC7B;IAEAI,qBAAqBtD,MAAc,EAAEuD,QAAkB,EAAEnD,KAAa,EAAE;QACtE,MAAMoD,YAAiBC,IAAAA,gBAAK,EAACN,kBAAK,EAAE;QACpC,OAAO,IAAI,CAACvC,EAAE,CACXC,MAAM,CAAC;YACNH,IAAIF,wBAAQ,CAACE,EAAE;YACfoB,SAAStB,wBAAQ,CAACsB,OAAO;YACzB4B,YAAYlD,wBAAQ,CAACkD,UAAU;YAC/B3C,QAAQ;gBAAEC,OAAOC,kBAAK,CAACD,KAAK;gBAAEE,UAAUC,IAAAA,4BAAe,EAACF,kBAAK,EAAE0C,EAAE,CAAC;gBAAavC,OAAOH,kBAAK,CAACG,KAAK;YAAC;YAClGwC,MAAM;gBACJC,MAAMvC,IAAAA,eAAG,CAAQ,CAAC,IAAI,EAAE6B,kBAAK,CAACzC,EAAE,CAAC,GAAG,EAAE8C,UAAU9C,EAAE,CAAC,EAAE,EAAEoD,oBAAM,CAACD,IAAI,CAAC,EAAE,EAAEV,kBAAK,CAACU,IAAI,CAAC,CAAC,CAAC,CAACF,EAAE,CAAC;gBACxFI,MAAMzC,IAAAA,eAAG,CAAQ,CAAC;0BACF,EAAEA,eAAG,CAAC0C,GAAG,CAACC,wBAAgB,CAACC,MAAM,EAAE;gBAC7C,EAAEV,UAAU9C,EAAE,CAAC;kBACb,EAAEyC,kBAAK,CAACzC,EAAE,CAAC,GAAG,EAAE8C,UAAU9C,EAAE,CAAC,uBAAuB,EAAEyC,kBAAK,CAACY,IAAI,CAAC,EAAE,EAAEI,IAAAA,wBAAW,EAACX,WAAW,EAAE,EAAEM,oBAAM,CAACL,KAAK,CAAC;6BAClG,EAAEK,oBAAM,CAACL,KAAK,CAAC,MAAM,EAAEN,kBAAK,CAACY,IAAI,CAAC,cAAc,EAAEZ,kBAAK,CAACY,IAAI,CAAC;;WAE/E,CAAC,CAACJ,EAAE,CAAC;gBACNS,MAAMjB,kBAAK,CAACiB,IAAI;gBAChBC,SAAS/C,IAAAA,eAAG,CAAQ,CAAC,CAAC,CAAC,CAACqC,EAAE,CAAC;gBAC3BW,WAAWhD,IAAAA,eAAG,CAAQ,CAAC,CAAC,CAAC,CAACqC,EAAE,CAAC;gBAC7BY,WAAWjD,IAAAA,eAAG,CAAQ,CAAC,CAAC,CAAC,CAACqC,EAAE,CAAC;YAC/B;QACF,GACClC,IAAI,CAACqC,oBAAM,EACXpC,QAAQ,CAAC8B,WAAWjD,IAAAA,cAAE,EAACiD,UAAU9C,EAAE,EAAEoD,oBAAM,CAACrD,MAAM,GAClDiB,QAAQ,CAAC8C,oBAAM,EAAEjE,IAAAA,cAAE,EAACiE,oBAAM,CAAC9D,EAAE,EAAE8C,UAAUiB,OAAO,GAChD/C,QAAQ,CAACgD,8BAAW,EAAEnE,IAAAA,cAAE,EAACmE,8BAAW,CAACD,OAAO,EAAED,oBAAM,CAAC9D,EAAE,GACvDgB,QAAQ,CACPyB,kBAAK,EACLT,IAAAA,cAAE,EACA,2BAA2B;QAC3BnC,IAAAA,cAAE,EAAC4C,kBAAK,CAACzC,EAAE,EAAE8C,UAAU9C,EAAE,GACzB,sCAAsC;QACtC6B,IAAAA,eAAG,EAACoC,IAAAA,kBAAM,EAACnB,UAAU9C,EAAE,GAAGH,IAAAA,cAAE,EAAC4C,kBAAK,CAACyB,eAAe,EAAEd,oBAAM,CAACpD,EAAE,IAC7D,4BAA4B;QAC5B6B,IAAAA,eAAG,EACDsC,IAAAA,qBAAS,EAACrB,UAAU9C,EAAE,GACtBH,IAAAA,cAAE,EAACiD,UAAUsB,KAAK,EAAE,OACpBxD,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACsB,OAAO,CAAC,KAAK,EAAEjB,UAAUiB,OAAO,CAAC,CAAC,EAC9CnD,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACC,OAAO,CAAC,KAAK,EAAEI,UAAUJ,OAAO,CAAC,CAAC,EAC9C9B,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAAC4B,mBAAmB,CAAC,KAAK,EAAEvB,UAAUuB,mBAAmB,CAAC,CAAC,EACtEzD,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACyB,eAAe,CAAC,KAAK,EAAEpB,UAAUoB,eAAe,CAAC,CAAC,EAC9DtD,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACY,IAAI,CAAC,uBAAuB,EAAEP,UAAUO,IAAI,CAAC,eAAe,EAAEP,UAAUK,IAAI,CAAC,qBAAqB,EAAEL,UAAUO,IAAI,CAAC,QAAQ,CAAC,IAI7If,SAAS,CAACxC,wBAAQ,EAAE+B,IAAAA,eAAG,EAAChC,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAE0C,kBAAK,CAACzC,EAAE,GAAGuC,IAAAA,cAAE,EAACzC,wBAAQ,CAACR,MAAM,EAAEA,UAC3EgD,SAAS,CAAC/B,kBAAK,EAAEV,IAAAA,cAAE,EAACU,kBAAK,CAACP,EAAE,EAAEF,wBAAQ,CAACR,MAAM,GAC7CM,KAAK,CAAC0E,IAAAA,mBAAO,EAAClB,oBAAM,CAACpD,EAAE,EAAE6C,WACzB0B,OAAO,CAACzE,wBAAQ,CAACE,EAAE,EACnBiB,OAAO,CAACC,IAAAA,gBAAI,EAACpB,wBAAQ,CAACE,EAAE,GACxBN,KAAK,CAACA;IACX;IAEA8E,qBAAqBlF,MAAc,EAAEmF,QAAkB,EAAE/E,KAAa,EAAE;QACtE,MAAMgF,gBAAqB3B,IAAAA,gBAAK,EAACN,kBAAK,EAAE;QACxC,OAAO,IAAI,CAACvC,EAAE,CACXC,MAAM,CAAC;YACNH,IAAIF,wBAAQ,CAACE,EAAE;YACfoB,SAAStB,wBAAQ,CAACsB,OAAO;YACzB4B,YAAYlD,wBAAQ,CAACkD,UAAU;YAC/B3C,QAAQ;gBAAEC,OAAOC,kBAAK,CAACD,KAAK;gBAAEE,UAAUC,IAAAA,4BAAe,EAACF,kBAAK,EAAE0C,EAAE,CAAC;gBAAavC,OAAOH,kBAAK,CAACG,KAAK;YAAC;YAClGwC,MAAM;gBACJC,MAAMvC,IAAAA,eAAG,CAAQ,CAAC,IAAI,EAAE6B,kBAAK,CAACzC,EAAE,CAAC,GAAG,EAAEgE,8BAAW,CAACjE,MAAM,CAAC,EAAE,EAAEiE,8BAAW,CAACb,IAAI,CAAC,EAAE,EAAEV,kBAAK,CAACU,IAAI,CAAC,CAAC,CAAC,CAACF,EAAE,CAAC;gBACnGI,MAAMzC,IAAAA,eAAG,CAAQ,CAAC;;gBAEZ,EAAE6B,kBAAK,CAACkB,OAAO,CAAC,OAAO,EAAE/C,eAAG,CAAC0C,GAAG,CAACC,wBAAgB,CAACoB,KAAK,EAAE,IAAI,EAAE/D,eAAG,CAAC0C,GAAG,CAACC,wBAAgB,CAACqB,KAAK,EAAE;gBAC/F,EAAEnC,kBAAK,CAACC,OAAO,CAAC,GAAG,EAAEpD,OAAO,GAAG,EAAEsB,eAAG,CAAC0C,GAAG,CAACuB,mBAAW,CAACC,QAAQ,EAAE,GAAG,EAAEhB,oBAAM,CAACf,KAAK,CAAC;gBACjF,EAAE2B,cAAc1E,EAAE,CAAC;oBACf,EAAEyC,kBAAK,CAACzC,EAAE,CAAC,GAAG,EAAE0E,cAAc1E,EAAE,CAAC,YAAY,EAAEyC,kBAAK,CAACY,IAAI,CAAC,6BAA6B,EAAEZ,kBAAK,CAACY,IAAI,CAAC,EAAE,EAAEI,IAAAA,wBAAW,EAACiB,eAAe,EAAE,EAAEV,8BAAW,CAACjB,KAAK,CAAC;0CACnI,EAAEN,kBAAK,CAAC4B,mBAAmB,CAAC,GAAG,EAAEL,8BAAW,CAAChE,EAAE,CAAC,EAAE,EAAEgE,8BAAW,CAACjB,KAAK,CAAC,aAAa,EAAEN,kBAAK,CAACY,IAAI,CAAC,cAAc,EAAEZ,kBAAK,CAACY,IAAI,CAAC;;WAE1J,CAAC,CAACJ,EAAE,CAAC;gBACNS,MAAMjB,kBAAK,CAACiB,IAAI;gBAChBC,SAAS/C,IAAAA,eAAG,CAAQ,CAAC,EAAE6B,kBAAK,CAACkB,OAAO,CAAC,CAAC,CAACV,EAAE,CAAC;gBAC1CW,WAAWhD,IAAAA,eAAG,CAAQ,CAAC,IAAI,EAAE6B,kBAAK,CAACC,OAAO,CAAC,GAAG,EAAEpD,OAAO,OAAO,CAAC,CAAC2D,EAAE,CAAC;gBACnEY,WAAWjD,IAAAA,eAAG,CAAQ,CAAC,CAAC,CAAC,CAACqC,EAAE,CAAC;YAC/B;QACF,GACClC,IAAI,CAAC+C,oBAAM,EACX9C,QAAQ,CAACgD,8BAAW,EAAEnE,IAAAA,cAAE,EAACmE,8BAAW,CAACD,OAAO,EAAED,oBAAM,CAAC9D,EAAE,GACvDgB,QAAQ,CAAC0D,eAAe7E,IAAAA,cAAE,EAAC6E,cAAc1E,EAAE,EAAEgE,8BAAW,CAACjE,MAAM,GAC/DiB,QAAQ,CACPyB,kBAAK,EACLT,IAAAA,cAAE,EACA,sBAAsB;QACtBnC,IAAAA,cAAE,EAAC4C,kBAAK,CAACC,OAAO,EAAEpD,SAClB,wBAAwB;QACxBO,IAAAA,cAAE,EAAC4C,kBAAK,CAACsB,OAAO,EAAED,oBAAM,CAAC9D,EAAE,GAC3B,6BAA6B;QAC7BH,IAAAA,cAAE,EAAC4C,kBAAK,CAACzC,EAAE,EAAEgE,8BAAW,CAACjE,MAAM,GAC/B,kCAAkC;QAClC8B,IAAAA,eAAG,EACDsC,IAAAA,qBAAS,EAACO,cAAc1E,EAAE,GAC1BH,IAAAA,cAAE,EAAC6E,cAAcN,KAAK,EAAE,OACxBxD,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACC,OAAO,CAAC,KAAK,EAAEgC,cAAchC,OAAO,CAAC,CAAC,EAClD9B,IAAAA,eAAG,CAAA,CAAC,EAAE6B,kBAAK,CAACY,IAAI,CAAC,uBAAuB,EAAEqB,cAAcrB,IAAI,CAAC,eAAe,EAAEqB,cAAcvB,IAAI,CAAC,qBAAqB,EAAEuB,cAAcrB,IAAI,CAAC,QAAQ,CAAC,IAIzJf,SAAS,CAACxC,wBAAQ,EAAE+B,IAAAA,eAAG,EAAChC,IAAAA,cAAE,EAACC,wBAAQ,CAACC,MAAM,EAAE0C,kBAAK,CAACzC,EAAE,GAAGuC,IAAAA,cAAE,EAACzC,wBAAQ,CAACR,MAAM,EAAEA,UAC3EgD,SAAS,CAAC/B,kBAAK,EAAEV,IAAAA,cAAE,EAACU,kBAAK,CAACP,EAAE,EAAEF,wBAAQ,CAACR,MAAM,GAC7CM,KAAK,CAAC0E,IAAAA,mBAAO,EAACR,oBAAM,CAAC9D,EAAE,EAAEyE,WACzBF,OAAO,CAACzE,wBAAQ,CAACE,EAAE,EACnBiB,OAAO,CAACC,IAAAA,gBAAI,EAACpB,wBAAQ,CAACE,EAAE,GACxBN,KAAK,CAACA;IACX;IAEA,MAAMqF,mBAAmBC,IAAe,EAAEtF,QAAQ,EAAE,EAA4B;QAC9E,MAAM,CAAC+E,UAAU5B,SAAS,GAAG,MAAMoC,QAAQC,GAAG,CAAC;YAAC,IAAI,CAACC,aAAa,CAACV,QAAQ,CAACO,KAAKhF,EAAE;YAAG,IAAI,CAACoF,aAAa,CAACvC,QAAQ,CAACmC,KAAKhF,EAAE,EAAE,CAACgF,KAAKK,OAAO;SAAE;QAC1I,MAAMC,aAAa,IAAI,CAACd,oBAAoB,CAACQ,KAAKhF,EAAE,EAAEyE,UAAU/E,QAAQ;QACxE,MAAM6F,aAAa,IAAI,CAAC3C,oBAAoB,CAACoC,KAAKhF,EAAE,EAAE6C,UAAUnD,QAAQ;QACxE,MAAM8F,aAAa7C,IAAAA,gBAAK,EAAC2C,YAAYC,YAAYtC,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC/C,EAAE,CAACC,MAAM,GAAGY,IAAI,CAACyE,YAAYjB,OAAO,CAACiB,WAAWxF,EAAE,EAAEiB,OAAO,CAACC,IAAAA,gBAAI,EAACsE,WAAWxF,EAAE,GAAGN,KAAK,CAACA;IACrG;IA/LA,YACE,AAA4CQ,EAAY,EACxD,AAAiBiF,aAA4B,EAC7C,AAAiBC,aAA4B,CAC7C;aAH4ClF,KAAAA;aAC3BiF,gBAAAA;aACAC,gBAAAA;IAChB;AA4LL"}
@@ -33,7 +33,6 @@ describe('Users (e2e)', ()=>{
33
33
  deleteSpace: true,
34
34
  isGuest: false
35
35
  })).resolves.not.toThrow();
36
- await (0, _utils.dbCloseConnection)(app);
37
36
  await app.close();
38
37
  });
39
38
  it('should be defined', ()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/applications/users/users.e2e-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 { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../../app.bootstrap'\nimport { TokenResponseDto } from '../../authentication/dto/token-response.dto'\nimport { AuthManager } from '../../authentication/services/auth-manager.service'\nimport { dbCheckConnection, dbCloseConnection } from '../../infrastructure/database/utils'\nimport { API_USERS_AVATAR, API_USERS_ME } from './constants/routes'\nimport { USER_ROLE } from './constants/user'\nimport { DeleteUserDto } from './dto/delete-user.dto'\nimport { UserModel } from './models/user.model'\nimport { AdminUsersManager } from './services/admin-users-manager.service'\nimport { generateUserTest } from './utils/test'\n\ndescribe('Users (e2e)', () => {\n let app: NestFastifyApplication\n let authManager: AuthManager\n let adminUsersManager: AdminUsersManager\n let userTest: UserModel\n let tokens: TokenResponseDto\n\n beforeAll(async () => {\n app = await appBootstrap()\n await app.init()\n await app.getHttpAdapter().getInstance().ready()\n authManager = app.get<AuthManager>(AuthManager)\n adminUsersManager = app.get<AdminUsersManager>(AdminUsersManager)\n userTest = new UserModel(generateUserTest(false), false)\n })\n\n afterAll(async () => {\n await expect(\n adminUsersManager.deleteUserOrGuest(userTest.id, userTest.login, { deleteSpace: true, isGuest: false } satisfies DeleteUserDto)\n ).resolves.not.toThrow()\n await dbCloseConnection(app)\n await app.close()\n })\n\n it('should be defined', () => {\n expect(authManager).toBeDefined()\n expect(adminUsersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should get the database connection', async () => {\n expect(await dbCheckConnection(app)).toBe(true)\n })\n\n it(`GET ${API_USERS_ME} => 401`, async () => {\n const res = await app.inject({\n method: 'GET',\n url: API_USERS_ME\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`GET ${API_USERS_ME} => 200`, async () => {\n userTest = await adminUsersManager.createUserOrGuest(userTest, USER_ROLE.USER)\n expect(userTest.id).toBeDefined()\n tokens = await authManager.getTokens(userTest)\n const res = await app.inject({\n method: 'GET',\n url: API_USERS_ME,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n expect(res.statusCode).toEqual(200)\n const content = res.json()\n expect(content.user).toBeDefined()\n expect(content.user.id).toBe(userTest.id)\n })\n\n it(`GET ${API_USERS_AVATAR} => 200`, async () => {\n const res1 = await app.inject({\n method: 'GET',\n url: `${API_USERS_AVATAR}/me`,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n const res2 = await app.inject({\n method: 'GET',\n url: `${API_USERS_AVATAR}/${userTest.login}`,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n for (const res of [res1, res2]) {\n expect(res.statusCode).toEqual(200)\n expect(res.rawPayload).toBeInstanceOf(Buffer)\n expect(res.rawPayload.byteLength).toBeGreaterThan(1)\n }\n expect((res1.raw.req as any).user).toBe((res2.raw.req as any).user)\n expect(res1.rawPayload.byteLength).toEqual(res2.rawPayload.byteLength)\n })\n})\n"],"names":["describe","app","authManager","adminUsersManager","userTest","tokens","beforeAll","appBootstrap","init","getHttpAdapter","getInstance","ready","get","AuthManager","AdminUsersManager","UserModel","generateUserTest","afterAll","expect","deleteUserOrGuest","id","login","deleteSpace","isGuest","resolves","not","toThrow","dbCloseConnection","close","it","toBeDefined","dbCheckConnection","toBe","API_USERS_ME","res","inject","method","url","statusCode","toEqual","createUserOrGuest","USER_ROLE","USER","getTokens","headers","authorization","access","content","json","user","API_USERS_AVATAR","res1","res2","rawPayload","toBeInstanceOf","Buffer","byteLength","toBeGreaterThan","raw","req"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/applications/users/users.e2e-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 { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../../app.bootstrap'\nimport { TokenResponseDto } from '../../authentication/dto/token-response.dto'\nimport { AuthManager } from '../../authentication/services/auth-manager.service'\nimport { dbCheckConnection } from '../../infrastructure/database/utils'\nimport { API_USERS_AVATAR, API_USERS_ME } from './constants/routes'\nimport { USER_ROLE } from './constants/user'\nimport { DeleteUserDto } from './dto/delete-user.dto'\nimport { UserModel } from './models/user.model'\nimport { AdminUsersManager } from './services/admin-users-manager.service'\nimport { generateUserTest } from './utils/test'\n\ndescribe('Users (e2e)', () => {\n let app: NestFastifyApplication\n let authManager: AuthManager\n let adminUsersManager: AdminUsersManager\n let userTest: UserModel\n let tokens: TokenResponseDto\n\n beforeAll(async () => {\n app = await appBootstrap()\n await app.init()\n await app.getHttpAdapter().getInstance().ready()\n authManager = app.get<AuthManager>(AuthManager)\n adminUsersManager = app.get<AdminUsersManager>(AdminUsersManager)\n userTest = new UserModel(generateUserTest(false), false)\n })\n\n afterAll(async () => {\n await expect(\n adminUsersManager.deleteUserOrGuest(userTest.id, userTest.login, { deleteSpace: true, isGuest: false } satisfies DeleteUserDto)\n ).resolves.not.toThrow()\n await app.close()\n })\n\n it('should be defined', () => {\n expect(authManager).toBeDefined()\n expect(adminUsersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should get the database connection', async () => {\n expect(await dbCheckConnection(app)).toBe(true)\n })\n\n it(`GET ${API_USERS_ME} => 401`, async () => {\n const res = await app.inject({\n method: 'GET',\n url: API_USERS_ME\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`GET ${API_USERS_ME} => 200`, async () => {\n userTest = await adminUsersManager.createUserOrGuest(userTest, USER_ROLE.USER)\n expect(userTest.id).toBeDefined()\n tokens = await authManager.getTokens(userTest)\n const res = await app.inject({\n method: 'GET',\n url: API_USERS_ME,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n expect(res.statusCode).toEqual(200)\n const content = res.json()\n expect(content.user).toBeDefined()\n expect(content.user.id).toBe(userTest.id)\n })\n\n it(`GET ${API_USERS_AVATAR} => 200`, async () => {\n const res1 = await app.inject({\n method: 'GET',\n url: `${API_USERS_AVATAR}/me`,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n const res2 = await app.inject({\n method: 'GET',\n url: `${API_USERS_AVATAR}/${userTest.login}`,\n headers: { authorization: `Bearer ${tokens.access}` }\n })\n for (const res of [res1, res2]) {\n expect(res.statusCode).toEqual(200)\n expect(res.rawPayload).toBeInstanceOf(Buffer)\n expect(res.rawPayload.byteLength).toBeGreaterThan(1)\n }\n expect((res1.raw.req as any).user).toBe((res2.raw.req as any).user)\n expect(res1.rawPayload.byteLength).toEqual(res2.rawPayload.byteLength)\n })\n})\n"],"names":["describe","app","authManager","adminUsersManager","userTest","tokens","beforeAll","appBootstrap","init","getHttpAdapter","getInstance","ready","get","AuthManager","AdminUsersManager","UserModel","generateUserTest","afterAll","expect","deleteUserOrGuest","id","login","deleteSpace","isGuest","resolves","not","toThrow","close","it","toBeDefined","dbCheckConnection","toBe","API_USERS_ME","res","inject","method","url","statusCode","toEqual","createUserOrGuest","USER_ROLE","USER","getTokens","headers","authorization","access","content","json","user","API_USERS_AVATAR","res1","res2","rawPayload","toBeInstanceOf","Buffer","byteLength","toBeGreaterThan","raw","req"],"mappings":"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"}
@@ -73,6 +73,9 @@ _export(exports, {
73
73
  get WEBDAV_APP_LOCK () {
74
74
  return WEBDAV_APP_LOCK;
75
75
  },
76
+ get WEBDAV_CONTENT_TYPES () {
77
+ return WEBDAV_CONTENT_TYPES;
78
+ },
76
79
  get XML_CONTENT_TYPE () {
77
80
  return XML_CONTENT_TYPE;
78
81
  }
@@ -86,6 +89,10 @@ const NS_PREFIX = 'D';
86
89
  const LOCK_PREFIX = 'urn:uuid:';
87
90
  const XML_CONTENT_TYPE = 'application/xml; charset=utf-8';
88
91
  const HTML_CONTENT_TYPE = 'text/html; charset=utf-8';
92
+ const WEBDAV_CONTENT_TYPES = [
93
+ 'application/xml',
94
+ 'text/xml'
95
+ ];
89
96
  const WEBDAV_APP_LOCK = 'WebDAV';
90
97
  const ALLOWED_WEBDAV_METHODS = [
91
98
  _applicationsconstants.HTTP_STANDARD_METHOD.OPTIONS,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/webdav/constants/webdav.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 { SERVER_NAME } from '../../../common/shared'\nimport { HTTP_STANDARD_METHOD, HTTP_WEBDAV_METHOD } from '../../applications.constants'\nimport { WEBDAV_BASE_PATH } from './routes'\n\nexport const REGEX_BASE_PATH = new RegExp(`^/?${WEBDAV_BASE_PATH}/`)\nexport const NS_DAV = 'DAV:'\nexport const NS_PREFIX = 'D'\nexport const LOCK_PREFIX = 'urn:uuid:'\nexport const XML_CONTENT_TYPE = 'application/xml; charset=utf-8'\nexport const HTML_CONTENT_TYPE = 'text/html; charset=utf-8'\nexport const WEBDAV_APP_LOCK = 'WebDAV' as const\n\nexport const ALLOWED_WEBDAV_METHODS: string = [\n HTTP_STANDARD_METHOD.OPTIONS,\n HTTP_STANDARD_METHOD.HEAD,\n HTTP_STANDARD_METHOD.GET,\n HTTP_STANDARD_METHOD.PUT,\n HTTP_STANDARD_METHOD.DELETE,\n ...Object.values(HTTP_WEBDAV_METHOD)\n].join(', ')\n\nexport const ALLOW_EMPTY_BODY_METHODS: string[] = [HTTP_WEBDAV_METHOD.PROPFIND, HTTP_WEBDAV_METHOD.LOCK]\n\nexport const OPTIONS_HEADERS = {\n Server: SERVER_NAME,\n 'MS-Author-Via': 'DAV',\n DAV: '1,2',\n Allow: ALLOWED_WEBDAV_METHODS,\n 'Content-Type': HTML_CONTENT_TYPE,\n 'Content-Length': '0',\n 'Accept-Ranges': 'bytes'\n} as const\n\nexport const HEADER = {\n DEPTH: 'depth',\n IF: 'if',\n LOCK_TOKEN: 'lock-token',\n DESTINATION: 'destination',\n OVERWRITE: 'overwrite',\n TIMEOUT: 'timeout'\n} as const\n\nexport const LOCK_DISCOVERY_PROP = 'lockdiscovery'\nexport const STANDARD_PROPS = [\n 'creationdate',\n 'getcontenttype',\n 'resourcetype',\n 'getlastmodified',\n 'getcontentlength',\n 'displayname',\n 'getetag',\n 'supportedlock',\n LOCK_DISCOVERY_PROP\n]\n\nexport enum LOCK_SCOPE {\n EXCLUSIVE = 'exclusive',\n SHARED = 'shared'\n}\n\nexport enum DEPTH {\n INFINITY = 'infinity',\n RESOURCE = '0',\n MEMBERS = '1'\n}\n\nexport type LOCK_DEPTH = Omit<DEPTH, DEPTH.MEMBERS>\n\nexport enum PROPSTAT {\n ALLPROP = 'allprop',\n PROP = 'prop',\n PROPNAME = 'propname'\n}\n\nexport const PROPPATCH_PROP_UPDATE = 'propertyupdate'\nexport const PROPPATCH_METHOD = { SET: 'set', REMOVE: 'remove' }\nexport const PROPPATCH_MODIFIED_PROPS = ['getlastmodified', 'lastmodified', 'Win32LastModifiedTime']\nexport const PROPPATCH_SUPPORTED_PROPS = [...PROPPATCH_MODIFIED_PROPS, 'Win32CreationTime', 'Win32LastAccessTime', 'Win32FileAttributes']\n\nexport const PRECONDITION = {\n PROTECTED_PROPERTY: 'cannot-modify-protected-property',\n MISSING_LOCK_TOKEN: 'lock-token-submitted',\n LOCK_TOKEN_MISMATCH: 'lock-token-matches-request-uri',\n LOCK_CONFLICT: 'no-conflicting-lock',\n PROPFIND_FINITE_DEPTH: 'propfind-finite-depth'\n} as const\n"],"names":["ALLOWED_WEBDAV_METHODS","ALLOW_EMPTY_BODY_METHODS","DEPTH","HEADER","HTML_CONTENT_TYPE","LOCK_DISCOVERY_PROP","LOCK_PREFIX","LOCK_SCOPE","NS_DAV","NS_PREFIX","OPTIONS_HEADERS","PRECONDITION","PROPPATCH_METHOD","PROPPATCH_MODIFIED_PROPS","PROPPATCH_PROP_UPDATE","PROPPATCH_SUPPORTED_PROPS","PROPSTAT","REGEX_BASE_PATH","STANDARD_PROPS","WEBDAV_APP_LOCK","XML_CONTENT_TYPE","RegExp","WEBDAV_BASE_PATH","HTTP_STANDARD_METHOD","OPTIONS","HEAD","GET","PUT","DELETE","Object","values","HTTP_WEBDAV_METHOD","join","PROPFIND","LOCK","Server","SERVER_NAME","DAV","Allow","IF","LOCK_TOKEN","DESTINATION","OVERWRITE","TIMEOUT","SET","REMOVE","PROTECTED_PROPERTY","MISSING_LOCK_TOKEN","LOCK_TOKEN_MISMATCH","LOCK_CONFLICT","PROPFIND_FINITE_DEPTH"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAcYA;eAAAA;;QASAC;eAAAA;;QAuCDC;eAAAA;;QA3BCC;eAAAA;;QAxBAC;eAAAA;;QAiCAC;eAAAA;;QAnCAC;eAAAA;;QAgDDC;eAAAA;;QAlDCC;eAAAA;;QACAC;eAAAA;;QAiBAC;eAAAA;;QAwDAC;eAAAA;;QAJAC;eAAAA;;QACAC;eAAAA;;QAFAC;eAAAA;;QAGAC;eAAAA;;QATDC;eAAAA;;QAhECC;eAAAA;;QAuCAC;eAAAA;;QAjCAC;eAAAA;;QAFAC;eAAAA;;;wBARe;uCAC6B;wBACxB;AAE1B,MAAMH,kBAAkB,IAAII,OAAO,CAAC,GAAG,EAAEC,wBAAgB,CAAC,CAAC,CAAC;AAC5D,MAAMd,SAAS;AACf,MAAMC,YAAY;AAClB,MAAMH,cAAc;AACpB,MAAMc,mBAAmB;AACzB,MAAMhB,oBAAoB;AAC1B,MAAMe,kBAAkB;AAExB,MAAMnB,yBAAiC;IAC5CuB,2CAAoB,CAACC,OAAO;IAC5BD,2CAAoB,CAACE,IAAI;IACzBF,2CAAoB,CAACG,GAAG;IACxBH,2CAAoB,CAACI,GAAG;IACxBJ,2CAAoB,CAACK,MAAM;OACxBC,OAAOC,MAAM,CAACC,yCAAkB;CACpC,CAACC,IAAI,CAAC;AAEA,MAAM/B,2BAAqC;IAAC8B,yCAAkB,CAACE,QAAQ;IAAEF,yCAAkB,CAACG,IAAI;CAAC;AAEjG,MAAMxB,kBAAkB;IAC7ByB,QAAQC,mBAAW;IACnB,iBAAiB;IACjBC,KAAK;IACLC,OAAOtC;IACP,gBAAgBI;IAChB,kBAAkB;IAClB,iBAAiB;AACnB;AAEO,MAAMD,SAAS;IACpBD,OAAO;IACPqC,IAAI;IACJC,YAAY;IACZC,aAAa;IACbC,WAAW;IACXC,SAAS;AACX;AAEO,MAAMtC,sBAAsB;AAC5B,MAAMa,iBAAiB;IAC5B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACAb;CACD;AAEM,IAAA,AAAKE,oCAAAA;;;WAAAA;;AAKL,IAAA,AAAKL,+BAAAA;;;;WAAAA;;AAQL,IAAA,AAAKc,kCAAAA;;;;WAAAA;;AAML,MAAMF,wBAAwB;AAC9B,MAAMF,mBAAmB;IAAEgC,KAAK;IAAOC,QAAQ;AAAS;AACxD,MAAMhC,2BAA2B;IAAC;IAAmB;IAAgB;CAAwB;AAC7F,MAAME,4BAA4B;OAAIF;IAA0B;IAAqB;IAAuB;CAAsB;AAElI,MAAMF,eAAe;IAC1BmC,oBAAoB;IACpBC,oBAAoB;IACpBC,qBAAqB;IACrBC,eAAe;IACfC,uBAAuB;AACzB"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/webdav/constants/webdav.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 { SERVER_NAME } from '../../../common/shared'\nimport { HTTP_STANDARD_METHOD, HTTP_WEBDAV_METHOD } from '../../applications.constants'\nimport { WEBDAV_BASE_PATH } from './routes'\n\nexport const REGEX_BASE_PATH = new RegExp(`^/?${WEBDAV_BASE_PATH}/`)\nexport const NS_DAV = 'DAV:'\nexport const NS_PREFIX = 'D'\nexport const LOCK_PREFIX = 'urn:uuid:'\nexport const XML_CONTENT_TYPE = 'application/xml; charset=utf-8'\nexport const HTML_CONTENT_TYPE = 'text/html; charset=utf-8'\nexport const WEBDAV_CONTENT_TYPES = ['application/xml', 'text/xml']\nexport const WEBDAV_APP_LOCK = 'WebDAV' as const\n\nexport const ALLOWED_WEBDAV_METHODS: string = [\n HTTP_STANDARD_METHOD.OPTIONS,\n HTTP_STANDARD_METHOD.HEAD,\n HTTP_STANDARD_METHOD.GET,\n HTTP_STANDARD_METHOD.PUT,\n HTTP_STANDARD_METHOD.DELETE,\n ...Object.values(HTTP_WEBDAV_METHOD)\n].join(', ')\n\nexport const ALLOW_EMPTY_BODY_METHODS: string[] = [HTTP_WEBDAV_METHOD.PROPFIND, HTTP_WEBDAV_METHOD.LOCK]\n\nexport const OPTIONS_HEADERS = {\n Server: SERVER_NAME,\n 'MS-Author-Via': 'DAV',\n DAV: '1,2',\n Allow: ALLOWED_WEBDAV_METHODS,\n 'Content-Type': HTML_CONTENT_TYPE,\n 'Content-Length': '0',\n 'Accept-Ranges': 'bytes'\n} as const\n\nexport const HEADER = {\n DEPTH: 'depth',\n IF: 'if',\n LOCK_TOKEN: 'lock-token',\n DESTINATION: 'destination',\n OVERWRITE: 'overwrite',\n TIMEOUT: 'timeout'\n} as const\n\nexport const LOCK_DISCOVERY_PROP = 'lockdiscovery'\nexport const STANDARD_PROPS = [\n 'creationdate',\n 'getcontenttype',\n 'resourcetype',\n 'getlastmodified',\n 'getcontentlength',\n 'displayname',\n 'getetag',\n 'supportedlock',\n LOCK_DISCOVERY_PROP\n]\n\nexport enum LOCK_SCOPE {\n EXCLUSIVE = 'exclusive',\n SHARED = 'shared'\n}\n\nexport enum DEPTH {\n INFINITY = 'infinity',\n RESOURCE = '0',\n MEMBERS = '1'\n}\n\nexport type LOCK_DEPTH = Omit<DEPTH, DEPTH.MEMBERS>\n\nexport enum PROPSTAT {\n ALLPROP = 'allprop',\n PROP = 'prop',\n PROPNAME = 'propname'\n}\n\nexport const PROPPATCH_PROP_UPDATE = 'propertyupdate'\nexport const PROPPATCH_METHOD = { SET: 'set', REMOVE: 'remove' }\nexport const PROPPATCH_MODIFIED_PROPS = ['getlastmodified', 'lastmodified', 'Win32LastModifiedTime']\nexport const PROPPATCH_SUPPORTED_PROPS = [...PROPPATCH_MODIFIED_PROPS, 'Win32CreationTime', 'Win32LastAccessTime', 'Win32FileAttributes']\n\nexport const PRECONDITION = {\n PROTECTED_PROPERTY: 'cannot-modify-protected-property',\n MISSING_LOCK_TOKEN: 'lock-token-submitted',\n LOCK_TOKEN_MISMATCH: 'lock-token-matches-request-uri',\n LOCK_CONFLICT: 'no-conflicting-lock',\n PROPFIND_FINITE_DEPTH: 'propfind-finite-depth'\n} as const\n"],"names":["ALLOWED_WEBDAV_METHODS","ALLOW_EMPTY_BODY_METHODS","DEPTH","HEADER","HTML_CONTENT_TYPE","LOCK_DISCOVERY_PROP","LOCK_PREFIX","LOCK_SCOPE","NS_DAV","NS_PREFIX","OPTIONS_HEADERS","PRECONDITION","PROPPATCH_METHOD","PROPPATCH_MODIFIED_PROPS","PROPPATCH_PROP_UPDATE","PROPPATCH_SUPPORTED_PROPS","PROPSTAT","REGEX_BASE_PATH","STANDARD_PROPS","WEBDAV_APP_LOCK","WEBDAV_CONTENT_TYPES","XML_CONTENT_TYPE","RegExp","WEBDAV_BASE_PATH","HTTP_STANDARD_METHOD","OPTIONS","HEAD","GET","PUT","DELETE","Object","values","HTTP_WEBDAV_METHOD","join","PROPFIND","LOCK","Server","SERVER_NAME","DAV","Allow","IF","LOCK_TOKEN","DESTINATION","OVERWRITE","TIMEOUT","SET","REMOVE","PROTECTED_PROPERTY","MISSING_LOCK_TOKEN","LOCK_TOKEN_MISMATCH","LOCK_CONFLICT","PROPFIND_FINITE_DEPTH"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAeYA;eAAAA;;QASAC;eAAAA;;QAuCDC;eAAAA;;QA3BCC;eAAAA;;QAzBAC;eAAAA;;QAkCAC;eAAAA;;QApCAC;eAAAA;;QAiDDC;eAAAA;;QAnDCC;eAAAA;;QACAC;eAAAA;;QAkBAC;eAAAA;;QAwDAC;eAAAA;;QAJAC;eAAAA;;QACAC;eAAAA;;QAFAC;eAAAA;;QAGAC;eAAAA;;QATDC;eAAAA;;QAjECC;eAAAA;;QAwCAC;eAAAA;;QAjCAC;eAAAA;;QADAC;eAAAA;;QAFAC;eAAAA;;;wBARe;uCAC6B;wBACxB;AAE1B,MAAMJ,kBAAkB,IAAIK,OAAO,CAAC,GAAG,EAAEC,wBAAgB,CAAC,CAAC,CAAC;AAC5D,MAAMf,SAAS;AACf,MAAMC,YAAY;AAClB,MAAMH,cAAc;AACpB,MAAMe,mBAAmB;AACzB,MAAMjB,oBAAoB;AAC1B,MAAMgB,uBAAuB;IAAC;IAAmB;CAAW;AAC5D,MAAMD,kBAAkB;AAExB,MAAMnB,yBAAiC;IAC5CwB,2CAAoB,CAACC,OAAO;IAC5BD,2CAAoB,CAACE,IAAI;IACzBF,2CAAoB,CAACG,GAAG;IACxBH,2CAAoB,CAACI,GAAG;IACxBJ,2CAAoB,CAACK,MAAM;OACxBC,OAAOC,MAAM,CAACC,yCAAkB;CACpC,CAACC,IAAI,CAAC;AAEA,MAAMhC,2BAAqC;IAAC+B,yCAAkB,CAACE,QAAQ;IAAEF,yCAAkB,CAACG,IAAI;CAAC;AAEjG,MAAMzB,kBAAkB;IAC7B0B,QAAQC,mBAAW;IACnB,iBAAiB;IACjBC,KAAK;IACLC,OAAOvC;IACP,gBAAgBI;IAChB,kBAAkB;IAClB,iBAAiB;AACnB;AAEO,MAAMD,SAAS;IACpBD,OAAO;IACPsC,IAAI;IACJC,YAAY;IACZC,aAAa;IACbC,WAAW;IACXC,SAAS;AACX;AAEO,MAAMvC,sBAAsB;AAC5B,MAAMa,iBAAiB;IAC5B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACAb;CACD;AAEM,IAAA,AAAKE,oCAAAA;;;WAAAA;;AAKL,IAAA,AAAKL,+BAAAA;;;;WAAAA;;AAQL,IAAA,AAAKc,kCAAAA;;;;WAAAA;;AAML,MAAMF,wBAAwB;AAC9B,MAAMF,mBAAmB;IAAEiC,KAAK;IAAOC,QAAQ;AAAS;AACxD,MAAMjC,2BAA2B;IAAC;IAAmB;IAAgB;CAAwB;AAC7F,MAAME,4BAA4B;OAAIF;IAA0B;IAAqB;IAAuB;CAAsB;AAElI,MAAMF,eAAe;IAC1BoC,oBAAoB;IACpBC,oBAAoB;IACpBC,qBAAqB;IACrBC,eAAe;IACfC,uBAAuB;AACzB"}
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Copyright (C) 2012-2026 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "bootstrapWebDAV", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return bootstrapWebDAV;
13
+ }
14
+ });
15
+ const _applicationsconstants = require("../../applications.constants");
16
+ const _routes = require("../constants/routes");
17
+ const _webdav = require("../constants/webdav");
18
+ function bootstrapWebDAV(app, fastifyInstance) {
19
+ // Enable XML body parser for WebDAV XML requests (PROPFIND, PROPPATCH, LOCK, etc.)
20
+ app.useBodyParser(_webdav.WEBDAV_CONTENT_TYPES);
21
+ // Register WebDAV-specific HTTP methods
22
+ for (const method of Object.values(_applicationsconstants.HTTP_WEBDAV_METHOD)){
23
+ fastifyInstance.addHttpMethod(method, {
24
+ hasBody: true
25
+ });
26
+ }
27
+ /**
28
+ * onRequest hook for WebDAV uploads.
29
+ *
30
+ * WebDAV clients may send JSON/XML files with a Content-Type that triggers
31
+ * Fastify's body parsers (application/json, text/plain, application/xml...).
32
+ * For PUT uploads we must always treat the payload as a raw binary stream.
33
+ *
34
+ * This hook forces `application/octet-stream` for WebDAV PUT requests only,
35
+ * leaving XML-based WebDAV methods unaffected.
36
+ */ fastifyInstance.addHook('onRequest', (req, _reply, done)=>{
37
+ // Only handle WebDAV PUT requests under the WebDAV base path
38
+ if (req.method !== _applicationsconstants.HTTP_METHOD.PUT) return done();
39
+ if (!req.originalUrl.startsWith(_routes.WEBDAV_SPACES[_routes.WEBDAV_NS.WEBDAV].route)) return done();
40
+ req.headers['content-type'] = 'application/octet-stream';
41
+ return done();
42
+ });
43
+ }
44
+
45
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/applications/webdav/utils/bootstrap.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2026 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 { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyInstance } from 'fastify'\nimport { HTTP_METHOD, HTTP_WEBDAV_METHOD } from '../../applications.constants'\nimport { WEBDAV_NS, WEBDAV_SPACES } from '../constants/routes'\nimport { WEBDAV_CONTENT_TYPES } from '../constants/webdav'\n\n/**\n * Bootstrap WebDAV-specific Nest/Fastify configuration.\n *\n * - Enables XML body parsing for WebDAV XML-based methods (PROPFIND/PROPPATCH/etc.)\n * - Registers additional WebDAV HTTP methods\n * - Forces binary Content-Type ONLY for WebDAV PUT requests (file uploads)\n *\n * Per RFC 4918, PUT is used to create/replace the content of a resource and the\n * request body must be treated as an opaque stream (even if the file is JSON/XML).\n */\nexport function bootstrapWebDAV(app: NestFastifyApplication, fastifyInstance: FastifyInstance) {\n // Enable XML body parser for WebDAV XML requests (PROPFIND, PROPPATCH, LOCK, etc.)\n app.useBodyParser(WEBDAV_CONTENT_TYPES)\n\n // Register WebDAV-specific HTTP methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n\n /**\n * onRequest hook for WebDAV uploads.\n *\n * WebDAV clients may send JSON/XML files with a Content-Type that triggers\n * Fastify's body parsers (application/json, text/plain, application/xml...).\n * For PUT uploads we must always treat the payload as a raw binary stream.\n *\n * This hook forces `application/octet-stream` for WebDAV PUT requests only,\n * leaving XML-based WebDAV methods unaffected.\n */\n fastifyInstance.addHook('onRequest', (req, _reply, done) => {\n // Only handle WebDAV PUT requests under the WebDAV base path\n if (req.method !== HTTP_METHOD.PUT) return done()\n if (!req.originalUrl.startsWith(WEBDAV_SPACES[WEBDAV_NS.WEBDAV].route)) return done()\n\n req.headers['content-type'] = 'application/octet-stream'\n return done()\n })\n}\n"],"names":["bootstrapWebDAV","app","fastifyInstance","useBodyParser","WEBDAV_CONTENT_TYPES","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addHook","req","_reply","done","HTTP_METHOD","PUT","originalUrl","startsWith","WEBDAV_SPACES","WEBDAV_NS","WEBDAV","route","headers"],"mappings":"AAAA;;;;CAIC;;;;+BAkBeA;;;eAAAA;;;uCAdgC;wBACP;wBACJ;AAY9B,SAASA,gBAAgBC,GAA2B,EAAEC,eAAgC;IAC3F,mFAAmF;IACnFD,IAAIE,aAAa,CAACC,4BAAoB;IAEtC,wCAAwC;IACxC,KAAK,MAAMC,UAAUC,OAAOC,MAAM,CAACC,yCAAkB,EAAG;QACtDN,gBAAgBO,aAAa,CAACJ,QAAQ;YAAEK,SAAS;QAAK;IACxD;IAEA;;;;;;;;;GASC,GACDR,gBAAgBS,OAAO,CAAC,aAAa,CAACC,KAAKC,QAAQC;QACjD,6DAA6D;QAC7D,IAAIF,IAAIP,MAAM,KAAKU,kCAAW,CAACC,GAAG,EAAE,OAAOF;QAC3C,IAAI,CAACF,IAAIK,WAAW,CAACC,UAAU,CAACC,qBAAa,CAACC,iBAAS,CAACC,MAAM,CAAC,CAACC,KAAK,GAAG,OAAOR;QAE/EF,IAAIW,OAAO,CAAC,eAAe,GAAG;QAC9B,OAAOT;IACT;AACF"}
@@ -105,7 +105,7 @@ _ts_decorate([
105
105
  typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest,
106
106
  typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply
107
107
  ]),
108
- _ts_metadata("design:returntype", void 0)
108
+ _ts_metadata("design:returntype", typeof Promise === "undefined" ? Object : Promise)
109
109
  ], WebDAVController.prototype, "serverPropFind", null);
110
110
  _ts_decorate([
111
111
  (0, _common.Options)(_routes.WEBDAV_BASE_PATH),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.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 { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions() {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind()\n serverPropFind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.SERVER)\n }\n\n @Options(WEBDAV_BASE_PATH)\n webdavOptions() {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind(WEBDAV_BASE_PATH)\n async webdavPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.WEBDAV)\n }\n\n @Options(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n repositoriesOptions() {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n return\n }\n\n @Propfind(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n async repositoriesPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply, @Param('repository') repository: string) {\n return this.webdavMethods.propfind(req, res, repository)\n }\n\n @All(`${WEBDAV_BASE_PATH}/*`)\n @UseGuards(SpaceGuard)\n async files(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n switch (req.method) {\n case HTTP_METHOD.PROPFIND:\n return this.webdavMethods.propfind(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.HEAD:\n case HTTP_METHOD.GET:\n return this.webdavMethods.headOrGet(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.PUT:\n return this.webdavMethods.put(req, res)\n case HTTP_METHOD.DELETE:\n return this.webdavMethods.delete(req, res)\n case HTTP_METHOD.LOCK:\n return this.webdavMethods.lock(req, res)\n case HTTP_METHOD.UNLOCK:\n return this.webdavMethods.unlock(req, res)\n case HTTP_METHOD.PROPPATCH:\n return this.webdavMethods.proppatch(req, res)\n case HTTP_METHOD.MKCOL:\n return this.webdavMethods.mkcol(req, res)\n case HTTP_METHOD.COPY:\n case HTTP_METHOD.MOVE:\n return this.webdavMethods.copyMove(req, res)\n default:\n return res.status(HttpStatus.METHOD_NOT_ALLOWED).send()\n }\n }\n}\n"],"names":["WebDAVController","serverOptions","serverPropFind","req","res","webdavMethods","propfind","WEBDAV_NS","SERVER","webdavOptions","webdavPropfind","WEBDAV","repositoriesOptions","repositoriesPropfind","repository","files","method","HTTP_METHOD","PROPFIND","SPACE_REPOSITORY","FILES","HEAD","GET","headOrGet","PUT","put","DELETE","delete","LOCK","lock","UNLOCK","unlock","PROPPATCH","proppatch","MKCOL","mkcol","COPY","MOVE","copyMove","status","HttpStatus","METHOD_NOT_ALLOWED","send","passthrough","WEBDAV_BASE_PATH","SPACES","TRASH"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.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 { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, StreamableFile, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind()\n serverPropFind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string> {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.SERVER)\n }\n\n @Options(WEBDAV_BASE_PATH)\n webdavOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind(WEBDAV_BASE_PATH)\n async webdavPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string> {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.WEBDAV)\n }\n\n @Options(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n repositoriesOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n return\n }\n\n @Propfind(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n async repositoriesPropfind(\n @Req() req: FastifyDAVRequest,\n @Res({ passthrough: true }) res: FastifyReply,\n @Param('repository') repository: string\n ): Promise<string> {\n return this.webdavMethods.propfind(req, res, repository)\n }\n\n @All(`${WEBDAV_BASE_PATH}/*`)\n @UseGuards(SpaceGuard)\n async files(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string | StreamableFile> {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n switch (req.method) {\n case HTTP_METHOD.PROPFIND:\n return this.webdavMethods.propfind(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.HEAD:\n case HTTP_METHOD.GET:\n return this.webdavMethods.headOrGet(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.PUT:\n return this.webdavMethods.put(req, res)\n case HTTP_METHOD.DELETE:\n return this.webdavMethods.delete(req, res)\n case HTTP_METHOD.LOCK:\n return this.webdavMethods.lock(req, res)\n case HTTP_METHOD.UNLOCK:\n return this.webdavMethods.unlock(req, res)\n case HTTP_METHOD.PROPPATCH:\n return this.webdavMethods.proppatch(req, res)\n case HTTP_METHOD.MKCOL:\n return this.webdavMethods.mkcol(req, res)\n case HTTP_METHOD.COPY:\n case HTTP_METHOD.MOVE:\n return this.webdavMethods.copyMove(req, res)\n default:\n return res.status(HttpStatus.METHOD_NOT_ALLOWED).send()\n }\n }\n}\n"],"names":["WebDAVController","serverOptions","serverPropFind","req","res","webdavMethods","propfind","WEBDAV_NS","SERVER","webdavOptions","webdavPropfind","WEBDAV","repositoriesOptions","repositoriesPropfind","repository","files","method","HTTP_METHOD","PROPFIND","SPACE_REPOSITORY","FILES","HEAD","GET","headOrGet","PUT","put","DELETE","delete","LOCK","lock","UNLOCK","unlock","PROPPATCH","proppatch","MKCOL","mkcol","COPY","MOVE","copyMove","status","HttpStatus","METHOD_NOT_ALLOWED","send","passthrough","WEBDAV_BASE_PATH","SPACES","TRASH"],"mappings":"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"}