Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
77.57% covered (warning)
77.57%
83 / 107
37.50% covered (danger)
37.50%
3 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProtectLogFormatter
77.57% covered (warning)
77.57%
83 / 107
37.50% covered (danger)
37.50%
3 / 8
52.45
0.00% covered (danger)
0.00%
0 / 1
 getPreloadTitles
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getMessageKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getMessageParameters
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
7.01
 getActionLinks
67.86% covered (warning)
67.86%
19 / 28
0.00% covered (danger)
0.00%
0 / 1
7.20
 getParametersForApi
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
8
 formatParametersForApi
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 createProtectDescription
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
4.01
 formatExpiry
20.00% covered (danger)
20.00%
2 / 10
0.00% covered (danger)
0.00%
0 / 1
4.05
1<?php
2/**
3 * Formatter for protect log entries.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @license GPL-2.0-or-later
22 * @since 1.26
23 */
24
25use MediaWiki\Message\Message;
26use MediaWiki\Title\Title;
27
28/**
29 * This class formats protect log entries.
30 *
31 * @since 1.26
32 */
33class ProtectLogFormatter extends LogFormatter {
34    public function getPreloadTitles() {
35        $subtype = $this->entry->getSubtype();
36        if ( $subtype === 'move_prot' ) {
37            $params = $this->extractParameters();
38            return [ Title::newFromText( $params[3] ) ];
39        }
40        return [];
41    }
42
43    protected function getMessageKey() {
44        $key = parent::getMessageKey();
45        $params = $this->extractParameters();
46        if ( isset( $params[4] ) && $params[4] ) {
47            // Messages: logentry-protect-protect-cascade, logentry-protect-modify-cascade
48            $key .= '-cascade';
49        }
50
51        return $key;
52    }
53
54    protected function getMessageParameters() {
55        $params = parent::getMessageParameters();
56
57        $subtype = $this->entry->getSubtype();
58        if ( $subtype === 'protect' || $subtype === 'modify' ) {
59            $rawParams = $this->entry->getParameters();
60            if ( isset( $rawParams['details'] ) ) {
61                $params[3] = $this->createProtectDescription( $rawParams['details'] );
62            } elseif ( isset( $params[3] ) ) {
63                // Old way of Restrictions and expiries
64                $params[3] = $this->context->getLanguage()->getDirMark() . $params[3];
65            } else {
66                // Very old way (nothing set)
67                $params[3] = '';
68            }
69            // Cascading flag
70            if ( isset( $params[4] ) ) {
71                // handled in getMessageKey
72                unset( $params[4] );
73            }
74        } elseif ( $subtype === 'move_prot' ) {
75            $oldname = $this->makePageLink( Title::newFromText( $params[3] ), [ 'redirect' => 'no' ] );
76            $params[3] = Message::rawParam( $oldname );
77        }
78
79        return $params;
80    }
81
82    public function getActionLinks() {
83        $linkRenderer = $this->getLinkRenderer();
84        $subtype = $this->entry->getSubtype();
85        if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
86            || $subtype === 'move_prot' // the move log entry has the right action link
87        ) {
88            return '';
89        }
90
91        // Show history link for pages that exist otherwise show nothing
92        $title = $this->entry->getTarget();
93        $links = [];
94        if ( $title->exists() ) {
95            $links[] = $linkRenderer->makeLink( $title,
96                $this->msg( 'hist' )->text(),
97                [],
98                [
99                    'action' => 'history',
100                    'offset' => $this->entry->getTimestamp(),
101                ]
102            );
103        }
104
105        // Show change protection link
106        if ( $this->context->getAuthority()->isAllowed( 'protect' ) ) {
107            $links[] = $linkRenderer->makeKnownLink(
108                $title,
109                $this->msg( 'protect_change' )->text(),
110                [],
111                [ 'action' => 'protect' ]
112            );
113        }
114
115        if ( !$links ) {
116            return '';
117        } else {
118            return $this->msg( 'parentheses' )->rawParams(
119                $this->context->getLanguage()->pipeList( $links )
120            )->escaped();
121        }
122    }
123
124    protected function getParametersForApi() {
125        $entry = $this->entry;
126        $subtype = $this->entry->getSubtype();
127        $params = $entry->getParameters();
128
129        $map = [];
130        if ( $subtype === 'protect' || $subtype === 'modify' ) {
131            $map = [
132                '4::description',
133                '5:bool:cascade',
134                'details' => ':array:details',
135            ];
136        } elseif ( $subtype === 'move_prot' ) {
137            $map = [
138                '4:title:oldtitle',
139                '4::oldtitle' => '4:title:oldtitle',
140            ];
141        }
142        foreach ( $map as $index => $key ) {
143            if ( isset( $params[$index] ) ) {
144                $params[$key] = $params[$index];
145                unset( $params[$index] );
146            }
147        }
148
149        // Change string to explicit boolean
150        if ( isset( $params['5:bool:cascade'] ) && is_string( $params['5:bool:cascade'] ) ) {
151            $params['5:bool:cascade'] = $params['5:bool:cascade'] === 'cascade';
152        }
153
154        return $params;
155    }
156
157    public function formatParametersForApi() {
158        $ret = parent::formatParametersForApi();
159        if ( isset( $ret['details'] ) && is_array( $ret['details'] ) ) {
160            $contLang = $this->getContentLanguage();
161            foreach ( $ret['details'] as &$detail ) {
162                if ( isset( $detail['expiry'] ) ) {
163                    $detail['expiry'] = $contLang->
164                        formatExpiry( $detail['expiry'], TS_ISO_8601, 'infinite' );
165                }
166            }
167        }
168
169        return $ret;
170    }
171
172    /**
173     * Create the protect description to show in the log formatter
174     *
175     * @param array[] $details
176     * @return string
177     */
178    public function createProtectDescription( array $details ) {
179        $protectDescription = '';
180
181        foreach ( $details as $param ) {
182            $expiryText = $this->formatExpiry( $param['expiry'] );
183
184            // Messages: restriction-edit, restriction-move, restriction-create,
185            // restriction-upload
186            $action = $this->context->msg( 'restriction-' . $param['type'] )->escaped();
187
188            $protectionLevel = $param['level'];
189            // Messages: protect-level-autoconfirmed, protect-level-sysop
190            $message = $this->context->msg( 'protect-level-' . $protectionLevel );
191            if ( $message->isDisabled() ) {
192                // Require "$1" permission
193                $restrictions = $this->context->msg( "protect-fallback", $protectionLevel )->parse();
194            } else {
195                $restrictions = $message->escaped();
196            }
197
198            if ( $protectDescription !== '' ) {
199                $protectDescription .= $this->context->msg( 'word-separator' )->escaped();
200            }
201
202            $protectDescription .= $this->context->msg( 'protect-summary-desc' )
203                ->params( $action, $restrictions, $expiryText )->escaped();
204        }
205
206        return $protectDescription;
207    }
208
209    private function formatExpiry( $expiry ) {
210        if ( wfIsInfinity( $expiry ) ) {
211            return $this->context->msg( 'protect-expiry-indefinite' )->text();
212        }
213        $lang = $this->context->getLanguage();
214        $user = $this->context->getUser();
215        return $this->context->msg(
216            'protect-expiring-local',
217            $lang->userTimeAndDate( $expiry, $user ),
218            $lang->userDate( $expiry, $user ),
219            $lang->userTime( $expiry, $user )
220        )->text();
221    }
222
223}