Passed
Push — master ( ff1a76...9dbd27 )
by
unknown
13:17
created

PermissionController::initializeView()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 13
rs 10
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Beuser\Controller;
17
18
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
19
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
20
use TYPO3\CMS\Backend\Utility\BackendUtility;
21
use TYPO3\CMS\Backend\View\BackendTemplateView;
22
use TYPO3\CMS\Core\DataHandling\DataHandler;
23
use TYPO3\CMS\Core\Imaging\Icon;
24
use TYPO3\CMS\Core\Messaging\FlashMessage;
25
use TYPO3\CMS\Core\Utility\GeneralUtility;
26
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
27
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
28
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
29
30
/**
31
 * Backend module page permissions
32
 * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
33
 */
34
class PermissionController extends ActionController
35
{
36
    /**
37
     * @var string prefix for session
38
     */
39
    const SESSION_PREFIX = 'tx_Beuser_';
40
41
    /**
42
     * @var int the current page id
43
     */
44
    protected $id;
45
46
    /**
47
     * @var string
48
     */
49
    protected $returnUrl = '';
50
51
    /**
52
     * @var int
53
     */
54
    protected $depth;
55
56
    /**
57
     * Number of levels to enable recursive settings for
58
     *
59
     * @var int
60
     */
61
    protected $getLevels = 10;
62
63
    /**
64
     * @var array
65
     */
66
    protected $pageInfo = [];
67
68
    /**
69
     * Backend Template Container
70
     *
71
     * @var string
72
     */
73
    protected $defaultViewObjectName = BackendTemplateView::class;
74
75
    /**
76
     * BackendTemplateContainer
77
     *
78
     * @var BackendTemplateView
79
     */
80
    protected $view;
81
82
    /**
83
     * Initialize action
84
     */
85
    protected function initializeAction()
86
    {
87
        // determine depth parameter
88
        $this->depth = (int)GeneralUtility::_GP('depth') > 0
89
            ? (int)GeneralUtility::_GP('depth')
90
            : (int)$this->getBackendUser()->getSessionData(self::SESSION_PREFIX . 'depth');
91
        if ($this->request->hasArgument('depth')) {
92
            $this->depth = (int)$this->request->getArgument('depth');
93
        }
94
        $this->getBackendUser()->setAndSaveSessionData(self::SESSION_PREFIX . 'depth', $this->depth);
95
96
        // determine id parameter
97
        $this->id = (int)GeneralUtility::_GP('id');
98
        if ($this->request->hasArgument('id')) {
99
            $this->id = (int)$this->request->getArgument('id');
100
        }
101
102
        if (!BackendUtility::getRecord('pages', $this->id)) {
103
            $this->id = 0;
104
        }
105
106
        $this->returnUrl = GeneralUtility::_GP('returnUrl');
107
        if ($this->request->hasArgument('returnUrl')) {
108
            $this->returnUrl = $this->request->getArgument('returnUrl');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->request->getArgument('returnUrl') can also be of type array. However, the property $returnUrl is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
109
        }
110
111
        $this->setPageInfo();
112
    }
113
114
    /**
115
     * Initializes view
116
     *
117
     * @param ViewInterface $view The view to be initialized
118
     */
119
    protected function initializeView(ViewInterface $view)
120
    {
121
        parent::initializeView($view);
122
        $this->setPageInfo();
123
124
        // the view of the update action has a different view class
125
        if ($view instanceof BackendTemplateView) {
126
            $view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Beuser/Permissions');
127
            $view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
128
129
            $this->registerDocHeaderButtons();
130
            $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($this->pageInfo);
0 ignored issues
show
Bug introduced by
It seems like $this->pageInfo can also be of type false; however, parameter $metaInformation of TYPO3\CMS\Backend\Templa...t::setMetaInformation() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
            $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation(/** @scrutinizer ignore-type */ $this->pageInfo);
Loading history...
131
            $this->view->getModuleTemplate()->setFlashMessageQueue($this->getFlashMessageQueue());
132
        }
133
    }
134
135
    /**
136
     * Registers the Icons into the docheader
137
     *
138
     * @throws \InvalidArgumentException
139
     */
140
    protected function registerDocHeaderButtons()
141
    {
142
        /** @var ButtonBar $buttonBar */
143
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
144
        $currentRequest = $this->request;
145
        $moduleName = $currentRequest->getPluginName();
146
        $lang = $this->getLanguageService();
147
148
        if ($currentRequest->getControllerActionName() === 'edit') {
149
            // CLOSE button:
150
            if (!empty($this->returnUrl)) {
151
                $closeButton = $buttonBar->makeLinkButton()
152
                    ->setHref($this->returnUrl)
153
                    ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
154
                    ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
155
                        'actions-close',
156
                        Icon::SIZE_SMALL
157
                    ));
158
                $buttonBar->addButton($closeButton);
159
            }
160
161
            // SAVE button:
162
            $saveButton = $buttonBar->makeInputButton()
163
                ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveCloseDoc'))
164
                ->setName('tx_beuser_system_beusertxpermission[submit]')
165
                ->setValue('Save')
166
                ->setForm('PermissionControllerEdit')
167
                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
168
                    'actions-document-save',
169
                    Icon::SIZE_SMALL
170
                ))
