Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
74.36% covered (warning)
74.36%
58 / 78
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SourceWikiCleanupSnippet
74.36% covered (warning)
74.36%
58 / 78
80.00% covered (warning)
80.00%
4 / 5
15.85
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getHtml
67.74% covered (warning)
67.74%
42 / 62
0.00% covered (danger)
0.00%
0 / 1
7.21
 isFreshImport
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isSourceEditAllowed
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 isSourceDeleteAllowed
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace FileImporter\Html;
4
5use FileImporter\Data\ImportPlan;
6use FileImporter\Data\ImportRequest;
7use FileImporter\Data\SourceUrl;
8use FileImporter\Remote\MediaWiki\RemoteApiActionExecutor;
9use FileImporter\Services\WikidataTemplateLookup;
10use MediaWiki\Context\IContextSource;
11use MediaWiki\Context\RequestContext;
12use MediaWiki\Html\Html;
13use MediaWiki\MediaWikiServices;
14use MediaWiki\User\User;
15use OOUI\CheckboxInputWidget;
16use OOUI\FieldLayout;
17
18/**
19 * @license GPL-2.0-or-later
20 */
21class SourceWikiCleanupSnippet {
22
23    public const ACTION_OFFERED_SOURCE_DELETE = 'offeredSourceDelete';
24    public const ACTION_OFFERED_SOURCE_EDIT = 'offeredSourceEdit';
25
26    private bool $sourceEditingEnabled;
27    private bool $sourceDeletionEnabled;
28    private WikidataTemplateLookup $lookup;
29    private RemoteApiActionExecutor $remoteActionApi;
30
31    public function __construct(
32        bool $sourceEditingEnabled = true,
33        bool $sourceDeletionEnabled = true
34    ) {
35        $this->sourceEditingEnabled = $sourceEditingEnabled;
36        $this->sourceDeletionEnabled = $sourceDeletionEnabled;
37
38        // TODO: Inject
39        $this->lookup = MediaWikiServices::getInstance()->getService(
40            'FileImporterTemplateLookup' );
41        $this->remoteActionApi = MediaWikiServices::getInstance()->getService(
42            'FileImporterMediaWikiRemoteApiActionExecutor' );
43    }
44
45    public function getHtml( ImportPlan $importPlan, User $user ): string {
46        /** @var IContextSource $context */
47        $context = RequestContext::getMain();
48        $sourceUrl = $importPlan->getRequest()->getUrl();
49
50        $canAutomateEdit = $this->isSourceEditAllowed(
51            $sourceUrl,
52            $user,
53            $importPlan->getOriginalTitle()->getPrefixedText()
54        );
55        $canAutomateDelete = $this->isSourceDeleteAllowed( $sourceUrl, $user );
56
57        if ( !$canAutomateEdit && !$canAutomateDelete ) {
58            return '';
59        }
60
61        $html = Html::element(
62            'h2',
63            [],
64            $context->msg( 'fileimporter-heading-cleanup' )->plain()
65        );
66
67        if ( $canAutomateDelete ) {
68            $automateDeleteSelected = $importPlan->getAutomateSourceWikiDelete();
69            $importPlan->setActionIsPerformed( self::ACTION_OFFERED_SOURCE_DELETE );
70
71            $html .= Html::rawElement(
72                    'p',
73                    [],
74                    $context->msg( 'fileimporter-delete-text' )->parse()
75                ) .
76                new FieldLayout(
77                    new CheckboxInputWidget(
78                        [
79                            'name' => 'automateSourceWikiDelete',
80                            'selected' => $automateDeleteSelected,
81                            'value' => true
82                        ]
83                    ),
84                    [
85                        'label' => $context->msg( 'fileimporter-delete-checkboxlabel' )->parse(),
86                        'align' => 'inline'
87                    ]
88                );
89        } elseif ( $canAutomateEdit ) {
90            $automateEditSelected = $importPlan->getAutomateSourceWikiCleanUp() ||
91                $this->isFreshImport( $importPlan->getRequest() );
92            $importPlan->setActionIsPerformed( self::ACTION_OFFERED_SOURCE_EDIT );
93
94            $html .= Html::rawElement(
95                    'p',
96                    [],
97                    $context->msg(
98                        'fileimporter-cleanup-text',
99                        $this->lookup->fetchNowCommonsLocalTitle( $sourceUrl ) ?? ''
100                    )->parse()
101                ) .
102                new FieldLayout(
103                    new CheckboxInputWidget(
104                        [
105                            'name' => 'automateSourceWikiCleanup',
106                            'selected' => $automateEditSelected,
107                            'value' => true
108                        ]
109                    ),
110                    [
111                        'label' => $context->msg( 'fileimporter-cleanup-checkboxlabel' )->parse(),
112                        'align' => 'inline'
113                    ]
114                );
115        }
116
117        return $html;
118    }
119
120    /**
121     * @return bool
122     */
123    private function isFreshImport( ImportRequest $importRequest ) {
124        return $importRequest->getImportDetailsHash() === '';
125    }
126
127    /**
128     * Warning, contrary to the method name this currently doesn't check if the user is allowed to
129     * edit the page!
130     *
131     * @return bool True if source wiki editing is enabled and a localized {{Now Commons}} template
132     *  can be found.
133     */
134    private function isSourceEditAllowed( SourceUrl $sourceUrl, User $user, string $title ) {
135        if ( !$this->sourceEditingEnabled ||
136            // Note: This intentionally doesn't allow a template with the name "0".
137            !$this->lookup->fetchNowCommonsLocalTitle( $sourceUrl )
138        ) {
139            return false;
140        }
141
142        return $this->remoteActionApi->executeTestEditActionQuery( $sourceUrl, $user, $title )
143            ->isGood();
144    }
145
146    /**
147     * @return bool True if source wiki deletions are enabled and the user does have the right to
148     *  delete pages. Also returns false if querying the user rights failed.
149     */
150    private function isSourceDeleteAllowed( SourceUrl $sourceUrl, User $user ) {
151        if ( !$this->sourceDeletionEnabled ) {
152            return false;
153        }
154
155        return $this->remoteActionApi->executeUserRightsQuery( $sourceUrl, $user )
156            ->isGood();
157    }
158
159}