From aa5552c5793c3342fe2b2ac3c0b321c255867e1a Mon Sep 17 00:00:00 2001 From: AlexisMora Date: Tue, 11 Nov 2025 11:13:31 +0100 Subject: [PATCH 1/5] Fix tests in propfind handler --- test/webdav/handlers/PROPFIND.handler.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/webdav/handlers/PROPFIND.handler.test.ts b/test/webdav/handlers/PROPFIND.handler.test.ts index bd607c26..8d17e881 100644 --- a/test/webdav/handlers/PROPFIND.handler.test.ts +++ b/test/webdav/handlers/PROPFIND.handler.test.ts @@ -56,7 +56,7 @@ describe('PROPFIND request handler', () => { }); const folderFixture = newFolderItem({ - id: UserSettingsFixture.root_folder_id, + id: parseInt(UserSettingsFixture.rootFolderId), }); const drive = crypto.randomInt(2000000000); const backups = crypto.randomInt(2000000000); @@ -111,11 +111,11 @@ describe('PROPFIND request handler', () => { }); const folderFixture = newFolderItem({ - id: UserSettingsFixture.root_folder_id, + id: parseInt(UserSettingsFixture.rootFolderId), }); const paginatedFolder1 = newPaginatedFolder({ plainName: 'folder_1', - updatedAt: new Date('2024-03-04T15:11:01.000Z'), + updatedAt: new Date('2024-03-04T15:11:01.000Z').toString(), uuid: 'FOLDER_UUID_1', }); const drive = crypto.randomInt(2000000000); From c3f6146cb2de116939210387732eb093b1403b8f Mon Sep 17 00:00:00 2001 From: AlexisMora Date: Tue, 11 Nov 2025 11:29:43 +0100 Subject: [PATCH 2/5] fix: now we dont need to pass down the whole urlObject since we only need the url from getrequestedResource --- src/utils/webdav.utils.ts | 10 +----- src/webdav/handlers/HEAD.handler.ts | 2 +- src/webdav/handlers/MKCOL.handler.ts | 2 +- src/webdav/handlers/MOVE.handler.ts | 2 +- src/webdav/handlers/OPTIONS.handler.ts | 2 +- src/webdav/handlers/PROPFIND.handler.ts | 2 +- src/webdav/handlers/PUT.handler.ts | 2 +- test/utils/webdav.utils.test.ts | 41 ---------------------- test/webdav/handlers/MKCOL.handler.test.ts | 2 +- 9 files changed, 8 insertions(+), 57 deletions(-) diff --git a/src/utils/webdav.utils.ts b/src/utils/webdav.utils.ts index e69f4e4e..7bd9195d 100644 --- a/src/utils/webdav.utils.ts +++ b/src/utils/webdav.utils.ts @@ -1,4 +1,3 @@ -import { Request } from 'express'; import path from 'node:path'; import { WebDavRequestedResource } from '../types/webdav.types'; import { DriveFolderService } from '../services/drive/drive-folder.service'; @@ -39,14 +38,7 @@ export class WebDavUtils { return normalizedPath; } - static async getRequestedResource(urlObject: string | Request, decodeUri = true): Promise { - let requestUrl: string; - if (typeof urlObject === 'string') { - requestUrl = urlObject; - } else { - requestUrl = urlObject.url; - } - + static async getRequestedResource(requestUrl: string, decodeUri = true): Promise { const decodedUrl = this.decodeUrl(requestUrl, decodeUri); const parsedPath = path.parse(decodedUrl); const parentPath = this.normalizeFolderPath(path.dirname(decodedUrl)); diff --git a/src/webdav/handlers/HEAD.handler.ts b/src/webdav/handlers/HEAD.handler.ts index 4eae7b37..10890316 100644 --- a/src/webdav/handlers/HEAD.handler.ts +++ b/src/webdav/handlers/HEAD.handler.ts @@ -16,7 +16,7 @@ export class HEADRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFileService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); if (resource.type === 'folder') { res.status(200).send(); diff --git a/src/webdav/handlers/MKCOL.handler.ts b/src/webdav/handlers/MKCOL.handler.ts index 4f29d981..305e7085 100644 --- a/src/webdav/handlers/MKCOL.handler.ts +++ b/src/webdav/handlers/MKCOL.handler.ts @@ -17,7 +17,7 @@ export class MKCOLRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFolderService, webDavFolderService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); webdavLogger.info(`[MKCOL] Request received for ${resource.type} at ${resource.url}`); diff --git a/src/webdav/handlers/MOVE.handler.ts b/src/webdav/handlers/MOVE.handler.ts index d7b3e568..b5dc71a4 100644 --- a/src/webdav/handlers/MOVE.handler.ts +++ b/src/webdav/handlers/MOVE.handler.ts @@ -19,7 +19,7 @@ export class MOVERequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); webdavLogger.info(`[MOVE] Request received for ${resource.type} at ${resource.url}`); diff --git a/src/webdav/handlers/OPTIONS.handler.ts b/src/webdav/handlers/OPTIONS.handler.ts index 0ab9ffa8..7b98c06c 100644 --- a/src/webdav/handlers/OPTIONS.handler.ts +++ b/src/webdav/handlers/OPTIONS.handler.ts @@ -5,7 +5,7 @@ import { webdavLogger } from '../../utils/logger.utils'; export class OPTIONSRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); webdavLogger.info(`[OPTIONS] Request received for ${resource.type} at ${resource.url}`); diff --git a/src/webdav/handlers/PROPFIND.handler.ts b/src/webdav/handlers/PROPFIND.handler.ts index a52b431a..548c458b 100644 --- a/src/webdav/handlers/PROPFIND.handler.ts +++ b/src/webdav/handlers/PROPFIND.handler.ts @@ -22,7 +22,7 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFolderService, driveFileService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); webdavLogger.info(`[PROPFIND] Request received for ${resource.type} at ${resource.url}`); const driveItem = await WebDavUtils.getDriveItemFromResource({ diff --git a/src/webdav/handlers/PUT.handler.ts b/src/webdav/handlers/PUT.handler.ts index 9af7a85b..ee4c6028 100644 --- a/src/webdav/handlers/PUT.handler.ts +++ b/src/webdav/handlers/PUT.handler.ts @@ -33,7 +33,7 @@ export class PUTRequestHandler implements WebDavMethodHandler { throw new UnsupportedMediaTypeError('Empty files are not supported'); } - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); if (resource.type === 'folder') throw new NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.'); diff --git a/test/utils/webdav.utils.test.ts b/test/utils/webdav.utils.test.ts index 040f2377..8d91da16 100644 --- a/test/utils/webdav.utils.test.ts +++ b/test/utils/webdav.utils.test.ts @@ -1,6 +1,5 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { WebDavUtils } from '../../src/utils/webdav.utils'; -import { createWebDavRequestFixture } from '../fixtures/webdav.fixture'; import { WebDavRequestedResource } from '../../src/types/webdav.types'; import { newFileItem, newFolderItem } from '../fixtures/drive.fixture'; import { DriveFolderService } from '../../src/services/drive/drive-folder.service'; @@ -37,26 +36,6 @@ describe('Webdav utils', () => { }); describe('getRequestedResource', () => { - it('When folder request is given, then it should return the requested resource', async () => { - const request = createWebDavRequestFixture({ - url: '/url/to/folder/', - }); - const resource = await WebDavUtils.getRequestedResource(request); - expect(resource).to.deep.equal({ - url: '/url/to/folder/', - type: 'folder', - name: 'folder', - parentPath: '/url/to/', - path: { - base: 'folder', - dir: '/url/to', - ext: '', - name: 'folder', - root: '/', - }, - }); - }); - it('When folder url is given, then it should generate the requested resource', async () => { const requestURL = '/url/to/folder/'; const resource = await WebDavUtils.getRequestedResource(requestURL); @@ -75,26 +54,6 @@ describe('Webdav utils', () => { }); }); - it('When file request is given, then it should generate the requested resource', async () => { - const request = createWebDavRequestFixture({ - url: '/url/to/test.png', - }); - const resource = await WebDavUtils.getRequestedResource(request); - expect(resource).to.deep.equal({ - url: '/url/to/test.png', - type: 'file', - name: 'test', - parentPath: '/url/to/', - path: { - base: 'test.png', - dir: '/url/to', - ext: '.png', - name: 'test', - root: '/', - }, - }); - }); - it('When file url is given, then it should generate the requested resource', async () => { const requestURL = '/url/to/test.png'; const resource = await WebDavUtils.getRequestedResource(requestURL); diff --git a/test/webdav/handlers/MKCOL.handler.test.ts b/test/webdav/handlers/MKCOL.handler.test.ts index f2b3f920..11f4c369 100644 --- a/test/webdav/handlers/MKCOL.handler.test.ts +++ b/test/webdav/handlers/MKCOL.handler.test.ts @@ -58,7 +58,7 @@ describe('MKCOL request handler', () => { await requestHandler.handle(request, response); expect(response.status).toHaveBeenCalledWith(201); - expect(getRequestedResourceStub).toHaveBeenCalledWith(request); + expect(getRequestedResourceStub).toHaveBeenCalledWith(request.url); expect(getDriveFolderItemFromPathStub).toHaveBeenCalledWith(requestedFolderResource.parentPath); expect(getAndSearchItemFromResourceStub).toHaveBeenCalledWith({ resource: requestedFolderResource, From 69b1737a97a077c4975dec7ee34345beb1e12c53 Mon Sep 17 00:00:00 2001 From: AlexisMora Date: Fri, 14 Nov 2025 13:16:32 +0100 Subject: [PATCH 3/5] Fix: nautilus integration --- WEBDAV.md | 1 + src/services/drive/drive-file.service.ts | 1 + src/types/drive.types.ts | 2 + src/types/webdav.types.ts | 1 - src/utils/drive.utils.ts | 3 + src/utils/webdav.utils.ts | 99 ++++++++++++------- src/webdav/handlers/DELETE.handler.ts | 10 +- src/webdav/handlers/GET.handler.ts | 17 ++-- src/webdav/handlers/HEAD.handler.ts | 15 +-- src/webdav/handlers/MKCOL.handler.ts | 6 +- src/webdav/handlers/MOVE.handler.ts | 46 ++++----- src/webdav/handlers/OPTIONS.handler.ts | 4 +- src/webdav/handlers/PROPFIND.handler.ts | 51 ++-------- src/webdav/handlers/PUT.handler.ts | 25 +++-- src/webdav/services/webdav-folder.service.ts | 6 +- src/webdav/webdav-server.ts | 1 + test/fixtures/drive.fixture.ts | 2 + test/fixtures/webdav.fixture.ts | 2 - test/utils/webdav.utils.test.ts | 14 +-- test/webdav/handlers/GET.handler.test.ts | 79 ++++++--------- test/webdav/handlers/HEAD.handler.test.ts | 35 +++---- test/webdav/handlers/MKCOL.handler.test.ts | 30 +++--- test/webdav/handlers/PROPFIND.handler.test.ts | 68 ++++--------- test/webdav/handlers/PUT.handler.test.ts | 90 +++++------------ 24 files changed, 256 insertions(+), 352 deletions(-) diff --git a/WEBDAV.md b/WEBDAV.md index 5282a2c2..e528c5b2 100644 --- a/WEBDAV.md +++ b/WEBDAV.md @@ -28,6 +28,7 @@ Below you can find a list of WebDav clients that we officially support in the In | CyberDuck for MacOS | ✅ | | Transmit | ✅ | | Cadaver | ✅ | +| Nautilus (GNOME Files)| ✅ | ## Supported WebDav methods diff --git a/src/services/drive/drive-file.service.ts b/src/services/drive/drive-file.service.ts index 40af7742..3c64d948 100644 --- a/src/services/drive/drive-file.service.ts +++ b/src/services/drive/drive-file.service.ts @@ -11,6 +11,7 @@ export class DriveFileService { const driveFile = await storageClient.createFileEntryByUuid(payload); return { + itemType: 'file', name: payload.plainName, id: driveFile.id, uuid: driveFile.uuid, diff --git a/src/types/drive.types.ts b/src/types/drive.types.ts index 7d5f241e..aafca712 100644 --- a/src/types/drive.types.ts +++ b/src/types/drive.types.ts @@ -12,6 +12,7 @@ export type DriveFileItem = Omit< | 'modificationTime' | 'type' > & { + itemType: 'file'; size: number; createdAt: Date; updatedAt: Date; @@ -21,6 +22,7 @@ export type DriveFileItem = Omit< }; export type DriveFolderItem = Pick & { + itemType: 'folder'; encryptedName: string; uuid: string; createdAt: Date; diff --git a/src/types/webdav.types.ts b/src/types/webdav.types.ts index 93c334b7..8bddce48 100644 --- a/src/types/webdav.types.ts +++ b/src/types/webdav.types.ts @@ -10,7 +10,6 @@ export type WebDavMethodHandlerOptions = { }; export type WebDavRequestedResource = { - type: 'file' | 'folder'; url: string; name: string; path: ParsedPath; diff --git a/src/utils/drive.utils.ts b/src/utils/drive.utils.ts index 666b0061..76e19f68 100644 --- a/src/utils/drive.utils.ts +++ b/src/utils/drive.utils.ts @@ -4,6 +4,7 @@ import { DriveFileItem, DriveFolderItem } from '../types/drive.types'; export class DriveUtils { static driveFileMetaToItem(fileMeta: FileMeta): DriveFileItem { return { + itemType: 'file', uuid: fileMeta.uuid ?? '', status: fileMeta.status, folderId: fileMeta.folderId, @@ -23,6 +24,7 @@ export class DriveUtils { static driveFolderMetaToItem(folderMeta: FolderMeta): DriveFolderItem { return { + itemType: 'folder', uuid: folderMeta.uuid, id: folderMeta.id, bucket: folderMeta.bucket, @@ -38,6 +40,7 @@ export class DriveUtils { static createFolderResponseToItem(folderResponse: CreateFolderResponse): DriveFolderItem { return { + itemType: 'folder', uuid: folderResponse.uuid, id: folderResponse.id, bucket: folderResponse.bucket, diff --git a/src/utils/webdav.utils.ts b/src/utils/webdav.utils.ts index 7bd9195d..c850ce0e 100644 --- a/src/utils/webdav.utils.ts +++ b/src/utils/webdav.utils.ts @@ -3,6 +3,7 @@ import { WebDavRequestedResource } from '../types/webdav.types'; import { DriveFolderService } from '../services/drive/drive-folder.service'; import { DriveFileService } from '../services/drive/drive-file.service'; import { DriveFileItem, DriveFolderItem, DriveItem } from '../types/drive.types'; +import { webdavLogger } from './logger.utils'; export class WebDavUtils { static joinURL(...pathComponents: string[]): string { @@ -38,67 +39,89 @@ export class WebDavUtils { return normalizedPath; } + // TODO: We can rename this method to parseUrlToPathMetadata so its more descriptive static async getRequestedResource(requestUrl: string, decodeUri = true): Promise { const decodedUrl = this.decodeUrl(requestUrl, decodeUri); const parsedPath = path.parse(decodedUrl); const parentPath = this.normalizeFolderPath(path.dirname(decodedUrl)); - const isFolder = requestUrl.endsWith('/'); - - if (isFolder) { - return { - type: 'folder', - url: decodedUrl, - name: parsedPath.base, - path: parsedPath, - parentPath, - }; - } else { - return { - type: 'file', - url: decodedUrl, - name: parsedPath.name, - path: parsedPath, - parentPath, - }; - } + return { + url: decodedUrl, + name: parsedPath.base, + path: parsedPath, + parentPath, + }; } - static async getDriveItemFromResource(params: { - resource: WebDavRequestedResource; + static async tryGetFileOrFolderMetadata({ + url, + driveFileService, + driveFolderService, + }: { + url: string; driveFolderService: DriveFolderService; - driveFileService?: never; - }): Promise; + driveFileService: DriveFileService; + }): Promise { + try { + return await driveFileService.getFileMetadataByPath(url); + } catch { + return await driveFolderService.getFolderMetadataByPath(url); + } + } - static async getDriveItemFromResource(params: { - resource: WebDavRequestedResource; - driveFolderService?: never; + static async getDriveFileFromResource({ + url, + driveFileService, + }: { + url: string; driveFileService: DriveFileService; - }): Promise; + }): Promise { + try { + return await driveFileService.getFileMetadataByPath(url); + } catch (err) { + webdavLogger.error('Exception while getting the file metadata by path', err); + } + } - static async getDriveItemFromResource(params: { - resource: WebDavRequestedResource; + static async getDriveFolderFromResource({ + url, + driveFolderService, + }: { + url: string; driveFolderService: DriveFolderService; - driveFileService: DriveFileService; - }): Promise; + }): Promise { + try { + return await driveFolderService.getFolderMetadataByPath(url); + } catch (err) { + webdavLogger.error('Exception while getting the folder metadata by path', err); + } + } + // This method will be used mainly for propfind, since we dont know what the user is requesting for static async getDriveItemFromResource({ resource, driveFolderService, driveFileService, }: { resource: WebDavRequestedResource; - driveFolderService?: DriveFolderService; - driveFileService?: DriveFileService; + driveFolderService: DriveFolderService; + driveFileService: DriveFileService; }): Promise { let item: DriveItem | undefined = undefined; + // This is exactly the problem, nautilus sends folder urls without trailing slash + // There is just no other way to check wether its a folder or file at this point other than checking ourselves + const isFolder = resource.url.endsWith('/'); + try { - if (resource.type === 'folder') { - item = await driveFolderService?.getFolderMetadataByPath(resource.url); - } - if (resource.type === 'file') { - item = await driveFileService?.getFileMetadataByPath(resource.url); + if (isFolder) { + item = await driveFolderService.getFolderMetadataByPath(resource.url); + } else { + item = await this.tryGetFileOrFolderMetadata({ + url: resource.url, + driveFileService, + driveFolderService, + }); } } catch { //no op diff --git a/src/webdav/handlers/DELETE.handler.ts b/src/webdav/handlers/DELETE.handler.ts index 791b57e0..fab8e211 100644 --- a/src/webdav/handlers/DELETE.handler.ts +++ b/src/webdav/handlers/DELETE.handler.ts @@ -18,8 +18,8 @@ export class DELETERequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFileService, driveFolderService, trashService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); - webdavLogger.info(`[DELETE] Request received for ${resource.type} at ${resource.url}`); + const resource = await WebDavUtils.getRequestedResource(req.url); + webdavLogger.info(`[DELETE] Request received for item at ${resource.url}`); const driveItem = await WebDavUtils.getDriveItemFromResource({ resource, @@ -31,13 +31,13 @@ export class DELETERequestHandler implements WebDavMethodHandler { throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`); } - webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${resource.type}`); + webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${driveItem.itemType}`); await trashService.trashItems({ - items: [{ type: resource.type, uuid: driveItem.uuid, id: null }], + items: [{ type: driveItem.itemType, uuid: driveItem.uuid, id: null }], }); res.status(204).send(); - const type = resource.type.charAt(0).toUpperCase() + resource.type.substring(1); + const type = driveItem.itemType.charAt(0).toUpperCase() + driveItem.itemType.substring(1); webdavLogger.info(`[DELETE] [${driveItem.uuid}] ${type} trashed successfully`); }; } diff --git a/src/webdav/handlers/GET.handler.ts b/src/webdav/handlers/GET.handler.ts index 752becfc..956af97d 100644 --- a/src/webdav/handlers/GET.handler.ts +++ b/src/webdav/handlers/GET.handler.ts @@ -8,7 +8,6 @@ import { CryptoService } from '../../services/crypto.service'; import { AuthService } from '../../services/auth.service'; import { NotFoundError } from '../../utils/errors.utils'; import { webdavLogger } from '../../utils/logger.utils'; -import { DriveFileItem } from '../../types/drive.types'; import { NetworkUtils } from '../../utils/network.utils'; export class GETRequestHandler implements WebDavMethodHandler { @@ -24,21 +23,21 @@ export class GETRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFileService, authService, networkFacade } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req); + const resource = await WebDavUtils.getRequestedResource(req.url); if (resource.name.startsWith('._')) throw new NotFoundError('File not found'); - if (resource.type === 'folder') throw new NotFoundError('Folders cannot be listed with GET. Use PROPFIND instead.'); - webdavLogger.info(`[GET] Request received for ${resource.type} at ${resource.url}`); - const driveItem = await WebDavUtils.getDriveItemFromResource({ - resource, + webdavLogger.info(`[GET] Request received item at ${resource.url}`); + const driveFile = await WebDavUtils.getDriveFileFromResource({ + url: resource.url, driveFileService, }); - if (!driveItem) { - throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`); + if (!driveFile) { + throw new NotFoundError( + `Resource not found on Internxt Drive at ${resource.url}, if trying to access a folder use PROPFIND instead.`, + ); } - const driveFile = driveItem as DriveFileItem; webdavLogger.info(`[GET] [${driveFile.uuid}] Found Drive File`); diff --git a/src/webdav/handlers/HEAD.handler.ts b/src/webdav/handlers/HEAD.handler.ts index 10890316..c7a99214 100644 --- a/src/webdav/handlers/HEAD.handler.ts +++ b/src/webdav/handlers/HEAD.handler.ts @@ -3,7 +3,6 @@ import { WebDavMethodHandler } from '../../types/webdav.types'; import { WebDavUtils } from '../../utils/webdav.utils'; import { webdavLogger } from '../../utils/logger.utils'; import { DriveFileService } from '../../services/drive/drive-file.service'; -import { DriveFileItem } from '../../types/drive.types'; import { NetworkUtils } from '../../utils/network.utils'; import { NotFoundError } from '../../utils/errors.utils'; @@ -18,23 +17,17 @@ export class HEADRequestHandler implements WebDavMethodHandler { const { driveFileService } = this.dependencies; const resource = await WebDavUtils.getRequestedResource(req.url); - if (resource.type === 'folder') { - res.status(200).send(); - return; - } - - webdavLogger.info(`[HEAD] Request received for ${resource.type} at ${resource.url}`); + webdavLogger.info(`[HEAD] Request received for file at ${resource.url}`); try { - const driveItem = await WebDavUtils.getDriveItemFromResource({ - resource, + const driveFile = await WebDavUtils.getDriveFileFromResource({ + url: resource.url, driveFileService, }); - if (!driveItem) { + if (!driveFile) { throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`); } - const driveFile = driveItem as DriveFileItem; webdavLogger.info(`[HEAD] [${driveFile.uuid}] Found Drive File`); diff --git a/src/webdav/handlers/MKCOL.handler.ts b/src/webdav/handlers/MKCOL.handler.ts index 305e7085..23264c9e 100644 --- a/src/webdav/handlers/MKCOL.handler.ts +++ b/src/webdav/handlers/MKCOL.handler.ts @@ -19,14 +19,14 @@ export class MKCOLRequestHandler implements WebDavMethodHandler { const { driveFolderService, webDavFolderService } = this.dependencies; const resource = await WebDavUtils.getRequestedResource(req.url); - webdavLogger.info(`[MKCOL] Request received for ${resource.type} at ${resource.url}`); + webdavLogger.info(`[MKCOL] Request received for folder at ${resource.url}`); const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ?? (await webDavFolderService.createParentPathOrThrow(resource.parentPath)); - const driveFolderItem = await WebDavUtils.getDriveItemFromResource({ - resource, + const driveFolderItem = await WebDavUtils.getDriveFolderFromResource({ + url: resource.url, driveFolderService, }); diff --git a/src/webdav/handlers/MOVE.handler.ts b/src/webdav/handlers/MOVE.handler.ts index b5dc71a4..0d68fc12 100644 --- a/src/webdav/handlers/MOVE.handler.ts +++ b/src/webdav/handlers/MOVE.handler.ts @@ -5,7 +5,6 @@ import { WebDavMethodHandler } from '../../types/webdav.types'; import { NotFoundError } from '../../utils/errors.utils'; import { webdavLogger } from '../../utils/logger.utils'; import { WebDavUtils } from '../../utils/webdav.utils'; -import { DriveFileItem, DriveFolderItem } from '../../types/drive.types'; import { WebDavFolderService } from '../services/webdav-folder.service'; export class MOVERequestHandler implements WebDavMethodHandler { @@ -21,7 +20,7 @@ export class MOVERequestHandler implements WebDavMethodHandler { const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies; const resource = await WebDavUtils.getRequestedResource(req.url); - webdavLogger.info(`[MOVE] Request received for ${resource.type} at ${resource.url}`); + webdavLogger.info(`[MOVE] Request received for item at ${resource.url}`); const destinationUrl = req.header('destination'); if (!destinationUrl) { @@ -42,49 +41,52 @@ export class MOVERequestHandler implements WebDavMethodHandler { throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`); } - const newName = destinationResource.name; - if (destinationResource.path.dir === resource.path.dir) { // RENAME (the operation is from the same dir) webdavLogger.info( - `[MOVE] Renaming ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationResource.name}`, + `[MOVE] Renaming ${originalDriveItem.itemType} + with UUID ${originalDriveItem.uuid} to ${destinationResource.name}`, ); - if (resource.type === 'folder') { - const folder = originalDriveItem as DriveFolderItem; + if (originalDriveItem.itemType === 'folder') { + const folder = originalDriveItem; await driveFolderService.renameFolder({ folderUuid: folder.uuid, - name: newName, + name: destinationResource.name, }); - } else if (resource.type === 'file') { - const newType = destinationResource.path.ext.replace('.', ''); - const file = originalDriveItem as DriveFileItem; + } else if (originalDriveItem.itemType === 'file') { + const file = originalDriveItem; + const plainName = destinationResource.path.name; + const fileType = destinationResource.path.ext.replace('.', ''); await driveFileService.renameFile(file.uuid, { - plainName: newName, - type: newType, + plainName: plainName, + type: fileType, }); } } else { // MOVE (the operation is from different dirs) - webdavLogger.info(`[MOVE] Moving ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationPath}`); + webdavLogger.info( + `[MOVE] Moving ${originalDriveItem.itemType} with UUID ${originalDriveItem.uuid} to ${destinationPath}`, + ); const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ?? (await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath)); - if (resource.type === 'folder') { - const folder = originalDriveItem as DriveFolderItem; + if (originalDriveItem.itemType === 'folder') { + const folder = originalDriveItem; await driveFolderService.moveFolder(folder.uuid, { destinationFolder: destinationFolderItem.uuid, - name: newName, + name: destinationResource.name, }); - } else if (resource.type === 'file') { - const file = originalDriveItem as DriveFileItem; - const newType = destinationResource.path.ext.replace('.', ''); + } else if (originalDriveItem.itemType === 'file') { + const file = originalDriveItem; + const plainName = destinationResource.path.name; + const fileType = destinationResource.path.ext.replace('.', ''); await driveFileService.moveFile(file.uuid, { destinationFolder: destinationFolderItem.uuid, - name: newName, - type: newType, + name: plainName, + type: fileType, }); } } diff --git a/src/webdav/handlers/OPTIONS.handler.ts b/src/webdav/handlers/OPTIONS.handler.ts index 7b98c06c..d9943398 100644 --- a/src/webdav/handlers/OPTIONS.handler.ts +++ b/src/webdav/handlers/OPTIONS.handler.ts @@ -7,7 +7,7 @@ export class OPTIONSRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const resource = await WebDavUtils.getRequestedResource(req.url); - webdavLogger.info(`[OPTIONS] Request received for ${resource.type} at ${resource.url}`); + webdavLogger.info(`[OPTIONS] Request received for item at ${resource.url}`); if (resource.url === '/' || resource.url === '') { // Root Folder @@ -16,7 +16,7 @@ export class OPTIONSRequestHandler implements WebDavMethodHandler { res.header('Allow', 'DELETE, GET, HEAD, MKCOL, MOVE, OPTIONS, PROPFIND, PUT'); res.header('DAV', '1, 2, ordered-collections'); res.status(200).send(); - } else if (resource.type === 'folder') { + } else if (resource.url.endsWith('/')) { // Children Folder const allowedMethods = 'DELETE, HEAD, MKCOL, MOVE, OPTIONS, PROPFIND'; webdavLogger.info(`[OPTIONS] Returning Allowed Options: ${allowedMethods}`); diff --git a/src/webdav/handlers/PROPFIND.handler.ts b/src/webdav/handlers/PROPFIND.handler.ts index 548c458b..9dfef410 100644 --- a/src/webdav/handlers/PROPFIND.handler.ts +++ b/src/webdav/handlers/PROPFIND.handler.ts @@ -21,9 +21,8 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { handle = async (req: Request, res: Response) => { const { driveFolderService, driveFileService } = this.dependencies; - const resource = await WebDavUtils.getRequestedResource(req.url); - webdavLogger.info(`[PROPFIND] Request received for ${resource.type} at ${resource.url}`); + webdavLogger.info(`[PROPFIND] Request received for item at ${resource.url}`); const driveItem = await WebDavUtils.getDriveItemFromResource({ resource, @@ -32,36 +31,22 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { }); if (!driveItem) { - res.status(207).send( - XMLUtils.toWebDavXML( - { - [XMLUtils.addDefaultNamespace('response')]: { - [XMLUtils.addDefaultNamespace('href')]: XMLUtils.encodeWebDavUri(resource.url), - [XMLUtils.addDefaultNamespace('propstat')]: { - [XMLUtils.addDefaultNamespace('status')]: 'HTTP/1.1 404 Not Found', - [XMLUtils.addDefaultNamespace('prop')]: {}, - }, - }, - }, - { - ignoreAttributes: false, - suppressEmptyNode: true, - }, - ), - ); + res.status(404).send(); return; } - switch (resource.type) { + switch (driveItem.itemType) { case 'file': { - const fileMetaXML = await this.getFileMetaXML(resource, driveItem as DriveFileItem); + // Here its only used the url + const fileMetaXML = await this.getFileMetaXML(resource, driveItem); res.status(207).send(fileMetaXML); break; } case 'folder': { const depth = req.header('depth') ?? '1'; - const folderMetaXML = await this.getFolderContentXML(resource, driveItem as DriveFolderItem, depth); + // Here its only used the url + const folderMetaXML = await this.getFolderContentXML(resource, driveItem, depth); res.status(207).send(folderMetaXML); break; } @@ -72,25 +57,7 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { resource: WebDavRequestedResource, driveFileItem: DriveFileItem, ): Promise => { - const driveFile = this.driveFileItemToXMLNode( - { - name: driveFileItem.name, - type: driveFileItem.type, - bucket: driveFileItem.bucket, - id: driveFileItem.id, - uuid: driveFileItem.uuid, - fileId: driveFileItem.fileId, - size: driveFileItem.size, - createdAt: driveFileItem.createdAt, - updatedAt: driveFileItem.updatedAt, - status: driveFileItem.status, - folderId: driveFileItem.folderId, - folderUuid: driveFileItem.folderUuid, - creationTime: driveFileItem.creationTime, - modificationTime: driveFileItem.modificationTime, - }, - resource.url, - ); + const driveFile = this.driveFileItemToXMLNode(driveFileItem, resource.url); const xml = XMLUtils.toWebDavXML([driveFile], { arrayNodeName: XMLUtils.addDefaultNamespace('response'), }); @@ -145,6 +112,7 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { return this.driveFolderItemToXMLNode( { + itemType: 'folder', name: folder.plainName, bucket: folder.bucket, status: folder.deleted || folder.removed ? 'TRASHED' : 'EXISTS', @@ -167,6 +135,7 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { ); return this.driveFileItemToXMLNode( { + itemType: 'file', name: file.plainName, bucket: file.bucket, id: file.id, diff --git a/src/webdav/handlers/PUT.handler.ts b/src/webdav/handlers/PUT.handler.ts index ee4c6028..aa78631a 100644 --- a/src/webdav/handlers/PUT.handler.ts +++ b/src/webdav/handlers/PUT.handler.ts @@ -15,11 +15,13 @@ import { isFileThumbnailable } from '../../utils/thumbnail.utils'; import { ThumbnailService } from '../../services/thumbnail.service'; import { WebDavFolderService } from '../services/webdav-folder.service'; import { AsyncUtils } from '../../utils/async.utils'; +import { DriveFolderService } from '../../services/drive/drive-folder.service'; export class PUTRequestHandler implements WebDavMethodHandler { constructor( private readonly dependencies: { driveFileService: DriveFileService; + driveFolderService: DriveFolderService; webDavFolderService: WebDavFolderService; trashService: TrashService; authService: AuthService; @@ -35,25 +37,28 @@ export class PUTRequestHandler implements WebDavMethodHandler { const resource = await WebDavUtils.getRequestedResource(req.url); - if (resource.type === 'folder') throw new NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.'); - - webdavLogger.info(`[PUT] Request received for ${resource.type} at ${resource.url}`); + // If the file already exists, the WebDAV specification states that 'PUT /…/file' should replace it. + // http://www.webdav.org/specs/rfc4918.html#put-resources + const driveFileItem = await WebDavUtils.getDriveItemFromResource({ + resource: resource, + driveFileService: this.dependencies.driveFileService, + driveFolderService: this.dependencies.driveFolderService, + }); + if (driveFileItem?.itemType === 'folder') { + throw new NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.'); + } + webdavLogger.info(`[PUT] Request received for file at ${resource.url}`); webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`); const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ?? (await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath)); + try { - // If the file already exists, the WebDAV specification states that 'PUT /…/file' should replace it. - // http://www.webdav.org/specs/rfc4918.html#put-resources - const driveFileItem = await WebDavUtils.getDriveItemFromResource({ - resource: resource, - driveFileService: this.dependencies.driveFileService, - }); if (driveFileItem && driveFileItem.status === 'EXISTS') { webdavLogger.info(`[PUT] File '${resource.name}' already exists in '${resource.path.dir}', trashing it...`); await this.dependencies.trashService.trashItems({ - items: [{ type: resource.type, uuid: driveFileItem.uuid, id: null }], + items: [{ type: driveFileItem.itemType, uuid: driveFileItem.uuid, id: null }], }); } } catch { diff --git a/src/webdav/services/webdav-folder.service.ts b/src/webdav/services/webdav-folder.service.ts index 01929af2..f38ad6cb 100644 --- a/src/webdav/services/webdav-folder.service.ts +++ b/src/webdav/services/webdav-folder.service.ts @@ -16,9 +16,9 @@ export class WebDavFolderService { ) {} public getDriveFolderItemFromPath = async (path: string): Promise => { - const resource = await WebDavUtils.getRequestedResource(path, false); - return await WebDavUtils.getDriveItemFromResource({ - resource, + const { url } = await WebDavUtils.getRequestedResource(path, false); + return await WebDavUtils.getDriveFolderFromResource({ + url, driveFolderService: this.dependencies.driveFolderService, }); }; diff --git a/src/webdav/webdav-server.ts b/src/webdav/webdav-server.ts index 62f6238b..acf7c6e8 100644 --- a/src/webdav/webdav-server.ts +++ b/src/webdav/webdav-server.ts @@ -126,6 +126,7 @@ export class WebDavServer { asyncHandler( new PUTRequestHandler({ driveFileService: this.driveFileService, + driveFolderService: this.driveFolderService, webDavFolderService: webDavFolderService, authService: this.authService, trashService: this.trashService, diff --git a/test/fixtures/drive.fixture.ts b/test/fixtures/drive.fixture.ts index fbeeba16..9b824968 100644 --- a/test/fixtures/drive.fixture.ts +++ b/test/fixtures/drive.fixture.ts @@ -24,6 +24,7 @@ const getRandomDate = (start = new Date(2000, 0, 1), end = new Date()) => { export const newFolderItem = (attributes?: Partial): DriveFolderItem => { const folder: DriveFolderItem = { + itemType: 'folder', id: randomInt(1, 100000), uuid: randomUUID(), parentId: randomInt(1, 100000), @@ -40,6 +41,7 @@ export const newFolderItem = (attributes?: Partial): DriveFolde export const newFileItem = (attributes?: Partial): DriveFileItem => { const file: DriveFileItem = { + itemType: 'file', id: randomInt(1, 100000), uuid: crypto.randomBytes(16).toString('hex'), fileId: crypto.randomBytes(16).toString('hex'), diff --git a/test/fixtures/webdav.fixture.ts b/test/fixtures/webdav.fixture.ts index 47452c3a..06ecbffb 100644 --- a/test/fixtures/webdav.fixture.ts +++ b/test/fixtures/webdav.fixture.ts @@ -29,7 +29,6 @@ export const getRequestedFileResource = ({ name: fileName, parentPath: parentFolder, path: path.parse(completeURL), - type: 'file', url: completeURL, }; }; @@ -54,7 +53,6 @@ export const getRequestedFolderResource = ({ name: folderName, parentPath: parentFolder, path: path.parse(completeURL), - type: 'folder', url: completeURL, }; }; diff --git a/test/utils/webdav.utils.test.ts b/test/utils/webdav.utils.test.ts index 8d91da16..94ab51a1 100644 --- a/test/utils/webdav.utils.test.ts +++ b/test/utils/webdav.utils.test.ts @@ -41,7 +41,6 @@ describe('Webdav utils', () => { const resource = await WebDavUtils.getRequestedResource(requestURL); expect(resource).to.deep.equal({ url: '/url/to/folder/', - type: 'folder', name: 'folder', parentPath: '/url/to/', path: { @@ -59,8 +58,7 @@ describe('Webdav utils', () => { const resource = await WebDavUtils.getRequestedResource(requestURL); expect(resource).to.deep.equal({ url: '/url/to/test.png', - type: 'file', - name: 'test', + name: 'test.png', parentPath: '/url/to/', path: { base: 'test.png', @@ -76,8 +74,7 @@ describe('Webdav utils', () => { describe('getDriveItemFromResource', () => { const requestFileFixture: WebDavRequestedResource = { url: '/url/to/test.png', - type: 'file', - name: 'test', + name: 'test.png', parentPath: '/url/to/', path: { base: 'test.png', @@ -89,7 +86,6 @@ describe('Webdav utils', () => { }; const requestFolderFixture: WebDavRequestedResource = { url: '/url/to/folder/', - type: 'folder', name: 'folder', parentPath: '/url/to/', path: { @@ -111,7 +107,7 @@ describe('Webdav utils', () => { const driveFolderItem = await WebDavUtils.getDriveItemFromResource({ resource: requestFolderFixture, driveFolderService: DriveFolderService.instance, - driveFileService: undefined, + driveFileService: DriveFileService.instance, }); expect(driveFolderItem).to.be.deep.equal(expectedFolder); expect(findFolderStub).toHaveBeenCalledOnce(); @@ -127,7 +123,7 @@ describe('Webdav utils', () => { const item = await WebDavUtils.getDriveItemFromResource({ resource: requestFolderFixture, driveFolderService: DriveFolderService.instance, - driveFileService: undefined, + driveFileService: DriveFileService.instance, }); expect(findFolderStub).toHaveBeenCalledOnce(); expect(findFileStub).not.toHaveBeenCalled(); @@ -143,7 +139,7 @@ describe('Webdav utils', () => { const driveFileItem = await WebDavUtils.getDriveItemFromResource({ resource: requestFileFixture, - driveFolderService: undefined, + driveFolderService: DriveFolderService.instance, driveFileService: DriveFileService.instance, }); expect(driveFileItem).to.be.deep.equal(expectedFile); diff --git a/test/webdav/handlers/GET.handler.test.ts b/test/webdav/handlers/GET.handler.test.ts index fd1876ca..e5a05beb 100644 --- a/test/webdav/handlers/GET.handler.test.ts +++ b/test/webdav/handlers/GET.handler.test.ts @@ -25,6 +25,8 @@ import { ConfigService } from '../../../src/services/config.service'; import { UserFixture } from '../../fixtures/auth.fixture'; describe('GET request handler', () => { + let networkFacade: NetworkFacade; + let sut: GETRequestHandler; const getNetworkMock = () => { return SdkManager.instance.getNetwork({ user: 'user', @@ -43,21 +45,24 @@ describe('GET request handler', () => { }; beforeEach(() => { - vi.restoreAllMocks(); - }); - - it('When the Drive file is not found, then it should throw a NotFoundError', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const requestHandler = new GETRequestHandler({ + networkFacade = new NetworkFacade( + getNetworkMock(), + getEnvironmentMock(), + DownloadService.instance, + CryptoService.instance, + ); + sut = new GETRequestHandler({ driveFileService: DriveFileService.instance, - downloadService, + downloadService: DownloadService.instance, authService: AuthService.instance, - cryptoService, + cryptoService: CryptoService.instance, networkFacade, }); + vi.restoreAllMocks(); + }); + + it('When the Drive file is not found, then it should throw a NotFoundError', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -72,33 +77,21 @@ describe('GET request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFileResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') - .mockResolvedValue(undefined); + const getFileMetadataStub = vi + .spyOn(DriveFileService.instance, 'getFileMetadataByPath') + .mockRejectedValue(new Error('File not found')); try { - await requestHandler.handle(request, response); + await sut.handle(request, response); fail('Expected function to throw an error, but it did not.'); } catch (error) { expect(error).to.be.instanceOf(NotFoundError); } expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFileMetadataStub).toHaveBeenCalledOnce(); }); it('When file is requested, then it should write a response with the content', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const authService = AuthService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const requestHandler = new GETRequestHandler({ - driveFileService: DriveFileService.instance, - downloadService, - authService, - cryptoService, - networkFacade, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -117,21 +110,21 @@ describe('GET request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFileResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getFileMetadataStub = vi + .spyOn(DriveFileService.instance, 'getFileMetadataByPath') .mockResolvedValue(mockFile); - const authDetailsStub = vi.spyOn(authService, 'getAuthDetails').mockResolvedValue(mockAuthDetails); + const authDetailsStub = vi.spyOn(AuthService.instance, 'getAuthDetails').mockResolvedValue(mockAuthDetails); const downloadStreamStub = vi .spyOn(networkFacade, 'downloadToStream') .mockResolvedValue([Promise.resolve(), new AbortController()]); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(200); expect(response.header).toHaveBeenCalledWith('Content-length', mockFile.size.toString()); expect(response.header).toHaveBeenCalledWith('Content-Type', 'application/octet-stream'); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFileMetadataStub).toHaveBeenCalledOnce(); expect(authDetailsStub).toHaveBeenCalledOnce(); expect(downloadStreamStub).toHaveBeenCalledWith( mockFile.bucket, @@ -144,18 +137,6 @@ describe('GET request handler', () => { }); it('When file is requested with Range, then it should write a response with the ranged content', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const authService = AuthService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const requestHandler = new GETRequestHandler({ - driveFileService: DriveFileService.instance, - downloadService, - authService, - cryptoService, - networkFacade, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const mockSize = randomInt(500, 10000); @@ -186,21 +167,21 @@ describe('GET request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFileResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getFileMetadataStub = vi + .spyOn(DriveFileService.instance, 'getFileMetadataByPath') .mockResolvedValue(mockFile); - const authDetailsStub = vi.spyOn(authService, 'getAuthDetails').mockResolvedValue(mockAuthDetails); + const authDetailsStub = vi.spyOn(AuthService.instance, 'getAuthDetails').mockResolvedValue(mockAuthDetails); const downloadStreamStub = vi .spyOn(networkFacade, 'downloadToStream') .mockResolvedValue([Promise.resolve(), new AbortController()]); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(200); expect(response.header).toHaveBeenCalledWith('Content-length', (mockSize - rangeStart).toString()); expect(response.header).toHaveBeenCalledWith('Content-Type', 'application/octet-stream'); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFileMetadataStub).toHaveBeenCalledOnce(); expect(authDetailsStub).toHaveBeenCalledOnce(); expect(downloadStreamStub).toHaveBeenCalledWith( mockFile.bucket, diff --git a/test/webdav/handlers/HEAD.handler.test.ts b/test/webdav/handlers/HEAD.handler.test.ts index 3a552b03..747c9a7c 100644 --- a/test/webdav/handlers/HEAD.handler.test.ts +++ b/test/webdav/handlers/HEAD.handler.test.ts @@ -13,17 +13,16 @@ import { WebDavUtils } from '../../../src/utils/webdav.utils'; import { randomInt } from 'crypto'; describe('HEAD request handler', () => { + let sut: HEADRequestHandler; beforeEach(() => { + sut = new HEADRequestHandler({ + driveFileService: DriveFileService.instance, + }); vi.restoreAllMocks(); }); it('When a folder is requested, it should reply with a 200', async () => { - const requestHandler = new HEADRequestHandler({ - driveFileService: DriveFileService.instance, - }); - const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource(); - const request = createWebDavRequestFixture({ method: 'HEAD', url: requestedFolderResource.url, @@ -33,15 +32,11 @@ describe('HEAD request handler', () => { status: vi.fn().mockReturnValue({ send: vi.fn() }), }); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(200); }); it('When a file is requested, it should reply with a 200 with the correct headers', async () => { - const requestHandler = new HEADRequestHandler({ - driveFileService: DriveFileService.instance, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -59,23 +54,19 @@ describe('HEAD request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFileResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getFileMetadataStub = vi + .spyOn(DriveFileService.instance, 'getFileMetadataByPath') .mockResolvedValue(mockFile); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(200); expect(response.header).toHaveBeenCalledWith('Content-Type', 'application/octet-stream'); expect(response.header).toHaveBeenCalledWith('Content-length', mockFile.size.toString()); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFileMetadataStub).toHaveBeenCalledOnce(); }); it('When a file is requested with range-request, it should reply with a 200 with the correct headers', async () => { - const requestHandler = new HEADRequestHandler({ - driveFileService: DriveFileService.instance, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const mockSize = randomInt(500, 10000); @@ -97,15 +88,15 @@ describe('HEAD request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFileResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getFileMetadataStub = vi + .spyOn(DriveFileService.instance, 'getFileMetadataByPath') .mockResolvedValue(mockFile); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(200); expect(response.header).toHaveBeenCalledWith('Content-length', (mockSize - rangeStart).toString()); expect(response.header).toHaveBeenCalledWith('Content-Type', 'application/octet-stream'); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFileMetadataStub).toHaveBeenCalledOnce(); }); }); diff --git a/test/webdav/handlers/MKCOL.handler.test.ts b/test/webdav/handlers/MKCOL.handler.test.ts index 11f4c369..60196d24 100644 --- a/test/webdav/handlers/MKCOL.handler.test.ts +++ b/test/webdav/handlers/MKCOL.handler.test.ts @@ -14,20 +14,22 @@ import { WebDavFolderService } from '../../../src/webdav/services/webdav-folder. import { ConfigService } from '../../../src/services/config.service'; describe('MKCOL request handler', () => { - beforeEach(() => { - vi.restoreAllMocks(); - }); + let webDavFolderService: WebDavFolderService; + let sut: MKCOLRequestHandler; - it('When a WebDav client sends a MKCOL request, it should reply with a 201 if success', async () => { - const driveFolderService = DriveFolderService.instance; - const webDavFolderService = new WebDavFolderService({ + beforeEach(() => { + webDavFolderService = new WebDavFolderService({ driveFolderService: DriveFolderService.instance, configService: ConfigService.instance, }); - const requestHandler = new MKCOLRequestHandler({ - driveFolderService, + sut = new MKCOLRequestHandler({ + driveFolderService: DriveFolderService.instance, webDavFolderService, }); + vi.restoreAllMocks(); + }); + + it('When a WebDav client sends a MKCOL request, it should reply with a 201 if success', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/test', folderName: 'FolderA', @@ -49,20 +51,20 @@ describe('MKCOL request handler', () => { const getDriveFolderItemFromPathStub = vi .spyOn(webDavFolderService, 'getDriveFolderItemFromPath') .mockResolvedValue(parentFolder); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getDriveFolderFromResourceStub = vi + .spyOn(WebDavUtils, 'getDriveFolderFromResource') .mockResolvedValue(undefined); const createFolderStub = vi .spyOn(webDavFolderService, 'createFolder') .mockResolvedValue(newFolderItem({ name: 'FolderA', uuid: 'new-folder-uuid' })); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(201); expect(getRequestedResourceStub).toHaveBeenCalledWith(request.url); expect(getDriveFolderItemFromPathStub).toHaveBeenCalledWith(requestedFolderResource.parentPath); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledWith({ - resource: requestedFolderResource, - driveFolderService, + expect(getDriveFolderFromResourceStub).toHaveBeenCalledWith({ + url: requestedFolderResource.url, + driveFolderService: DriveFolderService.instance, }); expect(createFolderStub).toHaveBeenCalledWith({ folderName: requestedFolderResource.path.base, diff --git a/test/webdav/handlers/PROPFIND.handler.test.ts b/test/webdav/handlers/PROPFIND.handler.test.ts index 8d17e881..69d60eb4 100644 --- a/test/webdav/handlers/PROPFIND.handler.test.ts +++ b/test/webdav/handlers/PROPFIND.handler.test.ts @@ -29,17 +29,16 @@ vi.mock('node:crypto', async () => { const randomUUIDStub = vi.mocked(randomUUID); describe('PROPFIND request handler', () => { + let sut: PROPFINDRequestHandler; beforeEach(() => { + sut = new PROPFINDRequestHandler({ + driveFileService: DriveFileService.instance, + driveFolderService: DriveFolderService.instance, + }); vi.restoreAllMocks(); }); - it('When the root folder exists and there is no content, then itshould return the correct XML', async () => { - const driveFolderService = DriveFolderService.instance; - const driveFileService = DriveFileService.instance; - const requestHandler = new PROPFINDRequestHandler({ - driveFileService, - driveFolderService, - }); + it('When the root folder exists and there is no content, then it should return the correct XML', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -67,35 +66,29 @@ describe('PROPFIND request handler', () => { const getRequestedResourceStub = vi .spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValue(requestedFolderResource); - const getAndSearchItemFromResourceStub = vi - .spyOn(WebDavUtils, 'getDriveItemFromResource') + const getFolderMetadataStub = vi + .spyOn(DriveFolderService.instance, 'getFolderMetadataByPath') .mockResolvedValue(folderFixture); const getFolderContentStub = vi - .spyOn(driveFolderService, 'getFolderContent') + .spyOn(DriveFolderService.instance, 'getFolderContent') .mockResolvedValue({ folders: [], files: [] }); const getUsageStub = vi.spyOn(UsageService.instance, 'fetchUsage').mockResolvedValue(usageFixture); const spaceLimitStub = vi.spyOn(UsageService.instance, 'fetchSpaceLimit').mockResolvedValue(spaceLimitFixture); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( // eslint-disable-next-line max-len `${XMLUtils.encodeWebDavUri('/')}HTTP/1.1 200 OKapplication/octet-stream${FormatUtils.formatDateForWebDav(folderFixture.updatedAt)}F00000030${spaceLimitFixture - usageFixture.total}${usageFixture.total}`, ); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getFolderMetadataStub).toHaveBeenCalledOnce(); expect(getFolderContentStub).toHaveBeenCalledOnce(); expect(getUsageStub).toHaveBeenCalledOnce(); expect(spaceLimitStub).toHaveBeenCalledOnce(); }); it('When the root folder exists and there is content, then it should return the correct XML', async () => { - const driveFolderService = DriveFolderService.instance; - const driveFileService = DriveFileService.instance; - const requestHandler = new PROPFINDRequestHandler({ - driveFileService, - driveFolderService, - }); const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -130,14 +123,14 @@ describe('PROPFIND request handler', () => { const getAndSearchItemFromResourceStub = vi .spyOn(WebDavUtils, 'getDriveItemFromResource') .mockResolvedValue(folderFixture); - const getFolderContentStub = vi.spyOn(driveFolderService, 'getFolderContent').mockResolvedValue({ + const getFolderContentStub = vi.spyOn(DriveFolderService.instance, 'getFolderContent').mockResolvedValue({ files: [], folders: [paginatedFolder1], }); const getUsageStub = vi.spyOn(UsageService.instance, 'fetchUsage').mockResolvedValue(usageFixture); const spaceLimitStub = vi.spyOn(UsageService.instance, 'fetchSpaceLimit').mockResolvedValue(spaceLimitFixture); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( // eslint-disable-next-line max-len @@ -151,12 +144,6 @@ describe('PROPFIND request handler', () => { }); it('When the file exists, then it should return the correct XML', async () => { - const driveFolderService = DriveFolderService.instance; - const driveFileService = DriveFileService.instance; - const requestHandler = new PROPFINDRequestHandler({ - driveFileService, - driveFolderService, - }); const requestedFileResource: WebDavRequestedResource = getRequestedFileResource({ parentFolder: '/', fileName: 'file', @@ -187,7 +174,7 @@ describe('PROPFIND request handler', () => { randomUUIDStub.mockClear(); const mimeLookupStub = vi.spyOn(mime, 'lookup').mockReturnValue(mimeFixture); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( // eslint-disable-next-line max-len @@ -200,12 +187,6 @@ describe('PROPFIND request handler', () => { }); it('When the folder exists, then it should return the correct XML', async () => { - const driveFolderService = DriveFolderService.instance; - const driveFileService = DriveFileService.instance; - const requestHandler = new PROPFINDRequestHandler({ - driveFileService, - driveFolderService, - }); const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: 'folder_a', @@ -229,12 +210,12 @@ describe('PROPFIND request handler', () => { const getAndSearchItemFromResourceStub = vi .spyOn(WebDavUtils, 'getDriveItemFromResource') .mockResolvedValue(folderFixture); - const getFolderContentStub = vi.spyOn(driveFolderService, 'getFolderContent').mockResolvedValue({ + const getFolderContentStub = vi.spyOn(DriveFolderService.instance, 'getFolderContent').mockResolvedValue({ files: [], folders: [paginatedFolder1], }); - await requestHandler.handle(request, response); + await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); // TODO: Test the XML response expect(getRequestedResourceStub).toHaveBeenCalledOnce(); @@ -242,13 +223,7 @@ describe('PROPFIND request handler', () => { expect(getFolderContentStub).toHaveBeenCalledOnce(); }); - it('When the folder does not exists, then it should return a 207 empty response', async () => { - const driveFolderService = DriveFolderService.instance; - const driveFileService = DriveFileService.instance; - const requestHandler = new PROPFINDRequestHandler({ - driveFileService, - driveFolderService, - }); + it('When the folder does not exists, then it should return a 404 empty response', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: 'folder_a', @@ -271,12 +246,9 @@ describe('PROPFIND request handler', () => { .spyOn(WebDavUtils, 'getDriveItemFromResource') .mockResolvedValue(undefined); - await requestHandler.handle(request, response); - expect(response.status).toHaveBeenCalledWith(207); - expect(response.send).toHaveBeenCalledWith( - // eslint-disable-next-line max-len - `${XMLUtils.encodeWebDavUri(requestedFolderResource.url)}HTTP/1.1 404 Not Found`, - ); + await sut.handle(request, response); + expect(response.status).toHaveBeenCalledWith(404); + expect(response.send).toHaveBeenCalledWith(); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); }); diff --git a/test/webdav/handlers/PUT.handler.test.ts b/test/webdav/handlers/PUT.handler.test.ts index eaad44c5..f6c82bbc 100644 --- a/test/webdav/handlers/PUT.handler.test.ts +++ b/test/webdav/handlers/PUT.handler.test.ts @@ -26,6 +26,8 @@ import { ConfigService } from '../../../src/services/config.service'; import { UserFixture } from '../../fixtures/auth.fixture'; describe('PUT request handler', () => { + let networkFacade: NetworkFacade; + let sut: PUTRequestHandler; const getNetworkMock = () => { return SdkManager.instance.getNetwork({ user: 'user', @@ -45,10 +47,7 @@ describe('PUT request handler', () => { beforeEach(() => { vi.restoreAllMocks(); - }); - - it('When the content-length request is 0, then it should throw an UnsupportedMediaTypeError', async () => { - const networkFacade = new NetworkFacade( + networkFacade = new NetworkFacade( getNetworkMock(), getEnvironmentMock(), DownloadService.instance, @@ -58,14 +57,17 @@ describe('PUT request handler', () => { driveFolderService: DriveFolderService.instance, configService: ConfigService.instance, }); - const sut = new PUTRequestHandler({ + sut = new PUTRequestHandler({ driveFileService: DriveFileService.instance, + driveFolderService: DriveFolderService.instance, webDavFolderService, authService: AuthService.instance, trashService: TrashService.instance, networkFacade, }); + }); + it('When the content-length request is 0, then it should throw an UnsupportedMediaTypeError', async () => { const request = createWebDavRequestFixture({ method: 'PUT', url: '/file.txt', @@ -87,22 +89,6 @@ describe('PUT request handler', () => { }); it('When the Drive destination folder is found, then it should upload the file to the folder', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const authService = AuthService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const webDavFolderService = new WebDavFolderService({ - driveFolderService: DriveFolderService.instance, - configService: ConfigService.instance, - }); - const sut = new PUTRequestHandler({ - driveFileService: DriveFileService.instance, - webDavFolderService, - authService: AuthService.instance, - trashService: TrashService.instance, - networkFacade, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', @@ -129,9 +115,13 @@ describe('PUT request handler', () => { .mockResolvedValueOnce(requestedParentFolderResource); const getAndSearchItemFromResourceStub = vi .spyOn(WebDavUtils, 'getDriveItemFromResource') - .mockResolvedValueOnce(folderFixture) .mockResolvedValue(undefined); - const getAuthDetailsStub = vi.spyOn(authService, 'getAuthDetails').mockResolvedValue(UserCredentialsFixture); + const getDriveFolderFromResourceStub = vi + .spyOn(WebDavUtils, 'getDriveFolderFromResource') + .mockResolvedValue(folderFixture); + const getAuthDetailsStub = vi + .spyOn(AuthService.instance, 'getAuthDetails') + .mockResolvedValue(UserCredentialsFixture); const uploadStub = vi.spyOn(networkFacade, 'uploadFile').mockImplementation( // @ts-expect-error - We only mock the properties we need (_, __, ___, callback: (err: Error | null, res: string | null) => void) => { @@ -145,30 +135,14 @@ describe('PUT request handler', () => { await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(201); expect(getRequestedResourceStub).toHaveBeenCalledTimes(2); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledTimes(2); + expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getDriveFolderFromResourceStub).toHaveBeenCalledOnce(); expect(getAuthDetailsStub).toHaveBeenCalledOnce(); expect(uploadStub).toHaveBeenCalledOnce(); expect(createDriveFileStub).toHaveBeenCalledOnce(); }); it('When the file already exists, then it should upload and replace the file to the folder', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const authService = AuthService.instance; - const trashService = TrashService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const webDavFolderService = new WebDavFolderService({ - driveFolderService: DriveFolderService.instance, - configService: ConfigService.instance, - }); - const sut = new PUTRequestHandler({ - driveFileService: DriveFileService.instance, - webDavFolderService, - authService: AuthService.instance, - trashService: TrashService.instance, - networkFacade, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', @@ -195,10 +169,14 @@ describe('PUT request handler', () => { .mockResolvedValueOnce(requestedParentFolderResource); const getAndSearchItemFromResourceStub = vi .spyOn(WebDavUtils, 'getDriveItemFromResource') - .mockResolvedValueOnce(folderFixture) .mockResolvedValueOnce(fileFixture.toItem()); - const deleteDriveFileStub = vi.spyOn(trashService, 'trashItems').mockResolvedValue(); - const getAuthDetailsStub = vi.spyOn(authService, 'getAuthDetails').mockResolvedValue(UserCredentialsFixture); + const getDriveFolderFromResourceStub = vi + .spyOn(WebDavUtils, 'getDriveFolderFromResource') + .mockResolvedValue(folderFixture); + const deleteDriveFileStub = vi.spyOn(TrashService.instance, 'trashItems').mockResolvedValue(); + const getAuthDetailsStub = vi + .spyOn(AuthService.instance, 'getAuthDetails') + .mockResolvedValue(UserCredentialsFixture); const uploadStub = vi.spyOn(networkFacade, 'uploadFile').mockImplementation( // @ts-expect-error - We only mock the properties we need (_, __, ___, callback: (err: Error | null, res: string | null) => void) => { @@ -212,7 +190,8 @@ describe('PUT request handler', () => { await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(201); expect(getRequestedResourceStub).toHaveBeenCalledTimes(2); - expect(getAndSearchItemFromResourceStub).toHaveBeenCalledTimes(2); + expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); + expect(getDriveFolderFromResourceStub).toHaveBeenCalledOnce(); expect(getAuthDetailsStub).toHaveBeenCalledOnce(); expect(uploadStub).toHaveBeenCalledOnce(); expect(createDriveFileStub).toHaveBeenCalledOnce(); @@ -220,22 +199,6 @@ describe('PUT request handler', () => { }); it('When file is uploaded, then it should wait 500ms for backend propagation before returning 201', async () => { - const downloadService = DownloadService.instance; - const cryptoService = CryptoService.instance; - const authService = AuthService.instance; - const networkFacade = new NetworkFacade(getNetworkMock(), getEnvironmentMock(), downloadService, cryptoService); - const webDavFolderService = new WebDavFolderService({ - driveFolderService: DriveFolderService.instance, - configService: ConfigService.instance, - }); - const sut = new PUTRequestHandler({ - driveFileService: DriveFileService.instance, - webDavFolderService, - authService: AuthService.instance, - trashService: TrashService.instance, - networkFacade, - }); - const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', @@ -259,8 +222,9 @@ describe('PUT request handler', () => { vi.spyOn(WebDavUtils, 'getRequestedResource') .mockResolvedValueOnce(requestedFileResource) .mockResolvedValueOnce(requestedParentFolderResource); - vi.spyOn(WebDavUtils, 'getDriveItemFromResource').mockResolvedValueOnce(folderFixture).mockResolvedValue(undefined); - vi.spyOn(authService, 'getAuthDetails').mockResolvedValue(UserCredentialsFixture); + vi.spyOn(WebDavUtils, 'getDriveItemFromResource').mockResolvedValue(undefined); + vi.spyOn(WebDavUtils, 'getDriveFolderFromResource').mockResolvedValue(folderFixture); + vi.spyOn(AuthService.instance, 'getAuthDetails').mockResolvedValue(UserCredentialsFixture); vi.spyOn(networkFacade, 'uploadFile').mockImplementation( // @ts-expect-error - We only mock the properties we need (_, __, ___, callback: (err: Error | null, res: string | null) => void) => { From bfd26c68dfecdaa452ddc60a12e22ff9dc536aa7 Mon Sep 17 00:00:00 2001 From: AlexisMora Date: Fri, 14 Nov 2025 13:34:01 +0100 Subject: [PATCH 4/5] Chore: remove unnecessary comments --- src/utils/webdav.utils.ts | 4 ---- src/webdav/handlers/PROPFIND.handler.ts | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/utils/webdav.utils.ts b/src/utils/webdav.utils.ts index c850ce0e..05b4e26c 100644 --- a/src/utils/webdav.utils.ts +++ b/src/utils/webdav.utils.ts @@ -39,7 +39,6 @@ export class WebDavUtils { return normalizedPath; } - // TODO: We can rename this method to parseUrlToPathMetadata so its more descriptive static async getRequestedResource(requestUrl: string, decodeUri = true): Promise { const decodedUrl = this.decodeUrl(requestUrl, decodeUri); const parsedPath = path.parse(decodedUrl); @@ -97,7 +96,6 @@ export class WebDavUtils { } } - // This method will be used mainly for propfind, since we dont know what the user is requesting for static async getDriveItemFromResource({ resource, driveFolderService, @@ -109,8 +107,6 @@ export class WebDavUtils { }): Promise { let item: DriveItem | undefined = undefined; - // This is exactly the problem, nautilus sends folder urls without trailing slash - // There is just no other way to check wether its a folder or file at this point other than checking ourselves const isFolder = resource.url.endsWith('/'); try { diff --git a/src/webdav/handlers/PROPFIND.handler.ts b/src/webdav/handlers/PROPFIND.handler.ts index 9dfef410..b55be4a4 100644 --- a/src/webdav/handlers/PROPFIND.handler.ts +++ b/src/webdav/handlers/PROPFIND.handler.ts @@ -37,7 +37,6 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { switch (driveItem.itemType) { case 'file': { - // Here its only used the url const fileMetaXML = await this.getFileMetaXML(resource, driveItem); res.status(207).send(fileMetaXML); break; @@ -45,7 +44,6 @@ export class PROPFINDRequestHandler implements WebDavMethodHandler { case 'folder': { const depth = req.header('depth') ?? '1'; - // Here its only used the url const folderMetaXML = await this.getFolderContentXML(resource, driveItem, depth); res.status(207).send(folderMetaXML); break; From 7b77f18e22976c326f6d719ea615f56fc4150b33 Mon Sep 17 00:00:00 2001 From: AlexisMora Date: Fri, 14 Nov 2025 13:38:22 +0100 Subject: [PATCH 5/5] chore: Fix sonarcloud pipeline --- src/services/database/drive-file/drive-file.domain.ts | 1 + src/services/database/drive-folder/drive-folder.domain.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/services/database/drive-file/drive-file.domain.ts b/src/services/database/drive-file/drive-file.domain.ts index 663662ff..55044886 100644 --- a/src/services/database/drive-file/drive-file.domain.ts +++ b/src/services/database/drive-file/drive-file.domain.ts @@ -78,6 +78,7 @@ export class DriveFile implements DriveFileAttributes { public toItem(): DriveFileItem { return { + itemType: 'file', id: this.id, name: this.name, type: this.type, diff --git a/src/services/database/drive-folder/drive-folder.domain.ts b/src/services/database/drive-folder/drive-folder.domain.ts index 00a74af0..8974f47a 100644 --- a/src/services/database/drive-folder/drive-folder.domain.ts +++ b/src/services/database/drive-folder/drive-folder.domain.ts @@ -54,6 +54,7 @@ export class DriveFolder implements DriveFolderAttributes { public toItem(): DriveFolderItem { return { + itemType: 'folder', id: this.id, name: this.name, uuid: this.uuid,