示例#1
0
 /**
  * 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);
 }