Passed
Pull Request — master (#374)
by MusikAnimal
10:56
created

DefaultController   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Test Coverage

Coverage 37.7%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 81
c 1
b 0
f 0
dl 0
loc 253
ccs 23
cts 61
cp 0.377
rs 10
wmc 20

13 Methods

Rating   Name   Duplication   Size   Complexity  
A configAction() 0 21 4
A getIndexRoute() 0 3 1
A indexAction() 0 4 1
A loginAction() 0 16 2
A aboutAction() 0 4 1
A getOauthClient() 0 20 2
A logoutAction() 0 4 1
A wikifyApiAction() 0 4 1
A assessmentsConfigApiAction() 0 12 1
A projectAssessmentsApiAction() 0 5 1
A namespacesApiAction() 0 8 1
A oauthCallbackAction() 0 35 3
A normalizeProjectApiAction() 0 7 1
1
<?php
2
/**
3
 * This file contains only the DefaultController class.
4
 */
5
6
declare(strict_types=1);
7
8
namespace AppBundle\Controller;
9
10
use AppBundle\Model\Edit;
11
use AppBundle\Repository\ProjectRepository;
12
use MediaWiki\OAuthClient\Client;
13
use MediaWiki\OAuthClient\ClientConfig;
14
use MediaWiki\OAuthClient\Consumer;
15
use MediaWiki\OAuthClient\Exception;
16
use Symfony\Component\HttpFoundation\JsonResponse;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\HttpFoundation\Session\Session;
21
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
22
use Symfony\Component\Routing\Annotation\Route;
23
24
/**
25
 * The DefaultController handles the homepage, about pages, and user authentication.
26
 */
27
class DefaultController extends XtoolsController
28
{
29
    /** @var Client The Oauth HTTP client. */
30
    protected $oauthClient;
31
32
    /**
33
     * Required to be defined by XtoolsController, though here it is unused.
34
     * @return string
35
     * @codeCoverageIgnore
36
     */
37
    public function getIndexRoute(): string
38
    {
39
        return 'homepage';
40
    }
41
42
    /**
43
     * Display the homepage.
44
     * @Route("/", name="homepage")
45
     * @Route("/index.php", name="homepageIndexPhp")
46
     * @return Response
47
     */
48 1
    public function indexAction(): Response
49
    {
50 1
        return $this->render('default/index.html.twig', [
51 1
            'xtPage' => 'home',
52
        ]);
53
    }
54
55
    /**
56
     * Diplay XTools' about page.
57
     * @Route("/about", name="aboutPage")
58
     * @Route("/info.php", name="info")
59
     * @return Response
60
     */
61 1
    public function aboutAction(): Response
62
    {
63 1
        return $this->render('default/about.html.twig', [
64 1
            'xtPage' => 'about',
65
        ]);
66
    }
67
68
    /**
69
     * Display some configuration details, when in development mode.
70
     * @Route("/config", name="configPage")
71
     * @return Response
72
     * @codeCoverageIgnore
73
     */
74
    public function configAction(): Response
75
    {
76
77
        if ('dev' !== $this->container->getParameter('kernel.environment')) {
78
            throw new NotFoundHttpException();
79
        }
80
81
        $params = $this->container->getParameterBag()->all();
0 ignored issues
show
Bug introduced by
The method getParameterBag() does not exist on Symfony\Component\Depend...tion\ContainerInterface. Did you maybe mean getParameter()? ( Ignorable by Annotation )

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

81
        $params = $this->container->/** @scrutinizer ignore-call */ getParameterBag()->all();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
82
83
        foreach (array_keys($params) as $key) {
84
            if (false !== strpos($key, 'password')) {
85
                $params[$key] = '<REDACTED>';
86
            }
87
        }
88
89
        // replace this example code with whatever you need
90
        return $this->render('default/config.html.twig', [
91
            'xtTitle' => 'Config',
92
            'xtPageTitle' => 'Config',
93
            'xtPage' => 'index',
94
            'dump' => print_r($params, true),
95
        ]);
96
    }
97
98
    /**
99
     * Redirect to the default project (or Meta) for Oauth authentication.
100
     * @Route("/login", name="login")
101
     * @return RedirectResponse
102
     * @throws Exception If initialization fails.
103
     */
104
    public function loginAction(): RedirectResponse
105
    {
106
        try {
107
            [ $next, $token ] = $this->getOauthClient()->initiate();
108
        } catch (Exception $oauthException) {
109
            throw $oauthException;
110
            // @TODO Make this work.
111
            //$this->addFlash('error', $oauthException->getMessage());
112
            //return $this->redirectToRoute('homepage');
113
        }
114
115
        // Save the request token to the session.
116
        /** @var Session $session */
117
        $session = $this->get('session');
118
        $session->set('oauth_request_token', $token);
119
        return new RedirectResponse($next);
120
    }
121
122
    /**
123
     * Receive authentication credentials back from the Oauth wiki.
124
     * @Route("/oauth_callback", name="oauth_callback")
125
     * @Route("/oauthredirector.php", name="old_oauth_callback")
126
     * @param Request $request The HTTP request.
127
     * @return RedirectResponse
128
     */
129 1
    public function oauthCallbackAction(Request $request): RedirectResponse
130
    {
131
        // Give up if the required GET params don't exist.
132 1
        if (!$request->get('oauth_verifier')) {
133 1
            throw $this->createNotFoundException('No OAuth verifier given.');
134
        }
135
136
        /** @var Session $session */
137
        $session = $this->get('session');
138
139
        // Complete authentication.
140
        $client = $this->getOauthClient();
141
        $token = $session->get('oauth_request_token');
142
143
        if (!is_a($token, \MediaWiki\OAuthClient\Token::class)) {
144
            $this->addFlashMessage('notice', 'error-login');
145
            return $this->redirectToRoute('homepage');
146
        }
147
148
        $verifier = $request->get('oauth_verifier');
149
        $accessToken = $client->complete($token, $verifier);
150
151
        // Store access token, and remove request token.
152
        $session->set('oauth_access_token', $accessToken);
153
        $session->remove('oauth_request_token');
154
155
        // Store user identity.
156
        $ident = $client->identify($accessToken);
157
        $session->set('logged_in_user', $ident);
158
159
        // Store reference to the client.
160
        $session->set('oauth_client', $this->oauthClient);
161
162
        // Send back to homepage.
163
        return $this->redirectToRoute('homepage');
164
    }
165
166
    /**
167
     * Get an OAuth client, configured to the default project.
168
     * (This shouldn't really be in this class, but oh well.)
169
     * @return Client
170
     * @codeCoverageIgnore
171
     */
172
    protected function getOauthClient(): Client
173
    {
174
        if ($this->oauthClient instanceof Client) {
0 ignored issues
show
introduced by
$this->oauthClient is always a sub-type of MediaWiki\OAuthClient\Client.
Loading history...
175
            return $this->oauthClient;
176
        }
177
        $defaultProject = ProjectRepository::getProject(
178
            $this->getParameter('central_auth_project'),
179
            $this->container
180
        );
181
        $endpoint = $defaultProject->getUrl(false)
182
                    . $defaultProject->getScript()
183
                    . '?title=Special:OAuth';
184
        $conf = new ClientConfig($endpoint);
185
        $consumerKey = $this->getParameter('oauth_key');
186
        $consumerSecret =  $this->getParameter('oauth_secret');
187
        $conf->setConsumer(new Consumer($consumerKey, $consumerSecret));
188
        $this->oauthClient = new Client($conf);
189
        // Callback URL is hardcoded in the consumer registration.
190
        $this->oauthClient->setCallback('oob');
191
        return $this->oauthClient;
192
    }
193
194
    /**
195
     * Log out the user and return to the homepage.
196
     * @Route("/logout", name="logout")
197
     * @return RedirectResponse
198
     */
199 1
    public function logoutAction(): RedirectResponse
200
    {
201 1
        $this->get('session')->invalidate();
202 1
        return $this->redirectToRoute('homepage');
203
    }
204
205
    /************************ API endpoints ************************/
206
207
    /**
208
     * Get domain name, URL, and API URL of the given project.
209
     * @Route("/api/project/normalize/{project}", name="ProjectApiNormalize")
210
     * @return JsonResponse
211
     */
212
    public function normalizeProjectApiAction(): JsonResponse
213
    {
214
        return $this->getFormattedApiResponse([
215
            'domain' => $this->project->getDomain(),
216
            'url' => $this->project->getUrl(),
217
            'api' => $this->project->getApiUrl(),
218
            'database' => $this->project->getDatabaseName(),
219
        ]);
220
    }
221
222
    /**
223
     * Get all namespaces of the given project. This endpoint also does the same thing
224
     * as the /project/normalize endpoint, returning other basic info about the project.
225
     * @Route("/api/project/namespaces/{project}", name="ProjectApiNamespaces")
226
     * @return JsonResponse
227
     */
228 1
    public function namespacesApiAction(): JsonResponse
229
    {
230 1
        return $this->getFormattedApiResponse([
231 1
            'domain' => $this->project->getDomain(),
232 1
            'url' => $this->project->getUrl(),
233 1
            'api' => $this->project->getApiUrl(),
234 1
            'database' => $this->project->getDatabaseName(),
235 1
            'namespaces' => $this->project->getNamespaces(),
236
        ]);
237
    }
238
239
    /**
240
     * Get assessment data for a given project.
241
     * @Route("/api/project/assessments/{project}", name="ProjectApiAssessments")
242
     * @return JsonResponse
243
     */
244 1
    public function projectAssessmentsApiAction(): JsonResponse
245
    {
246 1
        return $this->getFormattedApiResponse([
247 1
            'project' => $this->project->getDomain(),
248 1
            'assessments' => $this->project->getPageAssessments()->getConfig(),
249
        ]);
250
    }
251
252
    /**
253
     * Get assessment data for all projects.
254
     * @Route("/api/project/assessments", name="ApiAssessmentsConfig")
255
     * @return JsonResponse
256
     */
257
    public function assessmentsConfigApiAction(): JsonResponse
258
    {
259
        // Here there is no Project, so we don't use XtoolsController::getFormattedApiResponse().
260
        $response = new JsonResponse();
261
        $response->setEncodingOptions(JSON_NUMERIC_CHECK);
262
        $response->setStatusCode(Response::HTTP_OK);
263
        $response->setData([
264
            'projects' => array_keys($this->container->getParameter('assessments')),
265
            'config' => $this->container->getParameter('assessments'),
266
        ]);
267
268
        return $response;
269
    }
270
271
    /**
272
     * Transform given wikitext to HTML using the XTools parser. Wikitext must be passed in as the query 'wikitext'.
273
     * @Route("/api/project/parser/{project}")
274
     * @return JsonResponse Safe HTML.
275
     */
276
    public function wikifyApiAction(): JsonResponse
277
    {
278
        return new JsonResponse(
279
            Edit::wikifyString($this->request->query->get('wikitext', ''), $this->project)
280
        );
281
    }
282
}
283