]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/ProtectionForm.php
MediaWiki 1.11.0
[autoinstallsdev/mediawiki.git] / includes / ProtectionForm.php
1 <?php
2 /**
3  * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
4  * http://www.mediawiki.org/
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  * http://www.gnu.org/copyleft/gpl.html
20  */
21
22 /**
23  * @todo document, briefly.
24  * @addtogroup SpecialPage
25  */
26 class ProtectionForm {
27         var $mRestrictions = array();
28         var $mReason = '';
29         var $mCascade = false;
30         var $mExpiry = null;
31
32         function __construct( &$article ) {
33                 global $wgRequest, $wgUser;
34                 global $wgRestrictionTypes, $wgRestrictionLevels;
35                 $this->mArticle =& $article;
36                 $this->mTitle =& $article->mTitle;
37
38                 if( $this->mTitle ) {
39                         $this->mTitle->loadRestrictions();
40
41                         foreach( $wgRestrictionTypes as $action ) {
42                                 // Fixme: this form currently requires individual selections,
43                                 // but the db allows multiples separated by commas.
44                                 $this->mRestrictions[$action] = implode( '', $this->mTitle->getRestrictions( $action ) );
45                         }
46
47                         $this->mCascade = $this->mTitle->areRestrictionsCascading();
48
49                         if ( $this->mTitle->mRestrictionsExpiry == 'infinity' ) {
50                                 $this->mExpiry = 'infinite';
51                         } else if ( strlen($this->mTitle->mRestrictionsExpiry) == 0 ) {
52                                 $this->mExpiry = '';
53                         } else {
54                                 $this->mExpiry = wfTimestamp( TS_RFC2822, $this->mTitle->mRestrictionsExpiry );
55                         }
56                 }
57
58                 // The form will be available in read-only to show levels.
59                 $this->disabled = !$wgUser->isAllowed( 'protect' ) || wfReadOnly() || $wgUser->isBlocked();
60                 $this->disabledAttrib = $this->disabled
61                         ? array( 'disabled' => 'disabled' )
62                         : array();
63
64                 if( $wgRequest->wasPosted() ) {
65                         $this->mReason = $wgRequest->getText( 'mwProtect-reason' );
66                         $this->mCascade = $wgRequest->getBool( 'mwProtect-cascade' );
67                         $this->mExpiry = $wgRequest->getText( 'mwProtect-expiry' );
68
69                         foreach( $wgRestrictionTypes as $action ) {
70                                 $val = $wgRequest->getVal( "mwProtect-level-$action" );
71                                 if( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) {
72                                         $this->mRestrictions[$action] = $val;
73                                 }
74                         }
75                 }
76         }
77         
78         function execute() {
79                 global $wgRequest, $wgOut;
80                 if( $wgRequest->wasPosted() ) {
81                         if( $this->save() ) {
82                                 $article = new Article( $this->mTitle );
83                                 $q = $article->isRedirect() ? 'redirect=no' : '';
84                                 $wgOut->redirect( $this->mTitle->getFullUrl( $q ) );
85                         }
86                 } else {
87                         $this->show();
88                 }
89         }
90
91         function show( $err = null ) {
92                 global $wgOut, $wgUser;
93
94                 $wgOut->setRobotpolicy( 'noindex,nofollow' );
95
96                 if( is_null( $this->mTitle ) ||
97                         !$this->mTitle->exists() ||
98                         $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
99                         $wgOut->showFatalError( wfMsg( 'badarticleerror' ) );
100                         return;
101                 }
102
103                 list( $cascadeSources, /* $restrictions */ ) = $this->mTitle->getCascadeProtectionSources();
104
105                 if ( "" != $err ) {
106                         $wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
107                         $wgOut->addHTML( "<p class='error'>{$err}</p>\n" );
108                 }
109
110                 if ( $cascadeSources && count($cascadeSources) > 0 ) {
111                         $titles = '';
112
113                         foreach ( $cascadeSources as $title ) {
114                                 $titles .= '* [[:' . $title->getPrefixedText() . "]]\n";
115                         }
116
117                         $notice = wfMsgExt( 'protect-cascadeon', array('parsemag'), count($cascadeSources) ) . "\r\n$titles";
118
119                         $wgOut->addWikiText( $notice );
120                 }
121
122                 $wgOut->setPageTitle( wfMsg( 'confirmprotect' ) );
123                 $wgOut->setSubtitle( wfMsg( 'protectsub', $this->mTitle->getPrefixedText() ) );
124
125                 # Show an appropriate message if the user isn't allowed or able to change
126                 # the protection settings at this time
127                 if( $this->disabled ) {
128                         if( $wgUser->isAllowed( 'protect' ) ) {
129                                 if( $wgUser->isBlocked() ) {
130                                         # Blocked
131                                         $message = 'protect-locked-blocked';
132                                 } else {
133                                         # Database lock
134                                         $message = 'protect-locked-dblock';
135                                 }
136                         } else {
137                                 # Permission error
138                                 $message = 'protect-locked-access';
139                         }
140                 } else {
141                         $message = 'protect-text';
142                 }
143                 $wgOut->addWikiText( wfMsg( $message, wfEscapeWikiText( $this->mTitle->getPrefixedText() ) ) );
144
145                 $wgOut->addHTML( $this->buildForm() );
146
147                 $this->showLogExtract( $wgOut );
148         }
149
150         function save() {
151                 global $wgRequest, $wgUser, $wgOut;
152                 
153                 if( $this->disabled ) {
154                         $this->show();
155                         return false;
156                 }
157
158                 $token = $wgRequest->getVal( 'wpEditToken' );
159                 if( !$wgUser->matchEditToken( $token ) ) {
160                         $this->show( wfMsg( 'sessionfailure' ) );
161                         return false;
162                 }
163
164                 if ( strlen( $this->mExpiry ) == 0 ) {
165                         $this->mExpiry = 'infinite';
166                 }
167
168                 if ( $this->mExpiry == 'infinite' || $this->mExpiry == 'indefinite' ) {
169                         $expiry = Block::infinity();
170                 } else {
171                         # Convert GNU-style date, on error returns -1 for PHP <5.1 and false for PHP >=5.1
172                         $expiry = strtotime( $this->mExpiry );
173
174                         if ( $expiry < 0 || $expiry === false ) {
175                                 $this->show( wfMsg( 'protect_expiry_invalid' ) );
176                                 return false;
177                         }
178
179                         $expiry = wfTimestamp( TS_MW, $expiry );
180
181                         if ( $expiry < wfTimestampNow() ) {
182                                 $this->show( wfMsg( 'protect_expiry_old' ) );
183                                 return false;
184                         }
185
186                 }
187
188                 $ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason, $this->mCascade, $expiry );
189                 if( !$ok ) {
190                         throw new FatalError( "Unknown error at restriction save time." );
191                 }
192                 
193                 if( $wgRequest->getCheck( 'mwProtectWatch' ) ) {
194                         $this->mArticle->doWatch();
195                 } elseif( $this->mTitle->userIsWatching() ) {
196                         $this->mArticle->doUnwatch();
197                 }
198                 
199                 return $ok;
200         }
201
202         function buildForm() {
203                 global $wgUser;
204
205                 $out = '';
206                 if( !$this->disabled ) {
207                         $out .= $this->buildScript();
208                         // The submission needs to reenable the move permission selector
209                         // if it's in locked mode, or some browsers won't submit the data.
210                         $out .= wfOpenElement( 'form', array(
211                                 'id' => 'mw-Protect-Form',
212                                 'action' => $this->mTitle->getLocalUrl( 'action=protect' ),
213                                 'method' => 'post',
214                                 'onsubmit' => 'protectEnable(true)' ) );
215
216                         $out .= wfElement( 'input', array(
217                                 'type' => 'hidden',
218                                 'name' => 'wpEditToken',
219                                 'value' => $wgUser->editToken() ) );
220                 }
221
222                 $out .= "<table id='mwProtectSet'>";
223                 $out .= "<tbody>";
224                 $out .= "<tr>\n";
225                 foreach( $this->mRestrictions as $action => $required ) {
226                         /* Not all languages have V_x <-> N_x relation */
227                         $out .= "<th>" . wfMsgHtml( 'restriction-' . $action ) . "</th>\n";
228                 }
229                 $out .= "</tr>\n";
230                 $out .= "<tr>\n";
231                 foreach( $this->mRestrictions as $action => $selected ) {
232                         $out .= "<td>\n";
233                         $out .= $this->buildSelector( $action, $selected );
234                         $out .= "</td>\n";
235                 }
236                 $out .= "</tr>\n";
237
238                 // JavaScript will add another row with a value-chaining checkbox
239
240                 $out .= "</tbody>\n";
241                 $out .= "</table>\n";
242
243                 $out .= "<table>\n";
244                 $out .= "<tbody>\n";
245
246                 global $wgEnableCascadingProtection;
247                 if( $wgEnableCascadingProtection )
248                         $out .= '<tr><td></td><td>' . $this->buildCascadeInput() . "</td></tr>\n";
249
250                 $out .= $this->buildExpiryInput();
251
252                 if( !$this->disabled ) {
253                         $out .= "<tr><td>" . $this->buildReasonInput() . "</td></tr>\n";
254                         $out .= "<tr><td></td><td>" . $this->buildWatchInput() . "</td></tr>\n";
255                         $out .= "<tr><td></td><td>" . $this->buildSubmit() . "</td></tr>\n";
256                 }
257
258                 $out .= "</tbody>\n";
259                 $out .= "</table>\n";
260
261                 if ( !$this->disabled ) {
262                         $out .= "</form>\n";
263                         $out .= $this->buildCleanupScript();
264                 }
265
266                 return $out;
267         }
268
269         function buildSelector( $action, $selected ) {
270                 global $wgRestrictionLevels;
271                 $id = 'mwProtect-level-' . $action;
272                 $attribs = array(
273                         'id' => $id,
274                         'name' => $id,
275                         'size' => count( $wgRestrictionLevels ),
276                         'onchange' => 'protectLevelsUpdate(this)',
277                         ) + $this->disabledAttrib;
278
279                 $out = wfOpenElement( 'select', $attribs );
280                 foreach( $wgRestrictionLevels as $key ) {
281                         $out .= Xml::option( $this->getOptionLabel( $key ), $key, $key == $selected );
282                 }
283                 $out .= "</select>\n";
284                 return $out;
285         }
286
287         /**
288          * Prepare the label for a protection selector option
289          *
290          * @param string $permission Permission required
291          * @return string
292          */
293         private function getOptionLabel( $permission ) {
294                 if( $permission == '' ) {
295                         return wfMsg( 'protect-default' );
296                 } else {
297                         $key = "protect-level-{$permission}";
298                         $msg = wfMsg( $key );
299                         if( wfEmptyMsg( $key, $msg ) )
300                                 $msg = wfMsg( 'protect-fallback', $permission );
301                         return $msg;
302                 }
303         }
304
305         function buildReasonInput() {
306                 $id = 'mwProtect-reason';
307                 return wfElement( 'label', array(
308                                 'id' => "$id-label",
309                                 'for' => $id ),
310                                 wfMsg( 'protectcomment' ) ) .
311                         '</td><td>' .
312                         wfElement( 'input', array(
313                                 'size' => 60,
314                                 'name' => $id,
315                                 'id' => $id,
316                                 'value' => $this->mReason ) );
317         }
318
319         function buildCascadeInput() {
320                 $id = 'mwProtect-cascade';
321                 $ci = wfCheckLabel( wfMsg( 'protect-cascade' ), $id, $id, $this->mCascade, $this->disabledAttrib);
322                 return $ci;
323         }
324
325         function buildExpiryInput() {
326                 $attribs = array( 'id' => 'expires' ) + $this->disabledAttrib;
327                 return '<tr>'
328                         . '<td><label for="expires">' . wfMsgExt( 'protectexpiry', array( 'parseinline' ) ) . '</label></td>'
329                         . '<td>' . Xml::input( 'mwProtect-expiry', 60, $this->mExpiry, $attribs ) . '</td>'
330                         . '</tr>';
331         }
332         
333         function buildWatchInput() {
334                 global $wgUser;
335                 return Xml::checkLabel(
336                         wfMsg( 'watchthis' ),
337                         'mwProtectWatch',
338                         'mwProtectWatch',
339                         $this->mTitle->userIsWatching() || $wgUser->getOption( 'watchdefault' )
340                 );
341         }
342
343         function buildSubmit() {
344                 return wfElement( 'input', array(
345                         'id' => 'mw-Protect-submit',
346                         'type' => 'submit',
347                         'value' => wfMsg( 'confirm' ) ) );
348         }
349
350         function buildScript() {
351                 global $wgStylePath, $wgStyleVersion;
352                 return '<script type="text/javascript" src="' .
353                         htmlspecialchars( $wgStylePath . "/common/protect.js?$wgStyleVersion" ) .
354                         '"></script>';
355         }
356
357         function buildCleanupScript() {
358                 global $wgRestrictionLevels, $wgGroupPermissions;
359                 $script = 'var wgCascadeableLevels=';
360                 $CascadeableLevels = array();
361                 foreach( $wgRestrictionLevels as $key ) {
362                         if ( isset($wgGroupPermissions[$key]['protect']) && $wgGroupPermissions[$key]['protect'] ) {
363                                 $CascadeableLevels[]="'" . wfEscapeJsString($key) . "'";
364                         }
365                 }
366                 $script .= "[" . implode(',',$CascadeableLevels) . "];\n";
367                 $script .= 'protectInitialize("mwProtectSet","' . wfEscapeJsString( wfMsg( 'protect-unchain' ) ) . '")';
368                 return '<script type="text/javascript">' . $script . '</script>';
369         }
370
371         /**
372          * @param OutputPage $out
373          * @access private
374          */
375         function showLogExtract( &$out ) {
376                 # Show relevant lines from the protection log:
377                 $out->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'protect' ) ) . "</h2>\n" );
378                 $logViewer = new LogViewer(
379                         new LogReader(
380                                 new FauxRequest(
381                                         array( 'page' => $this->mTitle->getPrefixedText(),
382                                                'type' => 'protect' ) ) ) );
383                 $logViewer->showList( $out );
384         }
385
386 }