* (bug 2919) Allow the protection of non-existent pages using the regular protection interface.
* WARNING: This revision requires a schema change, which is included in maintenance/archives/patch-protected_titles.sql, and can be applied in the normal manner (update.php).
This commit is contained in:
parent
77b2fdec9b
commit
34d22f6edc
9 changed files with 199 additions and 36 deletions
|
|
@ -94,6 +94,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
|
|||
* (bug 11657) Support for Thai solar calendar
|
||||
* (bug 943) RSS feed for Recentchangeslinked
|
||||
* Introduced AbortMove hook
|
||||
* (bug 2919) Protection of nonexistent pages with regular protection interface.
|
||||
|
||||
=== Bug fixes in 1.12 ===
|
||||
|
||||
|
|
|
|||
|
|
@ -2898,6 +2898,7 @@ class Article {
|
|||
|
||||
$title->touchLinks();
|
||||
$title->purgeSquid();
|
||||
$title->deleteTitleProtection();
|
||||
}
|
||||
|
||||
static function onArticleDelete( $title ) {
|
||||
|
|
|
|||
|
|
@ -29,17 +29,19 @@ class ProtectionForm {
|
|||
var $mCascade = false;
|
||||
var $mExpiry = null;
|
||||
var $mPermErrors = array();
|
||||
var $mApplicableTypes = array();
|
||||
|
||||
function __construct( &$article ) {
|
||||
global $wgRequest, $wgUser;
|
||||
global $wgRestrictionTypes, $wgRestrictionLevels;
|
||||
$this->mArticle =& $article;
|
||||
$this->mTitle =& $article->mTitle;
|
||||
$this->mApplicableTypes = $this->mTitle->exists() ? $wgRestrictionTypes : array('create');
|
||||
|
||||
if( $this->mTitle ) {
|
||||
$this->mTitle->loadRestrictions();
|
||||
|
||||
foreach( $wgRestrictionTypes as $action ) {
|
||||
foreach( $this->mApplicableTypes as $action ) {
|
||||
// Fixme: this form currently requires individual selections,
|
||||
// but the db allows multiples separated by commas.
|
||||
$this->mRestrictions[$action] = implode( '', $this->mTitle->getRestrictions( $action ) );
|
||||
|
|
@ -67,7 +69,7 @@ class ProtectionForm {
|
|||
$this->mCascade = $wgRequest->getBool( 'mwProtect-cascade' );
|
||||
$this->mExpiry = $wgRequest->getText( 'mwProtect-expiry' );
|
||||
|
||||
foreach( $wgRestrictionTypes as $action ) {
|
||||
foreach( $this->mApplicableTypes as $action ) {
|
||||
$val = $wgRequest->getVal( "mwProtect-level-$action" );
|
||||
if( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) {
|
||||
$this->mRestrictions[$action] = $val;
|
||||
|
|
@ -95,7 +97,6 @@ class ProtectionForm {
|
|||
$wgOut->setRobotpolicy( 'noindex,nofollow' );
|
||||
|
||||
if( is_null( $this->mTitle ) ||
|
||||
!$this->mTitle->exists() ||
|
||||
$this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
|
||||
$wgOut->showFatalError( wfMsg( 'badarticleerror' ) );
|
||||
return;
|
||||
|
|
@ -185,7 +186,12 @@ class ProtectionForm {
|
|||
!(isset($wgGroupPermissions[$edit_restriction]['protect']) && $wgGroupPermissions[$edit_restriction]['protect'] ) )
|
||||
$this->mCascade = false;
|
||||
|
||||
$ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason, $this->mCascade, $expiry );
|
||||
if ($this->mTitle->exists()) {
|
||||
$ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason, $this->mCascade, $expiry );
|
||||
} else {
|
||||
$ok = $this->mTitle->updateTitleProtection( $this->mRestrictions['create'], $this->mReason, $expiry );
|
||||
}
|
||||
|
||||
if( !$ok ) {
|
||||
throw new FatalError( "Unknown error at restriction save time." );
|
||||
}
|
||||
|
|
@ -222,6 +228,7 @@ class ProtectionForm {
|
|||
$out .= "<table id='mwProtectSet'>";
|
||||
$out .= "<tbody>";
|
||||
$out .= "<tr>\n";
|
||||
|
||||
foreach( $this->mRestrictions as $action => $required ) {
|
||||
/* Not all languages have V_x <-> N_x relation */
|
||||
$out .= "<th>" . wfMsgHtml( 'restriction-' . $action ) . "</th>\n";
|
||||
|
|
@ -244,7 +251,7 @@ class ProtectionForm {
|
|||
$out .= "<tbody>\n";
|
||||
|
||||
global $wgEnableCascadingProtection;
|
||||
if( $wgEnableCascadingProtection )
|
||||
if( $wgEnableCascadingProtection && $this->mTitle->exists() )
|
||||
$out .= '<tr><td></td><td>' . $this->buildCascadeInput() . "</td></tr>\n";
|
||||
|
||||
$out .= $this->buildExpiryInput();
|
||||
|
|
|
|||
|
|
@ -718,6 +718,22 @@ class SkinTemplate extends Skin {
|
|||
'href' => $this->mTitle->getLocalUrl( 'action=history')
|
||||
);
|
||||
|
||||
if($wgUser->isAllowed('delete')){
|
||||
$content_actions['delete'] = array(
|
||||
'class' => ($action == 'delete') ? 'selected' : false,
|
||||
'text' => wfMsg('delete'),
|
||||
'href' => $this->mTitle->getLocalUrl( 'action=delete' )
|
||||
);
|
||||
}
|
||||
if ( $this->mTitle->quickUserCan( 'move' ) ) {
|
||||
$moveTitle = SpecialPage::getTitleFor( 'Movepage', $this->thispage );
|
||||
$content_actions['move'] = array(
|
||||
'class' => $this->mTitle->isSpecial( 'Movepage' ) ? 'selected' : false,
|
||||
'text' => wfMsg('move'),
|
||||
'href' => $moveTitle->getLocalUrl()
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
|
||||
if(!$this->mTitle->isProtected()){
|
||||
$content_actions['protect'] = array(
|
||||
|
|
@ -734,21 +750,6 @@ class SkinTemplate extends Skin {
|
|||
);
|
||||
}
|
||||
}
|
||||
if($wgUser->isAllowed('delete')){
|
||||
$content_actions['delete'] = array(
|
||||
'class' => ($action == 'delete') ? 'selected' : false,
|
||||
'text' => wfMsg('delete'),
|
||||
'href' => $this->mTitle->getLocalUrl( 'action=delete' )
|
||||
);
|
||||
}
|
||||
if ( $this->mTitle->quickUserCan( 'move' ) ) {
|
||||
$moveTitle = SpecialPage::getTitleFor( 'Movepage', $this->thispage );
|
||||
$content_actions['move'] = array(
|
||||
'class' => $this->mTitle->isSpecial( 'Movepage' ) ? 'selected' : false,
|
||||
'text' => wfMsg('move'),
|
||||
'href' => $moveTitle->getLocalUrl()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
//article doesn't exist or is deleted
|
||||
if( $wgUser->isAllowed( 'delete' ) ) {
|
||||
|
|
@ -762,7 +763,25 @@ class SkinTemplate extends Skin {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->mTitle->getNamespace() !== NS_MEDIAWIKI && $wgUser->isAllowed( 'protect' ) ) {
|
||||
if(!is_array($this->mTitle->getTitleProtection())){
|
||||
$content_actions['protect'] = array(
|
||||
'class' => ($action == 'protect') ? 'selected' : false,
|
||||
'text' => wfMsg('protect'),
|
||||
'href' => $this->mTitle->getLocalUrl( 'action=protect' )
|
||||
);
|
||||
|
||||
} else {
|
||||
$content_actions['unprotect'] = array(
|
||||
'class' => ($action == 'unprotect') ? 'selected' : false,
|
||||
'text' => wfMsg('unprotect'),
|
||||
'href' => $this->mTitle->getLocalUrl( 'action=unprotect' )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wfProfileOut( "$fname-live" );
|
||||
|
||||
if( $this->loggedin ) {
|
||||
|
|
|
|||
|
|
@ -1195,6 +1195,22 @@ class Title {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if ($action == 'create') {
|
||||
$title_protection = $this->getTitleProtection();
|
||||
|
||||
if (is_array($title_protection)) {
|
||||
extract($title_protection);
|
||||
|
||||
if ($pt_create_perm == 'sysop')
|
||||
$pt_create_perm = 'protect';
|
||||
|
||||
if ($pt_create_perm == '' || !$user->isAllowed($pt_create_perm)) {
|
||||
$errors[] = array ( 'titleprotected', User::whoIs($pt_by), $pt_reason );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( $action == 'create' ) {
|
||||
if( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
|
||||
( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) {
|
||||
|
|
@ -1235,6 +1251,77 @@ class Title {
|
|||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this title subject to title protection?
|
||||
* @return array An associative array representing any existent title protection.
|
||||
*/
|
||||
public function getTitleProtection() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
$res = $dbr->select( 'protected_titles', '*',
|
||||
array ('pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBKey()) );
|
||||
|
||||
if ($row = $dbr->fetchRow( $res )) {
|
||||
return $row;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateTitleProtection( $create_perm, $reason, $expiry ) {
|
||||
global $wgGroupPermissions,$wgUser,$wgContLang;
|
||||
|
||||
if ($create_perm == implode(',',$this->getRestrictions('create'))
|
||||
&& $expiry == $this->mRestrictionsExpiry) {
|
||||
// No change
|
||||
return true;
|
||||
}
|
||||
|
||||
list ($namespace, $title) = array( $this->getNamespace(), $this->getDBKey() );
|
||||
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
|
||||
$encodedExpiry = Block::encodeExpiry($expiry, $dbw );
|
||||
|
||||
$expiry_description = '';
|
||||
if ( $encodedExpiry != 'infinity' ) {
|
||||
$expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ) ).')';
|
||||
}
|
||||
|
||||
# Update protection table
|
||||
if ($create_perm != '' ) {
|
||||
$dbw->replace( 'protected_titles', array(array('pt_namespace', 'pt_title')),
|
||||
array( 'pt_namespace' => $namespace, 'pt_title' => $title
|
||||
, 'pt_create_perm' => $create_perm
|
||||
, 'pt_timestamp' => Block::encodeExpiry(wfTimestampNow(), $dbw)
|
||||
, 'pt_expiry' => $encodedExpiry
|
||||
, 'pt_by' => $wgUser->getId(), 'pt_reason' => $reason ), __METHOD__ );
|
||||
} else {
|
||||
$dbw->delete( 'protected_titles', array( 'pt_namespace' => $namespace,
|
||||
'pt_title' => $title ), __METHOD__ );
|
||||
}
|
||||
# Update the protection log
|
||||
$log = new LogPage( 'protect' );
|
||||
|
||||
if( $create_perm ) {
|
||||
$log->addEntry( $this->mRestrictions['create'] ? 'modify' : 'protect', $this, trim( $reason . " [create=$create_perm] $expiry_description" ) );
|
||||
} else {
|
||||
$log->addEntry( 'unprotect', $this, $reason );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any title protection (due to page existing
|
||||
*/
|
||||
public function deleteTitleProtection() {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
|
||||
$dbw->delete( 'protected_titles',
|
||||
array ('pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBKey()), __METHOD__ );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can $wgUser edit this page?
|
||||
* @return boolean
|
||||
|
|
@ -1612,12 +1699,32 @@ class Title {
|
|||
|
||||
public function loadRestrictions( $oldFashionedRestrictions = NULL ) {
|
||||
if( !$this->mRestrictionsLoaded ) {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
if ($this->exists()) {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
|
||||
$res = $dbr->select( 'page_restrictions', '*',
|
||||
array ( 'pr_page' => $this->getArticleId() ), __METHOD__ );
|
||||
$res = $dbr->select( 'page_restrictions', '*',
|
||||
array ( 'pr_page' => $this->getArticleId() ), __METHOD__ );
|
||||
|
||||
$this->loadRestrictionsFromRow( $res, $oldFashionedRestrictions );
|
||||
$this->loadRestrictionsFromRow( $res, $oldFashionedRestrictions );
|
||||
} else {
|
||||
$title_protection = $this->getTitleProtection();
|
||||
|
||||
if (is_array($title_protection)) {
|
||||
extract($title_protection);
|
||||
|
||||
$now = wfTimestampNow();
|
||||
$expiry = Block::decodeExpiry($pt_expiry);
|
||||
|
||||
if (!$expiry || $expiry > $now) {
|
||||
// Apply the restrictions
|
||||
$this->mRestrictionsExpiry = $expiry;
|
||||
$this->mRestrictions['create'] = explode(',', trim($pt_create_perm) );
|
||||
} else { // Get rid of the old restrictions
|
||||
Title::purgeExpiredRestrictions();
|
||||
}
|
||||
}
|
||||
$this->mRestrictionsLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1629,6 +1736,10 @@ class Title {
|
|||
$dbw->delete( 'page_restrictions',
|
||||
array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
|
||||
__METHOD__ );
|
||||
|
||||
$dbw->delete( 'protected_titles',
|
||||
array( 'pt_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
|
||||
__METHOD__ );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1638,16 +1749,12 @@ class Title {
|
|||
* @return array the array of groups allowed to edit this article
|
||||
*/
|
||||
public function getRestrictions( $action ) {
|
||||
if( $this->exists() ) {
|
||||
if( !$this->mRestrictionsLoaded ) {
|
||||
$this->loadRestrictions();
|
||||
}
|
||||
return isset( $this->mRestrictions[$action] )
|
||||
? $this->mRestrictions[$action]
|
||||
: array();
|
||||
} else {
|
||||
return array();
|
||||
if( !$this->mRestrictionsLoaded ) {
|
||||
$this->loadRestrictions();
|
||||
}
|
||||
return isset( $this->mRestrictions[$action] )
|
||||
? $this->mRestrictions[$action]
|
||||
: array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2794,6 +2901,4 @@ class Title {
|
|||
return Namespace::isContent( $this->getNamespace() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -803,6 +803,7 @@ $2',
|
|||
'namespaceprotected' => "You do not have permission to edit pages in the '''$1''' namespace.",
|
||||
'customcssjsprotected' => "You do not have permission to edit this page, because it contains another user's personal settings.",
|
||||
'ns-specialprotected' => 'Pages in the {{ns:special}} namespace cannot be edited.',
|
||||
'titleprotected' => 'This title has been protected from creation by [[User:$1|$1]]. The reason given is <i>$2</i>.',
|
||||
|
||||
# Login and logout pages
|
||||
'logouttitle' => 'User logout',
|
||||
|
|
@ -1956,6 +1957,7 @@ Here are the current settings for the page <strong>$1</strong>:',
|
|||
# Restrictions (nouns)
|
||||
'restriction-edit' => 'Edit',
|
||||
'restriction-move' => 'Move',
|
||||
'restriction-create' => 'Create',
|
||||
|
||||
# Restriction levels
|
||||
'restriction-level-sysop' => 'full protected',
|
||||
|
|
|
|||
13
maintenance/archives/patch-protected_titles.sql
Normal file
13
maintenance/archives/patch-protected_titles.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
-- Protected titles - nonexistent pages that have been protected
|
||||
CREATE TABLE `/*$wgDBPrefix*/protected_titles` (
|
||||
`pt_namespace` int(11) NOT NULL,
|
||||
`pt_title` varchar(255) NOT NULL,
|
||||
`pt_by` int(10) unsigned NOT NULL,
|
||||
`pt_reason` tinyblob,
|
||||
`pt_timestamp` binary(14) NOT NULL,
|
||||
`pt_expiry` varbinary(14) NOT NULL default '',
|
||||
`pt_create_perm` varbinary(60) NOT NULL,
|
||||
PRIMARY KEY (`pt_namespace`,`pt_title`),
|
||||
KEY `pt_by` (`pt_by`),
|
||||
KEY `pt_timestamp` (`pt_timestamp`)
|
||||
) /*$wgDBTableOptions*/
|
||||
|
|
@ -1168,4 +1168,18 @@ CREATE TABLE /*$wgDBprefix*/page_restrictions (
|
|||
KEY pr_cascade (pr_cascade)
|
||||
) /*$wgDBTableOptions*/;
|
||||
|
||||
-- Protected titles - nonexistent pages that have been protected
|
||||
CREATE TABLE `/*$wgDBPrefix*/protected_titles` (
|
||||
`pt_namespace` int(11) NOT NULL,
|
||||
`pt_title` varchar(255) NOT NULL,
|
||||
`pt_by` int(10) unsigned NOT NULL,
|
||||
`pt_reason` tinyblob,
|
||||
`pt_timestamp` binary(14) NOT NULL,
|
||||
`pt_expiry` varbinary(14) NOT NULL default '',
|
||||
`pt_create_perm` varbinary(60) NOT NULL,
|
||||
PRIMARY KEY (`pt_namespace`,`pt_title`),
|
||||
KEY `pt_by` (`pt_by`),
|
||||
KEY `pt_timestamp` (`pt_timestamp`)
|
||||
) /*$wgDBTableOptions*/
|
||||
|
||||
-- vim: sw=2 sts=2 et
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ $wgNewTables = array(
|
|||
array( 'filearchive', 'patch-filearchive.sql' ),
|
||||
array( 'querycachetwo', 'patch-querycachetwo.sql' ),
|
||||
array( 'redirect', 'patch-redirect.sql' ),
|
||||
array( 'protected_titles', 'patch-protected_titles.sql' ),
|
||||
);
|
||||
|
||||
$wgNewFields = array(
|
||||
|
|
|
|||
Loading…
Reference in a new issue