/**
  * Log the promotion of a local unattached to a global
  *
  * @param string $oldName
  * @param string $wiki
  * @param string $newName
  * @param string $reason
  */
 public function logPromotion($oldName, $wiki, $newName, $reason)
 {
     $logEntry = new ManualLogEntry('gblrename', 'promote');
     $logEntry->setPerformer($this->performingUser);
     $logEntry->setTarget(Title::makeTitleSafe(NS_SPECIAL, 'CentralAuth/' . $newName));
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::olduser' => $oldName, '5::newuser' => $newName, '6::oldwiki' => $wiki));
     $logEntry->setRelations(array('oldname' => $oldName));
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
示例#2
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);
 }
示例#3
0
 /**
  * Writes a tag action into the tag management log.
  *
  * @param string $action
  * @param string $tag
  * @param string $reason
  * @param User $user Who to attribute the action to
  * @param int $tagCount For deletion only, how many usages the tag had before
  * it was deleted.
  * @return int ID of the inserted log entry
  * @since 1.25
  */
 protected static function logTagManagementAction($action, $tag, $reason, User $user, $tagCount = null)
 {
     $dbw = wfGetDB(DB_MASTER);
     $logEntry = new ManualLogEntry('managetags', $action);
     $logEntry->setPerformer($user);
     // target page is not relevant, but it has to be set, so we just put in
     // the title of Special:Tags
     $logEntry->setTarget(Title::newFromText('Special:Tags'));
     $logEntry->setComment($reason);
     $params = array('4::tag' => $tag);
     if (!is_null($tagCount)) {
         $params['5:number:count'] = $tagCount;
     }
     $logEntry->setParameters($params);
     $logEntry->setRelations(array('Tag' => $tag));
     $logId = $logEntry->insert($dbw);
     $logEntry->publish($logId);
     return $logId;
 }
 /**
  * Given the form data, actually implement a block. This is also called from ApiBlock.
  *
  * @param array $data
  * @param IContextSource $context
  * @return bool|string
  */
 public static function processForm(array $data, IContextSource $context)
 {
     global $wgBlockAllowsUTEdit, $wgHideUserContribLimit, $wgContLang;
     $performer = $context->getUser();
     // Handled by field validator callback
     // self::validateTargetField( $data['Target'] );
     # This might have been a hidden field or a checkbox, so interesting data
     # can come from it
     $data['Confirm'] = !in_array($data['Confirm'], array('', '0', null, false), true);
     /** @var User $target */
     list($target, $type) = self::getTargetAndType($data['Target']);
     if ($type == Block::TYPE_USER) {
         $user = $target;
         $target = $user->getName();
         $userId = $user->getId();
         # Give admins a heads-up before they go and block themselves.  Much messier
         # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
         # permission anyway, although the code does allow for it.
         # Note: Important to use $target instead of $data['Target']
         # since both $data['PreviousTarget'] and $target are normalized
         # but $data['target'] gets overridden by (non-normalized) request variable
         # from previous request.
         if ($target === $performer->getName() && ($data['PreviousTarget'] !== $target || !$data['Confirm'])) {
             return array('ipb-blockingself', 'ipb-confirmaction');
         }
     } elseif ($type == Block::TYPE_RANGE) {
         $userId = 0;
     } elseif ($type == Block::TYPE_IP) {
         $target = $target->getName();
         $userId = 0;
     } else {
         # This should have been caught in the form field validation
         return array('badipaddress');
     }
     if (strlen($data['Expiry']) == 0 || strlen($data['Expiry']) > 50 || !self::parseExpiryInput($data['Expiry'])) {
         return array('ipb_expiry_invalid');
     }
     if (!isset($data['DisableEmail'])) {
         $data['DisableEmail'] = false;
     }
     # If the user has done the form 'properly', they won't even have been given the
     # option to suppress-block unless they have the 'hideuser' permission
     if (!isset($data['HideUser'])) {
         $data['HideUser'] = false;
     }
     if ($data['HideUser']) {
         if (!$performer->isAllowed('hideuser')) {
             # this codepath is unreachable except by a malicious user spoofing forms,
             # or by race conditions (user has hideuser and block rights, loads block form,
             # and loses hideuser rights before submission); so need to fail completely
             # rather than just silently disable hiding
             return array('badaccess-group0');
         }
         # Recheck params here...
         if ($type != Block::TYPE_USER) {
             $data['HideUser'] = false;
             # IP users should not be hidden
         } elseif (!wfIsInfinity($data['Expiry'])) {
             # Bad expiry.
             return array('ipb_expiry_temp');
         } elseif ($wgHideUserContribLimit !== false && $user->getEditCount() > $wgHideUserContribLimit) {
             # Typically, the user should have a handful of edits.
             # Disallow hiding users with many edits for performance.
             return array(array('ipb_hide_invalid', Message::numParam($wgHideUserContribLimit)));
         } elseif (!$data['Confirm']) {
             return array('ipb-confirmhideuser', 'ipb-confirmaction');
         }
     }
     # Create block object.
     $block = new Block();
     $block->setTarget($target);
     $block->setBlocker($performer);
     # Truncate reason for whole multibyte characters
     $block->mReason = $wgContLang->truncate($data['Reason'][0], 255);
     $block->mExpiry = self::parseExpiryInput($data['Expiry']);
     $block->prevents('createaccount', $data['CreateAccount']);
     $block->prevents('editownusertalk', !$wgBlockAllowsUTEdit || $data['DisableUTEdit']);
     $block->prevents('sendemail', $data['DisableEmail']);
     $block->isHardblock($data['HardBlock']);
     $block->isAutoblocking($data['AutoBlock']);
     $block->mHideName = $data['HideUser'];
     $reason = array('hookaborted');
     if (!Hooks::run('BlockIp', array(&$block, &$performer, &$reason))) {
         return $reason;
     }
     # Try to insert block. Is there a conflicting block?
     $status = $block->insert();
     if (!$status) {
         # Indicates whether the user is confirming the block and is aware of
         # the conflict (did not change the block target in the meantime)
         $blockNotConfirmed = !$data['Confirm'] || array_key_exists('PreviousTarget', $data) && $data['PreviousTarget'] !== $target;
         # Special case for API - bug 32434
         $reblockNotAllowed = array_key_exists('Reblock', $data) && !$data['Reblock'];
         # Show form unless the user is already aware of this...
         if ($blockNotConfirmed || $reblockNotAllowed) {
             return array(array('ipb_already_blocked', $block->getTarget()));
             # Otherwise, try to update the block...
         } else {
             # This returns direct blocks before autoblocks/rangeblocks, since we should
             # be sure the user is blocked by now it should work for our purposes
             $currentBlock = Block::newFromTarget($target);
             if ($block->equals($currentBlock)) {
                 return array(array('ipb_already_blocked', $block->getTarget()));
             }
             # If the name was hidden and the blocking user cannot hide
             # names, then don't allow any block changes...
             if ($currentBlock->mHideName && !$performer->isAllowed('hideuser')) {
                 return array('cant-see-hidden-user');
             }
             $currentBlock->isHardblock($block->isHardblock());
             $currentBlock->prevents('createaccount', $block->prevents('createaccount'));
             $currentBlock->mExpiry = $block->mExpiry;
             $currentBlock->isAutoblocking($block->isAutoblocking());
             $currentBlock->mHideName = $block->mHideName;
             $currentBlock->prevents('sendemail', $block->prevents('sendemail'));
             $currentBlock->prevents('editownusertalk', $block->prevents('editownusertalk'));
             $currentBlock->mReason = $block->mReason;
             $status = $currentBlock->update();
             $logaction = 'reblock';
             # Unset _deleted fields if requested
             if ($currentBlock->mHideName && !$data['HideUser']) {
                 RevisionDeleteUser::unsuppressUserName($target, $userId);
             }
             # If hiding/unhiding a name, this should go in the private logs
             if ((bool) $currentBlock->mHideName) {
                 $data['HideUser'] = true;
             }
         }
     } else {
         $logaction = 'block';
     }
     Hooks::run('BlockIpComplete', array($block, $performer));
     # Set *_deleted fields if requested
     if ($data['HideUser']) {
         RevisionDeleteUser::suppressUserName($target, $userId);
     }
     # Can't watch a rangeblock
     if ($type != Block::TYPE_RANGE && $data['Watch']) {
         WatchAction::doWatch(Title::makeTitle(NS_USER, $target), $performer, WatchedItem::IGNORE_USER_RIGHTS);
     }
     # Block constructor sanitizes certain block options on insert
     $data['BlockEmail'] = $block->prevents('sendemail');
     $data['AutoBlock'] = $block->isAutoblocking();
     # Prepare log parameters
     $logParams = array();
     $logParams['5::duration'] = $data['Expiry'];
     $logParams['6::flags'] = self::blockLogFlags($data, $type);
     # Make log entry, if the name is hidden, put it in the suppression log
     $log_type = $data['HideUser'] ? 'suppress' : 'block';
     $logEntry = new ManualLogEntry($log_type, $logaction);
     $logEntry->setTarget(Title::makeTitle(NS_USER, $target));
     $logEntry->setComment($data['Reason'][0]);
     $logEntry->setPerformer($performer);
     $logEntry->setParameters($logParams);
     # Relate log ID to block IDs (bug 25763)
     $blockIds = array_merge(array($status['id']), $status['autoIds']);
     $logEntry->setRelations(array('ipb_id' => $blockIds));
     $logId = $logEntry->insert();
     $logEntry->publish($logId);
     # Report to the user
     return true;
 }
