AjaxController   F
last analyzed

Complexity

Total Complexity 104

Size/Duplication

Total Lines 597
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 327
dl 0
loc 597
rs 2
c 0
b 0
f 0
wmc 104

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getStateAction() 0 3 1
A damGetLogoutUrlAction() 0 7 2
A getTreeFoldersAction() 0 22 6
C moveResourcesAction() 0 48 13
A setStateAction() 0 6 1
A getStoragesAndMountsAction() 0 18 5
A getBackendUser() 0 3 1
B fileExistsAction() 0 27 6
B prepareDownloadAction() 0 44 7
C copyResourcesAction() 0 51 13
B getFolderItemsAction() 0 36 9
B fileUploadAction() 0 37 11
A getNewStorageUrlAction() 0 16 2
A addFolderToArchiveRecursive() 0 13 3
B deleteResourcesAction() 0 29 6
A createFolderRecursive() 0 22 5
B renameResourcesAction() 0 44 10
A createFolderAction() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like AjaxController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AjaxController, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types = 1);
3
4
/*
5
 * This file is part of the package typo3/cms-digital-asset-management.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE file that was distributed with this source code.
9
 */
10
11
namespace TYPO3\CMS\DigitalAssetManagement\Controller;
12
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\ServerRequestInterface;
15
use TYPO3\CMS\Backend\Routing\UriBuilder;
16
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
17
use TYPO3\CMS\Core\Core\Environment;
18
use TYPO3\CMS\Core\Http\JsonResponse;
19
use TYPO3\CMS\Core\Http\Response;
20
use TYPO3\CMS\Core\Http\Stream;
21
use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
22
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
23
use TYPO3\CMS\Core\Resource\Exception as ResourceException;
24
use TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException;
25
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
26
use TYPO3\CMS\Core\Resource\FileInterface;
27
use TYPO3\CMS\Core\Resource\Folder;
28
use TYPO3\CMS\Core\Resource\ResourceFactory;
29
use TYPO3\CMS\Core\Utility\GeneralUtility;
30
use TYPO3\CMS\Core\Utility\StringUtility;
31
use TYPO3\CMS\DigitalAssetManagement\Entity\FileMount;
32
use TYPO3\CMS\DigitalAssetManagement\Entity\FileOperationResult;
33
use TYPO3\CMS\DigitalAssetManagement\Entity\FolderItemFile;
34
use TYPO3\CMS\DigitalAssetManagement\Entity\FolderItemFolder;
35
use TYPO3\CMS\DigitalAssetManagement\Entity\FolderItemImage;
36
use TYPO3\CMS\DigitalAssetManagement\Entity\Storage;
37
use TYPO3\CMS\DigitalAssetManagement\Entity\TreeItemFolder;
38
use TYPO3\CMS\DigitalAssetManagement\Exception\ControllerException;
39
use TYPO3\CMS\DigitalAssetManagement\Http\FileExistsResponse;
40
use TYPO3\CMS\DigitalAssetManagement\Http\FileOperationResponse;
41
use TYPO3\CMS\DigitalAssetManagement\Http\FolderItemsResponse;
42
use TYPO3\CMS\DigitalAssetManagement\Http\JsonExceptionResponse;
43
use TYPO3\CMS\DigitalAssetManagement\Http\StoragesAndMountsResponse;
44
45
/**
46
 * Main API endpoint. These are ajax actions called by JS side.
47
 *
48
 * Look up the end points in Configuration/Backend/Routes.php: A typical
49
 * path is something like /ajax/dam/getStoragesAndMounts which maps to a method
50
 * with the same name plus word "Action": getStoragesAndMountsAction().
51
 *
52
 * All actions return a JsonResponse, if all is good, the return code is
53
 * 200. A different code, usually in 4xx range will be returned if the
54
 * client sent a bogus request, often with some exception details.
55
 */
