Passed
Push — master ( 5de4ab...45fc26 )
by Greg
06:02
created

EditMediaController::addMediaFileAction()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 17
nc 3
nop 1
dl 0
loc 33
rs 9.3888
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Http\Controllers;
21
22
use Exception;
23
use Fig\Http\Message\StatusCodeInterface;
24
use Fisharebest\Webtrees\Auth;
25
use Fisharebest\Webtrees\FlashMessages;
26
use Fisharebest\Webtrees\GedcomRecord;
27
use Fisharebest\Webtrees\Html;
28
use Fisharebest\Webtrees\Http\RequestHandlers\TreePage;
29
use Fisharebest\Webtrees\I18N;
30
use Fisharebest\Webtrees\Media;
31
use Fisharebest\Webtrees\Services\MediaFileService;
32
use Fisharebest\Webtrees\Services\PendingChangesService;
33
use Fisharebest\Webtrees\Tree;
34
use League\Flysystem\FileExistsException;
35
use League\Flysystem\FileNotFoundException;
36
use League\Flysystem\FilesystemInterface;
37
use League\Flysystem\Util;
38
use Psr\Http\Message\ResponseInterface;
39
use Psr\Http\Message\ServerRequestInterface;
40
41
use function assert;
42
use function is_string;
43
44
/**
45
 * Controller for edit forms and responses.
46
 */
