Issues (326)

src/Controller/AppController.php (4 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Saito - The Threaded Web Forum
7
 *
8
 * @copyright Copyright (c) the Saito Project Developers
9
 * @link https://github.com/Schlaefer/Saito
10
 * @license http://opensource.org/licenses/MIT
11
 */
12
13
namespace App\Controller;
14
15
use App\Controller\Component\AuthUserComponent;
16
use App\Controller\Component\JsDataComponent;
0 ignored issues
show
The type App\Controller\Component\JsDataComponent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use App\Controller\Component\RefererComponent;
18
use App\Controller\Component\SaitoEmailComponent;
19
use App\Controller\Component\SlidetabsComponent;
20
use App\Controller\Component\ThemesComponent;
21
use App\Controller\Component\TitleComponent;
22
use App\Model\Table\UsersTable;
23
use Authentication\Controller\Component\AuthenticationComponent;
24
use Cake\Controller\Controller;
25
use Cake\Core\Configure;
26
use Cake\Core\InstanceConfigTrait;
27
use Cake\Event\Event;
28
use Cake\Http\Response;
29
use Cake\I18n\I18n;
30
use Cake\ORM\TableRegistry;
31
use Saito\App\Registry;
32
use Saito\App\SettingsImmutable;
33
use Saito\Event\SaitoEventManager;
34
use Saito\User\CurrentUser\CurrentUserInterface;
35
use Stopwatch\Lib\Stopwatch;
36
37
/**
38
 * Class AppController
39
 *
40
 * @property AuthUserComponent $AuthUser
41
 * @property AuthenticationComponent $Authentication
42
 * @property JsDataComponent $JsData
43
 * @property RefererComponent $Referer
44
 * @property SaitoEmailComponent $SaitoEmail
45
 * @property SlidetabsComponent $Slidetabs
46
 * @property ThemesComponent $Themes
47
 * @property TitleComponent $Title
48
 * @property UsersTable $Users
49
 */
50
class AppController extends Controller
51
{
52
    use InstanceConfigTrait;
53
54
    public $helpers = [
55
        'Form' => [
56
            // Bootstrap 4 CSS-class for invalid input elements
57
            'errorClass' => 'is-invalid',
58
            'templates' => [
59
                // Bootstrap 4 CSS-class for input validation message
60
                'error' => '<div class="invalid-feedback">{{content}}</div>',
61
            ],
62
        ],
63
        'Html',
64
        'JsData',
65
        'Layout',
66
        'Permissions',
67
        'SaitoHelp.SaitoHelp',
68
        'Stopwatch.Stopwatch',
69
        'TimeH',
70
        'Url',
71
        'User',
72
    ];
73
74
    /**
75
     * Default config used by InstanceConfigTrait
76
     *
77
     * @var array default configuration
78
     */
79
    protected $_defaultConfig = [
80
        'showStopwatch' => false,
81
    ];
82
83
    /**
84
     * The current user, set by the AuthUserComponent
85
     *
86
     * @var CurrentUserInterface
87
     */
88
    public $CurrentUser;
89
90
    /**
91
     * {@inheritDoc}
92
     */
93
    public function initialize()
94
    {
95
        Stopwatch::start('------------------- Controller -------------------');
96
97
        parent::initialize();
98
99
        $this->setConfig('showStopwatch', Configure::read('debug'));
100
101
        if (!$this->request->is('requested')) {
102
            $this->request->getSession()->start();
103
        }
104
105
        Registry::get('Permissions')->buildCategories(TableRegistry::getTableLocator()->get('Categories'));
106
107
        // Leave in front to have it available in all Components
108
        $this->loadComponent('Detectors.Detectors');
109
        $this->loadComponent('Cookie');
110
        $this->loadComponent('Authentication.Authentication');
111
        $this->loadComponent('Security', ['blackHoleCallback' => 'blackhole']);
112
        $this->loadComponent('Csrf', ['expiry' => time() + 10800]);
113
        if (PHP_SAPI !== 'cli') {
114
            // if: The security mock in testing doesn't allow seeting cookie-name.
115
            $this->Csrf->setConfig('cookieName', Configure::read('Session.cookie') . '-CSRF');
116
        }
117
        $this->loadComponent('RequestHandler', ['enableBeforeRedirect' => false]);
118
        $this->loadComponent('Cron.Cron');
119
        $this->loadComponent('CacheSupport');
120
        $this->loadComponent('AuthUser');
121
        $this->loadComponent('Parser');
122
        $this->loadComponent('SaitoEmail');
123
        $this->loadComponent('Slidetabs');
124
        $this->loadComponent('Themes', Configure::read('Saito.themes'));
125
        $this->loadComponent('Flash');
126
        $this->loadComponent('Title');
127
    }
128
129
    /**
130
     * {@inheritDoc}
131
     */
132
    public function beforeFilter(Event $event)
133
    {
134
        Stopwatch::start('App->beforeFilter()');
135
136
        // disable forum with admin pref
137
        if (
138
            Configure::read('Saito.Settings.forum_disabled') &&
139
            $this->request->getParam('action') !== 'login' &&
140
            !$this->CurrentUser->permission('saito.core.admin.backend')
141
        ) {
142
            $this->Themes->setDefault();
143
            $this->viewBuilder()->enableAutoLayout(false);
144
            $this->render('/Pages/forum_disabled');
145
            $this->response = $this->response->withStatus(503);
146
147
            return null;
148
        }
149
150
        // allow sql explain for DebugKit toolbar
151
        if ($this->request->getParam('plugin') === 'debug_kit') {
152
            $this->Authentication->allowUnauthenticated(['sql_explain']);
153
        }
154
155
        Stopwatch::stop('App->beforeFilter()');
156
    }
157
158
    /**
159
     * {@inheritDoc}
160
     */
161
    public function beforeRender(Event $event)
162
    {
163
        Stopwatch::start('App->beforeRender()');
164
        $this->Themes->set($this->CurrentUser);
165
        $this->_setConfigurationFromGetParams();
166
        $this->_l10nRenderFile();
167
168
        $this->set('SaitoSettings', new SettingsImmutable(Configure::read('Saito.Settings')));
169
        $this->set('SaitoEventManager', SaitoEventManager::getInstance());
170
        $this->set('showStopwatch', $this->getConfig('showStopwatch'));
171
172
        Stopwatch::stop('App->beforeRender()');
173
        Stopwatch::start('------------------- Rendering --------------------');
174
    }
175
176
    /**
177
     * Sets forum configuration from GET parameter in url
178
     *
179
     * - theme=<foo>
180
     * - stopwatch:true
181
     * - lang:<lang_id>
182
     *
183
     * @return void
184
     */
185
    protected function _setConfigurationFromGetParams()
186
    {
187
        if (!$this->CurrentUser->isLoggedIn()) {
188
            return;
189
        }
190
191
        //= change theme on the fly with ?theme=<name>
192
        $theme = $this->request->getQuery('theme');
193
        if ($theme) {
194
            $this->Themes->set($this->CurrentUser, $theme);
0 ignored issues
show
It seems like $theme can also be of type array; however, parameter $theme of App\Controller\Component\ThemesComponent::set() does only seem to accept string, 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

194
            $this->Themes->set($this->CurrentUser, /** @scrutinizer ignore-type */ $theme);
Loading history...
195
        }
196
197
        //= activate stopwatch
198
        $stopwatch = $this->request->getQuery('stopwatch');
199
        if (
200
            $stopwatch && Configure::read('Saito.Settings.stopwatch_get')
201
        ) {
202
            $this->setConfig('showStopwatch', true);
203
        };
204
205
        //= change language
206
        $lang = $this->request->getQuery('lang');
207
        if (!empty($lang)) {
208
            Configure::write('Saito.language', $lang);
209
        };
210
    }
211
212
    /**
213
     * Handle request-blackhole.
214
     *
215
     * @param string $type type
216
     * @return void
217
     * @throws \Saito\Exception\SaitoBlackholeException
218
     */
219
    public function blackhole($type)
220
    {
221
        throw new \Saito\Exception\SaitoBlackholeException(
222
            $type,
223
            ['CurrentUser' => $this->CurrentUser]
224
        );
225
    }
226
227
    /**
228
     * manually require auth and redirect cycle
229
     *
230
     * @return Response
231
     */
232
    protected function _requireAuth()
233
    {
234
        $this->Flash->set(__('authorization.autherror'), ['element' => 'error']);
235
        $here = $this->request->getRequestTarget();
236
237
        return $this->redirect([
238
            '_name' => 'login',
239
            '?' => ['redirect' => $here],
240
            'plugin' => false,
241
        ]);
242
    }
243
244
    /**
245
     * sets l10n .ctp file if available
246
     *
247
     * @return void
248
     */
249
    protected function _l10nRenderFile()
250
    {
251
        $locale = Configure::read('Saito.language');
252
        I18n::useFallback(false); // @see <https://github.com/cakephp/cakephp/pull/6812>
253
        I18n::setLocale($locale);
254
        if (!$locale) {
255
            return;
256
        }
257
258
        $check = function ($locale) {
259
            $l10nViewPath = $this->viewBuilder()->getTemplatePath() . DS . $locale;
260
            $l10nViewFile = $l10nViewPath . DS . $this->viewBuilder()->getName() . '.ctp';
261
            if (!file_exists(APP . 'Template' . DS . $l10nViewFile)) {
262
                return false;
263
            }
264
265
            return $l10nViewPath;
266
        };
267
268
        $path = $check($locale);
269
        if ($path) {
270
            $this->viewBuilder()->templatePath($path);
0 ignored issues
show
Deprecated Code introduced by
The function Cake\View\ViewBuilder::templatePath() has been deprecated: 3.4.0 Use setTemplatePath()/getTemplatePath() instead. ( Ignorable by Annotation )

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

270
            /** @scrutinizer ignore-deprecated */ $this->viewBuilder()->templatePath($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
271
272
            return;
273
        }
274
275
        if (strpos($locale, '_')) {
276
            list($locale) = explode('_', $locale);
277
            $path = $check($locale);
278
            if ($path) {
279
                $this->viewBuilder()->templatePath($path);
0 ignored issues
show
Deprecated Code introduced by
The function Cake\View\ViewBuilder::templatePath() has been deprecated: 3.4.0 Use setTemplatePath()/getTemplatePath() instead. ( Ignorable by Annotation )

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

279
                /** @scrutinizer ignore-deprecated */ $this->viewBuilder()->templatePath($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
280
            }
281
        }
282
    }
283
}
284