56
class AjaxController
57
{
58
    /**
59
     * @return JsonResponse
60
     */
61
    public function getNewStorageUrlAction(): JsonResponse
62
    {
63
        $backendUser = $this->getBackendUser();
64
        if (!$backendUser->isAdmin()) {
65
            return new JsonExceptionResponse(new ControllerException('User is not admin', 1554380677));
66
        }
67
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
68
        $urlParameters = [
69
            'edit' => [
70
                'sys_file_storage' => [
71
                    0 => 'new',
72
                ],
73
            ],
74
            'returnUrl' => (string)$uriBuilder->buildUriFromRoute('file_DigitalAssetManagement'),
75
        ];
76
        return new JsonResponse([(string)$uriBuilder->buildUriFromRoute('record_edit', $urlParameters)]);
77
    }
78
79
    /**
80
     * @param ServerRequestInterface $request
81
     * @return Response
82
     */
83
    public function prepareDownloadAction(ServerRequestInterface $request): ResponseInterface
84
    {
85
        $identifiers = $request->getQueryParams()['identifiers'] ?? '';
86
        try {
87
            if (empty($identifiers) || !is_array($identifiers)) {
88
                throw new ControllerException('List of files or folders needed', 1554375542);
89
            }
90
            // (Mis)-use the LocalDriver method to sanitize the filename prefix
91
            $archivePrefix = rtrim(
92
                GeneralUtility::makeInstance(LocalDriver::class)
93
                    ->sanitizeFileName($request->getQueryParams()['filenamePrefix'] ?? 'download'),
94
                '-'
95
            );
96
            $archiveFilename = Environment::getVarPath()
97
                . '/transient/'
98
                . $archivePrefix
99
                . '-'
100
                . GeneralUtility::hmac(StringUtility::getUniqueId(), 'damDownload')
101
                . '.zip';
102
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
103
            $zip = new \ZipArchive();
104
            $zip->open($archiveFilename, \ZipArchive::CREATE);
105
            foreach ($identifiers as $identifier) {
106
                $resource = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
107
                if ($resource instanceof FileInterface) {
108
                    /** @var FileInterface $resource */
109
                    $zip->addFile($resource->getForLocalProcessing(false), $resource->getName());
110
                } else {
111
                    /** @var Folder $resource */
112
                    $this->addFolderToArchiveRecursive($resource, $zip);
113
                }
114
            }
115
            $zip->close();
116
            GeneralUtility::fixPermissions($archiveFilename);
117
        } catch (ResourceException $e) {
118
            return new JsonExceptionResponse($e);
119
        } catch (ControllerException $e) {
120
            return new JsonExceptionResponse($e);
121
        }
122
        return (new Response())
123
            ->withHeader('Filename', basename($archiveFilename))
124
            ->withHeader('Content-Type', 'application/zip')
125
            ->withHeader('Content-Length', (string) filesize($archiveFilename))
126
            ->withBody(new Stream($archiveFilename));
127
    }
128
129
    /**
130
     * @param Folder $folder
131
     * @param \ZipArchive $zip
132
     * @param array $parentFolders
133
     */
134
    protected function addFolderToArchiveRecursive(Folder $folder, \ZipArchive $zip, array $parentFolders = []): void
135
    {
136
        $folderName = $folder->getName();
137
        $parentFolders[] = $folderName;
138
        $implodedParentFolders = implode('/', $parentFolders);
139
        $zip->addEmptyDir($implodedParentFolders);
140
        $files = $folder->getFiles();
141
        foreach ($files as $file) {
142
            $zip->addFile($file->getForLocalProcessing(false), $implodedParentFolders . '/' . $file->getName());
143
        }
144
        $subFolders = $folder->getSubfolders();
145
        foreach ($subFolders as $subFolder) {
146
            $this->addFolderToArchiveRecursive($subFolder, $zip, $parentFolders);
147
        }
148
    }
149
150
    /**
151
     * @return JsonResponse
152
     */
153
    public function damGetLogoutUrlAction(): JsonResponse
154
    {
155
        if (empty($this->getBackendUser()->user['uid'])) {
156
            return new JsonExceptionResponse(new ControllerException('User is not logged in', 1554380677));
157
        }
158
        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
159
        return new JsonResponse([ (string)$uriBuilder->buildUriFromRoute('logout') ]);
160
    }
161
162
    /**
163
     * Set module state of BE user. Send a json array as ['data'] POST
164
     *
165
     * @param ServerRequestInterface $request
166
     * @return JsonResponse
167
     */
168
    public function setStateAction(ServerRequestInterface $request): JsonResponse
169
    {
170
        $backendUser = $this->getBackendUser();
171
        $backendUser->uc['digital_asset_management'] = $request->getParsedBody()['data'] ?? [];
172
        $backendUser->writeUC();
173
        return new JsonResponse();
174
    }
175
176
    /**
177
     * @return JsonResponse
178
     */
179
    public function getStateAction(): JsonResponse
180
    {
181
        return new JsonResponse([ 'data' => $this->getBackendUser()->uc['digital_asset_management'] ?? []]);
182
    }
183
184
    /**
185
     * @param ServerRequestInterface $request
186
     *
187
     * @return JsonResponse
188
     */
189
    public function createFolderAction(ServerRequestInterface $request): JsonResponse
190
    {
191
        $identifier = $request->getQueryParams()['identifier'] ?? '';
192
        if (empty($identifier)) {
193
            return new JsonExceptionResponse(new ControllerException('Identifier needed', 1554204780));
194
        }
195
        try {
196
            $folder = $this->createFolderRecursive($identifier);
197
            return new JsonResponse([new FolderItemFolder($folder)]);
198
        } catch (ResourceException $e) {
199
            return new JsonExceptionResponse($e);
200
        }
201
    }
202
203
    /**
204
     * @param ServerRequestInterface $request
205
     *
206
     * @return JsonResponse
207
     */
208
    public function fileUploadAction(ServerRequestInterface $request): JsonResponse
209
    {
210
        $identifier = $request->getQueryParams()['identifier'] ?? '';
211
        $conflictMode = $request->getQueryParams()['conflictMode'] ?? '';
212
        $tempFilename = '';
213
        try {
214
            if (empty($identifier)) {
215
                throw new ControllerException('Identifier needed', 1554132801);
216
            }
217
            if (empty($conflictMode) || !in_array($conflictMode, ['replace', 'cancel', 'rename'], true)) {
218
                throw new ControllerException('conflictMode must be one of "replace", "cancel", "rename"');
219
            }
220
            $folderIdentifier = dirname($identifier) . '/';
221
            $fileIdentifier = basename($identifier);
222
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
223
            try {
224
                $folder = $resourceFactory->retrieveFileOrFolderObject($folderIdentifier);
225
            } catch (ResourceDoesNotExistException $e) {
226
                $folder = $this->createFolderRecursive($folderIdentifier);
227
            }
228
            $tempFilename = tempnam(sys_get_temp_dir(), 'upload_');
229
            file_put_contents($tempFilename, $request->getBody());
230
            $file = $folder->addFile($tempFilename, $fileIdentifier, (string)DuplicationBehavior::cast($conflictMode));
231
            $fileExtension = strtolower($file->getExtension());
232
            if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)
233
                || GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['mediafile_ext'], $fileExtension)
234
            ) {
235
                return new JsonResponse([new FolderItemImage($file)]);
236
            }
