Completed
Pull Request — master (#415)
by
unknown
02:29
created

AssetAdmin::getFileEditForm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Controller;
4
5
use Embed\Exceptions\InvalidUrlException;
6
use InvalidArgumentException;
7
use SilverStripe\AssetAdmin\Forms\FolderCreateFormFactory;
8
use SilverStripe\AssetAdmin\Forms\FolderFormFactory;
9
use SilverStripe\CampaignAdmin\AddToCampaignHandler;
10
use SilverStripe\Admin\CMSBatchActionHandler;
11
use SilverStripe\Admin\LeftAndMain;
12
use SilverStripe\AssetAdmin\BatchAction\DeleteAssets;
13
use SilverStripe\AssetAdmin\Forms\AssetFormFactory;
14
use SilverStripe\AssetAdmin\Forms\FileSearchFormFactory;
15
use SilverStripe\AssetAdmin\Forms\RemoteFileFormFactory;
16
use SilverStripe\AssetAdmin\Forms\UploadField;
17
use SilverStripe\AssetAdmin\Forms\FileFormFactory;
18
use SilverStripe\AssetAdmin\Forms\FileHistoryFormFactory;
19
use SilverStripe\AssetAdmin\Forms\ImageFormFactory;
20
use SilverStripe\Assets\File;
21
use SilverStripe\Assets\Folder;
22
use SilverStripe\Assets\Image;
23
use SilverStripe\Assets\Storage\AssetNameGenerator;
24
use SilverStripe\Assets\Upload;
25
use SilverStripe\Control\Controller;
26
use SilverStripe\Control\HTTPRequest;
27
use SilverStripe\Control\HTTPResponse;
28
use SilverStripe\Core\Injector\Injector;
29
use SilverStripe\Forms\FieldList;
30
use SilverStripe\Forms\Form;
31
use SilverStripe\Forms\FormFactory;
32
use SilverStripe\ORM\ArrayList;
33
use SilverStripe\ORM\DataObject;
34
use SilverStripe\ORM\FieldType\DBHTMLText;
35
use SilverStripe\ORM\ValidationResult;
36
use SilverStripe\Security\Member;
37
use SilverStripe\Security\PermissionProvider;
38
use SilverStripe\Security\SecurityToken;
39
use SilverStripe\View\Requirements;
40
use SilverStripe\Versioned\Versioned;
41
use Exception;
42
43
/**
44
 * AssetAdmin is the 'file store' section of the CMS.
45
 * It provides an interface for manipulating the File and Folder objects in the system.
46
 */
47
class AssetAdmin extends LeftAndMain implements PermissionProvider
48
{
49
    private static $url_segment = 'assets';
0 ignored issues
show
Unused Code introduced by
The property $url_segment is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
50
51
    private static $url_rule = '/$Action/$ID';
0 ignored issues
show
Unused Code introduced by
The property $url_rule is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
52
53
    private static $menu_title = 'Files';
0 ignored issues
show
Unused Code introduced by
The property $menu_title is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
54
55
    private static $menu_icon_class = 'font-icon-image';
0 ignored issues
show
Unused Code introduced by
The property $menu_icon_class is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
56
57
    private static $tree_class = 'SilverStripe\\Assets\\Folder';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $tree_class is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
58
59
    private static $url_handlers = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $url_handlers is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
60
        // Legacy redirect for SS3-style detail view
61
        'EditForm/field/File/item/$FileID/$Action' => 'legacyRedirectForEditView',
62
        // Pass all URLs to the index, for React to unpack
63
        'show/$FolderID/edit/$FileID' => 'index',
64
        // API access points with structured data
65
        'POST api/createFile' => 'apiCreateFile',
66
        'POST api/uploadFile' => 'apiUploadFile',
67
        'GET api/history' => 'apiHistory',
68
        // for validating before generating the schema
69
        'schemaWithValidate/$FormName' => 'schemaWithValidate'
70
    ];
71
72
    /**
73
     * Amount of results showing on a single page.
74
     *
75
     * @config
76
     * @var int
77
     */
78
    private static $page_length = 15;
0 ignored issues
show
Unused Code introduced by
The property $page_length is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
79
80
    /**
81
     * @config
82
     * @see Upload->allowedMaxFileSize
83
     * @var int
84
     */
85
    private static $allowed_max_file_size;
0 ignored issues
show
Unused Code introduced by
The property $allowed_max_file_size is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
86
87
    /**
88
     * @config
89
     *
90
     * @var int
91
     */
92
    private static $max_history_entries = 100;
0 ignored issues
show
Unused Code introduced by
The property $max_history_entries is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
93
94
    /**
95
     * @var array
96
     */
97
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
98
        'legacyRedirectForEditView',
99
        'apiCreateFile',
100
        'apiUploadFile',
101
        'apiHistory',
102
        'folderCreateForm',
103
        'fileEditForm',
104
        'fileHistoryForm',
105
        'addToCampaignForm',
106
        'fileInsertForm',
107
        'remoteEditForm',
108
        'remoteCreateForm',
109
        'schema',
110
        'fileSelectForm',
111
        'fileSearchForm',
112
        'schemaWithValidate',
113
    );
114
115
    private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $required_permission_codes is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
116
117
    private static $thumbnail_width = 400;
0 ignored issues
show
Unused Code introduced by
The property $thumbnail_width is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
118
119
    private static $thumbnail_height = 300;
0 ignored issues
show
Unused Code introduced by
The property $thumbnail_height is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
120
121
    /**
122
     * Set up the controller
123
     */
