Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 181
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialCentralNoticeLogs
0.00% covered (danger)
0.00%
0 / 181
0.00% covered (danger)
0.00%
0 / 6
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 1
210
 dateSelector
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 showLog
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
2
 getDateValue
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getLogSwitcher
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3use MediaWiki\Html\Html;
4use MediaWiki\SpecialPage\SpecialPage;
5use MediaWiki\Utils\UrlUtils;
6
7class SpecialCentralNoticeLogs extends CentralNotice {
8    /** @var string */
9    public $logType = 'campaignsettings';
10
11    public function __construct(
12        private readonly UrlUtils $urlUtils,
13    ) {
14        // Register special page
15        parent::__construct( 'CentralNoticeLogs' );
16    }
17
18    /**
19     * Handle different types of page requests
20     * @param string|null $sub
21     */
22    public function execute( $sub ) {
23        global $wgExtensionAssetsPath;
24
25        $out = $this->getOutput();
26        $request = $this->getRequest();
27
28        $this->logType = $request->getText( 'log', 'campaignsettings' );
29
30        // Begin output
31        $this->setHeaders();
32
33        // Output ResourceLoader module for styling and javascript functions
34        $out->addModules( 'ext.centralNotice.adminUi' );
35
36        // Initialize error variable
37        $this->centralNoticeError = false;
38
39        // Allow users to add a custom nav bar (T138284)
40        $navBar = $this->msg( 'centralnotice-navbar' )->inContentLanguage();
41        if ( !$navBar->isDisabled() ) {
42            $out->addHTML( $navBar->parseAsBlock() );
43        }
44        // Show summary
45        $out->addWikiMsg( 'centralnotice-summary' );
46
47        // Begin Banners tab content
48        $out->addHTML( Html::openElement( 'div', [ 'id' => 'preferences' ] ) );
49
50        $htmlOut = '';
51
52        // Begin log selection fieldset
53        $htmlOut .= Html::openElement( 'fieldset', [ 'class' => 'prefsection' ] );
54
55        $title = SpecialPage::getTitleFor( 'CentralNoticeLogs' );
56        $actionUrl = $title->getLocalURL();
57        $htmlOut .= Html::openElement( 'form', [ 'method' => 'get', 'action' => $actionUrl ] );
58        $htmlOut .= Html::element( 'h2', [], $this->msg( 'centralnotice-view-logs' )->text() );
59        $htmlOut .= Html::openElement( 'div', [ 'id' => 'cn-log-switcher' ] );
60        $title = SpecialPage::getTitleFor( 'CentralNoticeLogs' );
61
62        $fullUrl = $this->urlUtils->expand( $title->getFullURL(), PROTO_CURRENT ) ?? '';
63
64        // Build the radio buttons for switching the log type
65        $htmlOut .= $this->getLogSwitcher( 'campaignsettings', 'campaignSettings',
66            'centralnotice-campaign-settings', $fullUrl );
67        $htmlOut .= $this->getLogSwitcher( 'bannersettings', 'bannerSettings',
68            'centralnotice-banner-settings', $fullUrl );
69        $htmlOut .= $this->getLogSwitcher( 'bannercontent', 'bannerContent',
70            'centralnotice-banner-content', $fullUrl );
71        $htmlOut .= $this->getLogSwitcher( 'bannermessages', 'bannerMessages',
72            'centralnotice-banner-messages', $fullUrl );
73
74        $htmlOut .= Html::closeElement( 'div' );
75
76        if ( $this->logType == 'campaignsettings' ) {
77            $reset = $request->getVal( 'centralnoticelogreset' );
78            $campaign = $request->getVal( 'campaign' );
79            $user = $request->getVal( 'user' );
80            $start = $this->getDateValue( 'start' );
81            $end = $this->getDateValue( 'end' );
82
83            $htmlOut .= Html::openElement( 'div', [ 'id' => 'cn-log-filters-container' ] );
84
85            $collapsedImg = $this->getContext()->getLanguage()->isRTL() ?
86                '/CentralNotice/resources/images/collapsed-rtl.png' :
87                '/CentralNotice/resources/images/collapsed-ltr.png';
88
89            if ( $campaign || $user || $start || $end ) {
90                // filters on
91                $htmlOut .= '<a href="javascript:toggleFilterDisplay()">' .
92                    '<img src="' . $wgExtensionAssetsPath . $collapsedImg . '" ' .
93                    'id="cn-collapsed-filter-arrow" ' .
94                    'style="display:none;position:relative;top:-2px;"/>' .
95                    '<img src="' . $wgExtensionAssetsPath . '/CentralNotice/resources/images/uncollapsed.png" ' .
96                    'id="cn-uncollapsed-filter-arrow" ' .
97                    'style="display:inline-block;position:relative;top:-2px;"/>' .
98                    '</a>';
99                $htmlOut .= Html::element( 'span', [ 'style' => 'margin-left: 0.3em;' ],
100                    $this->msg( 'centralnotice-filters' )->text() );
101                $htmlOut .= Html::openElement( 'div', [ 'id' => 'cn-log-filters' ] );
102            } else {
103                // filters off
104                $htmlOut .= '<a href="javascript:toggleFilterDisplay()">' .
105                    '<img src="' . $wgExtensionAssetsPath . $collapsedImg . '" ' .
106                    'id="cn-collapsed-filter-arrow" ' .
107                    'style="display:inline-block;position:relative;top:-2px;"/>' .
108                    '<img src="' . $wgExtensionAssetsPath . '/CentralNotice/resources/images/uncollapsed.png" ' .
109                    'id="cn-uncollapsed-filter-arrow" ' .
110                    'style="display:none;position:relative;top:-2px;"/>' .
111                    '</a>';
112                $htmlOut .= Html::element( 'span', [ 'style' => 'margin-left: 0.3em;' ],
113                    $this->msg( 'centralnotice-filters' )->text() );
114                $htmlOut .= Html::openElement( 'div',
115                    [ 'id' => 'cn-log-filters', 'style' => 'display:none;' ] );
116            }
117
118            $htmlOut .= Html::openElement( 'table' );
119
120            $htmlOut .= Html::rawElement( 'tr', [],
121                Html::rawElement( 'td', [],
122                    Html::label( $this->msg( 'centralnotice-start-date' )->text(), 'month',
123                        [ 'class' => 'cn-log-filter-label' ] )
124                ) .
125                Html::rawElement( 'td', [],
126                    $this->dateSelector( 'start', true, $reset ? '' : $start )
127                )
128            );
129
130            $htmlOut .= Html::rawElement( 'tr', [],
131                Html::rawElement( 'td', [],
132                    Html::label( $this->msg( 'centralnotice-end-date' )->text(), 'month',
133                        [ 'class' => 'cn-log-filter-label' ] )
134                ) .
135                Html::rawElement( 'td', [],
136                    $this->dateSelector( 'end', true, $reset ? '' : $end )
137                )
138            );
139
140            $htmlOut .= Html::rawElement( 'tr', [],
141                Html::rawElement( 'td', [],
142                    Html::label( $this->msg( 'centralnotice-notice' )->text(), 'campaign',
143                        [ 'class' => 'cn-log-filter-label' ] )
144                ) .
145                Html::rawElement( 'td', [],
146                    Html::input(
147                        'campaign',
148                        ( $reset || $campaign === null ? '' : $campaign ),
149                        'text',
150                        [ 'size' => 25 ]
151                    )
152                )
153            );
154
155            $htmlOut .= Html::rawElement( 'tr', [],
156                Html::rawElement( 'td', [],
157                    Html::label( $this->msg( 'centralnotice-user' )->text(), 'user',
158                        [ 'class' => 'cn-log-filter-label' ] )
159                ) .
160                Html::rawElement( 'td', [],
161                    Html::input( 'user', ( $reset || $user === null ? '' : $user ), 'text', [ 'size' => 25 ] )
162                )
163            );
164
165            $htmlOut .= Html::openElement( 'tr' );
166
167            $htmlOut .= Html::openElement( 'td', [ 'colspan' => 2 ] );
168            $htmlOut .= Html::submitButton( $this->msg( 'centralnotice-apply-filters' )->text(),
169                [
170                    'id' => 'centralnoticesubmit',
171                    'name' => 'centralnoticesubmit',
172                    'class' => 'cn-filter-buttons',
173                ]
174            );
175            $link = $title->getLinkURL();
176            $htmlOut .= Html::submitButton( $this->msg( 'centralnotice-clear-filters' )->text(),
177                [
178                    'id' => 'centralnoticelogreset',
179                    'name' => 'centralnoticelogreset',
180                    'class' => 'cn-filter-buttons',
181                    'onclick' => "location.href = " . Html::encodeJsVar( $link ) . "; return false;",
182                ]
183            );
184            $htmlOut .= Html::closeElement( 'td' );
185
186            $htmlOut .= Html::closeElement( 'tr' );
187            $htmlOut .= Html::closeElement( 'table' );
188            $htmlOut .= Html::closeElement( 'div' );
189            // @phan-suppress-next-line PhanPluginDuplicateAdjacentStatement
190            $htmlOut .= Html::closeElement( 'div' );
191        }
192
193        $htmlOut .= Html::closeElement( 'form' );
194
195        // End log selection fieldset
196        // $htmlOut .= Html::closeElement( 'fieldset' );
197
198        $out->addHTML( $htmlOut );
199
200        $this->showLog( $this->logType );
201
202        // End Banners tab content
203        $out->addHTML( Html::closeElement( 'div' ) );
204    }
205
206    /**
207     * Render a field suitable for jquery.ui datepicker
208     * @param string $prefix
209     * @param bool $editable
210     * @param string|null $date
211     * @return string HTML
212     */
213    protected function dateSelector( $prefix, $editable = true, $date = '' ) {
214        $out = Html::element( 'input',
215            [
216                'id' => "{$prefix}Date",
217                'name' => "{$prefix}Date",
218                'type' => 'text',
219                'class' => 'centralnotice-datepicker',
220            ]
221        );
222        $out .= Html::element( 'input',
223            [
224                'id' => "{$prefix}Date_timestamp",
225                'name' => "{$prefix}Date_timestamp",
226                'type' => 'hidden',
227                'value' => (string)$date,
228            ]
229        );
230        return $out;
231    }
232
233    /**
234     * Show a log of changes.
235     * @param string $logType which type of log to show
236     */
237    private function showLog( $logType ) {
238        $pager = match ( $logType ) {
239            'bannersettings' => new CentralNoticeBannerLogPager( $this ),
240            'bannercontent',
241            'bannermessages' => new CentralNoticePageLogPager( $this, $logType ),
242            default => new CentralNoticeCampaignLogPager( $this ),
243        };
244
245        $htmlOut = '';
246
247        // Begin log fieldset
248        // $htmlOut .= Html::openElement( 'fieldset', array( 'class' => 'prefsection' ) );
249
250        // Show paginated list of log entries
251        $htmlOut .= Html::rawElement( 'div',
252            [ 'class' => 'cn-pager' ],
253            $pager->getNavigationBar() );
254        $htmlOut .= $pager->getBody();
255        $htmlOut .= Html::rawElement( 'div',
256            [ 'class' => 'cn-pager' ],
257            $pager->getNavigationBar() );
258
259        // End log fieldset
260        $htmlOut .= Html::closeElement( 'fieldset' );
261
262        $this->getOutput()->addHTML( $htmlOut );
263    }
264
265    /**
266     * Returns the jquery.ui datepicker value, or null if the field is blank.
267     * @param string $name
268     * @return null|string
269     */
270    public function getDateValue( $name ) {
271        $manual_entry = $this->getRequest()->getVal( "{$name}Date" );
272        if ( !$manual_entry ) {
273            return null;
274        }
275
276        return $this->getRequest()->getVal( "{$name}Date_timestamp" );
277    }
278
279    /**
280     * Build a radio button that switches the log type when you click it
281     * @param string $type
282     * @param string $id
283     * @param string $message
284     * @param string $fullUrl
285     * @return string HTML
286     */
287    private function getLogSwitcher( $type, $id, $message, $fullUrl ) {
288        $fullUrlEnc = Html::encodeJsVar( $fullUrl );
289        $typeEnc = Html::encodeJsVar( $type );
290        $htmlOut = '';
291        $htmlOut .= Html::radio(
292            'log_type',
293            $this->logType == $type,
294            [ 'value' => $id, 'onclick' => "switchLogs( " . $fullUrlEnc . ", " . $typeEnc . " )" ]
295        );
296        $htmlOut .= Html::label( $this->msg( $message )->text(), $id );
297        return $htmlOut;
298    }
299}