示例#5
0
 /**
  * @param User $user
  * @param string $reason
  * @param bool $createRedirect
  * @return Status
  */
 public function move(User $user, $reason, $createRedirect)
 {
     global $wgCategoryCollation;
     Hooks::run('TitleMove', array($this->oldTitle, $this->newTitle, $user));
     // If it is a file, move it first.
     // It is done before all other moving stuff is done because it's hard to revert.
     $dbw = wfGetDB(DB_MASTER);
     if ($this->oldTitle->getNamespace() == NS_FILE) {
         $file = wfLocalFile($this->oldTitle);
         $file->load(File::READ_LATEST);
         if ($file->exists()) {
             $status = $file->move($this->newTitle);
             if (!$status->isOk()) {
                 return $status;
             }
         }
         // Clear RepoGroup process cache
         RepoGroup::singleton()->clearCache($this->oldTitle);
         RepoGroup::singleton()->clearCache($this->newTitle);
         # clear false negative cache
     }
     $dbw->begin(__METHOD__);
     # If $file was a LocalFile, its transaction would have closed our own.
     $pageid = $this->oldTitle->getArticleID(Title::GAID_FOR_UPDATE);
     $protected = $this->oldTitle->isProtected();
     // Do the actual move
     $this->moveToInternal($user, $this->newTitle, $reason, $createRedirect);
     // Refresh the sortkey for this row.  Be careful to avoid resetting
     // cl_timestamp, which may disturb time-based lists on some sites.
     // @todo This block should be killed, it's duplicating code
     // from LinksUpdate::getCategoryInsertions() and friends.
     $prefixes = $dbw->select('categorylinks', array('cl_sortkey_prefix', 'cl_to'), array('cl_from' => $pageid), __METHOD__);
     if ($this->newTitle->getNamespace() == NS_CATEGORY) {
         $type = 'subcat';
     } elseif ($this->newTitle->getNamespace() == NS_FILE) {
         $type = 'file';
     } else {
         $type = 'page';
     }
     foreach ($prefixes as $prefixRow) {
         $prefix = $prefixRow->cl_sortkey_prefix;
         $catTo = $prefixRow->cl_to;
         $dbw->update('categorylinks', array('cl_sortkey' => Collation::singleton()->getSortKey($this->newTitle->getCategorySortkey($prefix)), 'cl_collation' => $wgCategoryCollation, 'cl_type' => $type, 'cl_timestamp=cl_timestamp'), array('cl_from' => $pageid, 'cl_to' => $catTo), __METHOD__);
     }
     $redirid = $this->oldTitle->getArticleID();
     if ($protected) {
         # Protect the redirect title as the title used to be...
         $dbw->insertSelect('page_restrictions', 'page_restrictions', array('pr_page' => $redirid, 'pr_type' => 'pr_type', 'pr_level' => 'pr_level', 'pr_cascade' => 'pr_cascade', 'pr_user' => 'pr_user', 'pr_expiry' => 'pr_expiry'), array('pr_page' => $pageid), __METHOD__, array('IGNORE'));
         // Build comment for log
         $comment = wfMessage('prot_1movedto2', $this->oldTitle->getPrefixedText(), $this->newTitle->getPrefixedText())->inContentLanguage()->text();
         if ($reason) {
             $comment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason;
         }
         // reread inserted pr_ids for log relation
         $insertedPrIds = $dbw->select('page_restrictions', 'pr_id', array('pr_page' => $redirid), __METHOD__);
         $logRelationsValues = array();
         foreach ($insertedPrIds as $prid) {
             $logRelationsValues[] = $prid->pr_id;
         }
         // Update the protection log
         $logEntry = new ManualLogEntry('protect', 'move_prot');
         $logEntry->setTarget($this->newTitle);
         $logEntry->setComment($comment);
         $logEntry->setPerformer($user);
         $logEntry->setParameters(array('4::oldtitle' => $this->oldTitle->getPrefixedText()));
         $logEntry->setRelations(array('pr_id' => $logRelationsValues));
         $logId = $logEntry->insert();
         $logEntry->publish($logId);
     }
     // Update *_from_namespace fields as needed
     if ($this->oldTitle->getNamespace() != $this->newTitle->getNamespace()) {
         $dbw->update('pagelinks', array('pl_from_namespace' => $this->newTitle->getNamespace()), array('pl_from' => $pageid), __METHOD__);
         $dbw->update('templatelinks', array('tl_from_namespace' => $this->newTitle->getNamespace()), array('tl_from' => $pageid), __METHOD__);
         $dbw->update('imagelinks', array('il_from_namespace' => $this->newTitle->getNamespace()), array('il_from' => $pageid), __METHOD__);
     }
     # Update watchlists
     $oldtitle = $this->oldTitle->getDBkey();
     $newtitle = $this->newTitle->getDBkey();
     $oldsnamespace = MWNamespace::getSubject($this->oldTitle->getNamespace());
     $newsnamespace = MWNamespace::getSubject($this->newTitle->getNamespace());
     if ($oldsnamespace != $newsnamespace || $oldtitle != $newtitle) {
         WatchedItem::duplicateEntries($this->oldTitle, $this->newTitle);
     }
     $dbw->commit(__METHOD__);
     Hooks::run('TitleMoveComplete', array(&$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason));
     return Status::newGood();
 }