171
                ->setShowLabelText(true);
172
173
            $buttonBar->addButton($saveButton);
174
        }
175
176
        $shortcutButton = $buttonBar->makeShortcutButton()
177
            ->setModuleName($moduleName)
178
            ->setDisplayName($this->getShortcutTitle())
179
            ->setArguments([
180
                'route' => GeneralUtility::_GP('route'),
181
                'id' => (int)$this->id,
182
            ]);
183
        $buttonBar->addButton($shortcutButton);
184
    }
185
186
    /**
187
     * Index action
188
     */
189
    public function indexAction()
190
    {
191
        if (!$this->id) {
192
            $this->pageInfo = ['title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], 'uid' => 0, 'pid' => 0];
193
        }
194
195
        if ($this->getBackendUser()->workspace != 0) {
196
            // Adding section with the permission setting matrix:
197
            $this->addFlashMessage(
198
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarningText', 'beuser') ?? '',
199
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarning', 'beuser') ?? '',
200
                FlashMessage::WARNING
201
            );
202
        }
203
204
        // depth options
205
        $depthOptions = [];
206
        $url = $this->uriBuilder->reset()->setArguments([
207
            'action' => 'index',
208
            'depth' => '${value}',
209
            'id' => $this->id
210
        ])->buildBackendUri();
211
        foreach ([1, 2, 3, 4, 10] as $depthLevel) {
212
            $levelLabel = $depthLevel === 1 ? 'level' : 'levels';
213
            $depthOptions[$depthLevel] = $depthLevel . ' ' . LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:' . $levelLabel, 'beuser');
214
        }
215
        $this->view->assign('currentId', $this->id);
216
        $this->view->assign('depthBaseUrl', $url);
217
        $this->view->assign('depth', $this->depth);
218
        $this->view->assign('depthOptions', $depthOptions);
219
220
        $beUserArray = BackendUtility::getUserNames();
221
        $this->view->assign('beUsers', $beUserArray);
222
        $beGroupArray = BackendUtility::getGroupNames();
223
        $this->view->assign('beGroups', $beGroupArray);
224
225
        /** @var PageTreeView $tree */
226
        $tree = GeneralUtility::makeInstance(PageTreeView::class);
227
        $tree->init();
228
        $tree->addField('perms_user', true);
229
        $tree->addField('perms_group', true);
230
        $tree->addField('perms_everybody', true);
231
        $tree->addField('perms_userid', true);
232
        $tree->addField('perms_groupid', true);
233
        $tree->addField('hidden');
234
        $tree->addField('fe_group');
235
        $tree->addField('starttime');
236
        $tree->addField('endtime');
237
        $tree->addField('editlock');
238
239
        // Create the tree from $this->id
240
        if ($this->id) {
241
            $tree->tree[] = ['row' => $this->pageInfo, 'HTML' => $tree->getIcon($this->pageInfo)];
242
        } else {
243
            $tree->tree[] = ['row' => $this->pageInfo, 'HTML' => $tree->getRootIcon($this->pageInfo)];
244
        }
245
        $tree->getTree($this->id, $this->depth);
246
        $this->view->assign('viewTree', $tree->tree);
247
248
        // CSH for permissions setting
249
        $this->view->assign('cshItem', BackendUtility::cshItem('xMOD_csh_corebe', 'perm_module', '', '<span class="btn btn-default btn-sm">|</span>'));
250
    }
251
252
    /**
253
     * Edit action
254
     */
255
    public function editAction()
256
    {
257
        $this->view->assign('id', $this->id);
258
        $this->view->assign('depth', $this->depth);
259
260
        if (!$this->id) {
261
            $this->pageInfo = ['title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], 'uid' => 0, 'pid' => 0];
262
        }
263
        if ($this->getBackendUser()->workspace != 0) {
264
            // Adding FlashMessage with the permission setting matrix:
265
            $this->addFlashMessage(
266
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarningText', 'beuser') ?? '',
267
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarning', 'beuser') ?? '',
268
                FlashMessage::WARNING
269
            );
270
        }
271
        // Get user names and group names
272
        $beGroupArray = BackendUtility::getGroupNames();
273
        $beUserArray  = BackendUtility::getUserNames();
274
275
        // Owner selector
276
        $beUserDataArray = [0 => LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone', 'beuser')];
277
        foreach ($beUserArray as $uid => &$row) {
278
            $beUserDataArray[$uid] = $row['username'];
279
        }
280
        $beUserDataArray[-1] = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectUnchanged', 'beuser');
281
        $this->view->assign('currentBeUser', $this->pageInfo['perms_userid']);
282
        $this->view->assign('beUserData', $beUserDataArray);
283
284
        // Group selector
285
        $beGroupDataArray = [0 => LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone', 'beuser')];
286
        foreach ($beGroupArray as $uid => $row) {
287
            $beGroupDataArray[$uid] = $row['title'];
288
        }
289
        $beGroupDataArray[-1] = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectUnchanged', 'beuser');
290
        $this->view->assign('currentBeGroup', $this->pageInfo['perms_groupid']);
291
        $this->view->assign('beGroupData', $beGroupDataArray);
292
        $this->view->assign('pageInfo', $this->pageInfo);
293
        $this->view->assign('returnUrl', $this->returnUrl);
294
        $this->view->assign('recursiveSelectOptions', $this->getRecursiveSelectOptions());
295
    }
296
297
    /**
298
     * Update action
299
     *
300
     * @param array $data
301
     * @param array $mirror
302
     */
303
    protected function updateAction(array $data, array $mirror)
304
    {
305
        $dataHandlerInput = [];
306
        // Prepare the input data for data handler
307
        if (!empty($data['pages'])) {
308
            foreach ($data['pages'] as $pageUid => $properties) {
309
                // if the owner and group field shouldn't be touched, unset the option
310
                if ((int)$properties['perms_userid'] === -1) {
311
                    unset($properties['perms_userid']);
312
                }
313
                if ((int)$properties['perms_groupid'] === -1) {
314
                    unset($properties['perms_groupid']);
315
                }
316
                $dataHandlerInput[$pageUid] = $properties;
317
                if (!empty($mirror['pages'][$pageUid])) {
318
                    $mirrorPages = GeneralUtility::intExplode(',', $mirror['pages'][$pageUid]);
319
                    foreach ($mirrorPages as $mirrorPageUid) {
320
                        $dataHandlerInput[$mirrorPageUid] = $properties;
321
                    }
322
                }
323
            }
324
        }
325
326
        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
327
        $dataHandler->start(
328
            [
329
                'pages' => $dataHandlerInput
330
            ],
331
            []
332
        );
333
        $dataHandler->process_datamap();
334
335
        $this->redirectToUri($this->returnUrl);
336
    }
337
338
    /**
339
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
340
     */
341
    protected function getBackendUser()
342
    {
343
        return $GLOBALS['BE_USER'];
344
    }
345
346
    /**
347
     * Finding tree and offer setting of values recursively.
348
     *
349
     * @return array
350
     */
351
    protected function getRecursiveSelectOptions()
352
    {
353
        // Initialize tree object:
354
        $tree = GeneralUtility::makeInstance(PageTreeView::class);
355
        $tree->init();
356
        $tree->addField('perms_userid', true);
357
        $tree->makeHTML = 0;
358
        $tree->setRecs = 1;
359
        // Make tree:
360
        $tree->getTree($this->id, $this->getLevels, '');
361
        $options = [];
362
        $options[''] = '';
363
        // If there are a hierarchy of page ids, then...
364
        if ($this->getBackendUser()->user['uid'] && !empty($tree->orig_ids_hierarchy)) {
365
            // Init:
366
            $labelRecursive = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:recursive', 'beuser');
367
            $labelLevel = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:level', 'beuser');
368
            $labelLevels = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:levels', 'beuser');
369
            $labelPageAffected = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:page_affected', 'beuser');
370
            $labelPagesAffected = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:pages_affected', 'beuser');
371
            $theIdListArr = [];
372
            // Traverse the number of levels we want to allow recursive
373
            // setting of permissions for:
374
            for ($a = $this->getLevels; $a > 0; $a--) {
375
                if (is_array($tree->orig_ids_hierarchy[$a])) {
376
                    foreach ($tree->orig_ids_hierarchy[$a] as $theId) {
377
                        $theIdListArr[] = $theId;
378
                    }
379
                    $lKey = $this->getLevels - $a + 1;
380
                    $pagesCount = count($theIdListArr);
381
                    $options[implode(',', $theIdListArr)] = $labelRecursive . ' ' . $lKey . ' ' . ($lKey === 1 ? $labelLevel : $labelLevels) .
382
                        ' (' . $pagesCount . ' ' . ($pagesCount === 1 ? $labelPageAffected : $labelPagesAffected) . ')';
383
                }
384
            }
385
        }
386
        return $options;
387
    }
388
389
    /**
390
     * Check if page record exists and set pageInfo
391
     */
392
    protected function setPageInfo(): void
393
    {
394
        $this->pageInfo = BackendUtility::readPageAccess(BackendUtility::getRecord('pages', $this->id) ? $this->id : 0, ' 1=1');
0 ignored issues
show
Documentation Bug introduced by
It seems like TYPO3\CMS\Backend\Utilit... $this->id : 0, ' 1=1') can also be of type false. However, the property $pageInfo is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
395
    }
396
397
    /**
398
     * Returns LanguageService
399
     *
400
     * @return \TYPO3\CMS\Core\Localization\LanguageService
401
     */
402
    protected function getLanguageService()
403
    {
404
        return $GLOBALS['LANG'];
405
    }
406
407
    /**
408
     * Returns the shortcut title for the current page
409
     *
410
     * @return string
411
     */
412
    protected function getShortcutTitle(): string
413
    {
414
        return sprintf(
415
            '%s: %s [%d]',
416
            $this->getLanguageService()->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'),
417
            BackendUtility::getRecordTitle('pages', $this->pageInfo),
418
            $this->id
419
        );
420
    }
421
}
422