124
    public function init()
125
    {
126
        parent::init();
127
128
        Requirements::add_i18n_javascript(ASSET_ADMIN_DIR . '/client/lang', false, true);
129
        Requirements::javascript(ASSET_ADMIN_DIR . "/client/dist/js/bundle.js");
130
        Requirements::css(ASSET_ADMIN_DIR . "/client/dist/styles/bundle.css");
131
132
        CMSBatchActionHandler::register('delete', DeleteAssets::class, Folder::class);
133
    }
134
135
    public function getClientConfig()
136
    {
137
        $baseLink = $this->Link();
138
        return array_merge(parent::getClientConfig(), [
139
            'reactRouter' => true,
140
            'createFileEndpoint' => [
141
                'url' => Controller::join_links($baseLink, 'api/createFile'),
142
                'method' => 'post',
143
                'payloadFormat' => 'urlencoded',
144
            ],
145
            'uploadFileEndpoint' => [
146
                'url' => Controller::join_links($baseLink, 'api/uploadFile'),
147
                'method' => 'post',
148
                'payloadFormat' => 'urlencoded',
149
            ],
150
            'historyEndpoint' => [
151
                'url' => Controller::join_links($baseLink, 'api/history'),
152
                'method' => 'get',
153
                'responseFormat' => 'json',
154
            ],
155
            'limit' => $this->config()->page_length,
156
            'form' => [
157
                'fileEditForm' => [
158
                    'schemaUrl' => $this->Link('schema/fileEditForm')
159
                ],
160
                'fileInsertForm' => [
161
                    'schemaUrl' => $this->Link('schema/fileInsertForm')
162
                ],
163
                'remoteEditForm' => [
164
                    'schemaUrl' => $this->Link('schemaWithValidate/remoteEditForm')
165
                ],
166
                'remoteCreateForm' => [
167
                    'schemaUrl' => $this->Link('schema/remoteCreateForm')
168
                ],
169
                'fileSelectForm' => [
170
                    'schemaUrl' => $this->Link('schema/fileSelectForm')
171
                ],
172
                'addToCampaignForm' => [
173
                    'schemaUrl' => $this->Link('schema/addToCampaignForm')
174
                ],
175
                'fileHistoryForm' => [
176
                    'schemaUrl' => $this->Link('schema/fileHistoryForm')
177
                ],
178
                'fileSearchForm' => [
179
                    'schemaUrl' => $this->Link('schema/fileSearchForm')
180
                ],
181
                'folderCreateForm' => [
182
                    'schemaUrl' => $this->Link('schema/folderCreateForm')
183
                ],
184
            ],
185
        ]);
186
    }
187
188
    /**
189
     * Creates a single file based on a form-urlencoded upload.
190
     *
191
     * @param HTTPRequest $request
192
     * @return HTTPRequest|HTTPResponse
193
     */
194
    public function apiCreateFile(HTTPRequest $request)
195
    {
196
        $data = $request->postVars();
197
198
        // When creating new files, rename on conflict
199
        $upload = $this->getUpload();
200
        $upload->setReplaceFile(false);
201
202
        // CSRF check
203
        $token = SecurityToken::inst();
204 View Code Duplication
        if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
            return new HTTPResponse(null, 400);
206
        }
207
208
        // Check parent record
209
        /** @var Folder $parentRecord */
210
        $parentRecord = null;
211
        if (!empty($data['ParentID']) && is_numeric($data['ParentID'])) {
212
            $parentRecord = Folder::get()->byID($data['ParentID']);
213
        }
214
        $data['Parent'] = $parentRecord;
215
216
        $tmpFile = $request->postVar('Upload');
217 View Code Duplication
        if (!$upload->validate($tmpFile)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
218
            $result = ['message' => null];
219
            $errors = $upload->getErrors();
220
            if ($message = array_shift($errors)) {
221
                $result['message'] = [
222
                    'type' => 'error',
223
                    'value' => $message,
224
                ];
225
            }
226
            return (new HTTPResponse(json_encode($result), 400))
227
                ->addHeader('Content-Type', 'application/json');
228
        }
229
230
        // TODO Allow batch uploads
231
        $fileClass = File::get_class_for_file_extension(File::get_file_extension($tmpFile['name']));
232
        /** @var File $file */
233
        $file = Injector::inst()->create($fileClass);
234
235
        // check canCreate permissions
236 View Code Duplication
        if (!$file->canCreate(null, $data)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237
            $result = ['message' => [
238
                'type' => 'error',
239
                'value' => _t(
240
                    'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.CreatePermissionDenied',
241
                    'You do not have permission to add files'
242
                )
243
            ]];
244
            return (new HTTPResponse(json_encode($result), 403))
245
                ->addHeader('Content-Type', 'application/json');
246
        }
247
248
        $uploadResult = $upload->loadIntoFile($tmpFile, $file, $parentRecord ? $parentRecord->getFilename() : '/');
249 View Code Duplication
        if (!$uploadResult) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
250
            $result = ['message' => [
251
                'type' => 'error',
252
                'value' => _t(
253
                    'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.LoadIntoFileFailed',
254
                    'Failed to load file'
255
                )
256
            ]];
257
            return (new HTTPResponse(json_encode($result), 400))
258
                ->addHeader('Content-Type', 'application/json');
259
        }
260
261
        $file->ParentID = $parentRecord ? $parentRecord->ID : 0;
262
        $file->write();
263
264
        $result = [$this->getObjectFromData($file)];
265
266
        return (new HTTPResponse(json_encode($result)))
