Browse code

Make permissions more granular

Benjamin Roth authored on02/08/2023 22:20:40
Showing1 changed files
... ...
@@ -20,6 +20,8 @@ use Contao\DataContainer;
20 20
 use Contao\Image;
21 21
 use Contao\Input;
22 22
 use Contao\StringUtil;
23
+use Contao\System;
24
+use Doctrine\DBAL\Connection;
23 25
 use Symfony\Component\HttpFoundation\Session\SessionInterface;
24 26
 use Symfony\Component\Security\Core\Security;
25 27
 use vonRotenberg\ModalBundle\Security\ModalPermissions;
... ...
@@ -43,11 +45,64 @@ class ModalDataContainerListener
43 45
         $user = $this->security->getUser();
44 46
         $userId = $user instanceof BackendUser ? (int)$user->id : 0;
45 47
 
48
+        $objSession = System::getContainer()->get('session');
49
+        $session = $objSession->all();
50
+
46 51
         if ($user->isAdmin)
47 52
         {
48 53
             return;
49 54
         }
50 55
 
56
+        // Set root IDs
57
+        if (empty($user->modals) || !is_array($user->modals))
58
+        {
59
+            $root = array(0);
60
+        }
61
+        else
62
+        {
63
+            $root = $user->modals;
64
+        }
65
+
66
+        if (is_array($session['CURRENT']['IDS'] ?? null))
67
+        {
68
+            $edit_all = array();
69
+            $delete_all = array();
70
+
71
+            foreach ($session['CURRENT']['IDS'] as $id)
72
+            {
73
+                if ($this->security->isGranted(ModalPermissions::USER_CAN_EDIT_MODALS, $id))
74
+                {
75
+                    $edit_all[] = $id;
76
+                }
77
+
78
+                if ($this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS, $id))
79
+                {
80
+                    $delete_all[] = $id;
81
+                }
82
+            }
83
+
84
+            $session['CURRENT']['IDS'] = (Input::get('act') == 'deleteAll') ? $delete_all : $edit_all;
85
+        }
86
+
87
+        // Set allowed clipboard IDs
88
+        if (!empty($session['CLIPBOARD']['tl_vr_modal']['id']) && is_array($session['CLIPBOARD']['tl_vr_modal']['id']))
89
+        {
90
+            $clipboard = array();
91
+
92
+            foreach ($session['CLIPBOARD']['tl_vr_modal']['id'] as $id)
93
+            {
94
+                if ($this->security->isGranted(ModalPermissions::USER_CAN_EDIT_MODALS, $id))
95
+                {
96
+                    $clipboard[] = $id;
97
+                }
98
+            }
99
+
100
+            $session['CLIPBOARD']['tl_article']['id'] = $clipboard;
101
+        }
102
+
103
+        // Overwrite the session
104
+        $objSession->replace($session);
105
+
51 106
         // Check permissions to add modals
52 107
         if (!$this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS))
53 108
         {
... ...
@@ -65,14 +120,27 @@ class ModalDataContainerListener
65 120
         // Check current action
66 121
         switch (Input::get('act'))
67 122
         {
68
-            case 'overrideAll':
69
-            case 'editAll':
70
-            case 'show':
71
-            case 'edit':
72 123
             case 'select':
73 124
                 // Allow
74 125
                 break;
75 126
 
127
+            case 'edit':
128
+            case 'show':
129
+                if (!in_array(Input::get('id'), $root))
130
+                {
131
+                    throw new AccessDeniedException('Not enough permissions to ' . Input::get('act') . ' form ID ' . Input::get('id') . '.');
132
+                }
133
+                break;
134
+
135
+            case 'editAll':
136
+            case 'overrideAll':
137
+                $session = $objSession->all();
138
+
139
+                $session['CURRENT']['IDS'] = array_intersect((array) $session['CURRENT']['IDS'], $root);
140
+
141
+                $objSession->replace($session);
142
+                break;
143
+
76 144
             case 'copy':
77 145
             case 'create':
78 146
                 if (!$this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS))
... ...
@@ -115,6 +183,95 @@ class ModalDataContainerListener
115 183
     }
116 184
 
