Passed
Branch main (e5ffd1)
by MusikAnimal
13:14
created

DefaultController   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Test Coverage

Coverage 35.7%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 77
c 1
b 0
f 0
dl 0
loc 237
ccs 20
cts 56
cp 0.357
rs 10
wmc 19

12 Methods

Rating   Name   Duplication   Size   Complexity  
A indexAction() 0 4 1
A logoutAction() 0 4 1
A loginAction() 0 14 2
A wikifyApiAction() 0 4 1
A assessmentsConfigApiAction() 0 12 1
A projectAssessmentsApiAction() 0 5 1
A getOauthClient() 0 20 2
A namespacesApiAction() 0 8 1
A configAction() 0 21 4
A getIndexRoute() 0 3 1
A oauthCallbackAction() 0 32 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 MediaWiki\OAuthClient\Token;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpFoundation\RedirectResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\HttpFoundation\Session\SessionInterface;
22
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
23
use Symfony\Component\Routing\Annotation\Route;
24
25
/**
26
 * The DefaultController handles the homepage, about pages, and user authentication.
27
 */
28
class DefaultController extends XtoolsController
29
{
30
    /** @var Client The Oauth HTTP client. */
31
    protected $oauthClient;
32
33
    /**
34
     * Required to be defined by XtoolsController, though here it is unused.
35
     * @return string
36
     * @codeCoverageIgnore
37
     */
38
    public function getIndexRoute(): string
39
    {
40
        return 'homepage';
41
    }
42
43
    /**
44
     * Display the homepage.
45
     * @Route("/", name="homepage")
46
     * @Route("/index.php", name="homepageIndexPhp")
47
     * @return Response
48
     */
49 1
    public function indexAction(): Response
50
    {
51 1
        return $this->render('default/index.html.twig', [
52 1
            'xtPage' => 'home',
53
        ]);
54
    }
55
56
    /**
57
     * Display some configuration details, when in development mode.
58
     * @Route("/config", name="configPage")
59
     * @return Response
60
     * @codeCoverageIgnore
61
     */
62
    public function configAction(): Response
63
    {
64
65
        if ('dev' !== $this->container->getParameter('kernel.environment')) {
66
            throw new NotFoundHttpException();
67
        }
68
69
        $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

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

249
            'projects' => array_keys(/** @scrutinizer ignore-type */ $this->container->getParameter('assessments')),
Loading history...
250
            'config' => $this->container->getParameter('assessments'),
251
        ]);
252
253
        return $response;
254
    }
255
256
    /**
257
     * Transform given wikitext to HTML using the XTools parser. Wikitext must be passed in as the query 'wikitext'.
258
     * @Route("/api/project/parser/{project}")
259
     * @return JsonResponse Safe HTML.
260
     */
261
    public function wikifyApiAction(): JsonResponse
262
    {
263
        return new JsonResponse(
264
            Edit::wikifyString($this->request->query->get('wikitext', ''), $this->project)
265
        );
266
    }
267
}
268