* (bug 4133) Allow page protections to be made with an expiry date, in the same forma...
authorAndrew Garrett <werdna@users.mediawiki.org>
Mon, 22 Jan 2007 08:26:41 +0000 (08:26 +0000)
committerAndrew Garrett <werdna@users.mediawiki.org>
Mon, 22 Jan 2007 08:26:41 +0000 (08:26 +0000)
RELEASE-NOTES
includes/Article.php
includes/ProtectionForm.php
includes/SpecialProtectedpages.php
includes/Title.php
languages/messages/MessagesEn.php

index c59558d..115d198 100644 (file)
@@ -136,6 +136,9 @@ lighter making things easier to read.
   and their protection status (full protection status is not pulled out due
   to performance considerations, so it just shows "full protected" or
   "semi protected".
+* (bug 4133) Allow page protections to be made with an expiry date, in the same format
+  as block expiry dates. Existing protections are assumed to be infinite, as are protections
+  made with the new field left blank. 
 
 == Languages updated ==
 
index 8c5b19d..20eb4ef 100644 (file)
@@ -1651,7 +1651,7 @@ class Article {
         * @param string $reason
         * @return bool true on success
         */
-       function updateRestrictions( $limit = array(), $reason = '', $cascade = 0 ) {
+       function updateRestrictions( $limit = array(), $reason = '', $cascade = 0, $expiry = null ) {
                global $wgUser, $wgRestrictionTypes, $wgContLang;
 
                $id = $this->mTitle->getArticleID();
@@ -1663,6 +1663,9 @@ class Article {
                        $cascade = false;
                }
 
+               // Take this opportunity to purge out expired restrictions
+               Title::purgeExpiredRestrictions();
+
                # FIXME: Same limitations as described in ProtectionForm.php (line 37);
                # we expect a single selection, but the schema allows otherwise.
                $current = array();
@@ -1674,6 +1677,7 @@ class Article {
 
                $changed = ( $current != $updated );
                $changed = $changed || ($this->mTitle->areRestrictionsCascading() != $cascade);
+               $changed = $changed || ($this->mTitle->mRestrictionsExpiry != $expiry);
                $protect = ( $updated != '' );
 
                # If nothing's changed, do nothing
@@ -1693,10 +1697,13 @@ class Article {
 
                                # Update restrictions table
                                foreach( $limit as $action => $restrictions ) {
+                                       $encodedExpiry = Block::encodeExpiry($expiry, $dbw );
+
                                        if ($restrictions != '' ) {
                                                $dbw->replace( 'page_restrictions', array( 'pr_pagetype'),
                                                        array( 'pr_page' => $id, 'pr_type' => $action
-                                                               , 'pr_level' => $restrictions, 'pr_cascade' => $cascade ? 1 : 0 ), __METHOD__  );
+                                                               , 'pr_level' => $restrictions, 'pr_cascade' => $cascade ? 1 : 0
+                                                               , 'pr_expiry' => $encodedExpiry ), __METHOD__  );
                                        } else {
                                                $dbw->delete( 'page_restrictions', array( 'pr_page' => $id,
                                                        'pr_type' => $action ), __METHOD__ );
@@ -1719,13 +1726,18 @@ class Article {
                                $log = new LogPage( 'protect' );
 
                                $cascade_description = '';
+                               $expiry_description = '';
 
                                if ($cascade) {
                                        $cascade_description = ' ['.wfMsg('protect-summary-cascade').']';
                                }
 
+                               if ( $encodedExpiry != 'infinity' ) {
+                                       $expiry_description = ' ' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ) );
+                               }
+
                                if( $protect ) {
-                                       $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$updated]$cascade_description" ) );
+                                       $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$updated]$cascade_description$expiry_description" ) );
                                } else {
                                        $log->addEntry( 'unprotect', $this->mTitle, $reason );
                                }
index 04b95bd..e349fba 100644 (file)
@@ -25,14 +25,17 @@ class ProtectionForm {
        var $mRestrictions = array();
        var $mReason = '';
        var $mCascade = false;
+       var $mExpiry = null;
 
        function __construct( &$article ) {
-               global $wgRequest, $wgUser;
+               global $wgRequest, $wgUser, $wgLang;
                global $wgRestrictionTypes, $wgRestrictionLevels;
                $this->mArticle =& $article;
                $this->mTitle =& $article->mTitle;
 
                if( $this->mTitle ) {
+                       $this->mTitle->loadRestrictions();
+
                        foreach( $wgRestrictionTypes as $action ) {
                                // Fixme: this form currently requires individual selections,
                                // but the db allows multiples separated by commas.
@@ -40,6 +43,14 @@ class ProtectionForm {
                        }
 
                        $this->mCascade = $this->mTitle->areRestrictionsCascading();
+
+                       if ( $this->mTitle->mRestrictionsExpiry == 'infinity' ) {
+                               $this->mExpiry = 'infinite';
+                       } else if ( strlen($this->mTitle->mRestrictionsExpiry) == 0 ) {
+                               $this->mExpiry = '';
+                       } else {
+                               $this->mExpiry = $wgLang->timeanddate( $this->mTitle->mRestrictionsExpiry );
+                       }
                }
 
                // The form will be available in read-only to show levels.
@@ -51,16 +62,24 @@ class ProtectionForm {
                if( $wgRequest->wasPosted() ) {
                        $this->mReason = $wgRequest->getText( 'mwProtect-reason' );
                        $this->mCascade = $wgRequest->getBool( 'mwProtect-cascade' );
+                       $this->mExpiry = $wgRequest->getText( 'mwProtect-expiry' );
+
                        foreach( $wgRestrictionTypes as $action ) {
                                $val = $wgRequest->getVal( "mwProtect-level-$action" );
                                if( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) {
                                        $this->mRestrictions[$action] = $val;
                                }
                        }
+
+                       if( $this->save() ) {
+                               global $wgOut;
+                               $wgOut->redirect( $this->mTitle->getFullUrl() );
+                               return;
+                       }
                }
        }
 
-       function show() {
+       function show( $err = null ) {
                global $wgOut;
 
                $wgOut->setRobotpolicy( 'noindex,nofollow' );
@@ -74,6 +93,11 @@ class ProtectionForm {
 
                $cascadeSources = $this->mTitle->getCascadeProtectionSources();
 
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
+                       $wgOut->addHTML( "<p class='error'>{$err}</p>\n" );
+               }
+
                if ( $cascadeSources && count($cascadeSources) > 0 ) {
                        $titles = '';
 
@@ -86,11 +110,6 @@ class ProtectionForm {
                        $wgOut->addWikiText( $notice );
                }
 
-               if( $this->save() ) {
-                       $wgOut->redirect( $this->mTitle->getFullUrl() );
-                       return;
-               }
-
                $wgOut->setPageTitle( wfMsg( 'confirmprotect' ) );
                $wgOut->setSubtitle( wfMsg( 'protectsub', $this->mTitle->getPrefixedText() ) );
 
@@ -118,7 +137,25 @@ class ProtectionForm {
                        throw new FatalError( wfMsg( 'sessionfailure' ) );
                }
 
-               $ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason, $this->mCascade );
+               if ( strlen( $this->mExpiry ) == 0 ) {
+                       $this->mExpiry = 'infinite';
+               }
+
+               if ( $this->mExpiry == 'infinite' || $this->mExpiry == 'indefinite' ) {
+                       $expiry = Block::infinity();
+               } else {
+                       # Convert GNU-style date, on error returns -1 for PHP <5.1 and false for PHP >=5.1
+                       $expiry = strtotime( $this->mExpiry );
+
+                       if ( $expiry < 0 || $expiry === false ) {
+                               $this->show( wfMsg( 'protect_expiry_invalid' ) );
+                               return;
+                       }
+
+                       $expiry = wfTimestamp( TS_MW, $expiry );
+               }
+
+               $ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason, $this->mCascade, $expiry );
                if( !$ok ) {
                        throw new FatalError( "Unknown error at restriction save time." );
                }
@@ -165,18 +202,25 @@ class ProtectionForm {
                $out .= "</tbody>\n";
                $out .= "</table>\n";
 
+               $out .= "<table>\n";
+               $out .= "<tbody>\n";
+
                global $wgEnableCascadingProtection;
 
                if ($wgEnableCascadingProtection)
                        $out .= $this->buildCascadeInput();
 
+               $out .= $this->buildExpiryInput();
+
                if( !$this->disabled ) {
-                       $out .= "<table>\n";
-                       $out .= "<tbody>\n";
                        $out .= "<tr><td>" . $this->buildReasonInput() . "</td></tr>\n";
                        $out .= "<tr><td></td><td>" . $this->buildSubmit() . "</td></tr>\n";
-                       $out .= "</tbody>\n";
-                       $out .= "</table>\n";
+               }
+
+               $out .= "</tbody>\n";
+               $out .= "</table>\n";
+
+               if ( !$this->disabled ) {
                        $out .= "</form>\n";
                        $out .= $this->buildCleanupScript();
                }
@@ -229,7 +273,26 @@ class ProtectionForm {
 
        function buildCascadeInput() {
                $id = 'mwProtect-cascade';
-               $ci = wfCheckLabel( wfMsg( 'protect-cascade' ), $id, $id, $this->mCascade, $this->disabledAttrib);
+               $ci = "<tr>" . wfCheckLabel( wfMsg( 'protect-cascade' ), $id, $id, $this->mCascade, $this->disabledAttrib) . "</tr>";
+
+               return $ci;
+       }
+
+       function buildExpiryInput() {
+               $id = 'mwProtect-expiry';
+
+               $ci = "<tr> <td align=\"right\">";
+               $ci .= wfElement( 'label', array (
+                               'id' => "$id-label",
+                               'for' => $id ),
+                               wfMsg( 'protectexpiry' ) );
+               $ci .= "</td> <td aligh=\"left\">";
+               $ci .= wfElement( 'input', array(
+                               'size' => 60,
+                               'name' => $id,
+                               'id' => $id,
+                               'value' => $this->mExpiry ) );
+               $ci .= "</td></tr>";
 
                return $ci;
        }
index a3674c0..b66f94e 100644 (file)
@@ -70,11 +70,13 @@ class ProtectedPagesPage extends PageQueryPage {
  */
 function wfSpecialProtectedpages() {
 
-    list( $limit, $offset ) = wfCheckLimits();
+       list( $limit, $offset ) = wfCheckLimits();
 
-    $depp = new ProtectedPagesPage();
+       $depp = new ProtectedPagesPage();
 
-    return $depp->doQuery( $offset, $limit );
+       Title::purgeExpiredRestrictions();
+
+       return $depp->doQuery( $offset, $limit );
 }
 
 ?>
index 62080d8..bc5af31 100644 (file)
@@ -52,6 +52,7 @@ class Title {
        var $mLatestID;                 # ID of most recent revision
        var $mRestrictions;             # Array of groups allowed to edit this article
        var $mCascadeRestriction;       # Cascade restrictions on this page to included templates and images?
+       var $mRestrictionsExpiry;       # When do the restrictions on this page expire?
        var $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
        var $mCascadeRestrictionSources;# Where are the cascading restrictions coming from on this page?
        var $mRestrictionsLoaded;       # Boolean for initialisation on demand
@@ -1471,17 +1472,27 @@ class Title {
 
                        $this->mOldRestrictions = true;
                        $this->mCascadeRestriction = false;
+                       $this->mRestrictionsExpiry = Block::decodeExpiry('');
 
                }
 
                if ($dbr->numRows( $res) ) {
                        # Current system - load second to make them override.
+                       $now = wfTimestampNow( );
+
                        while ($row = $dbr->fetchObject( $res ) ) {
                                # Cycle through all the restrictions.
-       
-                               $this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) );
-       
-                               $this->mCascadeRestriction |= $row->pr_cascade;
+
+                               // This code should be refactored, now that it's being used more generally,
+                               // But I don't really see any harm in leaving it in Block for now -werdna
+                               $this->mRestrictionsExpiry = Block::decodeExpiry( $row->pr_expiry );
+
+                               // Only apply the restrictions if they haven't expired!
+                               if ( !$this->mRestrictionsExpiry || $this->mRestrictionsExpiry > $now ) {
+                                       $this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) );
+               
+                                       $this->mCascadeRestriction |= $row->pr_cascade;
+                               }
                        }
                }
 
@@ -1499,6 +1510,16 @@ class Title {
                }
        }
 
+       /** 
+        * Purge expired restrictions from the page_restrictions table
+        */
+       static function purgeExpiredRestrictions() {
+               $dbw =& wfGetDB( DB_MASTER );
+
+               // Make sure we don't purge NULL pr_expiry, or we'll empty the pr_restrictions table of older protects.
+               $dbw->delete( 'page_restrictions', array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ), 'pr_expiry IS NOT NULL' ), __METHOD__ );
+       }
+
        /**
         * Accessor/initialisation for mRestrictions
         *
index 4f8b70d..7d97bfb 100644 (file)
@@ -1746,6 +1746,8 @@ Please hit "back" and reload the page you came from, then try again.',
 'confirmprotect' => 'Confirm protection',
 'protectmoveonly' => 'Protect from moves only',
 'protectcomment' => 'Reason for protecting',
+'protectexpiry' => 'Expiry',
+'protect_expiry_invalid'       => 'Expiry time invalid.',
 'unprotectsub' =>"(Unprotecting \"$1\")",
 'confirmunprotecttext' => 'Do you really want to unprotect this page?',
 'confirmunprotect' => 'Confirm unprotection',
@@ -1759,6 +1761,7 @@ page protection levels. Here are the current settings for the page <strong>$1</s
 'protect-level-autoconfirmed' => 'Block unregistered users',
 'protect-level-sysop' => 'Sysops only',
 'protect-summary-cascade' => 'cascading',
+'protect-expiring' => '(expires $1)',
 'protect-cascade' => 'Cascading protection - protect any pages included in this page.',
 
 # restrictions (nouns)