示例#6
0
 /**
  * Record a log entry on the action
  * @param array $params Associative array of parameters:
  *     newBits:         The new value of the *_deleted bitfield
  *     oldBits:         The old value of the *_deleted bitfield.
  *     title:           The target title
  *     ids:             The ID list
  *     comment:         The log comment
  *     authorsIds:      The array of the user IDs of the offenders
  *     authorsIPs:      The array of the IP/anon user offenders
  * @throws MWException
  */
 protected function updateLog($params)
 {
     // Get the URL param's corresponding DB field
     $field = RevisionDeleter::getRelationType($this->getType());
     if (!$field) {
         throw new MWException("Bad log URL param type!");
     }
     // Put things hidden from sysops in the suppression log
     if (($params['newBits'] | $params['oldBits']) & $this->getSuppressBit()) {
         $logType = 'suppress';
     } else {
         $logType = 'delete';
     }
     // Add params for affected page and ids
     $logParams = $this->getLogParams($params);
     // Actually add the deletion log entry
     $logEntry = new ManualLogEntry($logType, $this->getLogAction());
     $logEntry->setTarget($params['title']);
     $logEntry->setComment($params['comment']);
     $logEntry->setParameters($logParams);
     $logEntry->setPerformer($this->getUser());
     // Allow for easy searching of deletion log items for revision/log items
     $logEntry->setRelations(array($field => $params['ids'], 'target_author_id' => $params['authorIds'], 'target_author_ip' => $params['authorIPs']));
     $logId = $logEntry->insert();
     $logEntry->publish($logId);
 }
 protected function logTagAdded($tags, $revId, $user, $reason)
 {
     // log it
     $logEntry = new ManualLogEntry('tag', 'update');
     $logEntry->setPerformer($user);
     $logEntry->setComment($reason);
     // find the appropriate target page
     if ($revId) {
         $rev = Revision::newFromId($revId);
         if ($rev) {
             $logEntry->setTarget($rev->getTitle());
         }
     }
     if (!$logEntry->getTarget()) {
         // target is required, so we have to set something
         $logEntry->setTarget(SpecialPage::getTitleFor('Tags'));
     }
     $logParams = array('4::revid' => $revId, '6:list:tagsAdded' => $tags, '7:number:tagsAddedCount' => count($tags));
     $logEntry->setParameters($logParams);
     $logEntry->setRelations(array('Tag' => $tags));
     $dbw = wfGetDB(DB_MASTER);
     $logId = $logEntry->insert($dbw);
     // Only send this to UDP, not RC, similar to patrol events
     $logEntry->publish($logId, 'udp');
     //$logEntry->publish( $logId );
 }