117 185
     /**
186
+     * @Callback(table="tl_vr_modal", target="config.oncreate")
187
+     * @Callback(table="tl_vr_modal", target="config.oncopy")
188
+     */
189
+    public function adjustPermissions($insertId)
190
+    {
191
+        $user = $this->security->getUser();
192
+        $userId = $user instanceof BackendUser ? (int)$user->id : 0;
193
+
194
+        // The oncreate_callback passes $insertId as second argument
195
+        if (func_num_args() == 4)
196
+        {
197
+            $insertId = func_get_arg(1);
198
+        }
199
+
200
+        if ($user->isAdmin)
201
+        {
202
+            return;
203
+        }
204
+
205
+        // Set root IDs
206
+        if (empty($user->modals) || !is_array($user->modals))
207
+        {
208
+            $root = array(0);
209
+        }
210
+        else
211
+        {
212
+            $root = $user->modals;
213
+        }
214
+
215
+        // The form is enabled already
216
+        if (in_array($insertId, $root))
217
+        {
218
+            return;
219
+        }
220
+
221
+        /** @var AttributeBagInterface $objSessionBag */
222
+        $objSessionBag = System::getContainer()->get('session')->getBag('contao_backend');
223
+        $arrNew = $objSessionBag->get('new_records');
224
+
225
+        if (is_array($arrNew['tl_vr_modal']) && in_array($insertId, $arrNew['tl_vr_modal']))
226
+        {
227
+            /** @var Connection $db */
228
+            $db = System::getContainer()->get('database_connection');
229
+
230
+            // Add the permissions on group level
231
+            if ($user->inherit != 'custom')
232
+            {
233
+                $objGroup = $db->executeQuery("SELECT id, modals, modalp FROM tl_user_group WHERE id IN(" . implode(',', array_map('\intval', $user->groups)) . ")");
234
+
235
+                foreach ($objGroup->fetchAllAssociative() as $group)
236
+                {
237
+                    $arrModalp = StringUtil::deserialize($group['modalp']);
238
+
239
+                    if (is_array($arrModalp) && in_array('create', $arrModalp))
240
+                    {
241
+                        $arrModals = StringUtil::deserialize($group['modals'], true);
242
+                        $arrModals[] = $insertId;
243
+
244
+                        $db->prepare("UPDATE tl_user_group SET modals=? WHERE id=?")
245
+                            ->executeQuery([serialize($arrModals), $group['id']]);
246
+                    }
247
+                }
248
+            }
249
+
250
+            // Add the permissions on user level
251
+            if ($user->inherit != 'group')
252
+            {
253
+                $objUser = $db->prepare("SELECT modals, modalp FROM tl_user WHERE id=? LIMIT 1")
254
+                    ->executeQuery([$user->id]);
255
+
256
+                $arrModalp = StringUtil::deserialize($objUser->fetchOne());
257
+
258
+                if (is_array($arrModalp) && in_array('create', $arrModalp))
259
+                {
260
+                    $arrModals = StringUtil::deserialize($objUser->modals, true);
261
+                    $arrModals[] = $insertId;
262
+
263
+                    $db->prepare("UPDATE tl_user SET modals=? WHERE id=?")
264
+                        ->executeQuery([serialize($arrModals), $user->id]);
265
+                }
266
+            }
267
+
268
+            // Add the new element to the user object
269
+            $root[] = $insertId;
270
+            $user->forms = $root;
271
+        }
272
+    }
273
+
274
+    /**
118 275
      * @Callback(table="tl_vr_modal", target="list.operations.copy.button")
119 276
      */
120 277
     public function copyModal($row, $href, $label, $title, $icon, $attributes): string
... ...
@@ -129,4 +286,20 @@ class ModalDataContainerListener
129 286
     {
130 287
         return $this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS) ? '<a href="' . Backend::addToUrl($href . '&amp;id=' . $row['id']) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label) . '</a> ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
131 288
     }
289
+
290
+    /**
291
+     * @Callback(table="tl_vr_modal", target="list.operations.edit.button")
292
+     */
293
+    public function editModal($row, $href, $label, $title, $icon, $attributes): string
294
+    {
295
+        return $this->security->isGranted(ModalPermissions::USER_CAN_EDIT_MODALS, $row['id']) ? '<a href="' . Backend::addToUrl($href . '&amp;id=' . $row['id']) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label) . '</a> ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
296
+    }
297
+
298
+    /**
299
+     * @Callback(table="tl_vr_modal", target="list.operations.editheader.button")
300
+     */
301
+    public function editHeaderModal($row, $href, $label, $title, $icon, $attributes): string
302
+    {
303
+        return $this->security->isGranted(ModalPermissions::USER_CAN_EDIT_MODALS, $row['id']) ? '<a href="' . Backend::addToUrl($href . '&amp;id=' . $row['id']) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label) . '</a> ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
304
+    }
132 305
 }
Browse code

Add popup user privileges

