Browse code

Backport user based standort and reservation permissions

Benjamin Roth authored on19/09/2025 14:59:00
Showing7 changed files
... ...
@@ -30,6 +30,8 @@ ArrayUtil::arrayInsert($GLOBALS['BE_MOD'],1,[
30 30
     ]
31 31
 ]);
32 32
 
33
+$GLOBALS['TL_PERMISSIONS'][] = 'standorts';
34
+$GLOBALS['TL_PERMISSIONS'][] = 'reservationp';
33 35
 
34 36
 $GLOBALS['TL_MODELS']['tl_vr_wa_slot'] = WeinanlieferungSlotsModel::class;
35 37
 $GLOBALS['TL_MODELS']['tl_vr_wa_standort'] = WeinanlieferungStandortModel::class;
36 38
new file mode 100644
... ...
@@ -0,0 +1,39 @@
1
+<?php
2
+
3
+/**
4
+ * This file is part of contao-weinanlieferung-bundle.
5
+ *
6
+ * (c) vonRotenberg
7
+ *
8
+ * @license commercial
9
+ */
10
+
11
+use Contao\CoreBundle\DataContainer\PaletteManipulator;
12
+
13
+// Extend the default palette
14
+PaletteManipulator::create()
15
+    ->addLegend('luumicore_legend', 'imageSizes_legend', PaletteManipulator::POSITION_AFTER)
16
+    ->addField(array('standorts','reservationp'), 'luumicore_legend', PaletteManipulator::POSITION_APPEND)
17
+    ->applyToPalette('default', 'tl_user_group')
18
+;
19
+
20
+$GLOBALS['TL_DCA']['tl_user_group']['fields']['standorts'] = array
21
+(
22
+    'exclude'                 => true,
23
+    'inputType'               => 'checkbox',
24
+    'foreignKey'              => 'tl_vr_wa_standort.title',
25
+    'eval'                    => array('multiple'=>true),
26
+    'sql'                     => "blob NULL"
27
+);
28
+
29
+$GLOBALS['TL_DCA']['tl_user_group']['fields']['reservationp'] = array
30
+(
31
+    'exclude'               => true,
32
+    'filter'                => true,
33
+    'options'               => array('edit', 'delete'),
34
+    'eval'                  => array('multiple'=>true),
35
+    'reference'             => &$GLOBALS['TL_LANG']['MSC'],
36
+    'inputType'             => 'checkbox',
37
+    'sql'                   => "blob NULL"
38
+
39
+);
0 40
new file mode 100644
... ...
@@ -0,0 +1,16 @@
1
+<?php
2
+
3
+/**
4
+ * This file is part of contao-weinanlieferung-bundle.
5
+ *
6
+ * (c) vonRotenberg
7
+ *
8
+ * @license commercial
9
+ */
10
+
11
+// Legends
12
+$GLOBALS['TL_LANG']['tl_user_group']['luumicore_legend'] = 'luumiCORE-Berechtigungen';
13
+
14
+// Fields
15
+$GLOBALS['TL_LANG']['tl_user_group']['standorts'] = ['Erlaubte Standorte', 'Hier können Sie den Zugriff auf einen oder mehrere Standorte erlauben.'];
16
+$GLOBALS['TL_LANG']['tl_user_group']['reservationp'] = ['Buchung-Rechte', 'Hier können Sie die Buchungsrechte festlegen.'];
... ...
@@ -187,16 +187,20 @@
187 187
                                                             </div>
188 188
                                                         </div>
189 189
                                                         <div class="col u-text-right action">