示例#8
0
 /**
  * @param User $user
  * @param string $reason
  * @param bool $createRedirect
  * @return Status
  */
 public function move(User $user, $reason, $createRedirect)
 {
     global $wgCategoryCollation;
     Hooks::run('TitleMove', [$this->oldTitle, $this->newTitle, $user]);
     // If it is a file, move it first.
     // It is done before all other moving stuff is done because it's hard to revert.
     $dbw = wfGetDB(DB_MASTER);
     if ($this->oldTitle->getNamespace() == NS_FILE) {
         $file = wfLocalFile($this->oldTitle);
         $file->load(File::READ_LATEST);
         if ($file->exists()) {
             $status = $file->move($this->newTitle);
             if (!$status->isOK()) {
                 return $status;
             }
         }
         // Clear RepoGroup process cache
         RepoGroup::singleton()->clearCache($this->oldTitle);
         RepoGroup::singleton()->clearCache($this->newTitle);
         # clear false negative cache
     }
     $dbw->startAtomic(__METHOD__);
     Hooks::run('TitleMoveStarting', [$this->oldTitle, $this->newTitle, $user]);
     $pageid = $this->oldTitle->getArticleID(Title::GAID_FOR_UPDATE);
     $protected = $this->oldTitle->isProtected();
     // Do the actual move; if this fails, it will throw an MWException(!)
     $nullRevision = $this->moveToInternal($user, $this->newTitle, $reason, $createRedirect);
     // Refresh the sortkey for this row.  Be careful to avoid resetting
     // cl_timestamp, which may disturb time-based lists on some sites.
     // @todo This block should be killed, it's duplicating code
     // from LinksUpdate::getCategoryInsertions() and friends.
     $prefixes = $dbw->select('categorylinks', ['cl_sortkey_prefix', 'cl_to'], ['cl_from' => $pageid], __METHOD__);
     if ($this->newTitle->getNamespace() == NS_CATEGORY) {
         $type = 'subcat';
     } elseif ($this->newTitle->getNamespace() == NS_FILE) {
         $type = 'file';
     } else {
         $type = 'page';
     }
     foreach ($prefixes as $prefixRow) {
         $prefix = $prefixRow->cl_sortkey_prefix;
         $catTo = $prefixRow->cl_to;
         $dbw->update('categorylinks', ['cl_sortkey' => Collation::singleton()->getSortKey($this->newTitle->getCategorySortkey($prefix)), 'cl_collation' => $wgCategoryCollation, 'cl_type' => $type, 'cl_timestamp=cl_timestamp'], ['cl_from' => $pageid, 'cl_to' => $catTo], __METHOD__);
     }
     $redirid = $this->oldTitle->getArticleID();
     if ($protected) {
         # Protect the redirect title as the title used to be...
         $res = $dbw->select('page_restrictions', '*', ['pr_page' => $pageid], __METHOD__, 'FOR UPDATE');
         $rowsInsert = [];
         foreach ($res as $row) {
             $rowsInsert[] = ['pr_page' => $redirid, 'pr_type' => $row->pr_type, 'pr_level' => $row->pr_level, 'pr_cascade' => $row->pr_cascade, 'pr_user' => $row->pr_user, 'pr_expiry' => $row->pr_expiry];
         }
         $dbw->insert('page_restrictions', $rowsInsert, __METHOD__, ['IGNORE']);
         // Build comment for log
         $comment = wfMessage('prot_1movedto2', $this->oldTitle->getPrefixedText(), $this->newTitle->getPrefixedText())->inContentLanguage()->text();
         if ($reason) {
             $comment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason;
         }
         // reread inserted pr_ids for log relation
         $insertedPrIds = $dbw->select('page_restrictions', 'pr_id', ['pr_page' => $redirid], __METHOD__);
         $logRelationsValues = [];
         foreach ($insertedPrIds as $prid) {
             $logRelationsValues[] = $prid->pr_id;
         }
         // Update the protection log
         $logEntry = new ManualLogEntry('protect', 'move_prot');
         $logEntry->setTarget($this->newTitle);
         $logEntry->setComment($comment);
         $logEntry->setPerformer($user);
         $logEntry->setParameters(['4::oldtitle' => $this->oldTitle->getPrefixedText()]);
         $logEntry->setRelations(['pr_id' => $logRelationsValues]);
         $logId = $logEntry->insert();
         $logEntry->publish($logId);
     }
     // Update *_from_namespace fields as needed
     if ($this->oldTitle->getNamespace() != $this->newTitle->getNamespace()) {
         $dbw->update('pagelinks', ['pl_from_namespace' => $this->newTitle->getNamespace()], ['pl_from' => $pageid], __METHOD__);
         $dbw->update('templatelinks', ['tl_from_namespace' => $this->newTitle->getNamespace()], ['tl_from' => $pageid], __METHOD__);
         $dbw->update('imagelinks', ['il_from_namespace' => $this->newTitle->getNamespace()], ['il_from' => $pageid], __METHOD__);
     }
     # Update watchlists
     $oldtitle = $this->oldTitle->getDBkey();
     $newtitle = $this->newTitle->getDBkey();
     $oldsnamespace = MWNamespace::getSubject($this->oldTitle->getNamespace());
     $newsnamespace = MWNamespace::getSubject($this->newTitle->getNamespace());
     if ($oldsnamespace != $newsnamespace || $oldtitle != $newtitle) {
         $store = MediaWikiServices::getInstance()->getWatchedItemStore();
         $store->duplicateAllAssociatedEntries($this->oldTitle, $this->newTitle);
     }
     Hooks::run('TitleMoveCompleting', [$this->oldTitle, $this->newTitle, $user, $pageid, $redirid, $reason, $nullRevision]);
     $dbw->endAtomic(__METHOD__);
     $params = [&$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason, $nullRevision];
     // Keep each single hook handler atomic
     DeferredUpdates::addUpdate(new AtomicSectionUpdate($dbw, __METHOD__, function () use($params) {
         Hooks::run('TitleMoveComplete', $params);
     }));
     return Status::newGood();
 }