267
            ->addHeader('Content-Type', 'application/json');
268
    }
269
270
    /**
271
     * Upload a new asset for a pre-existing record. Returns the asset tuple.
272
     *
273
     * Note that conflict resolution is as follows:
274
     *  - If uploading a file with the same extension, we simply keep the same filename,
275
     *    and overwrite any existing files (same name + sha = don't duplicate).
276
     *  - If uploading a new file with a different extension, then the filename will
277
     *    be replaced, and will be checked for uniqueness against other File dataobjects.
278
     *
279
     * @param HTTPRequest $request Request containing vars 'ID' of parent record ID,
280
     * and 'Name' as form filename value
281
     * @return HTTPRequest|HTTPResponse
282
     */
283
    public function apiUploadFile(HTTPRequest $request)
284
    {
285
        $data = $request->postVars();
286
287
        // When updating files, replace on conflict
288
        $upload = $this->getUpload();
289
        $upload->setReplaceFile(true);
290
291
        // CSRF check
292
        $token = SecurityToken::inst();
293 View Code Duplication
        if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
            return new HTTPResponse(null, 400);
295
        }
296
        $tmpFile = $data['Upload'];
297
        if (empty($data['ID']) || empty($tmpFile['name']) || !array_key_exists('Name', $data)) {
298
            return new HTTPResponse('Invalid request', 400);
299
        }
300
301
        // Check parent record
302
        /** @var File $file */
303
        $file = File::get()->byID($data['ID']);
304
        if (!$file) {
305
            return new HTTPResponse('File not found', 404);
306
        }
307
        $folder = $file->ParentID ? $file->Parent()->getFilename() : '/';
308
309
        // If extension is the same, attempt to re-use existing name
310
        if (File::get_file_extension($tmpFile['name']) === File::get_file_extension($data['Name'])) {
311
            $tmpFile['name'] = $data['Name'];
312
        } else {
313
            // If we are allowing this upload to rename the underlying record,
314
            // do a uniqueness check.
315
            $renamer = $this->getNameGenerator($tmpFile['name']);
316
            foreach ($renamer as $name) {
317
                $filename = File::join_paths($folder, $name);
318
                if (!File::find($filename)) {
319
                    $tmpFile['name'] = $name;
320
                    break;
321
                }
322
            }
323
        }
324
325 View Code Duplication
        if (!$upload->validate($tmpFile)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
326
            $result = ['message' => null];
327
            $errors = $upload->getErrors();
328
            if ($message = array_shift($errors)) {
329
                $result['message'] = [
330
                    'type' => 'error',
331
                    'value' => $message,
332
                ];
333
            }
334
            return (new HTTPResponse(json_encode($result), 400))
335
                ->addHeader('Content-Type', 'application/json');
336
        }
337
338
        try {
339
            $tuple = $upload->load($tmpFile, $folder);
340
        } catch (Exception $e) {
341
            $result = [
342
                'message' => [
343
                    'type' => 'error',
344
                    'value' => $e->getMessage(),
345
                ]
346
            ];
347
            return (new HTTPResponse(json_encode($result), 400))
348
                ->addHeader('Content-Type', 'application/json');
349
        }
350
351
        if ($upload->isError()) {
352
            $result['message'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
353
                'type' => 'error',
354
                'value' => implode(' ' . PHP_EOL, $upload->getErrors()),
355
            ];
356
            return (new HTTPResponse(json_encode($result), 400))
357
                ->addHeader('Content-Type', 'application/json');
358
        }
359
360
        $tuple['Name'] = basename($tuple['Filename']);
361
        return (new HTTPResponse(json_encode($tuple)))
362
            ->addHeader('Content-Type', 'application/json');
363
    }
364
365
    /**
366
     * Returns a JSON array for history of a given file ID. Returns a list of all the history.
367
     *
368
     * @param HTTPRequest $request
369
     * @return HTTPResponse
370
     */
371
    public function apiHistory(HTTPRequest $request)
372
    {
373
        // CSRF check not required as the GET request has no side effects.
374
        $fileId = $request->getVar('fileId');
375
376
        if (!$fileId || !is_numeric($fileId)) {
377
            return new HTTPResponse(null, 400);
378
        }
379
380
        $class = File::class;
381
        $file = DataObject::get($class)->byID($fileId);
382
383
        if (!$file) {
384
            return new HTTPResponse(null, 404);
385
        }
386
387
        if (!$file->canView()) {
388
            return new HTTPResponse(null, 403);
389
        }
390
391
        $versions = Versioned::get_all_versions($class, $fileId)
392
            ->limit($this->config()->max_history_entries)
393
            ->sort('Version', 'DESC');
394
395
        $output = array();
396
        $next = array();
397
        $prev = null;
398
399
        // swap the order so we can get the version number to compare against.
400
        // i.e version 3 needs to know version 2 is the previous version
401
        $copy = $versions->map('Version', 'Version')->toArray();
402
        foreach (array_reverse($copy) as $k => $v) {
403
            if ($prev) {
404
                $next[$v] = $prev;
405
            }
406
407
            $prev = $v;
408
        }
409
410
        $_cachedMembers = array();
411
412
        /** @var File $version */
413
        foreach ($versions as $version) {
414
            $author = null;
415
416
            if ($version->AuthorID) {
417
                if (!isset($_cachedMembers[$version->AuthorID])) {
418
                    $_cachedMembers[$version->AuthorID] = DataObject::get(Member::class)
419
                        ->byID($version->AuthorID);
420
                }
421
422
                $author = $_cachedMembers[$version->AuthorID];
423
            }
424
425
            if ($version->canView()) {
426
                if (isset($next[$version->Version])) {
427
                    $summary = $version->humanizedChanges(
428
                        $version->Version,
429
                        $next[$version->Version]
430
                    );
431
432
                    // if no summary returned by humanizedChanges, i.e we cannot work out what changed, just show a
433
                    // generic message
434
                    if (!$summary) {
435
                        $summary = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.SAVEDFILE', "Saved file");
436
                    }
437
                } else {
438
                    $summary = _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.UPLOADEDFILE', "Uploaded file");
439
                }
440
441
                $output[] = array(
442
                    'versionid' => $version->Version,
443
                    'date_ago' => $version->dbObject('LastEdited')->Ago(),
444
                    'date_formatted' => $version->dbObject('LastEdited')->Nice(),
445
                    'status' => ($version->WasPublished) ? _t('File.PUBLISHED', 'Published') : '',
446
                    'author' => ($author)
447
                        ? $author->Name
448
                        : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.UNKNOWN', "Unknown"),
449
                    'summary' => ($summary)
450
                        ? $summary
451
                        : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.NOSUMMARY', "No summary available")
452
                );
453
            }
454
        }
455
456
        return
457
            (new HTTPResponse(json_encode($output)))->addHeader('Content-Type', 'application/json');
458
    }