Benjamin Roth authored on12/01/2023 22:23:51
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,132 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of modal bundle for Contao.
7
+ *
8
+ * (c) Benjamin Roth
9
+ *
10
+ * @license LGPL-3.0-or-later
11
+ */
12
+
13
+namespace vonRotenberg\ModalBundle\EventListener\DataContainer;
14
+
15
+use Contao\Backend;
16
+use Contao\BackendUser;
17
+use Contao\CoreBundle\Exception\AccessDeniedException;
18
+use Contao\CoreBundle\ServiceAnnotation\Callback;
19
+use Contao\DataContainer;
20
+use Contao\Image;
21
+use Contao\Input;
22
+use Contao\StringUtil;
23
+use Symfony\Component\HttpFoundation\Session\SessionInterface;
24
+use Symfony\Component\Security\Core\Security;
25
+use vonRotenberg\ModalBundle\Security\ModalPermissions;
26
+
27
+class ModalDataContainerListener
28
+{
29
+    private Security $security;
30
+    private SessionInterface $session;
31
+
32
+    public function __construct(Security $security, SessionInterface $session)
33
+    {
34
+        $this->security = $security;
35
+        $this->session = $session;
36
+    }
37
+
38
+    /**
39
+     * @Callback(table="tl_vr_modal", target="config.onload")
40
+     */
41
+    public function checkPermission(DataContainer $dc = null): void
42
+    {
43
+        $user = $this->security->getUser();
44
+        $userId = $user instanceof BackendUser ? (int)$user->id : 0;
45
+
46
+        if ($user->isAdmin)
47
+        {
48
+            return;
49
+        }
50
+
51
+        // Check permissions to add modals
52
+        if (!$this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS))
53
+        {
54
+            $GLOBALS['TL_DCA']['tl_vr_modal']['config']['closed'] = true;
55
+            $GLOBALS['TL_DCA']['tl_vr_modal']['config']['notCreatable'] = true;
56
+            $GLOBALS['TL_DCA']['tl_vr_modal']['config']['notCopyable'] = true;
57
+        }
58
+
59
+        // Check permissions to delete modals
60
+        if (!$this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS))
61
+        {
62
+            $GLOBALS['TL_DCA']['tl_vr_modal']['config']['notDeletable'] = true;
63
+        }
64
+
65
+        // Check current action
66
+        switch (Input::get('act'))
67
+        {
68
+            case 'overrideAll':
69
+            case 'editAll':
70
+            case 'show':
71
+            case 'edit':
72
+            case 'select':
73
+                // Allow
74
+                break;
75
+
76
+            case 'copy':
77
+            case 'create':
78
+                if (!$this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS))
79
+                {
80
+                    throw new AccessDeniedException('Not enough permissions to ' . Input::get('act') . ' modals.');
81
+                }
82
+                break;
83
+
84
+            case 'delete':
85
+                if (!$this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS))
86
+                {
87
+                    throw new AccessDeniedException('Not enough permissions to ' . Input::get('act') . ' modal ID ' . Input::get('id') . '.');
88
+                }
89
+                break;
90
+
91
+            case 'deleteAll':
92
+            case 'copyAll':
93
+                $session = $this->session->all();
94
+
95
+                if (Input::get('act') == 'deleteAll' && !$this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS))
96
+                {
97
+                    $session['CURRENT']['IDS'] = array();
98
+                } else
99
+                {
100
+                    if (Input::get('act') == 'copyAll' && !$this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS))
101
+                    {
102
+                        $session['CURRENT']['IDS'] = array();
103
+                    }
104
+                }
105
+                $this->session->replace($session);
106
+                break;
107
+
108
+            default:
109
+                if (Input::get('act'))
110
+                {
111
+                    throw new AccessDeniedException('Not enough permissions to ' . Input::get('act') . ' modals.');
112
+                }
113
+                break;
114
+        }
115
+    }
116
+
117
+    /**
118
+     * @Callback(table="tl_vr_modal", target="list.operations.copy.button")
119
+     */
120
+    public function copyModal($row, $href, $label, $title, $icon, $attributes): string
121
+    {
122
+        return $this->security->isGranted(ModalPermissions::USER_CAN_CREATE_MODALS) ? '<a href="' . Backend::addToUrl($href . '&amp;id=' . $row['id']) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label) . '</a> ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
123
+    }
124
+
125
+    /**
126
+     * @Callback(table="tl_vr_modal", target="list.operations.delete.button")
127
+     */
128
+    public function deleteModal($row, $href, $label, $title, $icon, $attributes): string
129
+    {
130
+        return $this->security->isGranted(ModalPermissions::USER_CAN_DELETE_MODALS) ? '<a href="' . Backend::addToUrl($href . '&amp;id=' . $row['id']) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label) . '</a> ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
131
+    }
132
+}