PageRenderTime 609ms CodeModel.GetById 400ms app.highlight 93ms RepoModel.GetById 108ms app.codeStats 1ms

/modules/Collections/Controller/Admin.php

https://github.com/agentejo/cockpit
PHP | 609 lines | 413 code | 183 blank | 13 comment | 92 complexity | ad31fd609d231b90f055cb64bb235835 MD5 | raw file
  1<?php
  2/**
  3 * This file is part of the Cockpit project.
  4 *
  5 * (c) Artur Heinze - πŸ…°πŸ…ΆπŸ…΄πŸ…½πŸ†ƒπŸ…΄πŸ…ΉπŸ…Ύ, http://agentejo.com
  6 *
  7 * For the full copyright and license information, please view the LICENSE
  8 * file that was distributed with this source code.
  9 */
 10
 11namespace Collections\Controller;
 12
 13
 14class Admin extends \Cockpit\AuthController {
 15
 16
 17    public function index() {
 18
 19        $_collections = $this->module('collections')->getCollectionsInGroup(null, false);
 20        $collections  = [];
 21
 22        foreach ($_collections as $collection => $meta) {
 23
 24            $meta['allowed'] = [
 25                'delete' => $this->module('cockpit')->hasaccess('collections', 'delete'),
 26                'create' => $this->module('cockpit')->hasaccess('collections', 'create'),
 27                'edit' => $this->module('collections')->hasaccess($collection, 'collection_edit'),
 28                'entries_create' => $this->module('collections')->hasaccess($collection, 'collection_create'),
 29                'entries_delete' => $this->module('collections')->hasaccess($collection, 'entries_delete'),
 30            ];
 31
 32            $meta['itemsCount'] = null;
 33
 34            $collections[] = [
 35                'name' => $collection,
 36                'label' => isset($meta['label']) && $meta['label'] ? $meta['label'] : $collection,
 37                'meta' => $meta
 38            ];
 39        }
 40
 41        // sort collections
 42        usort($collections, function($a, $b) {
 43            return mb_strtolower($a['label']) <=> mb_strtolower($b['label']);
 44        });
 45
 46        return $this->render('collections:views/index.php', compact('collections'));
 47    }
 48
 49    public function _collections() {
 50        return $this->module('collections')->collections();
 51    }
 52
 53    public function _find() {
 54
 55        if ($this->param('collection') && $this->param('options')) {
 56            return $this->module('collections')->find($this->param('collection'), $this->param('options'));
 57        }
 58
 59        return false;
 60    }
 61
 62    public function collection($name = null) {
 63
 64        if ($name && !$this->module('collections')->hasaccess($name, 'collection_edit')) {
 65            return $this->helper('admin')->denyRequest();
 66        }
 67
 68        if (!$name && !$this->module('cockpit')->hasaccess('collections', 'create')) {
 69            return $this->helper('admin')->denyRequest();
 70        }
 71
 72        $default = [
 73            'name' => '',
 74            'label' => '',
 75            'color' => '',
 76            'fields'=>[],
 77            'acl' => new \ArrayObject,
 78            'sortable' => false,
 79            'sort' => [
 80                'column' => '_created',
 81                'dir' => -1,
 82            ],
 83            'in_menu' => false
 84        ];
 85
 86        $collection = $default;
 87
 88        if ($name) {
 89
 90            $collection = $this->module('collections')->collection($name);
 91
 92            if (!$collection) {
 93                return false;
 94            }
 95
 96            if (!$this->app->helper('admin')->isResourceEditableByCurrentUser($collection['_id'], $meta)) {
 97                return $this->render('cockpit:views/base/locked.php', compact('meta'));
 98            }
 99
100            $this->app->helper('admin')->lockResourceId($collection['_id']);
101
102            $collection = array_merge($default, $collection);
103        }
104
105        // get field templates
106        $templates = [];
107
108        foreach ($this->app->helper('fs')->ls('*.php', 'collections:fields-templates') as $file) {
109            $templates[] = include($file->getRealPath());
110        }
111
112        foreach ($this->app->module('collections')->collections() as $col) {
113            $templates[] = $col;
114        }
115
116        // acl groups
117        $aclgroups = [];
118
119        foreach ($this->app->helper('acl')->getGroups() as $group => $superAdmin) {
120
121            if (!$superAdmin) $aclgroups[] = $group;
122        }
123
124        // rules
125        $rules = [
126            'create' => !$name ? "<?php\n\n" : $this->app->helper('fs')->read("#storage:collections/rules/{$name}.create.php"),
127            'read'   => !$name ? "<?php\n\n" : $this->app->helper('fs')->read("#storage:collections/rules/{$name}.read.php"),
128            'update' => !$name ? "<?php\n\n" : $this->app->helper('fs')->read("#storage:collections/rules/{$name}.update.php"),
129            'delete' => !$name ? "<?php\n\n" : $this->app->helper('fs')->read("#storage:collections/rules/{$name}.delete.php"),
130        ];
131
132        return $this->render('collections:views/collection.php', compact('collection', 'templates', 'aclgroups', 'rules'));
133    }
134
135    public function save_collection() {
136
137        $collection = $this->param('collection');
138        $rules      = $this->param('rules', null);
139
140        if (!$collection) {
141            return false;
142        }
143
144        $isUpdate = isset($collection['_id']);
145
146        if (!$isUpdate && !$this->module('cockpit')->hasaccess('collections', 'create')) {
147            return $this->helper('admin')->denyRequest();
148        }
149
150        if ($isUpdate && !$this->module('collections')->hasaccess($collection['name'], 'collection_edit')) {
151            return $this->helper('admin')->denyRequest();
152        }
153
154        if ($isUpdate && !$this->app->helper('admin')->isResourceEditableByCurrentUser($collection['_id'])) {
155            $this->stop(['error' => "Saving failed! Collection is locked!"], 412);
156        }
157
158        $collection = $this->module('collections')->saveCollection($collection['name'], $collection, $rules);
159
160        if (!$isUpdate) {
161            $this->app->helper('admin')->lockResourceId($collection['_id']);
162        }
163
164        return $collection;
165    }
166
167    public function entries($collection) {
168
169        if (!$this->module('collections')->hasaccess($collection, 'entries_view')) {
170            return $this->helper('admin')->denyRequest();
171        }
172
173        $collection = $this->module('collections')->collection($collection);
174
175        if (!$collection) {
176            return false;
177        }
178
179        $collection = array_merge([
180            'sortable' => false,
181            'sort' => [
182                'column' => '_created',
183                'dir' => -1,
184            ],
185            'color' => '',
186            'icon' => '',
187            'description' => ''
188        ], $collection);
189
190        $context = _check_collection_rule($collection, 'read', ['options' => ['filter'=>[]]]);
191
192        $this->app->helper('admin')->favicon = [
193            'path' => 'collections:icon.svg',
194            'color' => $collection['color']
195        ];
196
197        if ($context && isset($context->options['fields'])) {
198            foreach ($collection['fields'] as &$field) {
199                if (isset($context->options['fields'][$field['name']]) && !$context->options['fields'][$field['name']]) {
200                    $field['lst'] = false;
201                }
202            }
203        }
204
205        $view = 'collections:views/entries.php';
206
207        if ($override = $this->app->path('#config:collections/'.$collection['name'].'/views/entries.php')) {
208            $view = $override;
209        }
210
211        return $this->render($view, compact('collection'));
212    }
213
214    public function entry($collection, $id = null) {
215
216        if ($id && !$this->module('collections')->hasaccess($collection, 'entries_view')) {
217            return $this->helper('admin')->denyRequest();
218        }
219
220        if (!$id && !$this->module('collections')->hasaccess($collection, 'entries_create')) {
221            return $this->helper('admin')->denyRequest();
222        }
223
224        $collection    = $this->module('collections')->collection($collection);
225        $entry         = new \ArrayObject([]);
226        $excludeFields = [];
227
228        if (!$collection) {
229            return false;
230        }
231
232        $collection = array_merge([
233            'sortable' => false,
234            'sort' => [
235                'column' => '_created',
236                'dir' => -1,
237            ],
238            'color' => '',
239            'icon' => '',
240            'description' => ''
241        ], $collection);
242
243        $this->app->helper('admin')->favicon = [
244            'path' => 'collections:icon.svg',
245            'color' => $collection['color']
246        ];
247
248        if ($id) {
249
250            $entry = $this->module('collections')->findOne($collection['name'], ['_id' => $id]);
251            //$entry = $this->app->storage->findOne("collections/{$collection['_id']}", ['_id' => $id]);
252
253            if (!$entry) {
254                return cockpit()->helper('admin')->denyRequest();
255            }
256
257            if (!$this->app->helper('admin')->isResourceEditableByCurrentUser($id, $meta)) {
258                return $this->render('collections:views/locked.php', compact('meta', 'collection', 'entry'));
259            }
260
261            $this->app->helper('admin')->lockResourceId($id);
262        }
263
264        $context = _check_collection_rule($collection, 'read', ['options' => ['filter'=>[]]]);
265
266        if ($context && isset($context->options['fields'])) {
267            foreach ($context->options['fields'] as $field => $include) {
268                if(!$include) $excludeFields[] = $field;
269            }
270        }
271
272        $view = 'collections:views/entry.php';
273
274        if ($override = $this->app->path('#config:collections/'.$collection['name'].'/views/entry.php')) {
275            $view = $override;
276        }
277
278        return $this->render($view, compact('collection', 'entry', 'excludeFields'));
279    }
280
281    public function save_entry($collection) {
282
283        $collection = $this->module('collections')->collection($collection);
284
285        if (!$collection) {
286            return false;
287        }
288
289        $entry = $this->param('entry', false);
290
291        if (!$entry) {
292            return false;
293        }
294
295        if (!isset($entry['_id']) && !$this->module('collections')->hasaccess($collection['name'], 'entries_create')) {
296            return $this->helper('admin')->denyRequest();
297        }
298
299        if (isset($entry['_id']) && !$this->module('collections')->hasaccess($collection['name'], 'entries_edit')) {
300            return $this->helper('admin')->denyRequest();
301        }
302
303        $entry['_mby'] = $this->module('cockpit')->getUser('_id');
304
305        if (isset($entry['_id'])) {
306
307            if (!$this->app->helper('admin')->isResourceEditableByCurrentUser($entry['_id'])) {
308                $this->stop(['error' => "Saving failed! Entry is locked!"], 412);
309            }
310
311            $_entry = $this->module('collections')->findOne($collection['name'], ['_id' => $entry['_id']]);
312            $revision = !(json_encode($_entry) == json_encode($entry));
313
314        } else {
315
316            $entry['_by'] = $entry['_mby'];
317            $revision = true;
318
319            if ($collection['sortable']) {
320                 $entry['_o'] = $this->app->storage->count("collections/{$collection['_id']}", ['_pid' => ['$exists' => false]]);
321            }
322
323        }
324
325        $entry = $this->module('collections')->save($collection['name'], $entry, ['revision' => $revision]);
326
327        $this->app->helper('admin')->lockResourceId($entry['_id']);
328
329        return $entry;
330    }
331
332    public function delete_entries($collection) {
333
334        \session_write_close();
335
336        $collection = $this->module('collections')->collection($collection);
337
338        if (!$collection) {
339            return false;
340        }
341
342        if (!$this->module('collections')->hasaccess($collection['name'], 'entries_delete')) {
343            return $this->helper('admin')->denyRequest();
344        }
345
346        $filter = $this->param('filter', false);
347
348        if (!$filter) {
349            return false;
350        }
351
352        $items = $this->module('collections')->find($collection['name'], ['filter' => $filter]);
353
354        if (count($items)) {
355            
356            $trashItems = [];
357            $time = time();
358            $by = $this->module('cockpit')->getUser('_id');
359
360            foreach ($items as $item) {
361
362                $trashItems[] = [
363                    'collection' => $collection['name'],
364                    'data' => $item,
365                    '_by' => $by,
366                    '_created' => $time
367                ];
368            }
369
370            $this->app->storage->getCollection('collections/_trash')->insertMany($trashItems);
371        }
372
373        $this->module('collections')->remove($collection['name'], $filter);
374
375        return true;
376    }
377
378    public function update_order($collection) {
379
380        \session_write_close();
381
382        $collection = $this->module('collections')->collection($collection);
383        $entries = $this->param('entries');
384
385        if (!$collection) return false;
386        if (!$entries) return false;
387
388        $_collectionId = $collection['_id'];
389
390        if (is_array($entries) && count($entries)) {
391
392            foreach($entries as $entry) {
393                $this->app->storage->save("collections/{$_collectionId}", $entry);
394            }
395        }
396
397        return $entries;
398    }
399
400    public function export($collection) {
401
402        \session_write_close();
403
404        if (!$this->app->module("cockpit")->hasaccess('collections', 'manage')) {
405            return false;
406        }
407
408        $collection = $this->module('collections')->collection($collection);
409
410        if (!$collection) return false;
411
412        if (!$this->module('collections')->hasaccess($collection['name'], 'entries_view')) {
413            return $this->helper('admin')->denyRequest();
414        }
415
416        $entries = $this->module('collections')->find($collection['name']);
417
418        return json_encode($entries, JSON_PRETTY_PRINT);
419    }
420
421
422    public function tree() {
423
424        \session_write_close();
425
426        $collection = $this->app->param('collection');
427
428        if (!$collection) return false;
429
430        $items = $this->app->module('collections')->find($collection);
431
432        if (count($items)) {
433
434            $items = $this->helper('utils')->buildTree($items, [
435                'parent_id_column_name' => '_pid',
436                'children_key_name' => 'children',
437                'id_column_name' => '_id',
438    			'sort_column_name' => '_o'
439            ]);
440        }
441
442        return $items;
443    }
444
445    public function find() {
446
447        \session_write_close();
448
449        $collection = $this->app->param('collection');
450        $options    = $this->app->param('options');
451
452        if (!$collection) return false;
453
454        $collection = $this->app->module('collections')->collection($collection);
455
456        if (isset($options['filter']) && is_string($options['filter'])) {
457
458            $filter = null;
459
460            if (\preg_match('/^\{(.*)\}$/', $options['filter'])) {
461
462                try {
463                    $filter = json5_decode($options['filter'], true);
464                } catch (\Exception $e) {}
465            }
466
467            if (!$filter) {
468                $filter = $this->_filter($options['filter'], $collection, $options['lang'] ?? null);
469            }
470
471            $options['filter'] = $filter;
472        }
473
474        $this->app->trigger("collections.admin.find.before.{$collection['name']}", [&$options]);
475        $entries = $this->app->module('collections')->find($collection['name'], $options);
476        $this->app->trigger("collections.admin.find.after.{$collection['name']}", [&$entries, $options]);
477        
478        $count = $this->app->module('collections')->count($collection['name'], isset($options['filter']) ? $options['filter'] : []);
479        $pages = isset($options['limit']) ? ceil($count / $options['limit']) : 1;
480        $page  = 1;
481
482        if ($pages > 1 && isset($options['skip'])) {
483            $page = ceil($options['skip'] / $options['limit']) + 1;
484        }
485
486        return compact('entries', 'count', 'pages', 'page');
487    }
488
489
490    public function revisions($collection, $id) {
491
492        if (!$this->module('collections')->hasaccess($collection, 'entries_edit')) {
493            return $this->helper('admin')->denyRequest();
494        }
495
496        $collection = $this->module('collections')->collection($collection);
497
498        if (!$collection) {
499            return false;
500        }
501
502        $entry = $this->module('collections')->findOne($collection['name'], ['_id' => $id]);
503
504        if (!$entry) {
505            return false;
506        }
507
508        $revisions = $this->app->helper('revisions')->getList($id);
509
510
511        return $this->render('collections:views/revisions.php', compact('collection', 'entry', 'revisions'));
512    }
513
514    protected function _filter($filter, $collection, $lang = null) {
515
516        if ($this->app->storage->type == 'mongolite') {
517            return $this->_filterLight($filter, $collection, $lang);
518        }
519
520        if ($this->app->storage->type == 'mongodb') {
521            return $this->_filterMongo($filter, $collection, $lang);
522        }
523
524        return null;
525
526    }
527
528    protected function _filterLight($filter, $collection, $lang) {
529
530        $allowedtypes = ['text','longtext','boolean','select','html','wysiwyg','markdown','code'];
531        $criterias    = [];
532        $_filter      = null;
533
534        foreach ($collection['fields'] as $field) {
535
536            $name = $field['name'];
537
538            if ($lang && $field['localize']) {
539                $name = "{$name}_{$lang}";
540            }
541
542            if ($field['type'] != 'boolean' && in_array($field['type'], $allowedtypes)) {
543                $criteria = [];
544                $criteria[$name] = ['$regex' => $filter];
545                $criterias[] = $criteria;
546            }
547
548            if ($field['type']=='collectionlink') {
549                $criteria = [];
550                $criteria[$name.'.display'] = ['$regex' => $filter];
551                $criterias[] = $criteria;
552            }
553
554            if ($field['type']=='location') {
555                $criteria = [];
556                $criteria[$name.'.address'] = ['$regex' => $filter];
557                $criterias[] = $criteria;
558            }
559
560        }
561
562        if (count($criterias)) {
563            $_filter = ['$or' => $criterias];
564        }
565
566        return $_filter;
567    }
568
569    protected function _filterMongo($filter, $collection, $lang) {
570
571        $allowedtypes = ['text','longtext','boolean','select','html','wysiwyg','markdown','code'];
572        $criterias    = [];
573        $_filter      = null;
574
575        foreach ($collection['fields'] as $field) {
576
577            $name = $field['name'];
578
579            if ($lang && $field['localize']) {
580                $name = "{$name}_{$lang}";
581            }
582
583            if ($field['type'] != 'boolean' && in_array($field['type'], $allowedtypes)) {
584                $criteria = [];
585                $criteria[$name] = ['$regex' => $filter, '$options' => 'i'];
586                $criterias[] = $criteria;
587            }
588
589            if ($field['type']=='collectionlink') {
590                $criteria = [];
591                $criteria[$name.'.display'] = ['$regex' => $filter, '$options' => 'i'];
592                $criterias[] = $criteria;
593            }
594
595            if ($field['type']=='location') {
596                $criteria = [];
597                $criteria[$name.'.address'] = ['$regex' => $filter, '$options' => 'i'];
598                $criterias[] = $criteria;
599            }
600
601        }
602
603        if (count($criterias)) {
604            $_filter = ['$or' => $criterias];
605        }
606
607        return $_filter;
608    }
609}