190
-                                                            <a
191
-                                                                href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=edit&id={{ booking.id }}&rt={{ request_token }}&ref={{ ref }}"
192
-                                                                {#                        onclick="Backend.openModalIframe({'title':'Quellelement ID {{ booking.id }} bearbeiten','url':this.href});return false" #}
193
-                                                                title="Element ID {{ booking.id }} bearbeiten"
194
-                                                            ><img src="/system/themes/flexible/icons/edit.svg" width="16" height="16" alt="Element ID {{ booking.id }} bearbeiten"></a>
195
-                                                            <a
196
-                                                                href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=delete&id={{ booking.id }}&rt={{ request_token }}"
197
-                                                                onclick="if(!confirm('Soll das Element ID {{ booking.id }} wirklich gelöscht werden?'))return false;Backend.getScrollOffset()"
198
-                                                                title="Element ID {{ booking.id }} löschen"
199
-                                                            ><img src="/system/themes/flexible/icons/delete.svg" width="16" height="16" alt="Element ID {{ booking.id }} löschen"></a>
190
+                                                            {% if permissions.edit %}
191
+                                                                <a
192
+                                                                    href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=edit&id={{ booking.id }}&rt={{ request_token }}&ref={{ ref }}"
193
+                                                                    {#                        onclick="Backend.openModalIframe({'title':'Quellelement ID {{ booking.id }} bearbeiten','url':this.href});return false" #}
194
+                                                                    title="Element ID {{ booking.id }} bearbeiten"
195
+                                                                ><img src="/system/themes/flexible/icons/edit.svg" width="16" height="16" alt="Element ID {{ booking.id }} bearbeiten"></a>
196
+                                                            {% endif %}
197
+                                                            {% if permissions.delete %}
198
+                                                                <a
199
+                                                                    href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=delete&id={{ booking.id }}&rt={{ request_token }}"
200
+                                                                    onclick="if(!confirm('Soll das Element ID {{ booking.id }} wirklich gelöscht werden?'))return false;Backend.getScrollOffset()"
201
+                                                                    title="Element ID {{ booking.id }} löschen"
202
+                                                                ><img src="/system/themes/flexible/icons/delete.svg" width="16" height="16" alt="Element ID {{ booking.id }} löschen"></a>
203
+                                                            {% endif %}
200 204
                                                         </div>
201 205
                                                     </div>
202 206
                                                     {#<div class="row u-items-flex-start my-1 status status--{{ status }}">
... ...
@@ -13,8 +13,10 @@ declare(strict_types=1);
13 13
 namespace vonRotenberg\WeinanlieferungBundle\Controller\Backend;
14 14
 
15 15
 use Contao\Backend;
16
+use Contao\BackendUser;
16 17
 use Contao\CoreBundle\Controller\AbstractController;
17 18
 use Contao\CoreBundle\Csrf\ContaoCsrfTokenManager;
19
+use Contao\Database;
18 20
 use Contao\Date;
19 21
 use Contao\Environment;
20 22
 use Contao\FrontendUser;
... ...
@@ -33,7 +35,9 @@ use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel;
33 35
 use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel;
34 36
 use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungReservationModel;
35 37
 use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungSlotsModel;
38
+use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungStandortModel;
36 39
 use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungUnitModel;
40
+use vonRotenberg\WeinanlieferungBundle\Security\WeinanlieferungPermissions;
37 41
 
38 42
 /**
39 43
  * @Route("contao/weinanlieferung/buchungsliste", name=WeinanlieferungBookingsController::class, defaults={"_scope" = "backend"})
... ...
@@ -102,6 +106,10 @@ class WeinanlieferungBookingsController extends AbstractController
102 106
             ->select('id')
103 107
             ->from(WeinanlieferungSlotsModel::getTable());
104 108
 
109
+        // Allowed standorts
110
+        $allowedStandortIds = $this->getAllowedStandortIds();
111
+        $queryBuilder->andWhere('pid IN ('.implode(',',$allowedStandortIds).')');
112
+
105 113
         if (!empty($session['tl_vr_wa_reservation']['tl_day']) && is_numeric($session['tl_vr_wa_reservation']['tl_day']))
106 114
         {
107 115
             $Day = new Date($session['tl_vr_wa_reservation']['tl_day']);
... ...
@@ -136,7 +144,7 @@ class WeinanlieferungBookingsController extends AbstractController
136 144
                 ->setParameter('pid', (int) $session['tl_vr_wa_reservation']['tl_standort']);
137 145
         }
138 146
 
139
-        $arrSlots = $queryBuilder->fetchFirstColumn();
147
+        $arrSlots = array_merge([0],$queryBuilder->fetchFirstColumn());
140 148
 
141 149
 
142 150
         $arrDayOptions = [];
... ...
@@ -156,7 +164,7 @@ class WeinanlieferungBookingsController extends AbstractController
156 164
         }*/
157 165
 
158 166
         $arrStandortOptions = [];
159
-        $StandortRequest = $this->db->executeQuery("SELECT l.id, l.title FROM tl_vr_wa_reservation r INNER JOIN tl_vr_wa_slot s ON s.id = r.pid INNER JOIN tl_vr_wa_standort l ON l.id = s.pid GROUP BY l.id ORDER BY l.title ASC");
167
+        $StandortRequest = $this->db->executeQuery("SELECT l.id, l.title FROM tl_vr_wa_reservation r INNER JOIN tl_vr_wa_slot s ON s.id = r.pid INNER JOIN tl_vr_wa_standort l ON l.id = s.pid WHERE s.pid IN (".implode(',',$allowedStandortIds).") GROUP BY l.id ORDER BY l.title ASC");
160 168
         foreach ($StandortRequest->iterateAssociative() as $standort)
161 169
         {
162 170
             $arrStandortOptions[$standort['id']] = $standort['title'];
... ...
@@ -165,7 +173,7 @@ class WeinanlieferungBookingsController extends AbstractController
165 173
         $arrData['filter']['day']['options'] = $arrDayOptions;
166 174
 //        $arrData['filter']['month']['options'] = $arrMonthOptions;
167 175
         $arrData['filter']['standort']['options'] = $arrStandortOptions;
168
-
176
+dump($arrSlots);
169 177
 
170 178
         // Get bookings
171 179
         if (isset($queryBuilder))
... ...
@@ -342,6 +350,13 @@ class WeinanlieferungBookingsController extends AbstractController
342 350
             }
343 351
         }
344 352
 
353
+        // Security
354
+        $security = System::getContainer()->get('security.helper');
355
+        $arrData['permissions'] = [
356
+            'edit' => $security->isGranted(WeinanlieferungPermissions::USER_CAN_EDIT_RESERVATIONS),
357
+            'delete' => $security->isGranted(WeinanlieferungPermissions::USER_CAN_DELETE_RESERVATIONS),
358
+        ];
359
+
345 360
         return new Response(
346 361
             $this->twig->render(
347 362
                 '@Contao_VonrotenbergWeinanlieferungBundle/be_wa_buchungsliste.html.twig',
... ...
@@ -349,4 +364,39 @@ class WeinanlieferungBookingsController extends AbstractController
349 364
             )
350 365
         );
351 366
     }
367
+
368
+    protected function getAllowedStandortIds(): array
369
+    {
370
+        // If no frontend user is logged in, return empty array
371
+        if (!BackendUser::getInstance()->id) {
372
+            return [0];
373
+        }
374
+
375
+        if (BackendUser::getInstance()->isAdmin)
376
+        {
377
+            return WeinanlieferungStandortModel::findAll()->fetchEach('id');
378
+        }
379
+
380
+        // Get member groups
381
+        $userGroups = StringUtil::deserialize(BackendUser::getInstance()->groups, true);
382
+        if (empty($userGroups)) {
383
+            return [0];
384
+        }
385
+
386
+        // Get allowed standorts from member groups
387
+        $db = Database::getInstance();
388
+        $allowedStandorts = [0];
389
+
390
+        foreach ($userGroups as $groupId) {
391
+            $group = $db->prepare("SELECT standorts FROM tl_user_group WHERE id=?")
392
+                ->execute($groupId);
393
+
394
+            if ($group->standorts) {
395
+                $groupStandorts = StringUtil::deserialize($group->standorts, true);
396
+                $allowedStandorts = array_merge($allowedStandorts, $groupStandorts);
397
+            }
398
+        }
399
+
400
+        return array_unique($allowedStandorts);
401
+    }
352 402
 }
... ...
@@ -46,7 +46,8 @@ use vonRotenberg\WeinanlieferungBundle\Controller\Backend\WeinanlieferungBooking
46 46
 
47 47
          if (($contentNode = $tree->getChild('weinanlieferung')) === null)
48 48
          {
49
-             $contentNode = $tree->addChild('weinanlieferung');
49
+             $contentNode = $tree->addChild('weinanlieferung')
50
+                 ->setLabel('Weinanlieferung');
50 51
          }
51 52
 
52 53
          $node = $factory
53 54
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Contao.
7
+ *
8
+ * (c) Leo Feyer
9
+ *
10
+ * @license LGPL-3.0-or-later
11
+ */
12
+
13
+namespace vonRotenberg\WeinanlieferungBundle\Security;
14
+
15
+final class WeinanlieferungPermissions
16
+{
17
+    public const USER_CAN_EDIT_STANDORTE = 'contao_user.standorts';
18
+    public const USER_CAN_EDIT_RESERVATIONS = 'contao_user.reservationp.edit';
19
+    public const USER_CAN_DELETE_RESERVATIONS = 'contao_user.reservationp.delete';
20
+}