237
            return new JsonResponse([new FolderItemFile($file)]);
238
        } catch (ResourceException $e) {
239
            if (!empty($tempFilename) && file_exists($tempFilename)) {
240
                unlink($tempFilename);
241
            }
242
            return new JsonExceptionResponse($e);
243
        } catch (ControllerException $e) {
244
            return new JsonExceptionResponse($e);
245
        }
246
    }
247
248
    /**
249
     * @param string $folderIdentifier
250
     *
251
     * @return Folder
252
     */
253
    protected function createFolderRecursive(string $folderIdentifier): Folder
254
    {
255
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
256
        $stack = [];
257
        while (true) {
258
            $parentName = dirname($folderIdentifier);
259
            $folderName = basename($folderIdentifier);
260
            $stack[] = $folderName;
261
            try {
262
                $parentObject = $resourceFactory->retrieveFileOrFolderObject($parentName);
263
                break;
264
            } catch (ResourceDoesNotExistException $e) {
265
                $folderIdentifier = $parentName;
266
            }
267
        }
268
        while ($folderName = array_pop($stack)) {
269
            try {
270
                $parentObject = $parentObject->createFolder($folderName);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parentObject does not seem to be defined for all execution paths leading up to this point.
Loading history...
271
            } catch (ResourceException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
272
            }
273
        }
274
        return $parentObject;
275
    }
