From 38ce318603e99788afee7e8db075fec4a91f1172 Mon Sep 17 00:00:00 2001 From: Ashim Shrestha Date: Wed, 7 Oct 2026 09:43:13 +0545 Subject: [PATCH 1/2] feat: handle post_max_size and upload_max_filesize Signed-off-by: Ashim Shrestha --- lib/Controller/DirectUploadController.php | 53 +++++++---- .../features/api/directUpload.feature | 18 ++-- .../Controller/DirectUploadControllerTest.php | 91 +++++++++++++++---- 3 files changed, 120 insertions(+), 42 deletions(-) diff --git a/lib/Controller/DirectUploadController.php b/lib/Controller/DirectUploadController.php index d0c7bef49..02d377c34 100644 --- a/lib/Controller/DirectUploadController.php +++ b/lib/Controller/DirectUploadController.php @@ -154,38 +154,60 @@ public function directUpload(string $token):DataResponse { try { if (strlen($token) !== 64 || !preg_match('/^[a-zA-Z0-9]*/', $token)) { $this->databaseService->deleteToken($token); - throw new NotFoundException('invalid token'); + throw new OpenprojectUnauthorizedUserException('invalid token'); } - $tokenInfo = $this->directUploadService->getTokenInfo($token); + + $postMaxSize = ini_get('post_max_size'); + $postMaxSizeInBytes = (int)\OCP\Util::computerFileSize($postMaxSize); + $contentLength = (int)$this->request->getHeader('Content-Length'); + if ($postMaxSizeInBytes > 0 && $contentLength > $postMaxSizeInBytes) { + throw new OpenprojectFileNotUploadedException( + 'File was not uploaded. The request exceeds the maximum post size.', + ); + } + $directUploadFile = $this->request->getUploadedFile('file'); if (empty($directUploadFile)) { - throw new OpenprojectFileNotUploadedException( - 'File was not uploaded. post_max_size exceeded?' + throw new \InvalidArgumentException( + 'No file is present to upload.' ); } - $fileName = trim($directUploadFile['name']); - $this->scanForInvalidCharacters($fileName, "\\/"); - if (empty($directUploadFile['tmp_name']) || $directUploadFile['error'] === 1) { + + $phpFileUploadErrors = [ + UPLOAD_ERR_OK => 'The file was uploaded', + UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini', + UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', + UPLOAD_ERR_PARTIAL => 'The file was only partially uploaded', + UPLOAD_ERR_NO_FILE => 'No file was uploaded', + UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder', + UPLOAD_ERR_CANT_WRITE => 'Could not write file to disk', + UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload', + ]; + + if (array_key_exists('error', $directUploadFile) && $directUploadFile['error'] !== UPLOAD_ERR_OK) { throw new OpenprojectFileNotUploadedException( - 'File was not uploaded. upload_max_filesize exceeded?' + $phpFileUploadErrors[$directUploadFile['error']], ); } - $tmpPath = $directUploadFile['tmp_name']; + + $fileName = trim($directUploadFile['name']); + $this->scanForInvalidCharacters($fileName, "\\/"); if (Filesystem::isFileBlacklisted($fileName)) { throw new ForbiddenException('invalid file name'); } + $tmpPath = $directUploadFile['tmp_name']; + $overwrite = $this->request->getParam('overwrite'); if (isset($overwrite)) { $acceptedOverwriteValues = ['true','false']; $overwrite = strtolower($overwrite); - if (in_array($overwrite, $acceptedOverwriteValues)) { - $overwrite = $overwrite === 'true'; - } else { + if (!in_array($overwrite, $acceptedOverwriteValues)) { throw new \InvalidArgumentException('invalid overwrite value'); } - } else { - $overwrite = null; + $overwrite = $overwrite === 'true'; } + + $tokenInfo = $this->directUploadService->getTokenInfo($token); $user = $this->userManager->get($tokenInfo['user_id']); $this->userSession->setUser($user); $userFolder = $this->rootFolder->getUserFolder($user->getUID()); @@ -269,8 +291,7 @@ public function directUpload(string $token):DataResponse { ], Http::STATUS_INSUFFICIENT_STORAGE); } catch (OpenprojectFileNotUploadedException $e) { return new DataResponse([ - 'error' => $this->l->t($e->getMessage()), - 'upload_limit' => \OCP\Util::uploadLimit() + 'error' => $this->l->t($e->getMessage()) ], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); } catch (InvalidContentException $e) { // files_antivirus throws this exception return new DataResponse([ diff --git a/tests/acceptance/features/api/directUpload.feature b/tests/acceptance/features/api/directUpload.feature index c4c2492bc..80723d41e 100644 --- a/tests/acceptance/features/api/directUpload.feature +++ b/tests/acceptance/features/api/directUpload.feature @@ -70,18 +70,16 @@ Feature: API endpoint for direct upload When an anonymous user sends a multipart form data POST request to the "direct-upload/%last-created-direct-upload-token%" endpoint with: | file_name | "" | | data | some data | - Then the HTTP status code should be "413" + Then the HTTP status code should be "400" And the data of the response should match """" { "type": "object", "required": [ - "error", - "upload_limit" + "error" ], "properties": { - "error": {"type": "string", "pattern": "^File was not uploaded\\. post_max_size exceeded\\?$"}, - "upload_limit": {"type": "integer"} + "error": {"type": "string", "pattern": "No file is present to upload."} } } """ @@ -260,20 +258,22 @@ Feature: API endpoint for direct upload When an anonymous user sends a multipart form data POST request to the "direct-upload/%last-created-direct-upload-token%" endpoint with: | file_name | "" | | data | some data | - Then the HTTP status code should be "413" + Then the HTTP status code should be "400" When an anonymous user sends a multipart form data POST request to the "direct-upload/%last-created-direct-upload-token%" endpoint with: | file_name | file.txt | | data | some data | - Then the HTTP status code should be "401" + Then the HTTP status code should be "201" And the data of the response should match """" { "type": "object", "required": [ - "error" + "file_name", + "file_id" ], "properties": { - "error": {"type": "string", "pattern": "^unauthorized$"} + "file_name": {"type": "string", "pattern": "^file\\.txt$"}, + "file_id": {"type" : "integer"} } } """ diff --git a/tests/lib/Controller/DirectUploadControllerTest.php b/tests/lib/Controller/DirectUploadControllerTest.php index c0c25701e..998b8cf22 100644 --- a/tests/lib/Controller/DirectUploadControllerTest.php +++ b/tests/lib/Controller/DirectUploadControllerTest.php @@ -22,6 +22,7 @@ class DirectUploadControllerTest extends TestCase { * @var IL10N */ private $l; + private const TOKEN = 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3'; /** * @return mixed @@ -43,7 +44,7 @@ public function testprepareDirectUpload() { $result = $directUploadController->prepareDirectUpload(123); assertSame( [ - 'token' => 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3', + 'token' => self::TOKEN, 'expires_on' => 1671537939 ], $result->getData() @@ -113,7 +114,7 @@ public function testDirectUploadInvalidToken(string $token):void { ], $result->getData() ); - assertSame(404, $result->getStatus()); + assertSame(401, $result->getStatus()); } public function testDirectUploadNotEnoughSpace():void { @@ -126,7 +127,7 @@ public function testDirectUploadNotEnoughSpace():void { $userFolderMock, 101 ); $result = $directUploadController->directUpload( - 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3' + self::TOKEN, ); assertSame( [ @@ -142,34 +143,81 @@ public function testDirectUploadNotEnoughSpace():void { */ public function fileNotUploadedDataProvider() { return [ - ['', 1], - ['some name', 1], - ['', 0], + [UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'], + [UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'], + [UPLOAD_ERR_PARTIAL, 'The file was only partially uploaded'], + [UPLOAD_ERR_NO_FILE, 'No file was uploaded'], + [UPLOAD_ERR_NO_TMP_DIR, 'Missing a temporary folder'], + [UPLOAD_ERR_CANT_WRITE, 'Could not write file to disk'], + [UPLOAD_ERR_EXTENSION, 'A PHP extension stopped the file upload'], ]; } /** - * @param string $tmpName * @param int $error + * @param string $expectedErrorMessage * @return void * @dataProvider fileNotUploadedDataProvider */ - public function testDirectUploadFileNotUploaded(string $tmpName, int $error):void { + public function testDirectUploadFileNotUploaded(int $error, string $expectedErrorMessage):void { + $nodeMock = $this->getNodeMock('folder'); + + $userFolderMock = $this->getFolderMock(); + $userFolderMock->method('getById')->willReturn($nodeMock); + $directUploadController = $this->createDirectUploadController( + $userFolderMock, 100, '', $error + ); + $result = $directUploadController->directUpload( + self::TOKEN, + ); + $resultArray = $result->getData(); + assertSame( + $expectedErrorMessage, + $resultArray['error'] + ); + assertSame(413, $result->getStatus()); + } + + /** + * @return void + */ + public function testDirectUploadNoFile():void { $nodeMock = $this->getNodeMock('folder'); $userFolderMock = $this->getFolderMock(); $userFolderMock->method('getById')->willReturn($nodeMock); $directUploadController = $this->createDirectUploadController( - $userFolderMock, 100, $tmpName, $error + folderMock: $userFolderMock, noUploadedFile: true ); $result = $directUploadController->directUpload( - 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3' + self::TOKEN, ); $resultArray = $result->getData(); assertSame( - 'File was not uploaded. upload_max_filesize exceeded?', + 'No file is present to upload.', + $resultArray['error'] + ); + assertSame(400, $result->getStatus()); + } + + /** + * @return void + */ + public function testDirectUploadPostMaxSizeExceeded():void { + $nodeMock = $this->getNodeMock('folder'); + + $userFolderMock = $this->getFolderMock(); + $userFolderMock->method('getById')->willReturn($nodeMock); + $directUploadController = $this->createDirectUploadController( + folderMock: $userFolderMock, contentLength: (string)PHP_INT_MAX + ); + $result = $directUploadController->directUpload( + self::TOKEN, + ); + $resultArray = $result->getData(); + assertSame( + 'File was not uploaded. The request exceeds the maximum post size.', $resultArray['error'] ); - self::assertIsNumeric($resultArray['upload_limit']); assertSame(413, $result->getStatus()); } @@ -200,7 +248,7 @@ public function testDirectUploadException( $directUploadController = $this->createDirectUploadController( $userFolderMock, 0, $tmpFileName); $result = $directUploadController->directUpload( - 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3' + self::TOKEN, ); $resultArray = $result->getData(); assertSame( @@ -230,7 +278,7 @@ public function testNegativeFreeSpace(): void { $userFolderMock, 101, $tmpFileName ); $result = $directUploadController->directUpload( - 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3' + self::TOKEN, ); $resultArray = $result->getData(); assertSame( @@ -248,13 +296,17 @@ public function testNegativeFreeSpace(): void { * @param int $uploadedFileSize * @param string $uploadedFileTmpName * @param int $uploadedFileError + * @param string $contentLength + * @param bool $noUploadedFile * @return DirectUploadController */ private function createDirectUploadController( mixed $folderMock, int $uploadedFileSize = 9999, string $uploadedFileTmpName = '/tmp/andjashd', - int $uploadedFileError = 0 + int $uploadedFileError = 0, + string $contentLength = '100', + bool $noUploadedFile = false ): DirectUploadController { $storageMock = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); $storageMock->method('getUserFolder')->willReturn($folderMock); @@ -271,7 +323,7 @@ private function createDirectUploadController( $directUploadServiceMock->method('getTokenForDirectUpload') ->willReturn([ - 'token' => 'WampxL5Z97CndGwB7qLPfotosDT5mXk7oFyGLa64nmY35ANtkzT7zDQwYyXrbdC3', + 'token' => self::TOKEN, 'expires_on' => 1671537939 ]); @@ -293,8 +345,13 @@ private function createDirectUploadController( $userManagerMock->method('get')->willReturn($userMock); $requestMock = $this->getMockBuilder(IRequest::class)->disableOriginalConstructor()->getMock(); + $requestMock->method('getHeader')->willReturnCallback( + function (string $name) use ($contentLength) { + return $name === 'Content-Length' ? $contentLength : ''; + } + ); - $requestMock->method('getUploadedFile')->willReturn([ + $requestMock->method('getUploadedFile')->willReturn($noUploadedFile ? null : [ 'name' => 'file.txt', 'tmp_name' => $uploadedFileTmpName, 'size' => $uploadedFileSize, From 60d2cb6b9f791b4a651b6e78ae3a02a7265e5810 Mon Sep 17 00:00:00 2001 From: Ashim Shrestha Date: Mon, 12 Oct 2026 12:24:54 +0545 Subject: [PATCH 2/2] refactor: move function to service Signed-off-by: Ashim Shrestha --- lib/Controller/DirectUploadController.php | 68 +------------ lib/Service/DirectUploadService.php | 96 ++++++++++++++++++- psalm.xml | 2 +- .../Controller/DirectUploadControllerTest.php | 6 +- tests/lib/Service/DirectUploadServiceTest.php | 22 ++++- 5 files changed, 122 insertions(+), 72 deletions(-) diff --git a/lib/Controller/DirectUploadController.php b/lib/Controller/DirectUploadController.php index 02d377c34..23a751255 100644 --- a/lib/Controller/DirectUploadController.php +++ b/lib/Controller/DirectUploadController.php @@ -8,10 +8,8 @@ namespace OCA\OpenProject\Controller; use \OCP\AppFramework\ApiController; -use DateTime; use InvalidArgumentException; use OC\Files\Filesystem; -use OC\Files\Node\Folder; use OC\ForbiddenException; use OC\User\NoUserException; use OCA\OpenProject\Exception\OpenprojectFileNotUploadedException; @@ -195,7 +193,6 @@ public function directUpload(string $token):DataResponse { if (Filesystem::isFileBlacklisted($fileName)) { throw new ForbiddenException('invalid file name'); } - $tmpPath = $directUploadFile['tmp_name']; $overwrite = $this->request->getParam('overwrite'); if (isset($overwrite)) { @@ -206,63 +203,7 @@ public function directUpload(string $token):DataResponse { } $overwrite = $overwrite === 'true'; } - - $tokenInfo = $this->directUploadService->getTokenInfo($token); - $user = $this->userManager->get($tokenInfo['user_id']); - $this->userSession->setUser($user); - $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $nodes = $userFolder->getById($tokenInfo['folder_id']); - if (empty($nodes)) { - throw new NotFoundException('folder not found or not enough permissions'); - } - /** - * @var Folder $folderNode - */ - $folderNode = array_shift($nodes); - if (!$folderNode->isCreatable() && !$overwrite) { - throw new ForbiddenException('not enough permissions'); - } - $freeSpace = $folderNode->getFreeSpace(); - - // this is also true if we try to overwrite - // to overwrite a file we need enough free quota for the new data - // otherwise `putContent()` fails, - // if freeSpace is smaller than 0 then treat it as a unlimited space - // and don't throw an error - if ($directUploadFile['size'] > $freeSpace && $freeSpace >= 0) { - throw new NotEnoughSpaceException('insufficient quota'); - } - if ($folderNode->nodeExists($fileName) && $overwrite) { - /** - * @var File $file - */ - $file = $folderNode->get($fileName); - if ($file->getType() === FileInfo::TYPE_FOLDER) { - throw new Conflict('overwrite is not allowed on non-files'); - } - if (!$file->isUpdateable()) { - throw new ForbiddenException('not enough permissions'); - } - // overwrite the file - $file->putContent(fopen($tmpPath, 'r')); - $fileId = $file->getId(); - return new DataResponse([ - 'file_name' => $fileName, - 'file_id' => $fileId - ], Http::STATUS_OK); - } elseif ($folderNode->nodeExists($fileName) && $overwrite === false) { - // get unique name for duplicate file with number suffix - $fileName = $folderNode->getNonExistingName($fileName); - } elseif ($folderNode->nodeExists($fileName)) { - throw new Conflict('conflict, file name already exists'); - } - $fileInfo = $folderNode->newFile($fileName, fopen($tmpPath, 'r')); - $fileId = $fileInfo->getId(); - // setting the creation time for the uploaded file - $creationTime = (new DateTime())->getTimestamp(); - $fileInfo->getStorage()->getCache()->update($fileId, [ - 'creation_time' => $creationTime - ]); + $result = $this->directUploadService->uploadFile($token, $directUploadFile, $overwrite); } catch (OpenprojectUnauthorizedUserException $e) { return new DataResponse([ 'error' => $this->l->t($e->getMessage()) @@ -306,10 +247,11 @@ public function directUpload(string $token):DataResponse { 'error' => $this->l->t($e->getMessage()) ], Http::STATUS_INTERNAL_SERVER_ERROR); } + $statusCode = $result['overwritten'] ? Http::STATUS_OK : Http::STATUS_CREATED; return new DataResponse([ - 'file_name' => $fileName, - 'file_id' => $fileId - ], Http::STATUS_CREATED); + 'file_name' => $result['file_name'], + 'file_id' => $result['file_id'], + ], $statusCode); } /** diff --git a/lib/Service/DirectUploadService.php b/lib/Service/DirectUploadService.php index fb319f52e..32d9434e8 100644 --- a/lib/Service/DirectUploadService.php +++ b/lib/Service/DirectUploadService.php @@ -8,12 +8,20 @@ namespace OCA\OpenProject\Service; use DateTime; +use OC\Files\Node\Folder; +use OC\ForbiddenException; use OCA\OpenProject\Exception\OpenprojectUnauthorizedUserException; use OCP\DB\Exception; +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\IRootFolder; +use OCP\Files\NotEnoughSpaceException; use OCP\Files\NotFoundException; use OCP\IL10N; use OCP\IUserManager; +use OCP\IUserSession; use OCP\Security\ISecureRandom; +use Sabre\DAV\Exception\Conflict; class DirectUploadService { @@ -40,16 +48,30 @@ class DirectUploadService { /** @var string time of token expiration */ private string $expiryTime = '+1 hour'; + /** + * @var IUserSession + */ + private IUserSession $userSession; + + /** + * @var IRootFolder + */ + private IRootFolder $rootFolder; + public function __construct( - IUserManager $userManager, - IL10N $l, - ISecureRandom $secureRandom, - DatabaseService $databaseService + IUserManager $userManager, + IL10N $l, + ISecureRandom $secureRandom, + DatabaseService $databaseService, + IUserSession $userSession, + IRootFolder $rootFolder, ) { $this->l = $l; $this->userManager = $userManager; $this->secureRandom = $secureRandom; $this->databaseService = $databaseService; + $this->userSession = $userSession; + $this->rootFolder = $rootFolder; } /** @@ -100,4 +122,70 @@ public function getTokenInfo(string $token): ?array { } return $tokenInfo; } + + public function uploadFile(string $token, mixed $directUploadFile, ?bool $overwrite) : array { + $tokenInfo = $this->getTokenInfo($token); + $user = $this->userManager->get($tokenInfo['user_id']); + $this->userSession->setUser($user); + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $nodes = $userFolder->getById($tokenInfo['folder_id']); + if (empty($nodes)) { + throw new NotFoundException('folder not found or not enough permissions'); + } + /** + * @var Folder $folderNode + */ + $folderNode = array_shift($nodes); + if (!$folderNode->isCreatable() && !$overwrite) { + throw new ForbiddenException('not enough permissions'); + } + $freeSpace = $folderNode->getFreeSpace(); + + // this is also true if we try to overwrite + // to overwrite a file we need enough free quota for the new data + // otherwise `putContent()` fails, + // if freeSpace is smaller than 0 then treat it as a unlimited space + // and don't throw an error + if ($directUploadFile['size'] > $freeSpace && $freeSpace >= 0) { + throw new NotEnoughSpaceException('insufficient quota'); + } + $fileName = trim($directUploadFile['name']); + $tmpPath = $directUploadFile['tmp_name']; + if ($folderNode->nodeExists($fileName) && $overwrite) { + /** + * @var File $file + */ + $file = $folderNode->get($fileName); + if ($file->getType() === FileInfo::TYPE_FOLDER) { + throw new Conflict('overwrite is not allowed on non-files'); + } + if (!$file->isUpdateable()) { + throw new ForbiddenException('not enough permissions'); + } + // overwrite the file + $file->putContent(fopen($tmpPath, 'r')); + return [ + 'file_id' => $file->getId(), + 'file_name' => $fileName, + 'overwritten' => true, + ]; + } elseif ($folderNode->nodeExists($fileName) && $overwrite === false) { + // get unique name for duplicate file with number suffix + $fileName = $folderNode->getNonExistingName($fileName); + } elseif ($folderNode->nodeExists($fileName)) { + throw new Conflict('conflict, file name already exists'); + } + $fileInfo = $folderNode->newFile($fileName, fopen($tmpPath, 'r')); + $fileId = $fileInfo->getId(); + // setting the creation time for the uploaded file + $creationTime = (new DateTime())->getTimestamp(); + $fileInfo->getStorage()->getCache()->update($fileId, [ + 'creation_time' => $creationTime + ]); + return [ + 'file_id' => $fileId, + 'file_name' => $fileName, + 'overwritten' => false, + ]; + } } diff --git a/psalm.xml b/psalm.xml index b954657c1..475e25651 100644 --- a/psalm.xml +++ b/psalm.xml @@ -104,4 +104,4 @@ - \ No newline at end of file + diff --git a/tests/lib/Controller/DirectUploadControllerTest.php b/tests/lib/Controller/DirectUploadControllerTest.php index 998b8cf22..bdd82baf9 100644 --- a/tests/lib/Controller/DirectUploadControllerTest.php +++ b/tests/lib/Controller/DirectUploadControllerTest.php @@ -124,7 +124,7 @@ public function testDirectUploadNotEnoughSpace():void { $userFolderMock = $this->getFolderMock(); $userFolderMock->method('getById')->willReturn($nodeMock); $directUploadController = $this->createDirectUploadController( - $userFolderMock, 101 + folderMock: $userFolderMock, uploadedFileSize: 101, ); $result = $directUploadController->directUpload( self::TOKEN, @@ -246,7 +246,7 @@ public function testDirectUploadException( $userFolderMock = $this->getFolderMock(); $userFolderMock->method('getById')->willReturn($nodeMock); $directUploadController = $this->createDirectUploadController( - $userFolderMock, 0, $tmpFileName); + folderMock: $userFolderMock, uploadedFileSize: 0, uploadedFileTmpName: $tmpFileName); $result = $directUploadController->directUpload( self::TOKEN, ); @@ -306,7 +306,7 @@ private function createDirectUploadController( string $uploadedFileTmpName = '/tmp/andjashd', int $uploadedFileError = 0, string $contentLength = '100', - bool $noUploadedFile = false + bool $noUploadedFile = false, ): DirectUploadController { $storageMock = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); $storageMock->method('getUserFolder')->willReturn($folderMock); diff --git a/tests/lib/Service/DirectUploadServiceTest.php b/tests/lib/Service/DirectUploadServiceTest.php index 630b784cf..21347fe97 100644 --- a/tests/lib/Service/DirectUploadServiceTest.php +++ b/tests/lib/Service/DirectUploadServiceTest.php @@ -7,6 +7,8 @@ namespace OCA\OpenProject\Service; +use OC\Files\Node\Folder; +use OCP\Files\IUserFolder; use OCP\Files\NotFoundException; use OCP\IL10N; use OCP\IUser; @@ -15,6 +17,17 @@ use PHPUnit\Framework\TestCase; class DirectUploadServiceTest extends TestCase { + + /** + * @return mixed + */ + public function getFolderMock(): mixed { + if (interface_exists(IUserFolder::class)) { + return $this->createMock(IUserFolder::class); + } + return $this->createMock(Folder::class); + } + protected function getDirectUploadService(int $expiresOn): DirectUploadService { $databaseServiceMock = $this->getMockBuilder(DatabaseService::class)->disableOriginalConstructor()->getMock(); $databaseServiceMock->method('getTokenInfoFromDB')->willReturn([ @@ -29,12 +42,19 @@ protected function getDirectUploadService(int $expiresOn): DirectUploadService { $userManagerMock = $this->getMockBuilder(IUserManager::class)->disableOriginalConstructor()->getMock(); $userManagerMock->method('userExists')->willReturn(true); $userManagerMock->method('get')->willReturn($userMock); + $userSessionMock = $this->getMockBuilder('\OCP\IUserSession')->getMock(); + $userSessionMock->method('getUser')->willReturn($userMock); + $folderMock = $this->getFolderMock(); + $storageMock = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); + $storageMock->method('getUserFolder')->willReturn($folderMock); return new DirectUploadService( $userManagerMock, $this->createMock(IL10N::class), $this->createMock(ISecureRandom::class), - $databaseServiceMock + $databaseServiceMock, + $userSessionMock, + $storageMock ); }