459
460
    /**
461
     * Redirects 3.x style detail links to new 4.x style routing.
462
     *
463
     * @param HTTPRequest $request
464
     */
465
    public function legacyRedirectForEditView($request)
466
    {
467
        $fileID = $request->param('FileID');
468
        /** @var File $file */
469
        $file = File::get()->byID($fileID);
470
        $link = $this->getFileEditLink($file) ?: $this->Link();
471
        $this->redirect($link);
472
    }
473
474
    /**
475
     * Given a file return the CMS link to edit it
476
     *
477
     * @param File $file
478
     * @return string
479
     */
480
    public function getFileEditLink($file)
481
    {
482
        if (!$file || !$file->isInDB()) {
483
            return null;
484
        }
485
486
        return Controller::join_links(
487
            $this->Link('show'),
488
            $file->ParentID,
489
            'edit',
490
            $file->ID
491
        );
492
    }
493
494
    /**
495
     * Get an asset renamer for the given filename.
496
     *
497
     * @param  string             $filename Path name
498
     * @return AssetNameGenerator
499
     */
500
    protected function getNameGenerator($filename)
501
    {
502
        return Injector::inst()
503
            ->createWithArgs('AssetNameGenerator', array($filename));
504
    }
505
506
    /**
507
     * @todo Implement on client
508
     *
509
     * @param bool $unlinked
510
     * @return ArrayList
511
     */
512
    public function breadcrumbs($unlinked = false)
513
    {
514
        return null;
515
    }
516
517
518
    /**
519
     * Don't include class namespace in auto-generated CSS class
520
     */
521
    public function baseCSSClasses()
522
    {
523
        return 'AssetAdmin LeftAndMain';
524
    }
525
526
    public function providePermissions()
527
    {
528
        return array(
529
            "CMS_ACCESS_AssetAdmin" => array(
530
                'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array(
531
                    'title' => static::menu_title()
532
                )),
533
                'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
534
            )
535
        );
536
    }
537
538
    /**
539
     * Build a form scaffolder for this model
540
     *
541
     * NOTE: Volatile api. May be moved to {@see LeftAndMain}
542
     *
543
     * @param File $file
544
     * @return FormFactory
545
     */
546
    public function getFormFactory(File $file)
547
    {
548
        // Get service name based on file class
549
        $name = null;
0 ignored issues
show
Unused Code introduced by
$name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
550
        if ($file instanceof Folder) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\Assets\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
551
            $name = FolderFormFactory::class;
552
        } elseif ($file instanceof Image) {
0 ignored issues
show
Bug introduced by
The class SilverStripe\Assets\Image does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
553
            $name = ImageFormFactory::class;
554
        } else {
555
            $name = FileFormFactory::class;
556
        }
557
        return Injector::inst()->get($name);
558
    }
559
560
    /**
561
     * The form is used to generate a form schema,
562
     * as well as an intermediary object to process data through API endpoints.
563
     * Since it's used directly on API endpoints, it does not have any form actions.
564
     * It handles both {@link File} and {@link Folder} records.
565
     *
566
     * @param int $id
567
     * @return Form
568
     */
569
    public function getFileEditForm($id)
570
    {
571
        return $this->getAbstractFileForm($id, 'fileEditForm');
572
    }
573
574
    /**
575
     * Get file edit form
576
     *
577
     * @return Form
578
     */
579 View Code Duplication
    public function fileEditForm()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
580
    {
581
        // Get ID either from posted back value, or url parameter
582
        $request = $this->getRequest();
583
        $id = $request->param('ID') ?: $request->postVar('ID');
584
        return $this->getFileEditForm($id);
585
    }
586
587
    /**
588
     * The form is used to generate a form schema,
589
     * as well as an intermediary object to process data through API endpoints.
590
     * Since it's used directly on API endpoints, it does not have any form actions.
591
     * It handles both {@link File} and {@link Folder} records.
592
     *
593
     * @param int $id
594
     * @return Form
595
     */
596
    public function getFileInsertForm($id)
597
    {
598
        return $this->getAbstractFileForm($id, 'fileInsertForm', [ 'Type' => AssetFormFactory::TYPE_INSERT ]);
599
    }
