Passed
Pull Request — main (#442)
by MusikAnimal
07:58 queued 04:01
created

AutomatedEditsController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 10
dl 0
loc 16
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Controller;
6
7
use App\Helper\I18nHelper;
8
use App\Model\AutoEdits;
9
use App\Repository\AutoEditsRepository;
10
use App\Repository\EditRepository;
11
use App\Repository\PageRepository;
12
use App\Repository\ProjectRepository;
13
use App\Repository\UserRepository;
14
use GuzzleHttp\Client;
15
use Psr\Cache\CacheItemPoolInterface;
16
use Psr\Container\ContainerInterface;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpFoundation\RedirectResponse;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\Routing\Annotation\Route;
22
23
/**
24
 * This controller serves the AutomatedEdits tool.
25
 */
26
class AutomatedEditsController extends XtoolsController
27
{
28
    protected AutoEdits $autoEdits;
29
    protected AutoEditsRepository $autoEditsRepo;
30
    protected EditRepository $editRepo;
31
    protected PageRepository $pageRepo;
32
33
    /** @var array Data that is passed to the view. */
34
    private array $output;
35
36
    /**
37
     * Get the name of the tool's index route.
38
     * This is also the name of the associated model.
39
     * @return string
40
     * @codeCoverageIgnore
41
     */
42
    public function getIndexRoute(): string
43
    {
44
        return 'AutoEdits';
45
    }
46
47
    public function __construct(
48
        RequestStack $requestStack,
49
        ContainerInterface $container,
50
        CacheItemPoolInterface $cache,
51
        Client $guzzle,
52
        I18nHelper $i18n,
53
        ProjectRepository $projectRepo,
54
        UserRepository $userRepo,
55
        PageRepository $pageRepo,
56
        AutoEditsRepository $autoEditsRepo,
57
        EditRepository $editRepo
58
    ) {
59
        $this->autoEditsRepo = $autoEditsRepo;
60
        $this->editRepo = $editRepo;
61
        $this->pageRepo = $pageRepo;
62
        parent::__construct($requestStack, $container, $cache, $guzzle, $i18n, $projectRepo, $userRepo, $pageRepo);
63
    }
64
65
    /**
66
     * This causes the tool to redirect back to the index page, with an error,
67
     * if the user has too high of an edit count.
68
     * @return string
69
     */
70
    public function tooHighEditCountRoute(): string
71
    {
72
        return $this->getIndexRoute();
73
    }
74
75
    /**
76
     * Display the search form.
77
     * @Route("/autoedits", name="AutoEdits")
78
     * @Route("/automatededits", name="AutoEditsLong")
79
     * @Route("/autoedits/index.php", name="AutoEditsIndexPhp")
80
     * @Route("/automatededits/index.php", name="AutoEditsLongIndexPhp")
81
     * @Route("/autoedits/{project}", name="AutoEditsProject")
82
     * @return Response
83
     */
84
    public function indexAction(): Response
85
    {
86
        // Redirect if at minimum project and username are provided.
87
        if (isset($this->params['project']) && isset($this->params['username'])) {
88
            // If 'tool' param is given, redirect to corresponding action.
89
            $tool = $this->request->query->get('tool');
90
91
            if ('all' === $tool) {
92
                unset($this->params['tool']);
93
                return $this->redirectToRoute('AutoEditsContributionsResult', $this->params);
94
            } elseif ('' != $tool && 'none' !== $tool) {
95
                $this->params['tool'] = $tool;
96
                return $this->redirectToRoute('AutoEditsContributionsResult', $this->params);
97
            } elseif ('none' === $tool) {
98
                unset($this->params['tool']);
99
            }
100
101
            // Otherwise redirect to the normal result action.
102
            return $this->redirectToRoute('AutoEditsResult', $this->params);
103
        }
104
105
        return $this->render('autoEdits/index.html.twig', array_merge([
106
            'xtPageTitle' => 'tool-autoedits',
107
            'xtSubtitle' => 'tool-autoedits-desc',
108
            'xtPage' => 'AutoEdits',
109
110
            // Defaults that will get overridden if in $this->params.
111
            'username' => '',
112
            'namespace' => 0,
113
            'start' => '',
114
            'end' => '',
115
        ], $this->params, ['project' => $this->project]));
116
    }
117
118
    /**
119
     * Set defaults, and instantiate the AutoEdits model. This is called at the top of every view action.
120
     * @codeCoverageIgnore
121
     */
122
    private function setupAutoEdits(): void
123
    {
124
        $tool = $this->request->query->get('tool', null);
125
        $useSandbox = (bool)$this->request->query->get('usesandbox', false);
126
127
        if ($useSandbox && !$this->request->getSession()->get('logged_in_user')) {
128
            $this->addFlashMessage('danger', 'auto-edits-logged-out');
129
            $useSandbox = false;
130
        }
131
        $this->autoEditsRepo->setUseSandbox($useSandbox);
132
133
        $misconfigured = $this->autoEditsRepo->getInvalidTools($this->project);
134
        $helpLink = "https://w.wiki/ppr";
135
        foreach ($misconfigured as $tool) {
136
            $this->addFlashMessage('warning', 'auto-edits-misconfiguration', [$tool, $helpLink]);
137
        }
138
139
        // Validate tool.
140
        // FIXME: instead of redirecting to index page, show result page listing all tools for that project,
141
        //  clickable to show edits by the user, etc.
142
        if ($tool && !isset($this->autoEditsRepo->getTools($this->project)[$tool])) {
143
            $this->throwXtoolsException(
144
                $this->getIndexRoute(),
145
                'auto-edits-unknown-tool',
146
                [$tool],
147
                'tool'
148
            );
149
        }
150
151
        $this->autoEdits = new AutoEdits(
152
            $this->autoEditsRepo,
153
            $this->editRepo,
154
            $this->pageRepo,
155
            $this->userRepo,
156
            $this->project,
157
            $this->user,
0 ignored issues
show
Bug introduced by
It seems like $this->user can also be of type null; however, parameter $user of App\Model\AutoEdits::__construct() does only seem to accept App\Model\User, 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

157
            /** @scrutinizer ignore-type */ $this->user,
Loading history...
158
            $this->namespace,
159
            $this->start,
160
            $this->end,
161
            $tool,
162
            $this->offset,
163
            $this->limit
164
        );
165
166
        $this->output = [
167
            'xtPage' => 'AutoEdits',
168
            'xtTitle' => $this->user->getUsername(),
0 ignored issues
show
Bug introduced by
The method getUsername() does not exist on null. ( Ignorable by Annotation )

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

168
            'xtTitle' => $this->user->/** @scrutinizer ignore-call */ getUsername(),

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...
169
            'ae' => $this->autoEdits,
170
            'is_sub_request' => $this->isSubRequest,
171
        ];
172
    }
173
174
    /**
175
     * Display the results.
176
     * @Route(
177
     *     "/autoedits/{project}/{username}/{namespace}/{start}/{end}/{offset}", name="AutoEditsResult",
178
     *     requirements={
179
     *         "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
180
     *         "namespace"="|all|\d+",
181
     *         "start"="|\d{4}-\d{2}-\d{2}",
182
     *         "end"="|\d{4}-\d{2}-\d{2}",
183
     *         "offset"="|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}",
184
     *     },
185
     *     defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false}
186
     * )
187
     * @return Response
188
     * @codeCoverageIgnore
189
     */
190
    public function resultAction(): Response
191
    {
192
        // Will redirect back to index if the user has too high of an edit count.
193
        $this->setupAutoEdits();
194
195
        if (in_array('bot', $this->user->getUserRights($this->project))) {
196
            $this->addFlashMessage('warning', 'auto-edits-bot');
197
        }
198
199
        return $this->getFormattedResponse('autoEdits/result', $this->output);
200
    }
201
202
    /**
203
     * Get non-automated edits for the given user.
204
     * @Route(
205
     *   "/nonautoedits-contributions/{project}/{username}/{namespace}/{start}/{end}/{offset}",
206
     *   name="NonAutoEditsContributionsResult",
207
     *   requirements={
208
     *       "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
209
     *       "namespace"="|all|\d+",
210
     *       "start"="|\d{4}-\d{2}-\d{2}",
211
     *       "end"="|\d{4}-\d{2}-\d{2}",
212
     *       "offset"="|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}",
213
     *   },
214
     *   defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false}
215
     * )
216
     * @return Response|RedirectResponse
217
     * @codeCoverageIgnore
218
     */
219
    public function nonAutomatedEditsAction(): Response
220
    {
221
        $this->setupAutoEdits();
222
223
        return $this->getFormattedResponse('autoEdits/nonautomated_edits', $this->output);
224
    }
225
226
    /**
227
     * Get automated edits for the given user using the given tool.
228
     * @Route(
229
     *   "/autoedits-contributions/{project}/{username}/{namespace}/{start}/{end}/{offset}",
230
     *   name="AutoEditsContributionsResult",
231
     *   requirements={
232
     *       "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
233
     *       "namespace"="|all|\d+",
234
     *       "start"="|\d{4}-\d{2}-\d{2}",
235
     *       "end"="|\d{4}-\d{2}-\d{2}",
236
     *       "offset"="|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}",
237
     *   },
238
     *   defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false}
239
     * )
240
     * @return Response
241
     * @codeCoverageIgnore
242
     */
243
    public function automatedEditsAction(): Response
244
    {
245
        $this->setupAutoEdits();
246
247
        return $this->getFormattedResponse('autoEdits/automated_edits', $this->output);
248
    }
249
250
    /************************ API endpoints ************************/
251
252
    /**
253
     * Get a list of the automated tools and their regex/tags/etc.
254
     * @Route("/api/user/automated_tools/{project}", name="UserApiAutoEditsTools")
255
     * @Route("/api/project/automated_tools/{project}", name="ProjectApiAutoEditsTools")
256
     * @return JsonResponse
257
     * @codeCoverageIgnore
258
     */
259
    public function automatedToolsApiAction(): JsonResponse
260
    {
261
        $this->recordApiUsage('user/automated_tools');
262
        return $this->getFormattedApiResponse($this->autoEditsRepo->getTools($this->project));
263
    }
264
265
    /**
266
     * Count the number of automated edits the given user has made.
267
     * @Route(
268
     *   "/api/user/automated_editcount/{project}/{username}/{namespace}/{start}/{end}/{tools}",
269
     *   name="UserApiAutoEditsCount",
270
     *   requirements={
271
     *       "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
272
     *       "namespace"="|all|\d+",
273
     *       "start"="|\d{4}-\d{2}-\d{2}",
274
     *       "end"="|\d{4}-\d{2}-\d{2}"
275
     *   },
276
     *   defaults={"namespace"="all", "start"=false, "end"=false, "tools"=false}
277
     * )
278
     * @return JsonResponse
279
     * @codeCoverageIgnore
280
     */
281
    public function automatedEditCountApiAction(): JsonResponse
282
    {
283
        $this->recordApiUsage('user/automated_editcount');
284
285
        $this->setupAutoEdits();
286
287
        $ret = [
288
            'total_editcount' => $this->autoEdits->getEditCount(),
289
            'automated_editcount' => $this->autoEdits->getAutomatedCount(),
290
        ];
291
        $ret['nonautomated_editcount'] = $ret['total_editcount'] - $ret['automated_editcount'];
292
293
        if (isset($this->params['tools'])) {
294
            $tools = $this->autoEdits->getToolCounts();
295
            $ret['automated_tools'] = $tools;
296
        }
297
298
        return $this->getFormattedApiResponse($ret);
299
    }
300
301
    /**
302
     * Get non-automated edits for the given user.
303
     * @Route(
304
     *   "/api/user/nonautomated_edits/{project}/{username}/{namespace}/{start}/{end}/{offset}",
305
     *   name="UserApiNonAutoEdits",
306
     *   requirements={
307
     *       "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
308
     *       "namespace"="|all|\d+",
309
     *       "start"="|\d{4}-\d{2}-\d{2}",
310
     *       "end"="|\d{4}-\d{2}-\d{2}",
311
     *       "offset"="|\d{4}-?\d{2}-?\d{2}T?\d{2}:?\d{2}:?\d{2}"
312
     *   },
313
     *   defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false, "limit"=50}
314
     * )
315
     * @return JsonResponse
316
     * @codeCoverageIgnore
317
     */
318
    public function nonAutomatedEditsApiAction(): JsonResponse
319
    {
320
        $this->recordApiUsage('user/nonautomated_edits');
321
322
        $this->setupAutoEdits();
323
324
        $out = $this->addFullPageTitlesAndContinue(
325
            'nonautomated_edits',
326
            [],
327
            $this->autoEdits->getNonAutomatedEdits(true)
328
        );
329
330
        return $this->getFormattedApiResponse($out);
331
    }
332
333
    /**
334
     * Get (semi-)automated edits for the given user, optionally using the given tool.
335
     * @Route(
336
     *   "/api/user/automated_edits/{project}/{username}/{namespace}/{start}/{end}/{offset}",
337
     *   name="UserApiAutoEdits",
338
     *   requirements={
339
     *       "username" = "(ipr-.+\/\d+[^\/])|([^\/]+)",
340
     *       "namespace"="|all|\d+",
341
     *       "start"="|\d{4}-\d{2}-\d{2}",
342
     *       "end"="|\d{4}-\d{2}-\d{2}",
343
     *       "offset"="|\d{4}-?\d{2}-?\d{2}T?\d{2}:?\d{2}:?\d{2}",
344
     *   },
345
     *   defaults={"namespace"=0, "start"=false, "end"=false, "offset"=false, "limit"=50}
346
     * )
347
     * @return Response
348
     * @codeCoverageIgnore
349
     */
350
    public function automatedEditsApiAction(): Response
351
    {
352
        $this->recordApiUsage('user/automated_edits');
353
354
        $this->setupAutoEdits();
355
356
        $extras = $this->autoEdits->getTool()
357
            ? ['tool' => $this->autoEdits->getTool()]
358
            : [];
359
360
        $out = $this->addFullPageTitlesAndContinue(
361
            'automated_edits',
362
            $extras,
363
            $this->autoEdits->getAutomatedEdits(true)
364
        );
365
366
        return $this->getFormattedApiResponse($out);
367
    }
368
}
369