47
class EditMediaController extends AbstractEditController
48
{
49
    /** @var MediaFileService */
50
    private $media_file_service;
51
52
    /** @var PendingChangesService */
53
    private $pending_changes_service;
54
55
    /**
56
     * EditMediaController constructor.
57
     *
58
     * @param MediaFileService      $media_file_service
59
     * @param PendingChangesService $pending_changes_service
60
     */
61
    public function __construct(MediaFileService $media_file_service, PendingChangesService $pending_changes_service)
62
    {
63
        $this->media_file_service      = $media_file_service;
64
        $this->pending_changes_service = $pending_changes_service;
65
    }
66
67
    /**
68
     * Add a media file to an existing media object.
69
     *
70
     * @param ServerRequestInterface $request
71
     *
72
     * @return ResponseInterface
73
     */
74
    public function addMediaFile(ServerRequestInterface $request): ResponseInterface
75
    {
76
        $tree = $request->getAttribute('tree');
77
        assert($tree instanceof Tree);
78
79
        $data_filesystem = $request->getAttribute('filesystem.data');
80
        assert($data_filesystem instanceof FilesystemInterface);
81
82
        $xref  = $request->getQueryParams()['xref'];
83
        $media = Media::getInstance($xref, $tree);
84
85
        try {
86
            $media = Auth::checkMediaAccess($media);
87
        } catch (Exception $ex) {
88
            return response(view('modals/error', [
89
                'title' => I18N::translate('Add a media file'),
90
                'error' => $ex->getMessage(),
91
            ]));
92
        }
93
94
        return response(view('modals/add-media-file', [
95
            'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
96
            'media'           => $media,
97
            'media_types'     => $this->media_file_service->mediaTypes(),
98
            'tree'            => $tree,
99
            'unused_files'    => $this->media_file_service->unusedFiles($tree, $data_filesystem),
100
        ]));
101
    }
102
103
    /**
104
     * Add a media file to an existing media object.
105
     *
106
     * @param ServerRequestInterface $request
107
     *
108
     * @return ResponseInterface
109
     */
110
    public function addMediaFileAction(ServerRequestInterface $request): ResponseInterface
111
    {
112
        $tree = $request->getAttribute('tree');
113
        assert($tree instanceof Tree);
114
115
        $xref  = $request->getQueryParams()['xref'];
116
        $media = Media::getInstance($xref, $tree);
117
118
        $params = (array) $request->getParsedBody();
119
120
        $title = $params['title'];
121
        $type  = $params['type'];
122
123
        if ($media === null || $media->isPendingDeletion() || !$media->canEdit()) {
124
            return redirect(route(TreePage::class, ['tree' => $tree->name()]));
125
        }
126
127
        $file = $this->media_file_service->uploadFile($request);
128
129
        if ($file === '') {
130
            FlashMessages::addMessage(I18N::translate('There was an error uploading your file.'));
131
132
            return redirect($media->url());
133
        }
134
135
        $gedcom = $this->media_file_service->createMediaFileGedcom($file, $type, $title, '');
136
137
        $media->createFact($gedcom, true);
138
139
        // Accept the changes, to keep the filesystem in sync with the GEDCOM data.
140
        $this->pending_changes_service->acceptRecord($media);
141
142
        return redirect($media->url());
143
    }
144
145
    /**
146
     * Edit an existing media file.
147
     *
148
     * @param ServerRequestInterface $request
149
     *
150
     * @return ResponseInterface
151
     */
152
    public function editMediaFile(ServerRequestInterface $request): ResponseInterface
153
    {
154
        $tree = $request->getAttribute('tree');
155
        assert($tree instanceof Tree);
156
157
        $data_filesystem = $request->getAttribute('filesystem.data');
158
        assert($data_filesystem instanceof FilesystemInterface);
159
160
        $params  = $request->getQueryParams();
161
        $xref    = $params['xref'];
162
        $fact_id = $params['fact_id'];
163
        $media   = Media::getInstance($xref, $tree);
164
165
        try {
166
            $media = Auth::checkMediaAccess($media);
167
        } catch (Exception $ex) {
168
            return response(view('modals/error', [
169
                'title' => I18N::translate('Edit a media file'),
170
                'error' => $ex->getMessage(),
171
            ]), StatusCodeInterface::STATUS_FORBIDDEN);
172
        }
173
174
        foreach ($media->mediaFiles() as $media_file) {
175
            if ($media_file->factId() === $fact_id) {
176
                return response(view('modals/edit-media-file', [
177
                    'media_file'      => $media_file,
178
                    'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
179
                    'media'           => $media,
180
                    'media_types'     => $this->media_file_service->mediaTypes(),
181
                    'unused_files'    => $this->media_file_service->unusedFiles($tree, $data_filesystem),
182
                    'tree'            => $tree,
183
                ]));
184
            }
185
        }
186
187
        return response('', StatusCodeInterface::STATUS_NOT_FOUND);
188
    }
189
190
    /**
191
     * Save an edited media file.
192
     *
193
     * @param ServerRequestInterface $request
194
     *
195
     * @return ResponseInterface
196
     */
197
    public function editMediaFileAction(ServerRequestInterface $request): ResponseInterface
198
    {
199
        $tree = $request->getAttribute('tree');
200
        assert($tree instanceof Tree);
201
202
        $data_filesystem = $request->getAttribute('filesystem.data');
203
        assert($data_filesystem instanceof FilesystemInterface);
204
205
        $xref    = $request->getQueryParams()['xref'];
206
        $fact_id = $request->getQueryParams()['fact_id'];
207
208
        $params = (array) $request->getParsedBody();
209
210
        $folder   = $params['folder'];
211
        $new_file = $params['new_file'];
212
        $remote   = $params['remote'];
213
        $title    = $params['title'];
214
        $type     = $params['type'];
215
        $media    = Media::getInstance($xref, $tree);
216
217
        // Tidy whitespace
218
        $type  = trim(preg_replace('/\s+/', ' ', $type));
219
        $title = trim(preg_replace('/\s+/', ' ', $title));
220
221
        // Media object oes not exist?  Media object is read-only?
222
        if ($media === null || $media->isPendingDeletion() || !$media->canEdit()) {
223
            return redirect(route(TreePage::class, ['tree' => $tree->name()]));
224
        }
225
226
        // Find the fact we are editing.
227
        $media_file = null;
228
        foreach ($media->mediaFiles() as $tmp) {
229
            if ($tmp->factId() === $fact_id) {
230
                $media_file = $tmp;
231
            }
232
        }
233
234
        // Media file does not exist?
235
        if ($media_file === null) {
0 ignored issues
show
introduced by
The condition $media_file === null is always true.
Loading history...
236
            return redirect(route(TreePage::class, ['tree' => $tree->name()]));
237
        }
238
239
        // We can edit the file as either a URL or a folder/file
240
        if ($remote !== '') {
241
            $file = $remote;
242
        } else {
243
            $new_file = str_replace('\\', '/', $new_file);
244
            $folder   = str_replace('\\', '/', $folder);
245
            $folder   = trim($folder, '/');
246
247
            if ($folder === '') {
248
                $file = $new_file;
249
            } else {
250
                $file = $folder . '/' . $new_file;
251
            }
252
        }
253
254
        // Invalid filename?  Do not change it.
255
        if ($new_file === '') {
256
            $file = $media_file->filename();
257
        }
258
259
        $filesystem = $media->tree()->mediaFilesystem($data_filesystem);
260
        $old        = $media_file->filename();
261
        $new        = $file;
262
263
        // Update the filesystem, if we can.
264
        if ($old !== $new && !$media_file->isExternal()) {
265
            try {
266
                $new = Util::normalizePath($new);
267
                $filesystem->rename($old, $new);
268
                FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($media_file->filename()), Html::filename($file)), 'info');
269
            } catch (FileNotFoundException $ex) {
270
                // The "old" file may not exist.  For example, if the file was renamed on disk,
271
                // and we are now renaming the GEDCOM data to match.
272
            } catch (FileExistsException $ex) {
273
                // Don't overwrite existing file
274
                FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($media_file->filename()), Html::filename($file)), 'info');
275
                $file = $old;
276
            }