600
601
    /**
602
     * Get file insert form
603
     *
604
     * @return Form
605
     */
606 View Code Duplication
    public function fileInsertForm()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
607
    {
608
        // Get ID either from posted back value, or url parameter
609
        $request = $this->getRequest();
610
        $id = $request->param('ID') ?: $request->postVar('ID');
611
        return $this->getFileInsertForm($id);
612
    }
613
614
    /**
615
     * Abstract method for generating a form for a file
616
     *
617
     * @param int $id Record ID
618
     * @param string $name Form name
619
     * @param array $context Form context
620
     * @return Form
621
     */
622
    protected function getAbstractFileForm($id, $name, $context = [])
623
    {
624
        /** @var File $file */
625
        $file = File::get()->byID($id);
626
627 View Code Duplication
        if (!$file->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
628
            $this->httpError(403, _t(
629
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
630
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
631
                '',
632
                ['ObjectTitle' => $file->i18n_singular_name()]
633
            ));
634
            return null;
635
        }
636
637
        // Pass to form factory
638
        $augmentedContext = array_merge($context, ['Record' => $file]);
639
        $scaffolder = $this->getFormFactory($file);
640
        $form = $scaffolder->getForm($this, $name, $augmentedContext);
641
642
        // Configure form to respond to validation errors with form schema
643
        // if requested via react.
644
        $form->setValidationResponseCallback(function (ValidationResult $error) use ($form, $id, $name) {
645
            $schemaId = Controller::join_links($this->Link('schema'), $name, $id);
646
            return $this->getSchemaResponse($schemaId, $form, $error);
647
        });
648
649
        return $form;
650
    }
651
652
    /**
653
     * Get form for selecting a file
654
     *
655
     * @return Form
656
     */
657
    public function fileSelectForm()
658
    {
659
        // Get ID either from posted back value, or url parameter
660
        $request = $this->getRequest();
661
        $id = $request->param('ID') ?: $request->postVar('ID');
662
        return $this->getFileSelectForm($id);
663
    }
664
665
    /**
666
     * Get form for selecting a file
667
     *
668
     * @param int $id ID of the record being selected
669
     * @return Form
670
     */
671
    public function getFileSelectForm($id)
672
    {
673
        return $this->getAbstractFileForm($id, 'fileSelectForm', [ 'Type' => AssetFormFactory::TYPE_SELECT ]);
674
    }
675
676
    /**
677
     * @param array $context
678
     * @return Form
679
     * @throws InvalidArgumentException
680
     */
681
    public function getFileHistoryForm($context)
682
    {
683
        // Check context
684
        if (!isset($context['RecordID']) || !isset($context['RecordVersion'])) {
685
            throw new InvalidArgumentException("Missing RecordID / RecordVersion for this form");
686
        }
687
        $id = $context['RecordID'];
688
        $versionId = $context['RecordVersion'];
689
        if (!$id || !$versionId) {
690
            return $this->httpError(404);
691
        }
692
693
        /** @var File $file */
694
        $file = Versioned::get_version(File::class, $id, $versionId);
695
        if (!$file) {
696
            return $this->httpError(404);
697
        }
698
699 View Code Duplication
        if (!$file->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
700
            $this->httpError(403, _t(
701
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
702
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
703
                '',
704
                ['ObjectTitle' => $file->i18n_singular_name()]
705
            ));
706
            return null;
707
        }
708
709
        $effectiveContext = array_merge($context, ['Record' => $file]);
710
        /** @var FormFactory $scaffolder */
711
        $scaffolder = Injector::inst()->get(FileHistoryFormFactory::class);
712
        $form = $scaffolder->getForm($this, 'fileHistoryForm', $effectiveContext);
713
714
        // Configure form to respond to validation errors with form schema
715
        // if requested via react.
716 View Code Duplication
        $form->setValidationResponseCallback(function (ValidationResult $errors) use ($form, $id, $versionId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
717
            $schemaId = Controller::join_links($this->Link('schema/fileHistoryForm'), $id, $versionId);
718
            return $this->getSchemaResponse($schemaId, $form, $errors);
719
        });
720
721
        return $form;
722
    }
723
724
    /**
725
     * Gets a JSON schema representing the current edit form.
726
     *
727
     * WARNING: Experimental API.
728
     *
729
     * @param HTTPRequest $request
730
     * @return HTTPResponse
731
     */
732
    public function schema($request)
733
    {
734
        $formName = $request->param('FormName');
735
        if ($formName !== 'fileHistoryForm') {
736
            return parent::schema($request);
737
        }
738
739
        // Get schema for history form
740
        // @todo Eventually all form scaffolding will be based on context rather than record ID
741
        // See https://github.com/silverstripe/silverstripe-framework/issues/6362
742
        $itemID = $request->param('ItemID');
743
        $version = $request->param('OtherItemID');
744
        $form = $this->getFileHistoryForm([
745
            'RecordID' => $itemID,
746
            'RecordVersion' => $version,
747
        ]);
748
749
        // Respond with this schema
750
        $response = $this->getResponse();
751
        $response->addHeader('Content-Type', 'application/json');
752
        $schemaID = $this->getRequest()->getURL();
753
        return $this->getSchemaResponse($schemaID, $form);
754
    }
755
756
    /**
757
     * Get file history form
758
     *
759
     * @return Form
760
     */
761
    public function fileHistoryForm()