276
277
    /**
278
     * @param ServerRequestInterface $request
279
     *
280
     * @return JsonResponse
281
     */
282
    public function fileExistsAction(ServerRequestInterface $request): JsonResponse
283
    {
284
        $identifier = $request->getQueryParams()['identifier'];
285
        if (empty($identifier)) {
286
            return new JsonExceptionResponse(new ControllerException('Identifier needed', 1554125449));
287
        }
288
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
289
        $folderIdentifier = dirname($identifier) . '/';
290
        $fileIdentifier = basename($identifier);
291
        try {
292
            $folder = $resourceFactory->retrieveFileOrFolderObject($folderIdentifier);
293
        } catch (ResourceDoesNotExistException $e) {
294
            return new FileExistsResponse(FileExistsResponse::PARENT_FOLDER_DOES_NOT_EXIST);
295
        }
296
        $fileName = $folder->getStorage()->sanitizeFileName($fileIdentifier, $folder);
297
        if ($folder->hasFile($fileName)) {
298
            $file = $resourceFactory->getFileObjectFromCombinedIdentifier($folderIdentifier . $fileName);
299
            // If file is an image or media, create image object, else file object
300
            $fileExtension = strtolower($file->getExtension());
301
            if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)
302
                || GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['mediafile_ext'], $fileExtension)
303
            ) {
304
                return new JsonResponse([new FolderItemImage($file)]);
305
            }
306
            return new JsonResponse([new FolderItemFile($file)]);
307
        } else {
308
            return new FileExistsResponse(FileExistsResponse::FILE_DOES_NOT_EXIST);
309
        }
310
    }
311
312
    /**
313
     * Return item list (folders, files, images) of a storage:path
314
     * FAL folder identifier. GET request with identifier argument.
315
     *
316
     * @param ServerRequestInterface $request
317
     *
318
     * @return JsonResponse
319
     */
320
    public function getFolderItemsAction(ServerRequestInterface $request): JsonResponse
321
    {
322
        try {
323
            $identifier = $request->getQueryParams()['identifier'] ?? '';
324
            if (empty($identifier)) {
325
                throw new ControllerException('Identifier needed', 1553699828);
326
            }
327
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
328
            $folderObject = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
329
            if (!$folderObject instanceof Folder) {
330
                throw new ControllerException('Identifier is not a folder', 1553701684);
331
            }
332
            $subFolders = $folderObject->getSubfolders();
333
            $folders = [];
334
            foreach ($subFolders as $subFolder) {
335
                $folders[] = new FolderItemFolder($subFolder);
336
            }
337
            $allFiles = $folderObject->getFiles();
338
            $files = [];
339
            $images = [];
340
            foreach ($allFiles as $file) {
341
                // If file is an image or media, create image object, else file object
342
                $fileExtension = strtolower($file->getExtension());
343
                if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)
344
                    || GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['mediafile_ext'], $fileExtension)
345
                ) {
346
                    $images[] = new FolderItemImage($file);
347
                } else {
348
                    $files[] = new FolderItemFile($file);
349
                }
350
            }
351
            return new FolderItemsResponse($folders, $files, $images);
352
        } catch (ResourceException $e) {
353
            return new JsonExceptionResponse($e);
354
        } catch (ControllerException $e) {
355
            return new JsonExceptionResponse($e);
356
        }
357
    }
