Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 184
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
CentralNoticeBannerLogPager
0.00% covered (danger)
0.00%
0 / 184
0.00% covered (danger)
0.00%
0 / 9
812
0.00% covered (danger)
0.00%
0 / 1
 getIndexField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getQueryInfo
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 formatRow
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
56
 getStartBody
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
2
 getEndBody
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 showInitialSettings
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 showChanges
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
12
 testBooleanBannerChange
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 testTextBannerChange
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3use MediaWiki\Html\Html;
4use MediaWiki\SpecialPage\SpecialPage;
5use MediaWiki\User\User;
6use Wikimedia\Rdbms\SelectQueryBuilder;
7
8class CentralNoticeBannerLogPager extends CentralNoticeCampaignLogPager {
9
10    /**
11     * Sort the log list by timestamp
12     * @return string
13     */
14    public function getIndexField() {
15        return 'tmplog_timestamp';
16    }
17
18    /**
19     * Pull log entries from the database
20     * @return array
21     */
22    public function getQueryInfo() {
23        return [
24            'tables' => [ 'template_log' => 'cn_template_log' ],
25            'fields' => '*',
26        ];
27    }
28
29    /**
30     * Generate the content of each table row (1 row = 1 log entry)
31     * @param stdClass $row
32     * @return string HTML
33     */
34    public function formatRow( $row ) {
35        global $wgExtensionAssetsPath;
36        $lang = $this->getLanguage();
37
38        // Create a user object so we can pull the name, user page, etc.
39        $loggedUser = User::newFromId( $row->tmplog_user_id );
40        // Create the user page link
41        $userLink = $this->special->getLinkRenderer()->makeKnownLink(
42            $loggedUser->getUserPage(),
43            $loggedUser->getName()
44        );
45        $userTalkLink = $this->special->getLinkRenderer()->makeKnownLink(
46            $loggedUser->getTalkPage(),
47            $this->msg( 'centralnotice-talk-link' )->text()
48        );
49
50        // Create the banner link
51        $bannerLink = $this->special->getLinkRenderer()->makeKnownLink(
52            SpecialPage::getTitleFor( 'CentralNoticeBanners', "edit/{$row->tmplog_template_name}" ),
53            $row->tmplog_template_name
54        );
55
56        // Begin log entry primary row
57        $htmlOut = Html::openElement( 'tr' );
58
59        $htmlOut .= Html::openElement( 'td', [ 'valign' => 'top' ] );
60        if ( $row->tmplog_action !== 'removed' ) {
61            $collapsedImg = $this->getLanguage()->isRtl() ?
62                'collapsed-rtl.png' :
63                'collapsed-ltr.png';
64
65            $tmplogId = (int)$row->tmplog_id;
66            $htmlOut .= '<a href="javascript:toggleLogDisplay(\'' . $tmplogId . '\')">' .
67                '<img src="' . $wgExtensionAssetsPath . '/CentralNotice/resources/images/' . $collapsedImg . '" ' .
68                'id="cn-collapsed-' . $tmplogId . '" ' .
69                'style="display:block;vertical-align:baseline;"/>' .
70                '<img src="' . $wgExtensionAssetsPath . '/CentralNotice/resources/images/uncollapsed.png" ' .
71                'id="cn-uncollapsed-' . $tmplogId . '" ' .
72                'style="display:none;vertical-align:baseline;"/>' .
73                '</a>';
74        }
75        $htmlOut .= Html::closeElement( 'td' );
76        $htmlOut .= Html::element( 'td', [ 'valign' => 'top', 'class' => 'primary' ],
77            $lang->date( $row->tmplog_timestamp ) . ' ' . $lang->time( $row->tmplog_timestamp )
78        );
79        $htmlOut .= Html::rawElement( 'td', [ 'valign' => 'top', 'class' => 'primary' ],
80            $this->msg( 'centralnotice-user-links' )
81                ->rawParams( $userLink, $userTalkLink )
82                ->escaped()
83        );
84        // Give grep a chance to find the usages:
85        // centralnotice-action-created, centralnotice-action-modified,
86        // centralnotice-action-removed
87        $htmlOut .= Html::element( 'td', [ 'valign' => 'top', 'class' => 'primary' ],
88            $this->msg( 'centralnotice-action-' . $row->tmplog_action )->text()
89        );
90        $htmlOut .= Html::rawElement( 'td', [ 'valign' => 'top', 'class' => 'primary' ],
91            $bannerLink
92        );
93
94        $summary = $row->tmplog_comment === null
95            ? '&nbsp;'
96            : htmlspecialchars( $row->tmplog_comment );
97
98        $htmlOut .= Html::rawElement( 'td',
99            [ 'valign' => 'top', 'class' => 'primary-summary' ],
100            $summary
101        );
102
103        $htmlOut .= Html::rawElement( 'td', [],
104            '&nbsp;'
105        );
106
107        // End log entry primary row
108        $htmlOut .= Html::closeElement( 'tr' );
109
110        if ( $row->tmplog_action !== 'removed' ) {
111            // Begin log entry secondary row
112            $htmlOut .= Html::openElement( 'tr',
113                [ 'id' => 'cn-log-details-' . $tmplogId, 'style' => 'display:none;' ] );
114            // @phan-suppress-previous-line PhanPossiblyUndeclaredVariable
115
116            $htmlOut .= Html::rawElement( 'td', [ 'valign' => 'top' ],
117                // force a table cell in older browsers
118                '&nbsp;'
119            );
120            $htmlOut .= Html::openElement( 'td', [ 'valign' => 'top', 'colspan' => '5' ] );
121            if ( $row->tmplog_action === 'created' ) {
122                $htmlOut .= $this->showInitialSettings( $row );
123            } elseif ( $row->tmplog_action === 'modified' ) {
124                $htmlOut .= $this->showChanges( $row );
125            }
126            $htmlOut .= Html::closeElement( 'td' );
127
128            // End log entry primary row
129            $htmlOut .= Html::closeElement( 'tr' );
130        }
131
132        return $htmlOut;
133    }
134
135    /** @inheritDoc */
136    public function getStartBody() {
137        $htmlOut = '';
138        $htmlOut .= Html::openElement( 'table', [ 'id' => 'cn-campaign-logs', 'cellpadding' => 3 ] );
139        $htmlOut .= Html::openElement( 'tr' );
140        $htmlOut .= Html::element( 'th', [ 'style' => 'width: 20px;' ] );
141        $htmlOut .= Html::element( 'th', [ 'align' => 'left', 'style' => 'width: 130px;' ],
142            $this->msg( 'centralnotice-timestamp' )->text()
143        );
144        $htmlOut .= Html::element( 'th', [ 'align' => 'left', 'style' => 'width: 160px;' ],
145            $this->msg( 'centralnotice-user' )->text()
146        );
147        $htmlOut .= Html::element( 'th', [ 'align' => 'left', 'style' => 'width: 100px;' ],
148            $this->msg( 'centralnotice-action' )->text()
149        );
150        $htmlOut .= Html::element( 'th', [ 'align' => 'left', 'style' => 'width: 160px;' ],
151            $this->msg( 'centralnotice-banner' )->text()
152        );
153        $htmlOut .= Html::element( 'th', [ 'align' => 'left', 'style' => 'width: 250px;' ],
154            $this->msg( 'centralnotice-change-summary-heading' )->text()
155        );
156        $htmlOut .= Html::rawElement( 'td', [],
157            '&nbsp;'
158        );
159        $htmlOut .= Html::closeElement( 'tr' );
160        return $htmlOut;
161    }
162
163    /**
164     * Close table
165     * @return string
166     */
167    public function getEndBody() {
168        return Html::closeElement( 'table' );
169    }
170
171    /**
172     * @param stdClass $row
173     * @return string
174     */
175    public function showInitialSettings( $row ) {
176        $details = '';
177        $details .= $this->msg(
178            'centralnotice-log-label',
179            $this->msg( 'centralnotice-anon' )->text(),
180            ( $row->tmplog_end_anon ? 'on' : 'off' )
181        )->parse() . "<br/>";
182        $details .= $this->msg(
183            'centralnotice-log-label',
184            $this->msg( 'centralnotice-account' )->text(),
185            ( $row->tmplog_end_account ? 'on' : 'off' )
186        )->parse() . "<br/>";
187        $details .= $this->msg(
188            'centralnotice-log-label',
189            $this->msg( 'centralnotice-category' )->text(),
190            wfEscapeWikiText( $row->tmplog_end_category )
191        )->parse() . "<br/>";
192
193        // Autolink/landing pages feature has been removed, but we might as
194        // well show any info about it in the logs.
195        $details .= $this->msg(
196            'centralnotice-log-label',
197            $this->msg( 'centralnotice-autolink' )->text(),
198            ( $row->tmplog_end_autolink ? 'on' : 'off' )
199        )->parse() . "<br/>";
200        if ( $row->tmplog_end_landingpages ) {
201            $details .= $this->msg(
202                'centralnotice-log-label',
203                $this->msg( 'centralnotice-landingpages' )->text(),
204                wfEscapeWikiText( $row->tmplog_end_landingpages )
205            )->parse() . "<br/>";
206        }
207        $details .= $this->msg(
208            'centralnotice-log-label',
209            $this->msg( 'centralnotice-devices' )->text(),
210            wfEscapeWikiText( $row->tmplog_end_devices )
211        )->parse() . "<br/>";
212        return $details;
213    }
214
215    /**
216     * @param stdClass $newrow
217     * @return string
218     */
219    public function showChanges( $newrow ) {
220        $oldrow = false;
221        if ( $newrow->tmplog_action === 'modified' ) {
222            $db = CNDatabase::getReplicaDb();
223            $tmplogId = (int)$newrow->tmplog_id;
224            $oldrow = $db->newSelectQueryBuilder()
225                ->select( '*' )
226                ->from( 'cn_template_log' )
227                ->where( [
228                    'tmplog_template_id' => $newrow->tmplog_template_id,
229                    $db->expr( 'tmplog_id', '<', $tmplogId ),
230                ] )
231                ->orderBy( 'tmplog_id', SelectQueryBuilder::SORT_DESC )
232                ->caller( __METHOD__ )
233                ->fetchRow();
234        }
235
236        $details = $this->testBooleanBannerChange( 'anon', $newrow, $oldrow );
237        $details .= $this->testBooleanBannerChange( 'account', $newrow, $oldrow );
238        $details .= $this->testTextBannerChange( 'category', $newrow, $oldrow );
239        $details .= $this->testBooleanBannerChange( 'autolink', $newrow, $oldrow );
240        $details .= $this->testTextBannerChange( 'landingpages', $newrow, $oldrow );
241        $details .= $this->testTextBannerChange( 'controller_mixin', $newrow, $oldrow );
242        $details .= $this->testTextBannerChange( 'prioritylangs', $newrow, $oldrow );
243        $details .= $this->testTextBannerChange( 'devices', $newrow, $oldrow );
244        if ( $newrow->tmplog_content_change ) {
245            // Show changes to banner content
246            $details .= $this->msg(
247                'centralnotice-log-label',
248                $this->msg( 'centralnotice-banner-content' )->text(),
249                $this->msg( 'centralnotice-banner-content-changed' )->text()
250            )->parse() . "<br/>";
251        }
252        return $details;
253    }
254
255    /**
256     * @param string $param
257     * @param stdClass $newrow
258     * @param stdClass $oldrow
259     * @return string
260     */
261    private function testBooleanBannerChange( $param, $newrow, $oldrow ) {
262        $result = '';
263        $endField = 'tmplog_end_' . $param;
264
265        $oldval = ( $oldrow ) ? $oldrow->$endField : 0;
266        if ( $oldval !== $newrow->$endField ) {
267            // The following messages are generated here:
268            // * centralnotice-anon
269            // * centralnotice-account
270            // * centralnotice-autolink
271            $result .= $this->msg(
272                'centralnotice-log-label',
273                $this->msg( 'centralnotice-' . $param )->text(),
274                $this->msg(
275                    'centralnotice-changed',
276                    ( $oldval
277                        ? $this->msg( 'centralnotice-on' )->text()
278                        : $this->msg( 'centralnotice-off' )->text() ),
279                    ( $newrow->$endField
280                        ? $this->msg( 'centralnotice-on' )->text()
281                        : $this->msg( 'centralnotice-off' )->text() )
282                )->text()
283            )->parse() . "<br/>";
284        }
285        return $result;
286    }
287
288    /**
289     * @param string $param
290     * @param stdClass $newrow
291     * @param stdClass $oldrow
292     * @return string
293     */
294    private function testTextBannerChange( $param, $newrow, $oldrow ) {
295        $endField = 'tmplog_end_' . $param;
296
297        $oldval = ( ( $oldrow ) ? $oldrow->$endField : '' ) ?: '';
298        $newval = ( $newrow->$endField ) ?: '';
299
300        return $this->testTextChange( $param, $newval, $oldval );
301    }
302}