762
    {
763
        $request = $this->getRequest();
764
        $id = $request->param('ID') ?: $request->postVar('ID');
765
        $version = $request->param('OtherID') ?: $request->postVar('Version');
766
        $form = $this->getFileHistoryForm([
767
            'RecordID' => $id,
768
            'RecordVersion' => $version,
769
        ]);
770
        return $form;
771
    }
772
    
773
    /**
774
     * @param array $data
775
     * @param Form $form
776
     * @return HTTPResponse
777
     */
778
    public function createfolder($data, $form)
779
    {
780
        $parentID = isset($data['ParentID']) ? intval($data['ParentID']) : 0;
781
        $data['Parent'] = null;
782
        if ($parentID) {
783
            $parent = Folder::get()->byID($parentID);
784
            if (!$parent) {
785
                throw new \InvalidArgumentException(sprintf(
786
                    '%s#%s not found',
787
                    Folder::class,
788
                    $parentID
789
                ));
790
            }
791
            $data['Parent'] = $parent;
792
        }
793
    
794
        // Check permission
795
        if (!Folder::singleton()->canCreate(Member::currentUser(), $data)) {
796
            throw new \InvalidArgumentException(sprintf(
797
                '%s create not allowed',
798
                Folder::class
799
            ));
800
        }
801
    
802
        $folder = Folder::create();
803
        $form->saveInto($folder);
804
        $folder->write();
805
    
806
        // Return the record data in the same response as the schema to save a postback
807
        $schemaData = ['record' => $this->getObjectFromData($folder)];
808
        $schemaId = Controller::join_links($this->Link('schema/folderCreateForm'), $folder->ID);
809
        return $this->getSchemaResponse($schemaId, $form, null, $schemaData);
810
    }
811
    
812
    /**
813
     * @param array $data
814
     * @param Form $form
815
     * @return HTTPResponse
816
     */
817
    public function save($data, $form)
818
    {
819
        return $this->saveOrPublish($data, $form, false);
820
    }
821
822
    /**
823
     * @param array $data
824
     * @param Form $form
825
     * @return HTTPResponse
826
     */
827
    public function publish($data, $form)
828
    {
829
        return $this->saveOrPublish($data, $form, true);
830
    }
831
832
    /**
833
     * Update thisrecord
834
     *
835
     * @param array $data
836
     * @param Form $form
837
     * @param bool $doPublish
838
     * @return HTTPResponse
839
     */
840
    protected function saveOrPublish($data, $form, $doPublish = false)