358
359
    /**
360
     * Returns list of storages (admins), or file mounts (non-admin). Admins
361
     * do NOT receive a list of file mounts, just the storages.
362
     *
363
     * Storages are returned in no particular order, file mounts are ordered
364
     * by 'sorting' DB field.
365
     *
366
     * Return structure is an array of Storage or FileMount objects.
367
     *
368
     * @return JsonResponse
369
     */
370
    public function getStoragesAndMountsAction(): JsonResponse
371
    {
372
        $backendUser = $this->getBackendUser();
373
        $storages = $backendUser->getFileStorages();
374
        $entities = [];
375
        if ($backendUser->isAdmin()) {
376
            foreach ($storages as $storage) {
377
                $entities[] = new Storage($storage);
378
            }
379
        } else {
380
            foreach ($storages as $storage) {
381
                $fileMounts = $storage->getFileMounts();
382
                foreach ($fileMounts as $fileMount) {
383
                    $entities[] = new FileMount($storage, $fileMount);
384
                }
385
            }
386
        }
387
        return new StoragesAndMountsResponse($entities);
388
    }
389
390
    /**
391
     * Returns list of folders only. No files, no images
392
     * Result is sorted by name
393
     *
394
     * Return structure is an array of TreeItemFolder objects.
395
     *
396
     * @param ServerRequestInterface $request
397
     *
398
     * @return JsonResponse
399
     */
400
    public function getTreeFoldersAction(ServerRequestInterface $request): JsonResponse
401
    {
402
        try {
403
            $identifier = $request->getQueryParams()['identifier'] ?? '';
404
            if (empty($identifier)) {
405
                throw new ControllerException('Identifier needed', 1553699828);
406
            }
407
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
408
            $folderObject = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
409
            if (!$folderObject instanceof Folder) {
410
                throw new ControllerException('Identifier is not a folder', 1553701684);
411
            }
412
            $subFolders = $folderObject->getSubfolders();
413
            $folders = [];
414
            foreach ($subFolders as $subFolder) {
415
                $folders[] = new TreeItemFolder($subFolder);
416
            }
417
            return new JsonResponse($folders);
418
        } catch (ResourceException $e) {
419
            return new JsonExceptionResponse($e);
420
        } catch (ControllerException $e) {
421
            return new JsonExceptionResponse($e);
422
        }
423
    }
424
425
    /**
426
     * Copy files or folders
427
     * Query parameters
428
     *  'identifiers' array of identifier to copy
429
     *  'targetFolderIdentifier' string the target identifier. Must be a folder.
430
     *  'conflictMode' string one of: "replace", "cancel", "rename", as defined in \TYPO3\CMS\Core\Resource\DuplicationBehavior
431
     *
432
     * @param ServerRequestInterface $request
433
     *
434
     * @return JsonResponse
435
     */
436
    public function copyResourcesAction(ServerRequestInterface $request): JsonResponse
437
    {
438
        try {
439
            $identifiers = $request->getQueryParams()['identifiers'];
440
            $conflictMode = $request->getQueryParams()['conflictMode'] ?? '';
441
            $targetFolderIdentifier = $request->getQueryParams()['targetFolderIdentifier'];
442
            if (empty($identifiers)) {
443
                throw new ControllerException('Identifiers needed', 1553699828);
444
            }
445
            if (empty($conflictMode) || !in_array($conflictMode, ['replace', 'cancel', 'rename'], true)) {
446
                throw new ControllerException('conflictMode must be one of "replace", "cancel", "rename"');
447
            }
448
            if (empty($targetFolderIdentifier)) {
449
                throw new ControllerException(
450
                    'Target folder identifier needed',
451
                    1554122023
452
                );
453
            }
454
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
455
            $targetFolderObject = $resourceFactory->getObjectFromCombinedIdentifier($targetFolderIdentifier);
456
            if (!$targetFolderObject instanceof Folder) {
457
                throw new ControllerException('Target identifier is not a folder', 1553701684);
458
            }
459
        } catch (ResourceException $e) {
460
            return new JsonExceptionResponse($e);
461
        } catch (ControllerException $e) {
462
            return new JsonExceptionResponse($e);
463
        }
464
        $resources = [];
465
        foreach ($identifiers as $identifier) {
466
            $state = FileOperationResult::FAILED;
467
            $message = '';
468
            $resultEntity = null;
469
            try {
470
                $sourceObject = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
471
                if ($resultObject = $sourceObject->copyTo($targetFolderObject, null, (string)DuplicationBehavior::cast($conflictMode))) {
472
                    if ($resultObject instanceof Folder) {
473
                        $resultEntity = new FolderItemFolder($resultObject);
474
                    } else {
475
                        $resultEntity = new FolderItemFile($resultObject);
476
                    }
477
                    $state = FileOperationResult::COPIED;
478
                }
479
            } catch (InvalidTargetFolderException $e) {
480
                $message = $e->getMessage();
481
            } catch (ResourceException $e) {
482
                $message = $e->getMessage();
483
            }
484
            $resources[] = new FileOperationResult($identifier, $state, $message, $resultEntity);
485
        }
486
        return new FileOperationResponse($resources);
487
    }
