function execute( $par ) { $this->setHeaders(); $this->outputHeader(); // Purge expired entries on one in every 10 queries if ( !mt_rand( 0, 10 ) ) { Title::purgeExpiredRestrictions(); } $request = $this->getRequest(); $type = $request->getVal( $this->IdType ); $level = $request->getVal( $this->IdLevel ); $sizetype = $request->getVal( 'sizetype' ); $size = $request->getIntOrNull( 'size' ); $NS = $request->getIntOrNull( 'namespace' ); $pager = new ProtectedTitlesPager( $this, array(), $type, $level, $NS, $sizetype, $size ); $this->getOutput()->addHTML( $this->showOptions( $NS, $type, $level ) ); if ( $pager->getNumRows() ) { $this->getOutput()->addHTML( $pager->getNavigationBar() . '<ul>' . $pager->getBody() . '</ul>' . $pager->getNavigationBar() ); } else { $this->getOutput()->addWikiMsg( 'protectedtitlesempty' ); } }
function execute($par) { global $wgOut, $wgRequest; $this->setHeaders(); $this->outputHeader(); // Purge expired entries on one in every 10 queries if (!mt_rand(0, 10)) { Title::purgeExpiredRestrictions(); } $type = $wgRequest->getVal($this->IdType); $level = $wgRequest->getVal($this->IdLevel); $sizetype = $wgRequest->getVal('sizetype'); $size = $wgRequest->getIntOrNull('size'); $NS = $wgRequest->getIntOrNull('namespace'); $pager = new ProtectedTitlesPager($this, array(), $type, $level, $NS, $sizetype, $size); $wgOut->addHTML($this->showOptions($NS, $type, $level)); if ($pager->getNumRows()) { $s = $pager->getNavigationBar(); $s .= "<ul>" . $pager->getBody() . "</ul>"; $s .= $pager->getNavigationBar(); } else { $s = '<p>' . wfMsgHtml('protectedtitlesempty') . '</p>'; } $wgOut->addHTML($s); }
public function execute($par) { $this->setHeaders(); $this->outputHeader(); $this->getOutput()->addModuleStyles('mediawiki.special'); // Purge expired entries on one in every 10 queries if (!mt_rand(0, 10)) { Title::purgeExpiredRestrictions(); } $request = $this->getRequest(); $type = $request->getVal($this->IdType); $level = $request->getVal($this->IdLevel); $sizetype = $request->getVal('sizetype'); $size = $request->getIntOrNull('size'); $ns = $request->getIntOrNull('namespace'); $indefOnly = $request->getBool('indefonly') ? 1 : 0; $cascadeOnly = $request->getBool('cascadeonly') ? 1 : 0; $noRedirect = $request->getBool('noredirect') ? 1 : 0; $pager = new ProtectedPagesPager($this, array(), $type, $level, $ns, $sizetype, $size, $indefOnly, $cascadeOnly, $noRedirect); $this->getOutput()->addHTML($this->showOptions($ns, $type, $level, $sizetype, $size, $indefOnly, $cascadeOnly, $noRedirect)); if ($pager->getNumRows()) { $this->getOutput()->addHTML($pager->getNavigationBar() . $pager->getBody() . $pager->getNavigationBar()); } else { $this->getOutput()->addWikiMsg('protectedpagesempty'); } }
public function showList($msg = '') { global $wgOut, $wgRequest; if ("" != $msg) { $wgOut->setSubtitle($msg); } // Purge expired entries on one in every 10 queries if (!mt_rand(0, 10)) { Title::purgeExpiredRestrictions(); } $type = $wgRequest->getVal($this->IdType); $level = $wgRequest->getVal($this->IdLevel); $sizetype = $wgRequest->getVal('sizetype'); $size = $wgRequest->getIntOrNull('size'); $NS = $wgRequest->getIntOrNull('namespace'); $indefOnly = $wgRequest->getBool('indefonly') ? 1 : 0; $cascadeOnly = $wgRequest->getBool('cascadeonly') ? 1 : 0; $pager = new ProtectedPagesPager($this, array(), $type, $level, $NS, $sizetype, $size, $indefOnly, $cascadeOnly); $wgOut->addHTML($this->showOptions($NS, $type, $level, $sizetype, $size, $indefOnly, $cascadeOnly)); if ($pager->getNumRows()) { $s = $pager->getNavigationBar(); $s .= "<ul>" . $pager->getBody() . "</ul>"; $s .= $pager->getNavigationBar(); } else { $s = '<p>' . wfMsgHtml('protectedpagesempty') . '</p>'; } $wgOut->addHTML($s); }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit set of restriction keys * @param array $expiry per restriction type expiration * @param int &$cascade Set to false if cascading protection isn't allowed. * @param string $reason * @param User $user The user updating the restrictions * @return Status */ public function doUpdateRestrictions( array $limit, array $expiry, &$cascade, $reason, User $user ) { global $wgCascadingRestrictionLevels; if ( wfReadOnly() ) { return Status::newFatal( 'readonlytext', wfReadOnlyReason() ); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if ( !$cascade ) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB( DB_MASTER ); foreach ( $restrictionTypes as $action ) { if ( !isset( $expiry[$action] ) ) { $expiry[$action] = $dbw->getInfinity(); } if ( !isset( $limit[$action] ) ) { $limit[$action] = ''; } elseif ( $limit[$action] != '' ) { $protect = true; } // Get current restrictions on $action $current = implode( '', $this->mTitle->getRestrictions( $action ) ); if ( $current != '' ) { $isProtected = true; } if ( $limit[$action] != $current ) { $changed = true; } elseif ( $limit[$action] != '' ) { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ( $this->mTitle->getRestrictionExpiry( $action ) != $expiry[$action] ) { $changed = true; } } } if ( !$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade ) { $changed = true; } // If nothing has changed, do nothing if ( !$changed ) { return Status::newGood(); } if ( !$protect ) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ( $isProtected ) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } if ( $id ) { // Protection of existing page if ( !wfRunHooks( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) { return Status::newGood(); } // Only certain restrictions can cascade... $editrestriction = isset( $limit['edit'] ) ? array( $limit['edit'] ) : $this->mTitle->getRestrictions( 'edit' ); foreach ( array_keys( $editrestriction, 'sysop' ) as $key ) { $editrestriction[$key] = 'editprotected'; // backwards compatibility } foreach ( array_keys( $editrestriction, 'autoconfirmed' ) as $key ) { $editrestriction[$key] = 'editsemiprotected'; // backwards compatibility } $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; foreach ( array_keys( $cascadingRestrictionLevels, 'sysop' ) as $key ) { $cascadingRestrictionLevels[$key] = 'editprotected'; // backwards compatibility } foreach ( array_keys( $cascadingRestrictionLevels, 'autoconfirmed' ) as $key ) { $cascadingRestrictionLevels[$key] = 'editsemiprotected'; // backwards compatibility } // The schema allows multiple restrictions if ( !array_intersect( $editrestriction, $cascadingRestrictionLevels ) ) { $cascade = false; } // insert null revision to identify the page protection change as edit summary $latest = $this->getLatest(); $nullRevision = $this->insertProtectNullRevision( $revCommentMsg, $limit, $expiry, $cascade, $reason ); if ( $nullRevision === null ) { return Status::newFatal( 'no-null-revision', $this->mTitle->getPrefixedText() ); } // Update restrictions table foreach ( $limit as $action => $restrictions ) { if ( $restrictions != '' ) { $dbw->replace( 'page_restrictions', array( array( 'pr_page', 'pr_type' ) ), array( 'pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => ( $cascade && $action == 'edit' ) ? 1 : 0, 'pr_expiry' => $dbw->encodeExpiry( $expiry[$action] ) ), __METHOD__ ); } else { $dbw->delete( 'page_restrictions', array( 'pr_page' => $id, 'pr_type' => $action ), __METHOD__ ); } } // Clear out legacy restriction fields $dbw->update( 'page', array( 'page_restrictions' => '' ), array( 'page_id' => $id ), __METHOD__ ); wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) ); wfRunHooks( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) ); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ( $limit['create'] != '' ) { $dbw->replace( 'protected_titles', array( array( 'pt_namespace', 'pt_title' ) ), array( 'pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry( wfTimestampNow() ), 'pt_expiry' => $dbw->encodeExpiry( $expiry['create'] ), 'pt_user' => $user->getId(), 'pt_reason' => $reason, ), __METHOD__ ); } else { $dbw->delete( 'protected_titles', array( 'pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey() ), __METHOD__ ); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache( $this->mTitle ); if ( $logAction == 'unprotect' ) { $params = array(); } else { $protectDescriptionLog = $this->protectDescriptionLog( $limit, $expiry ); $params = array( $protectDescriptionLog, $cascade ? 'cascade' : '' ); } // Update the protection log $log = new LogPage( 'protect' ); $log->addEntry( $logAction, $this->mTitle, trim( $reason ), $params, $user ); return Status::newGood(); }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit Set of restriction keys * @param array $expiry Per restriction type expiration * @param int &$cascade Set to false if cascading protection isn't allowed. * @param string $reason * @param User $user The user updating the restrictions * @param string|string[] $tags Change tags to add to the pages and protection log entries * ($user should be able to add the specified tags before this is called) * @return Status Status object; if action is taken, $status->value is the log_id of the * protection log entry. */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user, $tags = null) { global $wgCascadingRestrictionLevels, $wgContLang; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $this->loadPageData('fromdbmaster'); $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action]) || $expiry[$action] === $dbw->getInfinity()) { $expiry[$action] = 'infinity'; } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } // Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } // If nothing has changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } // Truncate for whole multibyte characters $reason = $wgContLang->truncate($reason, 255); $logRelationsValues = []; $logRelationsField = null; $logParamsDetails = []; // Null revision (used for change tag insertion) $nullRevision = null; if ($id) { // Protection of existing page if (!Hooks::run('ArticleProtect', [&$this, &$user, $limit, $reason])) { return Status::newGood(); } // Only certain restrictions can cascade... $editrestriction = isset($limit['edit']) ? [$limit['edit']] : $this->mTitle->getRestrictions('edit'); foreach (array_keys($editrestriction, 'sysop') as $key) { $editrestriction[$key] = 'editprotected'; // backwards compatibility } foreach (array_keys($editrestriction, 'autoconfirmed') as $key) { $editrestriction[$key] = 'editsemiprotected'; // backwards compatibility } $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; foreach (array_keys($cascadingRestrictionLevels, 'sysop') as $key) { $cascadingRestrictionLevels[$key] = 'editprotected'; // backwards compatibility } foreach (array_keys($cascadingRestrictionLevels, 'autoconfirmed') as $key) { $cascadingRestrictionLevels[$key] = 'editsemiprotected'; // backwards compatibility } // The schema allows multiple restrictions if (!array_intersect($editrestriction, $cascadingRestrictionLevels)) { $cascade = false; } // insert null revision to identify the page protection change as edit summary $latest = $this->getLatest(); $nullRevision = $this->insertProtectNullRevision($revCommentMsg, $limit, $expiry, $cascade, $reason, $user); if ($nullRevision === null) { return Status::newFatal('no-null-revision', $this->mTitle->getPrefixedText()); } $logRelationsField = 'pr_id'; // Update restrictions table foreach ($limit as $action => $restrictions) { $dbw->delete('page_restrictions', ['pr_page' => $id, 'pr_type' => $action], __METHOD__); if ($restrictions != '') { $cascadeValue = $cascade && $action == 'edit' ? 1 : 0; $dbw->insert('page_restrictions', ['pr_id' => $dbw->nextSequenceValue('page_restrictions_pr_id_seq'), 'pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascadeValue, 'pr_expiry' => $dbw->encodeExpiry($expiry[$action])], __METHOD__); $logRelationsValues[] = $dbw->insertId(); $logParamsDetails[] = ['type' => $action, 'level' => $restrictions, 'expiry' => $expiry[$action], 'cascade' => (bool) $cascadeValue]; } } // Clear out legacy restriction fields $dbw->update('page', ['page_restrictions' => ''], ['page_id' => $id], __METHOD__); Hooks::run('NewRevisionFromEditComplete', [$this, $nullRevision, $latest, $user]); Hooks::run('ArticleProtectComplete', [&$this, &$user, $limit, $reason]); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', [['pt_namespace', 'pt_title']], ['pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->timestamp(), 'pt_expiry' => $dbw->encodeExpiry($expiry['create']), 'pt_user' => $user->getId(), 'pt_reason' => $reason], __METHOD__); $logParamsDetails[] = ['type' => 'create', 'level' => $limit['create'], 'expiry' => $expiry['create']]; } else { $dbw->delete('protected_titles', ['pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()], __METHOD__); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache($this->mTitle); if ($logAction == 'unprotect') { $params = []; } else { $protectDescriptionLog = $this->protectDescriptionLog($limit, $expiry); $params = ['4::description' => $protectDescriptionLog, '5:bool:cascade' => $cascade, 'details' => $logParamsDetails]; } // Update the protection log $logEntry = new ManualLogEntry('protect', $logAction); $logEntry->setTarget($this->mTitle); $logEntry->setComment($reason); $logEntry->setPerformer($user); $logEntry->setParameters($params); if (!is_null($nullRevision)) { $logEntry->setAssociatedRevId($nullRevision->getId()); } $logEntry->setTags($tags); if ($logRelationsField !== null && count($logRelationsValues)) { $logEntry->setRelations([$logRelationsField => $logRelationsValues]); } $logId = $logEntry->insert(); $logEntry->publish($logId); return Status::newGood($logId); }
/** * Loads a string into mRestrictions array * @param resource $res restrictions as an SQL result. */ private function loadRestrictionsFromRow($res, $oldFashionedRestrictions = NULL) { $dbr = wfGetDb(DB_SLAVE); $this->mRestrictions['edit'] = array(); $this->mRestrictions['move'] = array(); # Backwards-compatibility: also load the restrictions from the page record (old format). if ($oldFashionedRestrictions == NULL) { $oldFashionedRestrictions = $dbr->selectField('page', 'page_restrictions', array('page_id' => $this->getArticleId()), __METHOD__); } if ($oldFashionedRestrictions != '') { foreach (explode(':', trim($oldFashionedRestrictions)) as $restrict) { $temp = explode('=', trim($restrict)); if (count($temp) == 1) { // old old format should be treated as edit/move restriction $this->mRestrictions["edit"] = explode(',', trim($temp[0])); $this->mRestrictions["move"] = explode(',', trim($temp[0])); } else { $this->mRestrictions[$temp[0]] = explode(',', trim($temp[1])); } } $this->mOldRestrictions = true; $this->mCascadeRestriction = false; $this->mRestrictionsExpiry = Block::decodeExpiry(''); } if ($dbr->numRows($res)) { # Current system - load second to make them override. $now = wfTimestampNow(); $purgeExpired = false; while ($row = $dbr->fetchObject($res)) { # Cycle through all the restrictions. // 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 $expiry = Block::decodeExpiry($row->pr_expiry); // Only apply the restrictions if they haven't expired! if (!$expiry || $expiry > $now) { $this->mRestrictionsExpiry = $expiry; $this->mRestrictions[$row->pr_type] = explode(',', trim($row->pr_level)); $this->mCascadeRestriction |= $row->pr_cascade; } else { // Trigger a lazy purge of expired restrictions $purgeExpired = true; } } if ($purgeExpired) { Title::purgeExpiredRestrictions(); } } $this->mRestrictionsLoaded = true; }
/** * Update the article's restriction field, and leave a log entry. * * @param $limit Array: set of restriction keys * @param $reason String * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param $expiry Array: per restriction type expiration * @return bool true on success */ public function updateRestrictions($limit = array(), $reason = '', &$cascade = 0, $expiry = array()) { global $wgUser, $wgContLang; $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->mTitle->getArticleID(); if ($id <= 0) { wfDebug("updateRestrictions failed: article id {$id} <= 0\n"); return false; } if (wfReadOnly()) { wfDebug("updateRestrictions failed: read-only\n"); return false; } if (!$this->mTitle->userCan('protect')) { wfDebug("updateRestrictions failed: insufficient permissions\n"); return false; } if (!$cascade) { $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(); $updated = Article::flattenRestrictions($limit); $changed = false; foreach ($restrictionTypes as $action) { if (isset($expiry[$action])) { # Get current restrictions on $action $aLimits = $this->mTitle->getRestrictions($action); $current[$action] = implode('', $aLimits); # Are any actual restrictions being dealt with here? $aRChanged = count($aLimits) || !empty($limit[$action]); # If something changed, we need to log it. Checking $aRChanged # assures that "unprotecting" a page that is not protected does # not log just because the expiry was "changed". if ($aRChanged && $this->mTitle->mRestrictionsExpiry[$action] != $expiry[$action]) { $changed = true; } } } $current = Article::flattenRestrictions($current); $changed = $changed || $current != $updated; $changed = $changed || $updated && $this->mTitle->areRestrictionsCascading() != $cascade; $protect = $updated != ''; # If nothing's changed, do nothing if ($changed) { if (wfRunHooks('ArticleProtect', array(&$this, &$wgUser, $limit, $reason))) { $dbw = wfGetDB(DB_MASTER); # Prepare a null revision to be added to the history $modified = $current != '' && $protect; if ($protect) { $comment_type = $modified ? 'modifiedarticleprotection' : 'protectedarticle'; } else { $comment_type = 'unprotectedarticle'; } $comment = $wgContLang->ucfirst(wfMsgForContent($comment_type, $this->mTitle->getPrefixedText())); # Only restrictions with the 'protect' right can cascade... # Otherwise, people who cannot normally protect can "protect" pages via transclusion $editrestriction = isset($limit['edit']) ? array($limit['edit']) : $this->mTitle->getRestrictions('edit'); # The schema allows multiple restrictions if (!in_array('protect', $editrestriction) && !in_array('sysop', $editrestriction)) { $cascade = false; } $cascade_description = ''; if ($cascade) { $cascade_description = ' [' . wfMsgForContent('protect-summary-cascade') . ']'; } if ($reason) { $comment .= ": {$reason}"; } $editComment = $comment; $encodedExpiry = array(); $protect_description = ''; foreach ($limit as $action => $restrictions) { if (!isset($expiry[$action])) { $expiry[$action] = Block::infinity(); } $encodedExpiry[$action] = Block::encodeExpiry($expiry[$action], $dbw); if ($restrictions != '') { $protect_description .= "[{$action}={$restrictions}] ("; if ($encodedExpiry[$action] != 'infinity') { $protect_description .= wfMsgForContent('protect-expiring', $wgContLang->timeanddate($expiry[$action], false, false), $wgContLang->date($expiry[$action], false, false), $wgContLang->time($expiry[$action], false, false)); } else { $protect_description .= wfMsgForContent('protect-expiry-indefinite'); } $protect_description .= ') '; } } $protect_description = trim($protect_description); if ($protect_description && $protect) { $editComment .= " ({$protect_description})"; } if ($cascade) { $editComment .= "{$cascade_description}"; } # Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0, 'pr_expiry' => $encodedExpiry[$action]), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } # Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $editComment, true); $nullRevId = $nullRevision->insertOn($dbw); $latest = $this->getLatest(); # Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), 'Article::protect'); wfRunHooks('NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $wgUser)); wfRunHooks('ArticleProtectComplete', array(&$this, &$wgUser, $limit, $reason)); # Update the protection log $log = new LogPage('protect'); if ($protect) { $params = array($protect_description, $cascade ? 'cascade' : ''); $log->addEntry($modified ? 'modify' : 'protect', $this->mTitle, trim($reason), $params); } else { $log->addEntry('unprotect', $this->mTitle, $reason); } } # End hook } # End "changed" check return true; }
/** * Load restrictions from the page_restrictions table * * @param $oldFashionedRestrictions String comma-separated list of page * restrictions from page table (pre 1.10) */ public function loadRestrictions($oldFashionedRestrictions = null) { global $wgContLang; if (!$this->mRestrictionsLoaded) { if ($this->exists()) { $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('page_restrictions', '*', array('pr_page' => $this->getArticleId()), __METHOD__); $this->loadRestrictionsFromResultWrapper($res, $oldFashionedRestrictions); } else { $title_protection = $this->getTitleProtection(); if ($title_protection) { $now = wfTimestampNow(); $expiry = $wgContLang->formatExpiry($title_protection['pt_expiry'], TS_MW); if (!$expiry || $expiry > $now) { // Apply the restrictions $this->mRestrictionsExpiry['create'] = $expiry; $this->mRestrictions['create'] = explode(',', trim($title_protection['pt_create_perm'])); } else { // Get rid of the old restrictions Title::purgeExpiredRestrictions(); $this->mTitleProtection = false; } } else { $this->mRestrictionsExpiry['create'] = $wgContLang->formatExpiry('', TS_MW); } $this->mRestrictionsLoaded = true; } } }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param $limit Array: set of restriction keys * @param $reason String * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param $expiry Array: per restriction type expiration * @param $user User The user updating the restrictions * @return Status */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user) { global $wgContLang; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->mTitle->getArticleID(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); # @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); # we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action])) { $expiry[$action] = $dbw->getInfinity(); } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } # Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { # Only check expiry change if the action is actually being # protected, since expiry does nothing on an not-protected # action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } # If nothing's changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { # No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } $encodedExpiry = array(); $protectDescription = ''; foreach ($limit as $action => $restrictions) { $encodedExpiry[$action] = $dbw->encodeExpiry($expiry[$action]); if ($restrictions != '') { $protectDescription .= $wgContLang->getDirMark() . "[{$action}={$restrictions}] ("; if ($encodedExpiry[$action] != 'infinity') { $protectDescription .= wfMessage('protect-expiring', $wgContLang->timeanddate($expiry[$action], false, false), $wgContLang->date($expiry[$action], false, false), $wgContLang->time($expiry[$action], false, false))->inContentLanguage()->text(); } else { $protectDescription .= wfMessage('protect-expiry-indefinite')->inContentLanguage()->text(); } $protectDescription .= ') '; } } $protectDescription = trim($protectDescription); if ($id) { # Protection of existing page if (!wfRunHooks('ArticleProtect', array(&$this, &$user, $limit, $reason))) { return Status::newGood(); } # Only restrictions with the 'protect' right can cascade... # Otherwise, people who cannot normally protect can "protect" pages via transclusion $editrestriction = isset($limit['edit']) ? array($limit['edit']) : $this->mTitle->getRestrictions('edit'); # The schema allows multiple restrictions if (!in_array('protect', $editrestriction) && !in_array('sysop', $editrestriction)) { $cascade = false; } # Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0, 'pr_expiry' => $encodedExpiry[$action]), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } # Prepare a null revision to be added to the history $editComment = $wgContLang->ucfirst(wfMessage($revCommentMsg, $this->mTitle->getPrefixedText())->inContentLanguage()->text()); if ($reason) { $editComment .= ": {$reason}"; } if ($protectDescription) { $editComment .= " ({$protectDescription})"; } if ($cascade) { // FIXME: Should use 'brackets' message. $editComment .= ' [' . wfMessage('protect-summary-cascade')->inContentLanguage()->text() . ']'; } # Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $editComment, true); $nullRevId = $nullRevision->insertOn($dbw); $latest = $this->getLatest(); # Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), __METHOD__); wfRunHooks('NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $user)); wfRunHooks('ArticleProtectComplete', array(&$this, &$user, $limit, $reason)); } else { # Protection of non-existing page (also known as "title protection") # Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', array(array('pt_namespace', 'pt_title')), array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry(wfTimestampNow()), 'pt_expiry' => $encodedExpiry['create'], 'pt_user' => $user->getId(), 'pt_reason' => $reason), __METHOD__); } else { $dbw->delete('protected_titles', array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()), __METHOD__); } } $this->mTitle->flushRestrictions(); if ($logAction == 'unprotect') { $logParams = array(); } else { $logParams = array($protectDescription, $cascade ? 'cascade' : ''); } # Update the protection log $log = new LogPage('protect'); $log->addEntry($logAction, $this->mTitle, trim($reason), $logParams, $user); return Status::newGood(); }
public function loadRestrictions($oldFashionedRestrictions = NULL) { if (!$this->mRestrictionsLoaded) { if ($this->exists()) { $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('page_restrictions', '*', array('pr_page' => $this->getArticleId()), __METHOD__); $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; } } }
function doProtect($limit = array(), $reason = '', &$expiry = '') { global $wgUser, $wgRestrictionTypes, $wgContLang, $wgTitle; $id = $wgTitle->getArticleID(); if (wfReadOnly() || $id == 0) { return false; } if (strlen($expiry) == 0) { $expiry = 'infinite'; } if ($expiry == 'infinite' || $expiry == '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($expiry); if ($expiry < 0 || $expiry === false) { //invalid expiry, rewrite to infinity $expiry = Block::infinity(); } else { // Fixme: non-qualified absolute times are not in users specified timezone // and there isn't notice about it in the ui $expiry = wfTimestamp(TS_MW, $expiry); } } // 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(); foreach ($wgRestrictionTypes as $action) { $current[$action] = implode('', $wgTitle->getRestrictions($action)); } $current = Article::flattenRestrictions($current); $updated = Article::flattenRestrictions($limit); $changed = $current != $updated; $changed = $changed || $wgTitle->mRestrictionsExpiry != $expiry; $protect = $updated != ''; # If nothing's changed, do nothing if ($changed) { global $wgGroupPermissions; $dbw = wfGetDB(DB_MASTER); $encodedExpiry = Block::encodeExpiry($expiry, $dbw); $expiry_description = ''; if ($encodedExpiry != 'infinity') { $expiry_description = ' (' . wfMsgForContent('protect-expiring', $wgContLang->timeanddate($expiry, false, false)) . ')'; } # Prepare a null revision to be added to the history $modified = $current != '' && $protect; if ($protect) { $comment_type = $modified ? 'modifiedarticleprotection' : 'protectedarticle'; } else { $comment_type = 'unprotectedarticle'; } $comment = $wgContLang->ucfirst(wfMsgForContent($comment_type, $wgTitle->getPrefixedText())); if ($reason) { $comment .= ": {$reason}"; } if ($protect) { $comment .= " [{$updated}]"; } if ($expiry_description && $protect) { $comment .= "{$expiry_description}"; } # Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => 0, 'pr_expiry' => $encodedExpiry), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } # Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $comment, true); $nullRevId = $nullRevision->insertOn($dbw); # Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), 'Article::protect'); # Update the protection log $log = new LogPage('protect'); if ($protect) { $log->addEntry($modified ? 'modify' : 'protect', $wgTitle, trim($reason . " [{$updated}]{$expiry_description}")); } else { $log->addEntry('unprotect', $wgTitle, $reason); } } # End "changed" check return true; }
/** * Update the article's restriction field, and leave a log entry. * This works for protection both existing and non-existing pages. * * @param array $limit set of restriction keys * @param $reason String * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param array $expiry per restriction type expiration * @param $user User The user updating the restrictions * @return Status */ public function doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user) { global $wgContLang, $wgCascadingRestrictionLevels; if (wfReadOnly()) { return Status::newFatal('readonlytext', wfReadOnlyReason()); } $restrictionTypes = $this->mTitle->getRestrictionTypes(); $id = $this->getId(); if (!$cascade) { $cascade = false; } // Take this opportunity to purge out expired restrictions Title::purgeExpiredRestrictions(); // @todo FIXME: Same limitations as described in ProtectionForm.php (line 37); // we expect a single selection, but the schema allows otherwise. $isProtected = false; $protect = false; $changed = false; $dbw = wfGetDB(DB_MASTER); foreach ($restrictionTypes as $action) { if (!isset($expiry[$action])) { $expiry[$action] = $dbw->getInfinity(); } if (!isset($limit[$action])) { $limit[$action] = ''; } elseif ($limit[$action] != '') { $protect = true; } // Get current restrictions on $action $current = implode('', $this->mTitle->getRestrictions($action)); if ($current != '') { $isProtected = true; } if ($limit[$action] != $current) { $changed = true; } elseif ($limit[$action] != '') { // Only check expiry change if the action is actually being // protected, since expiry does nothing on an not-protected // action. if ($this->mTitle->getRestrictionExpiry($action) != $expiry[$action]) { $changed = true; } } } if (!$changed && $protect && $this->mTitle->areRestrictionsCascading() != $cascade) { $changed = true; } // If nothing has changed, do nothing if (!$changed) { return Status::newGood(); } if (!$protect) { // No protection at all means unprotection $revCommentMsg = 'unprotectedarticle'; $logAction = 'unprotect'; } elseif ($isProtected) { $revCommentMsg = 'modifiedarticleprotection'; $logAction = 'modify'; } else { $revCommentMsg = 'protectedarticle'; $logAction = 'protect'; } $encodedExpiry = array(); $protectDescription = ''; # Some bots may parse IRC lines, which are generated from log entries which contain plain # protect description text. Keep them in old format to avoid breaking compatibility. # TODO: Fix protection log to store structured description and format it on-the-fly. $protectDescriptionLog = ''; foreach ($limit as $action => $restrictions) { $encodedExpiry[$action] = $dbw->encodeExpiry($expiry[$action]); if ($restrictions != '') { $protectDescriptionLog .= $wgContLang->getDirMark() . "[{$action}={$restrictions}] ("; # $action is one of $wgRestrictionTypes = array( 'create', 'edit', 'move', 'upload' ). # All possible message keys are listed here for easier grepping: # * restriction-create # * restriction-edit # * restriction-move # * restriction-upload $actionText = wfMessage('restriction-' . $action)->inContentLanguage()->text(); # $restrictions is one of $wgRestrictionLevels = array( '', 'autoconfirmed', 'sysop' ), # with '' filtered out. All possible message keys are listed below: # * protect-level-autoconfirmed # * protect-level-sysop $restrictionsText = wfMessage('protect-level-' . $restrictions)->inContentLanguage()->text(); if ($encodedExpiry[$action] != 'infinity') { $expiryText = wfMessage('protect-expiring', $wgContLang->timeanddate($expiry[$action], false, false), $wgContLang->date($expiry[$action], false, false), $wgContLang->time($expiry[$action], false, false))->inContentLanguage()->text(); } else { $expiryText = wfMessage('protect-expiry-indefinite')->inContentLanguage()->text(); } if ($protectDescription !== '') { $protectDescription .= wfMessage('word-separator')->inContentLanguage()->text(); } $protectDescription .= wfMessage('protect-summary-desc')->params($actionText, $restrictionsText, $expiryText)->inContentLanguage()->text(); $protectDescriptionLog .= $expiryText . ') '; } } $protectDescriptionLog = trim($protectDescriptionLog); if ($id) { // Protection of existing page if (!wfRunHooks('ArticleProtect', array(&$this, &$user, $limit, $reason))) { return Status::newGood(); } // Only certain restrictions can cascade... Otherwise, users who cannot normally protect pages // could "protect" them by transcluding them on protected pages they are allowed to edit. $editrestriction = isset($limit['edit']) ? array($limit['edit']) : $this->mTitle->getRestrictions('edit'); $cascadingRestrictionLevels = $wgCascadingRestrictionLevels; if (in_array('sysop', $cascadingRestrictionLevels)) { $cascadingRestrictionLevels[] = 'protect'; // backwards compatibility } // The schema allows multiple restrictions if (!array_intersect($editrestriction, $cascadingRestrictionLevels)) { $cascade = false; } // Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade && $action == 'edit' ? 1 : 0, 'pr_expiry' => $encodedExpiry[$action]), __METHOD__); } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); } } // Prepare a null revision to be added to the history $editComment = $wgContLang->ucfirst(wfMessage($revCommentMsg, $this->mTitle->getPrefixedText())->inContentLanguage()->text()); if ($reason) { $editComment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason; } if ($protectDescription) { $editComment .= wfMessage('word-separator')->inContentLanguage()->text(); $editComment .= wfMessage('parentheses')->params($protectDescription)->inContentLanguage()->text(); } if ($cascade) { $editComment .= wfMessage('word-separator')->inContentLanguage()->text(); $editComment .= wfMessage('brackets')->params(wfMessage('protect-summary-cascade')->inContentLanguage()->text())->inContentLanguage()->text(); } // Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $editComment, true); $nullRevId = $nullRevision->insertOn($dbw); $latest = $this->getLatest(); // Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_latest' => $nullRevId), array('page_id' => $id), __METHOD__); wfRunHooks('NewRevisionFromEditComplete', array($this, $nullRevision, $latest, $user)); wfRunHooks('ArticleProtectComplete', array(&$this, &$user, $limit, $reason)); } else { // Protection of non-existing page (also known as "title protection") // Cascade protection is meaningless in this case $cascade = false; if ($limit['create'] != '') { $dbw->replace('protected_titles', array(array('pt_namespace', 'pt_title')), array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey(), 'pt_create_perm' => $limit['create'], 'pt_timestamp' => $dbw->encodeExpiry(wfTimestampNow()), 'pt_expiry' => $encodedExpiry['create'], 'pt_user' => $user->getId(), 'pt_reason' => $reason), __METHOD__); } else { $dbw->delete('protected_titles', array('pt_namespace' => $this->mTitle->getNamespace(), 'pt_title' => $this->mTitle->getDBkey()), __METHOD__); } } $this->mTitle->flushRestrictions(); InfoAction::invalidateCache($this->mTitle); if ($logAction == 'unprotect') { $logParams = array(); } else { $logParams = array($protectDescriptionLog, $cascade ? 'cascade' : ''); } // Update the protection log $log = new LogPage('protect'); $log->addEntry($logAction, $this->mTitle, trim($reason), $logParams, $user); return Status::newGood(); }
/** * Update the article's restriction field, and leave a log entry. * * @param array $limit set of restriction keys * @param string $reason * @return bool true on success */ function updateRestrictions($limit = array(), $reason = '', $cascade = 0, $expiry = null) { global $wgUser, $wgRestrictionTypes, $wgContLang; $id = $this->mTitle->getArticleID(); if (array() != $this->mTitle->getUserPermissionsErrors('protect', $wgUser) || wfReadOnly() || $id == 0) { return false; } if (!$cascade) { $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(); foreach ($wgRestrictionTypes as $action) { $current[$action] = implode('', $this->mTitle->getRestrictions($action)); } $current = Article::flattenRestrictions($current); $updated = Article::flattenRestrictions($limit); $changed = $current != $updated; $changed = $changed || $this->mTitle->areRestrictionsCascading() != $cascade; $changed = $changed || $this->mTitle->mRestrictionsExpiry != $expiry; $protect = $updated != ''; # If nothing's changed, do nothing if ($changed) { global $wgGroupPermissions; if (wfRunHooks('ArticleProtect', array(&$this, &$wgUser, $limit, $reason))) { $dbw = wfGetDB(DB_MASTER); $encodedExpiry = Block::encodeExpiry($expiry, $dbw); $expiry_description = ''; if ($encodedExpiry != 'infinity') { $expiry_description = ' (' . wfMsgForContent('protect-expiring', $wgContLang->timeanddate($expiry, false, false)) . ')'; } # Prepare a null revision to be added to the history $modified = $current != '' && $protect; if ($protect) { $comment_type = $modified ? 'modifiedarticleprotection' : 'protectedarticle'; } else { $comment_type = 'unprotectedarticle'; } $comment = $wgContLang->ucfirst(wfMsgForContent($comment_type, $this->mTitle->getPrefixedText())); foreach ($limit as $action => $restrictions) { # Check if the group level required to edit also can protect pages # Otherwise, people who cannot normally protect can "protect" pages via transclusion $cascade = $cascade && isset($wgGroupPermissions[$restrictions]['protect']) && $wgGroupPermissions[$restrictions]['protect']; } $cascade_description = ''; if ($cascade) { $cascade_description = ' [' . wfMsg('protect-summary-cascade') . ']'; } if ($reason) { $comment .= ": {$reason}"; } if ($protect) { $comment .= " [{$updated}]"; } if ($expiry_description && $protect) { $comment .= "{$expiry_description}"; } if ($cascade) { $comment .= "{$cascade_description}"; } $rowsAffected = false; # Update restrictions table foreach ($limit as $action => $restrictions) { if ($restrictions != '') { $dbw->replace('page_restrictions', array(array('pr_page', 'pr_type')), array('pr_page' => $id, 'pr_type' => $action, 'pr_level' => $restrictions, 'pr_cascade' => $cascade ? 1 : 0, 'pr_expiry' => $encodedExpiry), __METHOD__); if ($dbw->affectedRows() != 0) { $rowsAffected = true; } } else { $dbw->delete('page_restrictions', array('pr_page' => $id, 'pr_type' => $action), __METHOD__); if ($dbw->affectedRows() != 0) { $rowsAffected = true; } } } if (!$rowsAffected) { // No change return true; } # Insert a null revision $nullRevision = Revision::newNullRevision($dbw, $id, $comment, true); $nullRevId = $nullRevision->insertOn($dbw); # Update page record $dbw->update('page', array('page_touched' => $dbw->timestamp(), 'page_restrictions' => '', 'page_catinfo' => $this->mTitle->getCategoryMask(), 'page_latest' => $nullRevId), array('page_id' => $id), 'Article::protect'); wfRunHooks('ArticleProtectComplete', array(&$this, &$wgUser, $limit, $reason)); # Update the protection log $log = new LogPage('protect'); if ($protect) { $log->addEntry($modified ? 'modify' : 'protect', $this->mTitle, trim($reason . " [{$updated}]{$cascade_description}{$expiry_description}")); } else { $log->addEntry('unprotect', $this->mTitle, $reason); } } # End hook } # End "changed" check return true; }