277
        }
278
279
        $gedcom = $this->media_file_service->createMediaFileGedcom($file, $type, $title);
280
281
        $media->updateFact($fact_id, $gedcom, true);
282
283
        // Accept the changes, to keep the filesystem in sync with the GEDCOM data.
284
        if ($old !== $new && !$media_file->isExternal()) {
285
            $this->pending_changes_service->acceptRecord($media);
286
        }
287
288
        return redirect($media->url());
289
    }
290
291
    /**
292
     * Show a form to create a new media object.
293
     *
294
     * @param ServerRequestInterface $request
295
     *
296
     * @return ResponseInterface
297
     */
298
    public function createMediaObject(ServerRequestInterface $request): ResponseInterface
299
    {
300
        $tree = $request->getAttribute('tree');
301
        assert($tree instanceof Tree);
302
303
        $data_filesystem = $request->getAttribute('filesystem.data');
304
        assert($data_filesystem instanceof FilesystemInterface);
305
306
        return response(view('modals/create-media-object', [
307
            'max_upload_size' => $this->media_file_service->maxUploadFilesize(),
308
            'media_types'     => $this->media_file_service->mediaTypes(),
309
            'unused_files'    => $this->media_file_service->unusedFiles($tree, $data_filesystem),
310
        ]));
311
    }
312
313
    /**
314
     * @param ServerRequestInterface $request
315
     *
316
     * @return ResponseInterface
317
     */
318
    public function createMediaObjectFromFileAction(ServerRequestInterface $request): ResponseInterface
319
    {
320
        $tree = $request->getAttribute('tree');
321
        assert($tree instanceof Tree);
322
323
        $params = (array) $request->getParsedBody();
324
        $file   = $params['file'];
325
        $type   = $params['type'];
326
        $title  = $params['title'];
327
        $note   = $params['note'];
328
329
        $gedcom = "0 @@ OBJE\n" . $this->media_file_service->createMediaFileGedcom($file, $type, $title, $note);
330
331
        $media_object = $tree->createRecord($gedcom);
332
333
        // Accept the new record.  Rejecting it would leave the filesystem out-of-sync with the genealogy
334
        $this->pending_changes_service->acceptRecord($media_object);
335
336
        return redirect($media_object->url());
337
    }
338
339
    /**
340
     * @param ServerRequestInterface $request
341
     *
342
     * @return ResponseInterface
343
     */
344
    public function linkMediaToIndividual(ServerRequestInterface $request): ResponseInterface
345
    {
346
        $tree = $request->getAttribute('tree');
347
        assert($tree instanceof Tree);
348
349
        $xref = $request->getQueryParams()['xref'];
350
        $media = Media::getInstance($xref, $tree);
351
352
        return response(view('modals/link-media-to-individual', [
353
            'media' => $media,
354
            'tree'  => $tree,
355
        ]));
356
    }
357
358
    /**
359
     * @param ServerRequestInterface $request
360
     *
361
     * @return ResponseInterface
362
     */
363
    public function linkMediaToFamily(ServerRequestInterface $request): ResponseInterface
364
    {
365
        $tree = $request->getAttribute('tree');
366
        assert($tree instanceof Tree);
367
368
        $xref = $request->getQueryParams()['xref'];
369
370
        $media = Media::getInstance($xref, $tree);
371
372
        return response(view('modals/link-media-to-family', [
373
            'media' => $media,
374
            'tree'  => $tree,
375
        ]));
376
    }
377
378
    /**
379
     * @param ServerRequestInterface $request
380
     *
381
     * @return ResponseInterface
382
     */
383
    public function linkMediaToSource(ServerRequestInterface $request): ResponseInterface
384
    {
385
        $tree = $request->getAttribute('tree');
386
        assert($tree instanceof Tree);
387
388
        $xref = $request->getQueryParams()['xref'];
389
390
        $media = Media::getInstance($xref, $tree);
391
392
        return response(view('modals/link-media-to-source', [
393
            'media' => $media,
394
            'tree'  => $tree,
395
        ]));
396
    }
397
398
    /**
399
     * @param ServerRequestInterface $request
400
     *
401
     * @return ResponseInterface
402
     */
403
    public function linkMediaToRecordAction(ServerRequestInterface $request): ResponseInterface
404
    {
405
        $tree = $request->getAttribute('tree');
406
        assert($tree instanceof Tree);
407
408
        $xref = $request->getAttribute('xref');
409
        assert(is_string($xref));
410
411
        $params = (array) $request->getParsedBody();
412
413
        $link = $params['link'];
414
415
        $media  = Media::getInstance($xref, $tree);
416
        $record = GedcomRecord::getInstance($link, $tree);
417
418
        $record->createFact('1 OBJE @' . $xref . '@', true);
419
420
        return redirect($media->url());
421
    }
422
}
423