488
489
    /**
490
     * Move files or folders
491
     * Query parameters
492
     *  'identifiers' array of identifier to move
493
     *  'targetFolderIdentifier' string the target identifier. Must be a folder.
494
     *  'conflictMode' string one of: "replace", "cancel", "rename", as defined in \TYPO3\CMS\Core\Resource\DuplicationBehavior
495
     *
496
     * @param ServerRequestInterface $request
497
     *
498
     * @return JsonResponse
499
     */
500
    public function moveResourcesAction(ServerRequestInterface $request): JsonResponse
501
    {
502
        try {
503
            $identifiers = $request->getQueryParams()['identifiers'];
504
            $conflictMode = $request->getQueryParams()['conflictMode'] ?? '';
505
            $targetFolderIdentifier = $request->getQueryParams()['targetFolderIdentifier'];
506
            if (empty($identifiers)) {
507
                throw new ControllerException('Identifiers needed', 1553699828);
508
            }
509
            if (empty($conflictMode) || !in_array($conflictMode, ['replace', 'cancel', 'rename'], true)) {
510
                throw new ControllerException('conflictMode must be one of "replace", "cancel", "rename"');
511
            }
512
            if (empty($targetFolderIdentifier)) {
513
                throw new ControllerException('Target folder identifier needed', 1554122023);
514
            }
515
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
516
            $targetFolderObject = $resourceFactory->getObjectFromCombinedIdentifier($targetFolderIdentifier);
517
            if (!$targetFolderObject instanceof Folder) {
518
                throw new ControllerException('Target identifier is not a folder', 1553701684);
519
            }
520
        } catch (ResourceException $e) {
521
            return new JsonExceptionResponse($e);
522
        } catch (ControllerException $e) {
523
            return new JsonExceptionResponse($e);
524
        }
525
        $resources = [];
526
        foreach ($identifiers as $identifier) {
527
            $state = FileOperationResult::FAILED;
528
            $message = '';
529
            $resultEntity = null;
530
            try {
531
                $sourceObject = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
532
                if ($resultObject = $sourceObject->moveTo($targetFolderObject, null, (string)DuplicationBehavior::cast($conflictMode))) {
533
                    if ($resultObject instanceof Folder) {
534
                        $resultEntity = new FolderItemFolder($resultObject);
535
                    } else {
536
                        $resultEntity = new FolderItemFile($resultObject);
537
                    }
538
                    $state = FileOperationResult::MOVED;
539
                }
540
            } catch (InvalidTargetFolderException $e) {
541
                $message = $e->getMessage();
542
            } catch (ResourceException $e) {
543
                $message = $e->getMessage();
544
            }
545
            $resources[] = new FileOperationResult($identifier, $state, $message, $resultEntity);
546
        }
547
        return new FileOperationResponse($resources);
548
    }