841
    {
842 View Code Duplication
        if (!isset($data['ID']) || !is_numeric($data['ID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
843
            return (new HTTPResponse(json_encode(['status' => 'error']), 400))
844
                ->addHeader('Content-Type', 'application/json');
845
        }
846
847
        $id = (int) $data['ID'];
848
        /** @var File $record */
849
        $record = DataObject::get_by_id(File::class, $id);
850
851
        if (!$record) {
852
            return (new HTTPResponse(json_encode(['status' => 'error']), 404))
853
                ->addHeader('Content-Type', 'application/json');
854
        }
855
856
        if (!$record->canEdit() || ($doPublish && !$record->canPublish())) {
857
            return (new HTTPResponse(json_encode(['status' => 'error']), 401))
858
                ->addHeader('Content-Type', 'application/json');
859
        }
860
861
        // check File extension
862
        if (!empty($data['FileFilename'])) {
863
            $extension = File::get_file_extension($data['FileFilename']);
864
            $newClass = File::get_class_for_file_extension($extension);
865
866
            // if the class has changed, cast it to the proper class
867
            if ($record->getClassName() !== $newClass) {
868
                $record = $record->newClassInstance($newClass);
869
870
                // update the allowed category for the new file extension
871
                $category = File::get_app_category($extension);
872
                $record->File->setAllowedCategories($category);
873
            }
874
        }
875
876
        $form->saveInto($record);
877
        $record->write();
878
879
        // Publish this record and owned objects
880
        if ($doPublish) {
881
            $record->publishRecursive();
882
        }
883
884
        // Note: Force return of schema / state in success result
885
        return $this->getRecordUpdatedResponse($record, $form);
886
    }
887
888
    public function unpublish($data, $form)
889
    {
890 View Code Duplication
        if (!isset($data['ID']) || !is_numeric($data['ID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
891
            return (new HTTPResponse(json_encode(['status' => 'error']), 400))
892
                ->addHeader('Content-Type', 'application/json');
893
        }
894
895
        $id = (int) $data['ID'];
896
        /** @var File $record */
897
        $record = DataObject::get_by_id(File::class, $id);
898
899
        if (!$record) {
900
            return (new HTTPResponse(json_encode(['status' => 'error']), 404))
901
                ->addHeader('Content-Type', 'application/json');
902
        }
903
904
        if (!$record->canUnpublish()) {
905
            return (new HTTPResponse(json_encode(['status' => 'error']), 401))
906
                ->addHeader('Content-Type', 'application/json');
907
        }
908
909
        $record->doUnpublish();
910
        return $this->getRecordUpdatedResponse($record, $form);
911
    }
912
913
    /**
914
     * @param File $file
915
     *
916
     * @return array
917
     */
918
    public function getObjectFromData(File $file)
919
    {
920
        $object = array(
921
            'id' => $file->ID,
922
            'created' => $file->Created,
923
            'lastUpdated' => $file->LastEdited,
924
            'owner' => null,
925
            'parent' => null,
926
            'title' => $file->Title,
927
            'exists' => $file->exists(), // Broken file check
928
            'type' => $file instanceof Folder ? 'folder' : $file->FileType,
0 ignored issues
show
Bug introduced by
The class SilverStripe\Assets\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
929
            'category' => $file instanceof Folder ? 'folder' : $file->appCategory(),
0 ignored issues
show
Bug introduced by
The class SilverStripe\Assets\Folder does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
930
            'name' => $file->Name,
931
            'filename' => $file->Filename,
932
            'extension' => $file->Extension,
933
            'size' => $file->AbsoluteSize,
934
            'url' => $file->AbsoluteURL,
935
            'published' => $file->isPublished(),
936
            'modified' => $file->isModifiedOnDraft(),
937
            'draft' => $file->isOnDraftOnly(),
938
            'canEdit' => $file->canEdit(),
939
            'canDelete' => $file->canArchive(),
940
        );
941
942
        /** @var Member $owner */
943
        $owner = $file->Owner();
944
945
        if ($owner) {
946
            $object['owner'] = array(
947
                'id' => $owner->ID,
948
                'title' => trim($owner->FirstName . ' ' . $owner->Surname),
949
            );
950
        }
951
952
        /** @var Folder $parent */
953
        $parent = $file->Parent();
954
955
        if ($parent) {
956
            $object['parent'] = array(
957
                'id' => $parent->ID,
958
                'title' => $parent->Title,
959
                'filename' => $parent->Filename,
960
            );
961
        }
962
963
        /** @var File $file */
964
        if ($file->getIsImage()) {
965
            // Small thumbnail
966
            $smallWidth = UploadField::config()->uninherited('thumbnail_width');
967
            $smallHeight = UploadField::config()->uninherited('thumbnail_height');
968
            $smallThumbnail = $file->FitMax($smallWidth, $smallHeight);
969
            if ($smallThumbnail && $smallThumbnail->exists()) {
970
                $object['smallThumbnail'] = $smallThumbnail->getAbsoluteURL();
971
            }
972
973
            // Large thumbnail
974
            $width = $this->config()->get('thumbnail_width');
975
            $height = $this->config()->get('thumbnail_height');
976
            $thumbnail = $file->FitMax($width, $height);
977
            if ($thumbnail && $thumbnail->exists()) {
978
                $object['thumbnail'] = $thumbnail->getAbsoluteURL();
979
            }
980
            $object['width'] = $file->Width;
981
            $object['height'] = $file->Height;
982
        } else {
983
            $object['thumbnail'] = $file->PreviewLink();
984
        }
985
986
        return $object;
987
    }
988
989
    /**
990
     * Action handler for adding pages to a campaign
991
     *
992
     * @param array $data
993
     * @param Form $form
994
     * @return DBHTMLText|HTTPResponse
995
     */
996
    public function addtocampaign($data, $form)
997
    {
998
        $id = $data['ID'];
999
        $record = File::get()->byID($id);
1000
1001
        $handler = AddToCampaignHandler::create($this, $record, 'addToCampaignForm');
1002
        $results = $handler->addToCampaign($record, $data['Campaign']);
1003
        if (!isset($results)) {
1004
            return null;
1005
        }
1006
1007
        // Send extra "message" data with schema response
1008
        $extraData = ['message' => $results];
1009
        $schemaId = Controller::join_links($this->Link('schema/addToCampaignForm'), $id);
1010
        return $this->getSchemaResponse($schemaId, $form, null, $extraData);
1011
    }
1012
1013
    /**
1014
     * Url handler for add to campaign form
1015
     *
1016
     * @param HTTPRequest $request
1017
     * @return Form
1018
     */
1019
    public function addToCampaignForm($request)
1020
    {
1021
        // Get ID either from posted back value, or url parameter
1022
        $id = $request->param('ID') ?: $request->postVar('ID');
1023
        return $this->getAddToCampaignForm($id);
1024
    }
1025
1026
    /**
1027
     * @param int $id
1028
     * @return Form
1029
     */
1030
    public function getAddToCampaignForm($id)
1031
    {
1032
        // Get record-specific fields
1033
        $record = File::get()->byID($id);
1034
1035
        if (!$record) {
1036
            $this->httpError(404, _t(
1037
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorNotFound',
1038
                'That {Type} couldn\'t be found',
1039
                '',
1040
                ['Type' => File::singleton()->i18n_singular_name()]
1041
            ));
1042
            return null;
1043
        }
1044 View Code Duplication
        if (!$record->canView()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1045
            $this->httpError(403, _t(
1046
                'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ErrorItemPermissionDenied',
1047
                'You don\'t have the necessary permissions to modify {ObjectTitle}',
1048
                '',
1049
                ['ObjectTitle' => $record->i18n_singular_name()]
1050
            ));
1051
            return null;
1052
        }
1053
1054
        $handler = AddToCampaignHandler::create($this, $record, 'addToCampaignForm');
1055
        $form = $handler->Form($record);
1056
1057 View Code Duplication
        $form->setValidationResponseCallback(function (ValidationResult $errors) use ($form, $id) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1058
            $schemaId = Controller::join_links($this->Link('schema/addToCampaignForm'), $id);
1059
            return $this->getSchemaResponse($schemaId, $form, $errors);
1060
        });
1061
1062
        return $form;
1063
    }
1064
1065
    /**
1066
     * @return Upload
1067
     */
1068
    protected function getUpload()
1069
    {
1070
        $upload = Upload::create();
1071
        $upload->getValidator()->setAllowedExtensions(
1072
            // filter out '' since this would be a regex problem on JS end
1073
            array_filter(File::config()->uninherited('allowed_extensions'))
1074
        );
1075
1076
        return $upload;
1077
    }
1078
1079
    /**
1080
     * Get response for successfully updated record
1081
     *
1082
     * @param File $record
1083
     * @param Form $form
1084
     * @return HTTPResponse
1085
     */
1086
    protected function getRecordUpdatedResponse($record, $form)
1087
    {
1088
        // Return the record data in the same response as the schema to save a postback
1089
        $schemaData = ['record' => $this->getObjectFromData($record)];
1090
        $schemaId = Controller::join_links($this->Link('schema/fileEditForm'), $record->ID);
1091
        return $this->getSchemaResponse($schemaId, $form, null, $schemaData);
1092
    }
1093
    
1094
    /**
1095
     * @return Form
1096
     */
1097
    public function folderCreateForm()
1098
    {
1099
        // Get ID either from posted back value, or url parameter
1100
        $request = $this->getRequest();
1101
        $id = $request->param('ID') ?: 0;
1102
        return $this->getFolderCreateForm($id);
1103
    }
1104
    
1105
    /**
1106
     * Returns the form to be used for creating a new folder
1107
     * @param $parentId
1108
     * @return Form
1109
     */
1110
    public function getFolderCreateForm($parentId = 0)
1111
    {
1112
        $factory = Injector::inst()->get(FolderCreateFormFactory::class);
1113
        $form = $factory->getForm($this, 'folderCreateForm', [ 'ParentID' => $parentId ]);
1114
        
1115
        return $form;
1116
    }
1117
    
1118
    /**
1119
     * Scaffold a search form.
1120
     * Note: This form does not submit to itself, but rather uses the apiReadFolder endpoint
1121
     * (to be replaced with graphql)
1122
     *
1123
     * @return Form
1124
     */
1125
    public function fileSearchForm()
1126
    {
1127
        $scaffolder = FileSearchFormFactory::singleton();
1128
        return $scaffolder->getForm($this, 'fileSearchForm', []);
1129
    }
1130
1131
    /**
1132
     * Allow search form to be accessible to schema
1133
     *
1134
     * @return Form
1135
     */
1136
    public function getFileSearchform()
1137
    {
1138
        return $this->fileSearchForm();
1139
    }
1140
    
1141
    /**
1142
     * Form for creating a new OEmbed object in the WYSIWYG, used by the InsertEmbedModal component
1143
     *
1144
     * @param null $id
1145
     * @return mixed
1146
     */
1147
    public function getRemoteCreateForm($id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1148
    {
1149
        return Injector::inst()->get(RemoteFileFormFactory::class)
1150
            ->getForm($this, 'remoteCreateForm', ['type' => 'create']);
1151
    }
1152
    
1153
    /**
1154
     * Allow form to be accessible for schema
1155
     *
1156
     * @return mixed
1157
     */
1158
    public function remoteCreateForm()
1159
    {
1160
        return $this->getRemoteCreateForm();
1161
    }
1162
    
1163
    /**
1164
     * Form for editing a OEmbed object in the WYSIWYG, used by the InsertEmbedModal component
1165
     *
1166
     * @return mixed
1167
     */
1168
    public function getRemoteEditForm()
1169
    {
1170
        $url = $this->request->requestVar('embedurl');
1171
        $form = null;
0 ignored issues
show
Unused Code introduced by
$form is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1172
        $form = Injector::inst()->get(RemoteFileFormFactory::class)
1173
            ->getForm($this, 'remoteEditForm', ['type' => 'edit', 'url' => $url]);
1174
        return $form;
1175
    }
1176
    
1177
    /**
1178
     * Allow form to be accessible for schema
1179
     *
1180
     * @return mixed
1181
     */
1182
    public function remoteEditForm()
1183
    {
1184
        return $this->getRemoteEditForm();
1185
    }
1186
    
1187
    /**
1188
     * Capture the schema handling process, as there is validation done to the URL provided before form is generated
1189
     *
1190
     * @param $request
1191
     * @return HTTPResponse
1192
     */
1193
    public function schemaWithValidate(HTTPRequest $request)
1194
    {
1195
        $formName = $request->param('FormName');
1196
        $itemID = $request->param('ItemID');
1197
    
1198
        if (!$formName) {
1199
            return (new HTTPResponse('Missing request params', 400));
1200
        }
1201
    
1202
        $formMethod = "get{$formName}";
1203
        if (!$this->hasMethod($formMethod)) {
1204
            var_dump($formMethod);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($formMethod); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
1205
            return (new HTTPResponse('Form not found', 404));
1206
        }
1207
    
1208
        if (!$this->hasAction($formName)) {
1209
            return (new HTTPResponse('Form not accessible', 401));
1210
        }
1211
    
1212
        $schemaID = $request->getURL();
1213
        try {
1214
            if ($itemID) {
1215
                $form = $this->{$formMethod}($itemID);
1216
            } else {
1217
                $form = $this->{$formMethod}();
1218
            }
1219
            return $this->getSchemaResponse($schemaID, $form);
1220
        } catch (InvalidUrlException $exception) {
1221
            $errors = ValidationResult::create()
1222
                ->addError($exception->getMessage());
1223
            $form = Form::create(null, 'Form', FieldList::create(), FieldList::create());
1224
            $code = $exception->getCode();
1225
            
1226
            if ($code < 300) {
1227
                $code = 500;
1228
            }
1229
            
1230
            return $this->getSchemaResponse($schemaID, $form, $errors)
1231
                ->setStatusCode($code);
1232
        }
1233
    }
1234
}
1235