示例#9
0
 /**
  * Record a log entry on the action
  * @param string $logType One of (delete,suppress)
  * @param array $params Associative array of parameters:
  *     newBits:         The new value of the *_deleted bitfield
  *     oldBits:         The old value of the *_deleted bitfield.
  *     title:           The target title
  *     ids:             The ID list
  *     comment:         The log comment
  *     authorsIds:      The array of the user IDs of the offenders
  *     authorsIPs:      The array of the IP/anon user offenders
  * @throws MWException
  */
 private function updateLog($logType, $params)
 {
     // Get the URL param's corresponding DB field
     $field = RevisionDeleter::getRelationType($this->getType());
     if (!$field) {
         throw new MWException("Bad log URL param type!");
     }
     // Add params for affected page and ids
     $logParams = $this->getLogParams($params);
     // Actually add the deletion log entry
     $logEntry = new ManualLogEntry($logType, $this->getLogAction());
     $logEntry->setTarget($params['title']);
     $logEntry->setComment($params['comment']);
     $logEntry->setParameters($logParams);
     $logEntry->setPerformer($this->getUser());
     // Allow for easy searching of deletion log items for revision/log items
     $logEntry->setRelations([$field => $params['ids'], 'target_author_id' => $params['authorIds'], 'target_author_ip' => $params['authorIPs']]);
     $logId = $logEntry->insert();
     $logEntry->publish($logId);
 }