549
550
    /**
551
     * rename file or folder
552
     * Query parameters
553
     *  'identifier' string identifier to rename
554
     *  'targetName' string The new name of file or folder.
555
     *  'conflictMode' string one of: "replace", "cancel", "rename"
556
     *
557
     * @param ServerRequestInterface $request
558
     *
559
     * @return JsonResponse
560
     */
561
    public function renameResourcesAction(ServerRequestInterface $request): JsonResponse
562
    {
563
        try {
564
            $identifier = $request->getQueryParams()['identifier'];
565
            $targetName = $request->getQueryParams()['targetName'];
566
            $conflictMode = $request->getQueryParams()['conflictMode'] ?? '';
567
            if (empty($identifier)) {
568
                throw new ControllerException('Identifier needed', 1553699828);
569
            }
570
            if (empty($conflictMode) || !in_array($conflictMode, ['replace', 'cancel', 'rename'], true)) {
571
                throw new ControllerException('conflictMode must be one of "replace", "cancel", "rename"');
572
            }
573
            if (empty($targetName)) {
574
                throw new ControllerException('Target name needed', 1554193259);
575
            }
576
            $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
577
            $fileOrFolder = $resourceFactory->retrieveFileOrFolderObject($identifier);
578
        } catch (ResourceException $e) {
579
            return new JsonExceptionResponse($e);
580
        } catch (ControllerException $e) {
581
            return new JsonExceptionResponse($e);
582
        }
583
        $resources = [];
584
        $state = FileOperationResult::FAILED;
585
        $resultEntity = null;
586
        try {
587
            if ($fileOrFolder === null) {
588
                throw new ResourceException\ResourceDoesNotExistException('Resource does not exist');
589
            } else {
590
                $resultObject = $fileOrFolder->rename($targetName, (string)DuplicationBehavior::cast($conflictMode));
591
                if ($resultObject instanceof Folder) {
592
                    $resultEntity = new FolderItemFolder($resultObject);
593
                    $message = 'Folder was successfully renamed';
594
                } else {
595
                    $resultEntity = new FolderItemFile($resultObject);
596
                    $message = 'File was successfully renamed';
597
                }
598
                $state = FileOperationResult::RENAMED;
599
            }
600
        } catch (ResourceException $e) {
601
            $message = $e->getMessage();
602
        }
603
        $resources[] = new FileOperationResult($identifier, $state, $message, $resultEntity);
604
        return new JsonResponse($resources);
605
    }
606
607
    /**
608
     * delete file or folder
609
     * Query parameters
610
     *  'identifiers' array of strings identifier of file or folder to delete
611
     *
612
     * @param ServerRequestInterface $request
613
     *
614
     * @return JsonResponse
615
     */
616
    public function deleteResourcesAction(ServerRequestInterface $request): JsonResponse
617
    {
618
        try {
619
            $identifiers = $request->getQueryParams()['identifiers'];
620
            if (empty($identifiers)) {
621
                throw new ControllerException('Identifiers needed', 1553699828);
622
            }
623
        } catch (ControllerException $e) {
624
            return new JsonExceptionResponse($e);
625
        }
626
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
627
        $resources = [];
628
        foreach ($identifiers as $identifier) {
629
            try {
630
                $sourceObject = $resourceFactory->getObjectFromCombinedIdentifier($identifier);
631
                if ($sourceObject->delete(true)) {
632
                    $state = FileOperationResult::DELETED;
633
                    $message = 'Resource deleted';
634
                } else {
635
                    $state = FileOperationResult::FAILED;
636
                    $message = 'Resource could not be deleted';
637
                }
638
            } catch (ResourceException $e) {
639
                $state = FileOperationResult::FAILED;
640
                $message = $e->getMessage();
641
            }
642
            $resources[] = new FileOperationResult($identifier, $state, $message, null);
643
        }
644
        return new FileOperationResponse($resources);
645
    }
646
647
    /**
648
     * @return BackendUserAuthentication
649
     */
650
    protected function getBackendUser(): BackendUserAuthentication
651
    {
652
        return $GLOBALS['BE_USER'];
653
    }
654
}
655