PluginProbe
Depicter — Popup & Slider Builder / trunk
Depicter — Popup & Slider Builder vtrunk
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / app / src / Controllers / Ajax / EditorAjaxController.php

EditorAjaxController.php in Depicter — Popup & Slider Builder trunk, at app/src/Controllers/Ajax/EditorAjaxController.php

586 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Depicter\Controllers\Ajax;
4
5 use Averta\Core\Controllers\RestMethodsInterface;
6 use Averta\Core\Utility\Arr;
7 use Averta\Core\Utility\Data;
8 use Averta\WordPress\Utility\JSON;
9 use Depicter;
10 use Depicter\Editor\EditorLocalization;
11 use Depicter\GuzzleHttp\Exception\GuzzleException;
12 use Depicter\Utility\Http;
13 use Depicter\Utility\Sanitize;
14 use Exception;
15 use Psr\Http\Message\ResponseInterface;
16 use Psr\Http\Message\UploadedFileInterface;
17 use WPEmerge\Requests\RequestInterface;
18
19 class EditorAjaxController implements RestMethodsInterface
20 {
21 /**
22 * Retrieves Lists of all entries. (GET)
23 *
24 * @param RequestInterface $request
25 * @param string $view
26 *
27 * @return string
28 */
29 public function index(RequestInterface $request, $view)
30 {
31 return '';
32 }
33
34 /**
35 * Adds a new entry. (POST)
36 *
37 * @param RequestInterface $request
38 * @param string $view
39 *
40 * @throws Exception
41 * @throws GuzzleException
42 * @return ResponseInterface
43 */
44 public function store(RequestInterface $request, $view)
45 {
46 // fields to update
47 $properties = [];
48
49 // Get editor data
50 $editor = $request->body('editor');
51 if (!empty($editor) && JSON::isJson($editor)) {
52
53 if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) {
54 $pattern = '/<script[^>]*?>.*?<\/script>/si';
55 // Replace script tags with an empty string
56 $editor = preg_replace($pattern, '', $editor);
57
58 $pattern = '/<iframe[^>]*?>/si';
59 // Replace iframe tags with an empty string
60 $editor = preg_replace($pattern, '', $editor);
61 }
62
63 $properties['editor'] = $editor;
64 }
65
66 // Get document ID
67 $id = Sanitize::int($request->body('ID'));
68
69 if (empty($id)) {
70 return Depicter::json(['errors' => ['Document "ID" is required.']])->withStatus(400);
71 }
72
73 // Get document name
74 $name = Sanitize::textfield($request->body('name'));
75
76 if (!empty($name)) {
77 $properties['name'] = $name;
78 }
79
80 // Get document slug
81 $slug = Sanitize::slug($request->body('slug'));
82
83 if (!empty($slug)) {
84 $properties['slug'] = $slug;
85 }
86
87 // Get document status
88 $status = Sanitize::textfield($request->body('status')) ?? 'draft';
89 $properties['status'] = $status === 'published' ? 'publish' : $status;
90
91 try {
92 if ($properties['status'] == 'publish') {
93
94 if (\Depicter::auth()->isPaid() && !\Depicter::auth()->verifyActivation()) {
95 throw new Exception(esc_html__('License is not valid.', 'depicter'));
96 }
97
98 if (function_exists('get_filesystem_method') && get_filesystem_method() != 'direct') {
99 throw new Exception(esc_html__('Media files cannot be published due to lack of proper file permissions for uploads directory.', 'depicter'));
100 }
101
102 if ( ! \Depicter::authorization()->userHasPublishQuota() && ! \Depicter::documentRepository()->isPublishedBefore($id) ) {
103 throw new Exception(esc_html__('You’ve reached your limit. On the free plan, you can publish up to 2 projects. To publish more, you can unpublish an existing project, or upgrade to PRO for unlimited publishing.', 'depicter'));
104 }
105
106 $editorRawData = $properties['editor'] ?? Depicter::document()->getEditorRawData($id);
107
108 // Download media if document published
109 \Depicter::media()->importDocumentAssets($editorRawData);
110 }
111
112 if (!empty($properties['editor'])) {
113 $documentHasForm = strpos($properties['editor'], '"type":"form"') || strpos( $properties['editor'], '"documentType":"survey"') ? 1 : 0;
114 Depicter::document()->meta()->update($id, 'hasForm', $documentHasForm);
115
116 $documentHasShortcode = strpos($properties['editor'], '"type":"wpShortcode"') ? 1 : 0;
117 Depicter::document()->meta()->update($id, 'hasShortcode', $documentHasShortcode);
118 }
119
120 $result = Depicter::documentRepository()->saveEditorData($id, $properties);
121
122 if (false === $result['result']) {
123 return Depicter::json(['errors' => ['Document does not exist.', $result]])->withStatus(404);
124 }
125
126 do_action('depicter/editor/after/store', $id, $properties, $result);
127
128 $this->setDocumentPoster($request, $id);
129
130 $result = ['hits' => [
131 'status' => $status,
132 'modifiedAt' => $result['modifiedAt'],
133 'publishedAt' => $result['publishedAt']
134 ]
135 ];
136 $revisions = Depicter::documentRepository()->getRevisionsID($id);
137 if (!empty($revisions)) {
138 foreach ($revisions as $revisionID) {
139 $revision = Depicter::documentRepository()->findById($revisionID)->getApiProperties();
140 $author = get_user_by('id', $revision['author']);
141 $result['hits']['revisions'][] = [
142 'id' => $revisionID,
143 'author' => [
144 'id' => $author->ID,
145 'name' => $author->display_name,
146 'avatar' => get_avatar_url($author->ID),
147 ],
148 'publishedAt' => $revision['publishedAt'],
149 ];
150 }
151 }
152
153 return Depicter::json($result)->withStatus(200);
154 } catch (Exception $exception) {
155 $error = Http::getErrorExceptionResponse($exception);
156
157 return \Depicter::json([
158 'errors' => $error
159 ])->withStatus($error['statusCode']);
160 }
161
162 }
163
164 /**
165 * Displays an entry. (GET)
166 *
167 * @param RequestInterface $request
168 * @param string $view
169 *
170 * @throws Exception
171 * @return ResponseInterface
172 */
173 public function show(RequestInterface $request, $view)
174 {
175 if (!$documentId = Sanitize::int($request->query('ID'))) {
176 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
177 }
178
179 if (!$document = Depicter::documentRepository()->findById($documentId)) {
180 return Depicter::json(['errors' => ['Document ID not found.', $documentId]])
181 ->withHeader('X-Document-ID', $documentId)
182 ->withStatus(404);
183 }
184
185 $hits = Arr::camelizeKeys($document->getApiProperties(), '_');
186 $author = get_user_by('id', $hits['author']);
187 $hits['author'] = [
188 'id' => $author->ID,
189 'name' => $author->display_name,
190 'avatar' => get_avatar_url($author->ID),
191 ];
192
193 $revisions = Depicter::documentRepository()->getRevisionsID($documentId);
194 if (!empty($revisions)) {
195 foreach ($revisions as $revisionID) {
196 $revision = Depicter::documentRepository()->findById($revisionID)->getApiProperties();
197 $author = get_user_by('id', $revision['author']);
198 $hits['revisions'][] = [
199 'id' => $revisionID,
200 'author' => [
201 'id' => $author->ID,
202 'name' => $author->display_name,
203 'avatar' => get_avatar_url($author->ID),
204 ],
205 'publishedAt' => $revision['publishedAt'],
206 ];
207 }
208 }
209
210 $hits['content'] = Depicter::document()->migrations()->apply($hits['content']);
211
212 return Depicter::json(['hits' => $hits])->withHeader('X-Document-ID', $documentId)->withStatus(200);
213 }
214
215 /**
216 * Retrieves list of document revisions with details
217 *
218 * @param RequestInterface $request
219 * @param string $view
220 *
221 * @throws Exception
222 * @return ResponseInterface
223 */
224 public function getHistory(RequestInterface $request, $view)
225 {
226 if (!$documentId = Sanitize::int($request->query('ID'))) {
227 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
228 }
229
230 if (!$document = Depicter::documentRepository()->findById($documentId)) {
231 return Depicter::json(['errors' => ['Document ID not found.', $documentId]])
232 ->withHeader('X-Document-ID', $documentId)
233 ->withStatus(404);
234 }
235
236 $hits = [];
237 $revisions = Depicter::documentRepository()->getRevisionsID($documentId);
238 if (!empty($revisions)) {
239 foreach ($revisions as $revisionID) {
240 $revision = Depicter::documentRepository()->findById($revisionID)->getApiProperties();
241 $author = get_user_by('id', $revision['author']);
242 $hits[] = [
243 'id' => $revisionID,
244 'author' => [
245 'id' => $author->ID,
246 'name' => $author->display_name,
247 'avatar' => get_avatar_url($author->ID),
248 ],
249 'publishedAt' => $revision['publishedAt'],
250 ];
251 }
252 }
253
254 return Depicter::json(['hits' => $hits])->withHeader('X-Document-ID', $documentId)->withStatus(200);
255 }
256
257 /**
258 * Renames a document name.
259 *
260 * @param RequestInterface $request
261 * @param string $view
262 *
263 * @throws Exception
264 * @return ResponseInterface
265 */
266 public function checkSlug(RequestInterface $request, $view)
267 {
268 // Get document ID
269 $slug = Sanitize::textfield($request->body('slug'));
270
271 if (empty($slug)) {
272 return Depicter::json(['errors' => ['Document slug is required.']])->withStatus(400);
273 }
274
275 $result = Depicter::documentRepository()->checkSlug($slug);
276
277 if ($result) {
278 return Depicter::json(['errors' => ['Taken!']])
279 ->withHeader('X-Taken-Slug', $slug)
280 ->withHeader('X-Available-Slug', Depicter::documentRepository()->makeSlug())
281 ->withStatus(423);
282 }
283
284 return Depicter::json(['hits' => $slug])->withStatus(200);
285 }
286
287 /**
288 * Retrieves editor and dashboard localized texts
289 *
290 * @param RequestInterface $request
291 * @param $view
292 *
293 * @return ResponseInterface
294 */
295 public function getLocalization(RequestInterface $request, $view)
296 {
297 return Depicter::json(
298 EditorLocalization::getTranslateList()
299 )->withHeader('Access-Control-Allow-Origin', '*')->withStatus(200);
300 }
301
302 /**
303 * Renders a document markup.
304 *
305 * @param RequestInterface $request
306 * @param string $view
307 *
308 * @throws Exception
309 * @return ResponseInterface
310 */
311 public function render(RequestInterface $request, $view)
312 {
313 if (!$documentId = Sanitize::int($request->query('ID'))) {
314 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
315 }
316
317 $args = [];
318 if (Data::isBool($request->query('addImportant'))) {
319 $args['addImportant'] = Sanitize::textfield($request->query('addImportant'));
320 }
321
322 return Depicter::output(Depicter::front()->render()->document($documentId, $args));
323 }
324
325 /**
326 * Outputs markup to preview a document
327 *
328 * @param RequestInterface $request
329 * @param $view
330 *
331 * @return ResponseInterface
332 */
333 public function preview(RequestInterface $request, $view)
334 {
335 $gutenberg = $request->query('gutenberg', '');
336 $documentId = Sanitize::int($request->query('ID'));
337
338 if (!$documentId && empty($gutenberg)) {
339 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
340 }
341
342 $status = Sanitize::textfield($request->query('status'));
343
344 $previewArgs = [
345 'status' => !empty($status) ? $status : 'auto',
346 'start' => Sanitize::int($request->query('startSection')),
347 'gutenberg' => !empty($gutenberg)
348 ];
349
350 return Depicter::output(Depicter::front()->preview()->document($documentId, $previewArgs));
351 }
352
353 /**
354 * Retrieves object of document editor data
355 *
356 * @param RequestInterface $request
357 * @param string $view
358 *
359 * @return ResponseInterface
360 */
361 public function getEditorData(RequestInterface $request, $view)
362 {
363 if (!$documentId = Sanitize::int($request->query('ID'))) {
364 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
365 }
366
367 $output = '';
368
369 try {
370 $output = Depicter::document()->getEditorData($documentId);
371 $output = Depicter::document()->migrations()->apply($output);
372
373 } catch (Exception $exception) {
374 return Depicter::json([
375 'errors' => [$exception->getMessage()]
376 ])->withHeader('X-Document-ID', $documentId)->withStatus(404);
377 }
378
379 return Depicter::json($output);
380 }
381
382 public function getRevisions(RequestInterface $request, $view)
383 {
384
385 $id = Sanitize::int($request->query('ID', ''));
386 if (empty($id)) {
387 return Depicter::json([
388 'errors' => [__('ID required', 'depicter')]
389 ])->withStatus(400);
390 }
391
392 try {
393 $hits = Depicter::documentRepository()->getRevisionsID($id);
394
395 return Depicter::json(['hits' => $hits])->withStatus(200);
396 } catch (\Exception $e) {
397 return Depicter::json(['errors' => [$e->getMessage()]])->withStatus(400);
398 }
399 }
400
401 /**
402 * Reverts a document to previous snapshots
403 *
404 * @param RequestInterface $request
405 * @param string $view
406 *
407 * @return ResponseInterface
408 */
409 public function revert(RequestInterface $request, $view)
410 {
411 if (!$documentId = Sanitize::int($request->body('ID'))) {
412 return Depicter::json(['errors' => ['Document ID is required.']])->withStatus(400);
413 }
414 $to = Sanitize::textfield($request->body('to'));
415
416 try {
417 $output = Depicter::document()->repository()->revert($documentId, $to);
418
419 return Depicter::json($output);
420
421 } catch (Exception $exception) {
422 return Depicter::json(['errors' => [$exception->getMessage()]])
423 ->withHeader('X-Document-ID', $documentId)
424 ->withStatus(404);
425 }
426 }
427
428 /**
429 * Updates an entry. (PUT/PATCH)
430 *
431 * @param RequestInterface $request
432 * @param string $view
433 *
434 * @return ResponseInterface
435 */
436 public function update(RequestInterface $request, $view)
437 {
438 return Depicter::json(['hits' => []])->withStatus(200);
439 }
440
441 /**
442 * Upload cover photo of slider
443 *
444 * @param RequestInterface $request
445 * @param int $id
446 *
447 * @return bool
448 */
449 public function setDocumentPoster(RequestInterface $request, int $id)
450 {
451 $uploadedFiles = $request->getUploadedFiles();
452
453 if (empty($uploadedFiles['previewImage']) || empty($id)) {
454 return false;
455 }
456 $previewImages = $uploadedFiles['previewImage'];
457
458 if (!is_array($previewImages)) {
459 /* @var $previewImages UploadedFileInterface */
460 if ($previewImages->getError() || !$previewImages->getSize()) {
461 return false;
462 }
463
464 return $this->uploadPreviewImage($previewImages, $id);
465
466 }
467 /* @var $previewImages UploadedFileInterface[] */
468 foreach ($previewImages as $key => $image) {
469 if (empty($image) || $image->getError() || !$image->getSize()) {
470 continue;
471 }
472 if ($key === 0) {
473 $this->uploadPreviewImage($image, $id);
474 $this->uploadPreviewImage($image, $id . '-1');
475 } else {
476 $fileName = $id . '-' . ($key + 1);
477 $this->uploadPreviewImage($image, $fileName);
478 }
479 }
480
481 return true;
482
483 }
484
485 /**
486 * Upload preview image to depicter upload folder
487 *
488 * @param UploadedFileInterface $imageFile
489 * @param string $fileName
490 *
491 * @return bool
492 */
493 public function uploadPreviewImage(UploadedFileInterface $imageFile, string $fileName): bool
494 {
495 $mediaType = $imageFile->getClientMediaType();
496
497 if (false === strpos($mediaType, 'image/')) {
498 // Not an image file
499 return false;
500 }
501
502 return Depicter::storage()->filesystem()->write(Depicter::storage()->getPluginUploadsDirectory() . '/preview-images/' . $fileName . '.png', (string) $imageFile->getStream());
503 }
504
505 /**
506 * Upload multiple document posters
507 *
508 * @param RequestInterface $request
509 * @param $view
510 *
511 * @return ResponseInterface
512 */
513 public function uploadDocumentPosters(RequestInterface $request, $view)
514 {
515
516 $documentId = Sanitize::textfield($request->body('ID', ''));
517
518 try {
519 $coverPhoto = $request->getUploadedFiles();
520
521 if (empty($documentId)) {
522 throw new \Exception(__('Document ID is required.', 'depicter'), 400);
523 }
524 if (empty($coverPhoto)) {
525 throw new \Exception(__('Cover image not found.', 'depicter'), 400);
526 }
527 if (!$this->setDocumentPoster($request, $documentId)) {
528 throw new \Exception(__('Error occurred! Cannot upload cover photos.', 'depicter'), 400);
529 }
530
531 } catch (\Exception $exception) {
532 return Depicter::json([
533 'errors' => [$exception->getMessage()]
534 ])->withStatus($exception->getCode());
535 }
536
537 return Depicter::json(['success' => true, 'message' => 'Cover images uploaded successfully.'])->withStatus(200);
538 }
539
540 /**
541 * Get Document Status
542 *
543 * @param RequestInterface $request
544 * @param string $view
545 *
546 * @return ResponseInterface
547 */
548 public function getDocumentStatus(RequestInterface $request, $view)
549 {
550 $documentId = absint($request->query('ID', 0));
551 try {
552 return Depicter::json([
553 'status' => Depicter::documentRepository()->getStatus($documentId)
554 ])->withStatus(200);
555 } catch (\Exception $exception) {
556 return Depicter::json([
557 'errors' => [$exception->getMessage()]
558 ])->withStatus(400);
559 }
560 }
561
562 public function destroy(RequestInterface $request, $view)
563 {
564 // TODO: Implement destroy() method.
565 }
566
567 /**
568 * Render Just Shortcodes without any header or footer
569 *
570 * @param RequestInterface $request
571 * @param string $view
572 *
573 * @return ResponseInterface
574 */
575 public function renderShortcode(RequestInterface $request, $view): ResponseInterface
576 {
577 $shortcode = Sanitize::textfield($request->query('shortcode', ''));
578
579 $output = Depicter::view('render-shortcode.php')->with('view_args', [
580 'shortcode' => $shortcode
581 ])->toString();
582
583 return Depicter::output($output);
584 }
585 }
586