Completed
Push — rbac ( 30515f...5102b5 )
by Simon
06:58
created

WebStart::setupHelpers()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 19
nc 4
nop 4
dl 0
loc 30
ccs 0
cts 18
cp 0
crap 20
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca;
10
11
use Waca\DataObjects\User;
12
use Waca\Exceptions\EnvironmentException;
13
use Waca\Exceptions\ReadableException;
14
use Waca\Helpers\BlacklistHelper;
15
use Waca\Helpers\FakeBlacklistHelper;
16
use Waca\Helpers\TypeAheadHelper;
17
use Waca\Providers\GlobalState\GlobalStateProvider;
18
use Waca\Router\IRequestRouter;
19
use Waca\Security\RoleConfiguration;
20
use Waca\Security\SecurityManager;
21
use Waca\Security\TokenManager;
22
use Waca\Tasks\ITask;
23
use Waca\Tasks\InternalPageBase;
24
use Waca\Tasks\PageBase;
25
26
/**
27
 * Application entry point.
28
 *
29
 * @package Waca
30
 */
31
class WebStart extends ApplicationBase
32
{
33
    /**
34
     * @var IRequestRouter $requestRouter The request router to use. Note that different entry points have different
35
     *                                    routers and hence different URL mappings
36
     */
37
    private $requestRouter;
38
    /**
39
     * @var bool $isPublic Determines whether to use public interface objects or internal interface objects
40
     */
41
    private $isPublic = false;
42
43
    /**
44
     * WebStart constructor.
45
     *
46
     * @param SiteConfiguration $configuration The site configuration
47
     * @param IRequestRouter    $router        The request router to use
48
     */
49 2
    public function __construct(SiteConfiguration $configuration, IRequestRouter $router)
50
    {
51 2
        parent::__construct($configuration);
52
53 2
        $this->requestRouter = $router;
54 2
    }
55
56
    /**
57
     * @param ITask             $page
58
     * @param SiteConfiguration $siteConfiguration
59
     * @param PdoDatabase       $database
60
     * @param PdoDatabase       $notificationsDatabase
0 ignored issues
show
Documentation introduced by
Should the type for parameter $notificationsDatabase not be null|PdoDatabase?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
61
     *
62
     * @return void
63
     */
64
    protected function setupHelpers(
65
        ITask $page,
66
        SiteConfiguration $siteConfiguration,
67
        PdoDatabase $database,
68
        PdoDatabase $notificationsDatabase = null
69
    ) {
70
        parent::setupHelpers($page, $siteConfiguration, $database, $notificationsDatabase);
71
72
        if ($page instanceof PageBase) {
73
            $page->setTokenManager(new TokenManager());
74
75
            if ($page instanceof InternalPageBase) {
76
                $page->setTypeAheadHelper(new TypeAheadHelper());
77
78
                $identificationVerifier = new IdentificationVerifier($page->getHttpHelper(), $siteConfiguration,
79
                    $database);
80
                $page->setIdentificationVerifier($identificationVerifier);
81
82
                $page->setSecurityManager(new SecurityManager($identificationVerifier, new RoleConfiguration()));
83
84
                if ($siteConfiguration->getTitleBlacklistEnabled()) {
85
                    $page->setBlacklistHelper(new FakeBlacklistHelper());
86
                }
87
                else {
88
                    $page->setBlacklistHelper(new BlacklistHelper($page->getHttpHelper(),
89
                        $siteConfiguration->getMediawikiWebServiceEndpoint()));
90
                }
91
            }
92
        }
93
    }
94
95
    /**
96
     * Application entry point.
97
     *
98
     * Sets up the environment and runs the application, performing any global cleanup operations when done.
99
     */
100
    public function run()
101
    {
102
        try {
103
            if ($this->setupEnvironment()) {
104
                $this->main();
105
            }
106
        }
107
        catch (EnvironmentException $ex) {
108
            ob_end_clean();
109
            print Offline::getOfflineMessage($this->isPublic(), $ex->getMessage());
110
        }
111
        catch (ReadableException $ex) {
112
            ob_end_clean();
113
            print $ex->getReadableError();
114
        }
115
        finally {
116
            $this->cleanupEnvironment();
117
        }
118
    }
119
120
    /**
121
     * Environment setup
122
     *
123
     * This method initialises the tool environment. If the tool cannot be initialised correctly, it will return false
124
     * and shut down prematurely.
125
     *
126
     * @return bool
127
     * @throws EnvironmentException
128
     */
129
    protected function setupEnvironment()
130
    {
131
        // initialise global exception handler
132
        set_exception_handler(array(ExceptionHandler::class, 'exceptionHandler'));
133
        set_error_handler(array(ExceptionHandler::class, 'errorHandler'), E_RECOVERABLE_ERROR);
134
135
        // start output buffering if necessary
136
        if (ob_get_level() === 0) {
137
            ob_start();
138
        }
139
140
        // initialise super-global providers
141
        WebRequest::setGlobalStateProvider(new GlobalStateProvider());
142
143
        if (Offline::isOffline()) {
144
            print Offline::getOfflineMessage($this->isPublic());
145
            ob_end_flush();
146
147
            return false;
148
        }
149
150
        // Call parent setup
151
        if (!parent::setupEnvironment()) {
152
            return false;
153
        }
154
155
        // Start up sessions
156
        Session::start();
157
158
        // Check the user is allowed to be logged in still. This must be before we call any user-loading functions and
159
        // get the current user cached.
160
        // I'm not sure if this function call being here is particularly a good thing, but it's part of starting up a
161
        // session I suppose.
162
        $this->checkForceLogout();
163
164
        // environment initialised!
165
        return true;
166
    }
167
168
    /**
169
     * Main application logic
170
     */
171
    protected function main()
172
    {
173
        // Get the right route for the request
174
        $page = $this->requestRouter->route();
175
176
        $siteConfiguration = $this->getConfiguration();
177
        $database = PdoDatabase::getDatabaseConnection('acc');
178
179
        if ($siteConfiguration->getIrcNotificationsEnabled()) {
180
            $notificationsDatabase = PdoDatabase::getDatabaseConnection('notifications');
181
        }
182
        else {
183
            // @todo federated table here?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
184
            $notificationsDatabase = $database;
185
        }
186
187
        $this->setupHelpers($page, $siteConfiguration, $database, $notificationsDatabase);
188
189
        /* @todo Remove this global statement! It's here for User.php, which does far more than it should. */
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
190
        global $oauthHelper;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
191
        $oauthHelper = $page->getOAuthHelper();
192
193
        /* @todo Remove this global statement! It's here for Request.php, which does far more than it should. */
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
194
        global $globalXffTrustProvider;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
195
        $globalXffTrustProvider = $page->getXffTrustProvider();
196
197
        // run the route code for the request.
198
        $page->execute();
199
    }
200
201
    /**
202
     * Any cleanup tasks should go here
203
     *
204
     * Note that we need to be very careful here, as exceptions may have been thrown and handled.
205
     * This should *only* be for cleaning up, no logic should go here.
206
     */
207
    protected function cleanupEnvironment()
208
    {
209
        // Clean up anything we splurged after sending the page.
210
        if (ob_get_level() > 0) {
211
            for ($i = ob_get_level(); $i > 0; $i--) {
212
                ob_end_clean();
213
            }
214
        }
215
    }
216
217
    private function checkForceLogout()
218
    {
219
        $database = PdoDatabase::getDatabaseConnection('acc');
220
221
        $sessionUserId = WebRequest::getSessionUserId();
222
        iF ($sessionUserId === null) {
223
            return;
224
        }
225
226
        // Note, User::getCurrent() caches it's result, which we *really* don't want to trigger.
227
        $currentUser = User::getById($sessionUserId, $database);
228
229
        if ($currentUser === false) {
230
            // Umm... this user has a session cookie with a userId set, but no user exists...
231
            Session::restart();
232
233
            $currentUser = User::getCurrent($database);
234
        }
235
236
        if ($currentUser->getForceLogout()) {
237
            Session::restart();
238
239
            $currentUser->setForceLogout(false);
240
            $currentUser->save();
241
        }
242
    }
243
244 1
    public function isPublic()
245
    {
246 1
        return $this->isPublic;
247
    }
248
249 1
    public function setPublic($isPublic)
250
    {
251 1
        $this->isPublic = $isPublic;
252 1
    }
253
}
254