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 );
 }
 public function onSubmit(array $formData)
 {
     global $IP, $wgCreateWikiSQLfiles;
     $DBname = $formData['dbname'];
     $founderName = $formData['founder'];
     $siteName = $formData['sitename'];
     $language = $formData['language'];
     $private = $formData['private'];
     $reason = $formData['reason'];
     $dbw = wfGetDB(DB_MASTER);
     $farmerLogEntry = new ManualLogEntry('farmer', 'createwiki');
     $farmerLogEntry->setPerformer($this->getUser());
     $farmerLogEntry->setTarget($this->getTitle());
     $farmerLogEntry->setComment($reason);
     $farmerLogEntry->setParameters(array('4::wiki' => $DBname));
     $farmerLogID = $farmerLogEntry->insert();
     $farmerLogEntry->publish($farmerLogID);
     $dbw->query('SET storage_engine=InnoDB;');
     $dbw->query('CREATE DATABASE ' . $dbw->addIdentifierQuotes($DBname) . ';');
     $dbw->selectDB($DBname);
     foreach ($wgCreateWikiSQLfiles as $sqlfile) {
         $dbw->sourceFile($sqlfile);
     }
     $this->writeToDBlist($DBname, $siteName, $language, $private);
     $this->createMainPage($language);
     $shcreateaccount = exec("/usr/bin/php " . "{$IP}/extensions/CentralAuth/maintenance/createLocalAccount.php " . wfEscapeShellArg($founderName) . " --wiki " . wfEscapeShellArg($DBname));
     if (!strpos($shcreateaccount, 'created')) {
         wfDebugLog('CreateWiki', 'Failed to create local account for founder. - error: ' . $shcreateaccount);
         return wfMessage('createwiki-error-usernotcreated')->escaped();
     }
     $shpromoteaccount = exec("/usr/bin/php " . "{$IP}/maintenance/createAndPromote.php " . wfEscapeShellArg($founderName) . " --bureaucrat --sysop --force --wiki " . wfEscapeShellArg($DBname));
     $this->getOutput()->addHTML('<div class="successbox">' . wfMessage('createwiki-success')->escaped() . '</div>');
     return true;
 }
示例#3
0
 public function execute($par)
 {
     // Shortcut by using $par
     if ($par) {
         $this->getOutput()->redirect($this->getTitle()->getLinkURL(array('user' => $par)));
         return;
     }
     $this->setHeaders();
     $this->outputHeader();
     // Parse options
     $opt = new \FormOptions();
     $opt->add('user', '');
     $opt->add('delete', '');
     $opt->add('reason', '');
     $opt->fetchValuesFromRequest($this->getRequest());
     // Parse user
     $user = $opt->getValue('user');
     $userObj = \User::newFromName($user);
     $userExists = $userObj && $userObj->getId() !== 0;
     // If current task is delete and user is not allowed
     $canDoAdmin = $this->getUser()->isAllowed('avataradmin');
     if ($opt->getValue('delete')) {
         if (!$canDoAdmin) {
             throw new \PermissionsError('avataradmin');
         }
         // Delete avatar if the user exists
         if ($userExists) {
             if (Avatars::deleteAvatar($userObj)) {
                 global $wgAvatarLogInRC;
                 $logEntry = new \ManualLogEntry('avatar', 'delete');
                 $logEntry->setPerformer($this->getUser());
                 $logEntry->setTarget($userObj->getUserPage());
                 $logEntry->setComment($opt->getValue('reason'));
                 $logId = $logEntry->insert();
                 $logEntry->publish($logId, $wgAvatarLogInRC ? 'rcandudp' : 'udp');
             }
         }
     }
     $this->getOutput()->addModules(array('mediawiki.userSuggest'));
     $this->showForm($user);
     if ($userExists) {
         $haveAvatar = Avatars::hasAvatar($userObj);
         if ($haveAvatar) {
             $html = \Xml::tags('img', array('src' => Avatars::getLinkFor($user, 'original') . '&nocache&ver=' . dechex(time()), 'height' => 400), '');
             $html = \Xml::tags('p', array(), $html);
             $this->getOutput()->addHTML($html);
             // Add a delete button
             if ($canDoAdmin) {
                 $this->showDeleteForm($user);
             }
         } else {
             $this->getOutput()->addWikiMsg('viewavatar-noavatar');
         }
     } else {
         if ($user) {
             $this->getOutput()->addWikiMsg('viewavatar-nouser');
         }
     }
 }
 public function newLogEntry($action, $params)
 {
     $logEntry = new ManualLogEntry('phpunit', $action);
     $logEntry->setPerformer($this->user);
     $logEntry->setTarget($this->title);
     $logEntry->setComment('A very good reason');
     $logEntry->setParameters($params);
     return $logEntry;
 }
 /**
  * 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);
 }
 /**
  * @param CentralAuthUser[] $oldNames
  * @param string $newName
  * @param string $reason
  */
 public function log(array $oldNames, $newName, $reason)
 {
     $logEntry = new ManualLogEntry('gblrename', 'merge');
     $logEntry->setPerformer($this->performingUser);
     $logEntry->setTarget(Title::makeTitleSafe(NS_SPECIAL, 'CentralAuth/' . $newName));
     $imploded = implode('|', array_map(function (CentralAuthUser $user) {
         return $user->getName();
     }, $oldNames));
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::olduser' => $imploded, '5::newuser' => $newName));
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
示例#7
0
 /**
  * adds a log entry to the database.
  *
  * @param $type string: type of the log entry
  * @param $subtype string: subtype of the log entry
  * @param $user User: user that performs the logged operation
  * @param $ns int: number of the namespace for the entry's target's title
  * @param $title string: title of the entry's target
  * @param $comment string: comment of the log entry
  * @param $parameters Array: (optional) accompanying data that is attached
  *               to the entry
  *
  * @return int id of the added log entry
  */
 private function addLogEntry($type, $subtype, User $user, $ns, $title, $comment = null, $parameters = null)
 {
     $logEntry = new ManualLogEntry($type, $subtype);
     $logEntry->setPerformer($user);
     $logEntry->setTarget(Title::newFromText($title, $ns));
     if ($comment !== null) {
         $logEntry->setComment($comment);
     }
     if ($parameters !== null) {
         $logEntry->setParameters($parameters);
     }
     return $logEntry->insert();
 }
 /**
  * Create new Log entry
  *
  * @param string $action Action name as defined above
  * @param integer $mapId Map id
  * @param string $comment Comment
  * @param array $params Additional params
  * @return ManualLogEntry
  */
 public static function newLogEntry($action, $user, $mapId, $comment, $params = [])
 {
     $logEntry = new ManualLogEntry(self::LOG_TYPE_NAME, $action);
     $logEntry->setPerformer($user);
     $logEntry->setTarget(SpecialPage::getTitleFor(WikiaMapsSpecialController::PAGE_NAME, $mapId));
     $logEntry->setComment($comment);
     if (!empty($params)) {
         // we can't allow to pass those elements
         // more info: https://www.mediawiki.org/wiki/Manual:Logging_to_Special:Log#1.19_and_later
         unset($params[1], $params[2], $params[3]);
         $logEntry->setParameters($params);
     }
     return $logEntry;
 }
示例#9
0
 /**
  * Create a log entry using the provided info.
  * Takes care about the logging interface changes in MediaWiki 1.19.
  * 
  * @since 0.1
  * 
  * @param array $info
  */
 public static function log(array $info)
 {
     $user = array_key_exists('user', $info) ? $info['user'] : $GLOBALS['wgUser'];
     $logEntry = new ManualLogEntry($info['type'], $info['subtype']);
     $logEntry->setPerformer($user);
     $logEntry->setTarget($info['title']);
     if (array_key_exists('comment', $info)) {
         $logEntry->setComment($info['comment']);
     }
     if (array_key_exists('parameters', $info)) {
         $logEntry->setParameters($info['parameters']);
     }
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
 function onSubmitInput(array $params)
 {
     if (!$this->getUser()->isAllowed('managewiki')) {
         throw new MWException("User '{$this->getUser()->getName()}' without managewiki right tried to change wiki settings!");
     }
     $values = array('wiki_sitename' => $params['sitename'], 'wiki_language' => $params['language'], 'wiki_closed' => $params['closed'] == true ? 1 : 0);
     if ($this->getUser()->isAllowed('managewiki-restricted')) {
         $values['wiki_private'] = $params['private'] == true ? 1 : 0;
     }
     $dbw = wfGetDB(DB_MASTER);
     $dbw->update('cw_wikis', $values, array('wiki_dbname' => $params['dbname']), __METHOD__);
     $farmerLogEntry = new ManualLogEntry('farmer', 'managewiki');
     $farmerLogEntry->setPerformer($this->getUser());
     $farmerLogEntry->setTarget($this->getTitle());
     $farmerLogEntry->setComment($params['reason']);
     $farmerLogEntry->setParameters(array('4::wiki' => $params['dbname']));
     $farmerLogID = $farmerLogEntry->insert();
     $farmerLogEntry->publish($farmerLogID);
     $this->getOutput()->addHTML('<div class="successbox">' . wfMessage('managewiki-success')->escaped() . '</div>');
     return true;
 }
示例#11
0
 /**
  * Create a log entry using the provided info.
  * Takes care about the logging interface changes in MediaWiki 1.19.
  * 
  * @since 0.1
  * 
  * @param array $info
  */
 public static function log(array $info)
 {
     $user = array_key_exists('user', $info) ? $info['user'] : $GLOBALS['wgUser'];
     if ($info !== false) {
         if (class_exists('ManualLogEntry')) {
             $logEntry = new ManualLogEntry($info['type'], $info['subtype']);
             $logEntry->setPerformer($user);
             $logEntry->setTarget($info['title']);
             if (array_key_exists('comment', $info)) {
                 $logEntry->setComment($info['comment']);
             }
             if (array_key_exists('parameters', $info)) {
                 $logEntry->setParameters($info['parameters']);
             }
             $logid = $logEntry->insert();
             $logEntry->publish($logid);
         } else {
             // Compatibility with MediaWiki 1.18.
             $log = new LogPage($info['type']);
             $log->addEntry($info['subtype'], $info['title'], array_key_exists('comment', $info) ? $info['comment'] : '', array_key_exists('parameters', $info) ? $info['parameters'] : array(), $user);
         }
     }
 }
示例#12
0
 /**
  * Move page to a title which is either a redirect to the
  * source page or nonexistent
  *
  * @param $nt Title the page to move to, which should be a redirect or nonexistent
  * @param $reason String The reason for the move
  * @param $createRedirect Bool Whether to leave a redirect at the old title.  Ignored
  *   if the user doesn't have the suppressredirect right
  */
 private function moveToInternal(&$nt, $reason = '', $createRedirect = true)
 {
     global $wgUser, $wgContLang;
     if ($nt->exists()) {
         $moveOverRedirect = true;
         $logType = 'move_redir';
     } else {
         $moveOverRedirect = false;
         $logType = 'move';
     }
     $redirectSuppressed = !$createRedirect && $wgUser->isAllowed('suppressredirect');
     $logEntry = new ManualLogEntry('move', $logType);
     $logEntry->setPerformer($wgUser);
     $logEntry->setTarget($this);
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::target' => $nt->getPrefixedText(), '5::noredir' => $redirectSuppressed ? '1' : '0'));
     $formatter = LogFormatter::newFromEntry($logEntry);
     $formatter->setContext(RequestContext::newExtraneousContext($this));
     $comment = $formatter->getPlainActionText();
     if ($reason) {
         $comment .= wfMsgForContent('colon-separator') . $reason;
     }
     # Truncate for whole multibyte characters.
     $comment = $wgContLang->truncate($comment, 255);
     $oldid = $this->getArticleID();
     $latest = $this->getLatestRevID();
     $dbw = wfGetDB(DB_MASTER);
     $newpage = WikiPage::factory($nt);
     if ($moveOverRedirect) {
         $newid = $nt->getArticleID();
         # Delete the old redirect. We don't save it to history since
         # by definition if we've got here it's rather uninteresting.
         # We have to remove it so that the next step doesn't trigger
         # a conflict on the unique namespace+title index...
         $dbw->delete('page', array('page_id' => $newid), __METHOD__);
         $newpage->doDeleteUpdates($newid);
     }
     # Save a null revision in the page's history notifying of the move
     $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true);
     if (!is_object($nullRevision)) {
         throw new MWException('No valid null revision produced in ' . __METHOD__);
     }
     $nullRevId = $nullRevision->insertOn($dbw);
     # Change the name of the target page:
     $dbw->update('page', array('page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey()), array('page_id' => $oldid), __METHOD__);
     $this->resetArticleID(0);
     $nt->resetArticleID($oldid);
     $newpage->updateRevisionOn($dbw, $nullRevision);
     wfRunHooks('NewRevisionFromEditComplete', array($newpage, $nullRevision, $latest, $wgUser));
     $newpage->doEditUpdates($nullRevision, $wgUser, array('changed' => false));
     if (!$moveOverRedirect) {
         WikiPage::onArticleCreate($nt);
     }
     # Recreate the redirect, this time in the other direction.
     if ($redirectSuppressed) {
         WikiPage::onArticleDelete($this);
     } else {
         $mwRedir = MagicWord::get('redirect');
         $redirectText = $mwRedir->getSynonym(0) . ' [[' . $nt->getPrefixedText() . "]]\n";
         $redirectArticle = WikiPage::factory($this);
         $newid = $redirectArticle->insertOn($dbw);
         if ($newid) {
             // sanity
             $redirectRevision = new Revision(array('page' => $newid, 'comment' => $comment, 'text' => $redirectText));
             $redirectRevision->insertOn($dbw);
             $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
             wfRunHooks('NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false, $wgUser));
             $redirectArticle->doEditUpdates($redirectRevision, $wgUser, array('created' => true));
         }
     }
     # Log the move
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
示例#13
0
 /**
  * @param array $formData
  * @param HtmlForm $form
  *
  * @return bool|string
  * @throws DBUnexpectedError
  * @throws Exception
  * @throws MWException
  */
 public static function processInput(array $formData, HtmlForm $form)
 {
     error_reporting(0);
     global $wgCreateWikiSQLfiles, $IP;
     $DBname = $formData['dbname'];
     $founderName = $formData['founder'];
     $dbw = wfGetDB(DB_MASTER);
     $dbTest = $dbw->query('SHOW DATABASES LIKE ' . $dbw->addQuotes($DBname) . ';');
     $rows = $dbTest->numRows();
     $dbTest->free();
     if ($rows !== 0) {
         return wfMessage('createwiki-error-dbexists')->plain();
     }
     $farmerLogEntry = new ManualLogEntry('farmer', 'createandpromote');
     $farmerLogEntry->setPerformer($form->getUser());
     $farmerLogEntry->setTarget($form->getTitle());
     $farmerLogEntry->setComment($formData['comment']);
     $farmerLogEntry->setParameters(array('4::wiki' => $DBname, '5::founder' => $founderName));
     $farmerLogID = $farmerLogEntry->insert();
     $farmerLogEntry->publish($farmerLogID);
     $dbw->query('SET storage_engine=InnoDB;');
     $dbw->query('CREATE DATABASE ' . $dbw->addIdentifierQuotes($DBname) . ';');
     $dbw->selectDB($DBname);
     foreach ($wgCreateWikiSQLfiles as $file) {
         $dbw->sourceFile($file);
     }
     $dbw->insert('site_stats', array('ss_row_id' => 1));
     $dbw->close();
     // Add DNS record to cloudflare
     global $wgCreateWikiUseCloudFlare, $wgCloudFlareUser, $wgCloudFlareKey;
     if ($wgCreateWikiUseCloudFlare) {
         $domainPrefix = substr($DBname, 0, -4);
         $cloudFlare = new cloudflare_api($wgCloudFlareUser, $wgCloudFlareKey);
         $cloudFlareResult = $cloudFlare->rec_new('orain.org', 'CNAME', $domainPrefix, 'lb.orain.org');
         if (!is_object($cloudFlareResult) || $cloudFlareResult->result !== 'success') {
             wfDebugLog('CreateWiki', 'CloudFlare FAILED to add CNAME for ' . $domainPrefix . '.orain.org');
         } else {
             wfDebugLog('CreateWiki', 'CloudFlare CNAME added for ' . $domainPrefix . '.orain.org');
         }
     }
     // Create local account for founder (hack)
     $out = exec("php5 {$IP}/extensions/CentralAuth/maintenance/createLocalAccount.php " . escapeshellarg($founderName) . ' --wiki ' . escapeshellarg($DBname));
     if (!strpos($out, 'created')) {
         return wfMessage('createwiki-error-usernotcreated')->plain();
     }
     require_once "{$IP}/includes/UserRightsProxy.php";
     // Grant founder sysop and bureaucrat rights
     $founderUser = UserRightsProxy::newFromName($DBname, $founderName);
     $newGroups = array('sysop', 'bureaucrat');
     array_map(array($founderUser, 'addGroup'), $newGroups);
     $founderUser->invalidateCache();
     $form->getOutput()->addWikiMsg('createwiki-success', $DBname);
     return true;
 }
示例#14
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;
 }
示例#15
0
 /**
  * Record a file upload in the upload log and the image table
  * @param string $oldver
  * @param string $comment
  * @param string $pageText
  * @param bool|array $props
  * @param string|bool $timestamp
  * @param null|User $user
  * @return bool
  */
 function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null)
 {
     wfProfileIn(__METHOD__);
     if (is_null($user)) {
         global $wgUser;
         $user = $wgUser;
     }
     $dbw = $this->repo->getMasterDB();
     $dbw->begin(__METHOD__);
     if (!$props) {
         wfProfileIn(__METHOD__ . '-getProps');
         $props = $this->repo->getFileProps($this->getVirtualUrl());
         wfProfileOut(__METHOD__ . '-getProps');
     }
     if ($timestamp === false) {
         $timestamp = $dbw->timestamp();
     }
     $props['description'] = $comment;
     $props['user'] = $user->getId();
     $props['user_text'] = $user->getName();
     $props['timestamp'] = wfTimestamp(TS_MW, $timestamp);
     // DB -> TS_MW
     $this->setProps($props);
     # Fail now if the file isn't there
     if (!$this->fileExists) {
         wfDebug(__METHOD__ . ": File " . $this->getRel() . " went missing!\n");
         wfProfileOut(__METHOD__);
         return false;
     }
     $reupload = false;
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $this->getName(), 'img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), __METHOD__, 'IGNORE');
     if ($dbw->affectedRows() == 0) {
         # (bug 34993) Note: $oldver can be empty here, if the previous
         # version of the file was broken. Allow registration of the new
         # version to continue anyway, because that's better than having
         # an image that's not fixable by user operations.
         $reupload = true;
         # Collision, this is an update of a file
         # Insert previous contents into oldimage
         $dbw->insertSelect('oldimage', 'image', array('oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes($oldver), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', 'oi_metadata' => 'img_metadata', 'oi_media_type' => 'img_media_type', 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1'), array('img_name' => $this->getName()), __METHOD__);
         # Update the current image row
         $dbw->update('image', array('img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), array('img_name' => $this->getName()), __METHOD__);
     } else {
         # This is a new file, so update the image count
         DeferredUpdates::addUpdate(SiteStatsUpdate::factory(array('images' => 1)));
     }
     $descTitle = $this->getTitle();
     $wikiPage = new WikiFilePage($descTitle);
     $wikiPage->setFile($this);
     # Add the log entry
     $action = $reupload ? 'overwrite' : 'upload';
     $logEntry = new ManualLogEntry('upload', $action);
     $logEntry->setPerformer($user);
     $logEntry->setComment($comment);
     $logEntry->setTarget($descTitle);
     // Allow people using the api to associate log entries with the upload.
     // Log has a timestamp, but sometimes different from upload timestamp.
     $logEntry->setParameters(array('img_sha1' => $this->sha1, 'img_timestamp' => $timestamp));
     // Note we keep $logId around since during new image
     // creation, page doesn't exist yet, so log_page = 0
     // but we want it to point to the page we're making,
     // so we later modify the log entry.
     // For a similar reason, we avoid making an RC entry
     // now and wait until the page exists.
     $logId = $logEntry->insert();
     $exists = $descTitle->exists();
     if ($exists) {
         // Page exists, do RC entry now (otherwise we wait for later).
         $logEntry->publish($logId);
     }
     wfProfileIn(__METHOD__ . '-edit');
     if ($exists) {
         # Create a null revision
         $latest = $descTitle->getLatestRevID();
         $editSummary = LogFormatter::newFromEntry($logEntry)->getPlainActionText();
         $nullRevision = Revision::newNullRevision($dbw, $descTitle->getArticleID(), $editSummary, false);
         if (!is_null($nullRevision)) {
             $nullRevision->insertOn($dbw);
             wfRunHooks('NewRevisionFromEditComplete', array($wikiPage, $nullRevision, $latest, $user));
             $wikiPage->updateRevisionOn($dbw, $nullRevision);
         }
     }
     # Commit the transaction now, in case something goes wrong later
     # The most important thing is that files don't get lost, especially archives
     # NOTE: once we have support for nested transactions, the commit may be moved
     #       to after $wikiPage->doEdit has been called.
     $dbw->commit(__METHOD__);
     # Save to memcache.
     # We shall not saveToCache before the commit since otherwise
     # in case of a rollback there is an usable file from memcached
     # which in fact doesn't really exist (bug 24978)
     $this->saveToCache();
     if ($exists) {
         # Invalidate the cache for the description page
         $descTitle->invalidateCache();
         $descTitle->purgeSquid();
     } else {
         # New file; create the description page.
         # There's already a log entry, so don't make a second RC entry
         # Squid and file cache for the description page are purged by doEditContent.
         $content = ContentHandler::makeContent($pageText, $descTitle);
         $status = $wikiPage->doEditContent($content, $comment, EDIT_NEW | EDIT_SUPPRESS_RC, false, $user);
         $dbw->begin(__METHOD__);
         // XXX; doEdit() uses a transaction
         // Now that the page exists, make an RC entry.
         $logEntry->publish($logId);
         if (isset($status->value['revision'])) {
             $dbw->update('logging', array('log_page' => $status->value['revision']->getPage()), array('log_id' => $logId), __METHOD__);
         }
         $dbw->commit(__METHOD__);
         // commit before anything bad can happen
     }
     wfProfileOut(__METHOD__ . '-edit');
     if ($reupload) {
         # Delete old thumbnails
         wfProfileIn(__METHOD__ . '-purge');
         $this->purgeThumbnails();
         wfProfileOut(__METHOD__ . '-purge');
         # Remove the old file from the squid cache
         SquidUpdate::purge(array($this->getURL()));
     }
     # Hooks, hooks, the magic of hooks...
     wfProfileIn(__METHOD__ . '-hooks');
     wfRunHooks('FileUpload', array($this, $reupload, $descTitle->exists()));
     wfProfileOut(__METHOD__ . '-hooks');
     # Invalidate cache for all pages using this file
     $update = new HTMLCacheUpdate($this->getTitle(), 'imagelinks');
     $update->doUpdate();
     if (!$reupload) {
         LinksUpdate::queueRecursiveJobsForTable($this->getTitle(), 'imagelinks');
     }
     wfProfileOut(__METHOD__);
     return true;
 }
示例#16
0
 /**
  * Add a newuser log entry for this user.
  * Before 1.19 the return value was always true.
  *
  * @param string|bool $action Account creation type.
  *   - String, one of the following values:
  *     - 'create' for an anonymous user creating an account for himself.
  *       This will force the action's performer to be the created user itself,
  *       no matter the value of $wgUser
  *     - 'create2' for a logged in user creating an account for someone else
  *     - 'byemail' when the created user will receive its password by e-mail
  *     - 'autocreate' when the user is automatically created (such as by CentralAuth).
  *   - Boolean means whether the account was created by e-mail (deprecated):
  *     - true will be converted to 'byemail'
  *     - false will be converted to 'create' if this object is the same as
  *       $wgUser and to 'create2' otherwise
  *
  * @param string $reason User supplied reason
  *
  * @return int|bool True if not $wgNewUserLog; otherwise ID of log item or 0 on failure
  */
 public function addNewUserLogEntry($action = false, $reason = '')
 {
     global $wgUser, $wgNewUserLog;
     if (empty($wgNewUserLog)) {
         return true;
         // disabled
     }
     if ($action === true) {
         $action = 'byemail';
     } elseif ($action === false) {
         if ($this->equals($wgUser)) {
             $action = 'create';
         } else {
             $action = 'create2';
         }
     }
     if ($action === 'create' || $action === 'autocreate') {
         $performer = $this;
     } else {
         $performer = $wgUser;
     }
     $logEntry = new ManualLogEntry('newusers', $action);
     $logEntry->setPerformer($performer);
     $logEntry->setTarget($this->getUserPage());
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::userid' => $this->getId()));
     $logid = $logEntry->insert();
     if ($action !== 'autocreate') {
         $logEntry->publish($logid);
     }
     return (int) $logid;
 }
 public function onSubmit(array $data)
 {
     global $wgContLang;
     if ($data['pagetitle'] === '') {
         // Initial form view of special page, pass
         return false;
     }
     // At this point, it has to be a POST request. This is enforced by HTMLForm,
     // but lets be safe verify that.
     if (!$this->getRequest()->wasPosted()) {
         throw new RuntimeException("Form submission was not POSTed");
     }
     $this->title = Title::newFromText($data['pagetitle']);
     $user = $this->getUser();
     // Check permissions and make sure the user has permission to edit the specific page
     $errors = $this->title->getUserPermissionsErrors('editcontentmodel', $user);
     $errors = wfMergeErrorArrays($errors, $this->title->getUserPermissionsErrors('edit', $user));
     if ($errors) {
         $out = $this->getOutput();
         $wikitext = $out->formatPermissionsErrorMessage($errors);
         // Hack to get our wikitext parsed
         return Status::newFatal(new RawMessage('$1', array($wikitext)));
     }
     $page = WikiPage::factory($this->title);
     if ($this->oldRevision === null) {
         $this->oldRevision = $page->getRevision() ?: false;
     }
     $oldModel = $this->title->getContentModel();
     if ($this->oldRevision) {
         $oldContent = $this->oldRevision->getContent();
         try {
             $newContent = ContentHandler::makeContent($oldContent->getNativeData(), $this->title, $data['model']);
         } catch (MWException $e) {
             return Status::newFatal($this->msg('changecontentmodel-cannot-convert')->params($this->title->getPrefixedText(), ContentHandler::getLocalizedName($data['model'])));
         }
     } else {
         // Page doesn't exist, create an empty content object
         $newContent = ContentHandler::getForModelID($data['model'])->makeEmptyContent();
     }
     $flags = $this->oldRevision ? EDIT_UPDATE : EDIT_NEW;
     if ($user->isAllowed('bot')) {
         $flags |= EDIT_FORCE_BOT;
     }
     $log = new ManualLogEntry('contentmodel', 'change');
     $log->setPerformer($user);
     $log->setTarget($this->title);
     $log->setComment($data['reason']);
     $log->setParameters(array('4::oldmodel' => $oldModel, '5::newmodel' => $data['model']));
     $formatter = LogFormatter::newFromEntry($log);
     $formatter->setContext(RequestContext::newExtraneousContext($this->title));
     $reason = $formatter->getPlainActionText();
     if ($data['reason'] !== '') {
         $reason .= $this->msg('colon-separator')->inContentLanguage()->text() . $data['reason'];
     }
     # Truncate for whole multibyte characters.
     $reason = $wgContLang->truncate($reason, 255);
     $status = $page->doEditContent($newContent, $reason, $flags, $this->oldRevision ? $this->oldRevision->getId() : false, $user);
     if (!$status->isOK()) {
         return $status;
     }
     $logid = $log->insert();
     $log->publish($logid);
     return $status;
 }
示例#18
0
 /**
  * Back-end article deletion
  * Deletes the article with database consistency, writes logs, purges caches
  *
  * @since 1.19
  *
  * @param string $reason Delete reason for deletion log
  * @param bool $suppress Suppress all revisions and log the deletion in
  *   the suppression log instead of the deletion log
  * @param int $id Article ID
  * @param bool $commit Defaults to true, triggers transaction end
  * @param array &$error Array of errors to append to
  * @param User $user The deleting user
  * @return Status Status object; if successful, $status->value is the log_id of the
  *   deletion log entry. If the page couldn't be deleted because it wasn't
  *   found, $status is a non-fatal 'cannotdelete' error
  */
 public function doDeleteArticleReal($reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null)
 {
     global $wgUser, $wgContentHandlerUseDB;
     wfDebug(__METHOD__ . "\n");
     $status = Status::newGood();
     if ($this->mTitle->getDBkey() === '') {
         $status->error('cannotdelete', wfEscapeWikiText($this->getTitle()->getPrefixedText()));
         return $status;
     }
     $user = is_null($user) ? $wgUser : $user;
     if (!Hooks::run('ArticleDelete', array(&$this, &$user, &$reason, &$error, &$status, $suppress))) {
         if ($status->isOK()) {
             // Hook aborted but didn't set a fatal status
             $status->fatal('delete-hook-aborted');
         }
         return $status;
     }
     $dbw = wfGetDB(DB_MASTER);
     $dbw->begin(__METHOD__);
     if ($id == 0) {
         $this->loadPageData(self::READ_LATEST);
         $id = $this->getID();
         // T98706: lock the page from various other updates but avoid using
         // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to
         // the revisions queries (which also JOIN on user). Only lock the page
         // row and CAS check on page_latest to see if the trx snapshot matches.
         $lockedLatest = $this->lock();
         if ($id == 0 || $this->getLatest() != $lockedLatest) {
             // Page not there or trx snapshot is stale
             $dbw->rollback(__METHOD__);
             $status->error('cannotdelete', wfEscapeWikiText($this->getTitle()->getPrefixedText()));
             return $status;
         }
     }
     // we need to remember the old content so we can use it to generate all deletion updates.
     $content = $this->getContent(Revision::RAW);
     // Bitfields to further suppress the content
     if ($suppress) {
         $bitfield = 0;
         // This should be 15...
         $bitfield |= Revision::DELETED_TEXT;
         $bitfield |= Revision::DELETED_COMMENT;
         $bitfield |= Revision::DELETED_USER;
         $bitfield |= Revision::DELETED_RESTRICTED;
     } else {
         $bitfield = 'rev_deleted';
     }
     /**
      * For now, shunt the revision data into the archive table.
      * Text is *not* removed from the text table; bulk storage
      * is left intact to avoid breaking block-compression or
      * immutable storage schemes.
      *
      * For backwards compatibility, note that some older archive
      * table entries will have ar_text and ar_flags fields still.
      *
      * In the future, we may keep revisions and mark them with
      * the rev_deleted field, which is reserved for this purpose.
      */
     $row = array('ar_namespace' => 'page_namespace', 'ar_title' => 'page_title', 'ar_comment' => 'rev_comment', 'ar_user' => 'rev_user', 'ar_user_text' => 'rev_user_text', 'ar_timestamp' => 'rev_timestamp', 'ar_minor_edit' => 'rev_minor_edit', 'ar_rev_id' => 'rev_id', 'ar_parent_id' => 'rev_parent_id', 'ar_text_id' => 'rev_text_id', 'ar_text' => '\'\'', 'ar_flags' => '\'\'', 'ar_len' => 'rev_len', 'ar_page_id' => 'page_id', 'ar_deleted' => $bitfield, 'ar_sha1' => 'rev_sha1');
     if ($wgContentHandlerUseDB) {
         $row['ar_content_model'] = 'rev_content_model';
         $row['ar_content_format'] = 'rev_content_format';
     }
     $dbw->insertSelect('archive', array('page', 'revision'), $row, array('page_id' => $id, 'page_id = rev_page'), __METHOD__);
     // Now that it's safely backed up, delete it
     $dbw->delete('page', array('page_id' => $id), __METHOD__);
     $ok = $dbw->affectedRows() > 0;
     // $id could be laggy
     if (!$ok) {
         $dbw->rollback(__METHOD__);
         $status->error('cannotdelete', wfEscapeWikiText($this->getTitle()->getPrefixedText()));
         return $status;
     }
     if (!$dbw->cascadingDeletes()) {
         $dbw->delete('revision', array('rev_page' => $id), __METHOD__);
     }
     // Clone the title, so we have the information we need when we log
     $logTitle = clone $this->mTitle;
     // Log the deletion, if the page was suppressed, put it in the suppression log instead
     $logtype = $suppress ? 'suppress' : 'delete';
     $logEntry = new ManualLogEntry($logtype, 'delete');
     $logEntry->setPerformer($user);
     $logEntry->setTarget($logTitle);
     $logEntry->setComment($reason);
     $logid = $logEntry->insert();
     $dbw->onTransactionPreCommitOrIdle(function () use($dbw, $logEntry, $logid) {
         // Bug 56776: avoid deadlocks (especially from FileDeleteForm)
         $logEntry->publish($logid);
     });
     if ($commit) {
         $dbw->commit(__METHOD__);
     }
     // Show log excerpt on 404 pages rather than just a link
     $key = wfMemcKey('page-recent-delete', md5($logTitle->getPrefixedText()));
     ObjectCache::getMainStashInstance()->set($key, 1, 86400);
     $this->doDeleteUpdates($id, $content);
     Hooks::run('ArticleDeleteComplete', array(&$this, &$user, $reason, $id, $content, $logEntry));
     $status->value = $logid;
     return $status;
 }
示例#19
0
文件: LocalFile.php 项目: paladox/2
 /**
  * Record a file upload in the upload log and the image table
  * @param string $oldver
  * @param string $comment
  * @param string $pageText
  * @param bool|array $props
  * @param string|bool $timestamp
  * @param null|User $user
  * @param string[] $tags
  * @return bool
  */
 function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null, $tags = array())
 {
     if (is_null($user)) {
         global $wgUser;
         $user = $wgUser;
     }
     $dbw = $this->repo->getMasterDB();
     # Imports or such might force a certain timestamp; otherwise we generate
     # it and can fudge it slightly to keep (name,timestamp) unique on re-upload.
     if ($timestamp === false) {
         $timestamp = $dbw->timestamp();
         $allowTimeKludge = true;
     } else {
         $allowTimeKludge = false;
     }
     $props = $props ?: $this->repo->getFileProps($this->getVirtualUrl());
     $props['description'] = $comment;
     $props['user'] = $user->getId();
     $props['user_text'] = $user->getName();
     $props['timestamp'] = wfTimestamp(TS_MW, $timestamp);
     // DB -> TS_MW
     $this->setProps($props);
     # Fail now if the file isn't there
     if (!$this->fileExists) {
         wfDebug(__METHOD__ . ": File " . $this->getRel() . " went missing!\n");
         return false;
     }
     $dbw->startAtomic(__METHOD__);
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $this->getName(), 'img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), __METHOD__, 'IGNORE');
     $reupload = $dbw->affectedRows() == 0;
     if ($reupload) {
         if ($allowTimeKludge) {
             # Use LOCK IN SHARE MODE to ignore any transaction snapshotting
             $ltimestamp = $dbw->selectField('image', 'img_timestamp', array('img_name' => $this->getName()), __METHOD__, array('LOCK IN SHARE MODE'));
             $lUnixtime = $ltimestamp ? wfTimestamp(TS_UNIX, $ltimestamp) : false;
             # Avoid a timestamp that is not newer than the last version
             # TODO: the image/oldimage tables should be like page/revision with an ID field
             if ($lUnixtime && wfTimestamp(TS_UNIX, $timestamp) <= $lUnixtime) {
                 sleep(1);
                 // fast enough re-uploads would go far in the future otherwise
                 $timestamp = $dbw->timestamp($lUnixtime + 1);
                 $this->timestamp = wfTimestamp(TS_MW, $timestamp);
                 // DB -> TS_MW
             }
         }
         # (bug 34993) Note: $oldver can be empty here, if the previous
         # version of the file was broken. Allow registration of the new
         # version to continue anyway, because that's better than having
         # an image that's not fixable by user operations.
         # Collision, this is an update of a file
         # Insert previous contents into oldimage
         $dbw->insertSelect('oldimage', 'image', array('oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes($oldver), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', 'oi_metadata' => 'img_metadata', 'oi_media_type' => 'img_media_type', 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1'), array('img_name' => $this->getName()), __METHOD__);
         # Update the current image row
         $dbw->update('image', array('img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $dbw->encodeBlob($this->metadata), 'img_sha1' => $this->sha1), array('img_name' => $this->getName()), __METHOD__);
     }
     $descTitle = $this->getTitle();
     $descId = $descTitle->getArticleID();
     $wikiPage = new WikiFilePage($descTitle);
     $wikiPage->setFile($this);
     // Add the log entry...
     $logEntry = new ManualLogEntry('upload', $reupload ? 'overwrite' : 'upload');
     $logEntry->setTimestamp($this->timestamp);
     $logEntry->setPerformer($user);
     $logEntry->setComment($comment);
     $logEntry->setTarget($descTitle);
     // Allow people using the api to associate log entries with the upload.
     // Log has a timestamp, but sometimes different from upload timestamp.
     $logEntry->setParameters(array('img_sha1' => $this->sha1, 'img_timestamp' => $timestamp));
     // Note we keep $logId around since during new image
     // creation, page doesn't exist yet, so log_page = 0
     // but we want it to point to the page we're making,
     // so we later modify the log entry.
     // For a similar reason, we avoid making an RC entry
     // now and wait until the page exists.
     $logId = $logEntry->insert();
     if ($descTitle->exists()) {
         // Use own context to get the action text in content language
         $formatter = LogFormatter::newFromEntry($logEntry);
         $formatter->setContext(RequestContext::newExtraneousContext($descTitle));
         $editSummary = $formatter->getPlainActionText();
         $nullRevision = Revision::newNullRevision($dbw, $descId, $editSummary, false, $user);
         if ($nullRevision) {
             $nullRevision->insertOn($dbw);
             Hooks::run('NewRevisionFromEditComplete', array($wikiPage, $nullRevision, $nullRevision->getParentId(), $user));
             $wikiPage->updateRevisionOn($dbw, $nullRevision);
             // Associate null revision id
             $logEntry->setAssociatedRevId($nullRevision->getId());
         }
         $newPageContent = null;
     } else {
         // Make the description page and RC log entry post-commit
         $newPageContent = ContentHandler::makeContent($pageText, $descTitle);
     }
     # Defer purges, page creation, and link updates in case they error out.
     # The most important thing is that files and the DB registry stay synced.
     $dbw->endAtomic(__METHOD__);
     # Do some cache purges after final commit so that:
     # a) Changes are more likely to be seen post-purge
     # b) They won't cause rollback of the log publish/update above
     $that = $this;
     $dbw->onTransactionIdle(function () use($that, $reupload, $wikiPage, $newPageContent, $comment, $user, $logEntry, $logId, $descId, $tags) {
         # Update memcache after the commit
         $that->invalidateCache();
         $updateLogPage = false;
         if ($newPageContent) {
             # New file page; create the description page.
             # There's already a log entry, so don't make a second RC entry
             # CDN and file cache for the description page are purged by doEditContent.
             $status = $wikiPage->doEditContent($newPageContent, $comment, EDIT_NEW | EDIT_SUPPRESS_RC, false, $user);
             if (isset($status->value['revision'])) {
                 // Associate new page revision id
                 $logEntry->setAssociatedRevId($status->value['revision']->getId());
             }
             // This relies on the resetArticleID() call in WikiPage::insertOn(),
             // which is triggered on $descTitle by doEditContent() above.
             if (isset($status->value['revision'])) {
                 /** @var $rev Revision */
                 $rev = $status->value['revision'];
                 $updateLogPage = $rev->getPage();
             }
         } else {
             # Existing file page: invalidate description page cache
             $wikiPage->getTitle()->invalidateCache();
             $wikiPage->getTitle()->purgeSquid();
             # Allow the new file version to be patrolled from the page footer
             Article::purgePatrolFooterCache($descId);
         }
         # Update associated rev id. This should be done by $logEntry->insert() earlier,
         # but setAssociatedRevId() wasn't called at that point yet...
         $logParams = $logEntry->getParameters();
         $logParams['associated_rev_id'] = $logEntry->getAssociatedRevId();
         $update = array('log_params' => LogEntryBase::makeParamBlob($logParams));
         if ($updateLogPage) {
             # Also log page, in case where we just created it above
             $update['log_page'] = $updateLogPage;
         }
         $that->getRepo()->getMasterDB()->update('logging', $update, array('log_id' => $logId), __METHOD__);
         $that->getRepo()->getMasterDB()->insert('log_search', array('ls_field' => 'associated_rev_id', 'ls_value' => $logEntry->getAssociatedRevId(), 'ls_log_id' => $logId), __METHOD__);
         # Now that the log entry is up-to-date, make an RC entry.
         $recentChange = $logEntry->publish($logId);
         if ($tags) {
             ChangeTags::addTags($tags, $recentChange ? $recentChange->getAttribute('rc_id') : null, $logEntry->getAssociatedRevId(), $logId);
         }
         # Run hook for other updates (typically more cache purging)
         Hooks::run('FileUpload', array($that, $reupload, !$newPageContent));
         if ($reupload) {
             # Delete old thumbnails
             $that->purgeThumbnails();
             # Remove the old file from the CDN cache
             DeferredUpdates::addUpdate(new CdnCacheUpdate(array($that->getUrl())), DeferredUpdates::PRESEND);
         } else {
             # Update backlink pages pointing to this title if created
             LinksUpdate::queueRecursiveJobsForTable($that->getTitle(), 'imagelinks');
         }
     });
     if (!$reupload) {
         # This is a new file, so update the image count
         DeferredUpdates::addUpdate(SiteStatsUpdate::factory(array('images' => 1)));
     }
     # Invalidate cache for all pages using this file
     DeferredUpdates::addUpdate(new HTMLCacheUpdate($this->getTitle(), 'imagelinks'));
     return true;
 }
示例#20
0
 /**
  * Move page to a title which is either a redirect to the
  * source page or nonexistent
  *
  * @param Title $nt The page to move to, which should be a redirect or nonexistent
  * @param string $reason The reason for the move
  * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check
  *   if the user has the suppressredirect right
  * @throws MWException
  */
 private function moveToInternal(&$nt, $reason = '', $createRedirect = true)
 {
     global $wgUser, $wgContLang;
     if ($nt->exists()) {
         $moveOverRedirect = true;
         $logType = 'move_redir';
     } else {
         $moveOverRedirect = false;
         $logType = 'move';
     }
     if ($createRedirect) {
         if ($this->getNamespace() == NS_CATEGORY && !wfMessage('category-move-redirect-override')->inContentLanguage()->isDisabled()) {
             $redirectContent = new WikitextContent(wfMessage('category-move-redirect-override')->params($nt->getPrefixedText())->inContentLanguage()->plain());
         } else {
             $contentHandler = ContentHandler::getForTitle($this);
             $redirectContent = $contentHandler->makeRedirectContent($nt, wfMessage('move-redirect-text')->inContentLanguage()->plain());
         }
         // NOTE: If this page's content model does not support redirects, $redirectContent will be null.
     } else {
         $redirectContent = null;
     }
     // bug 57084: log_page should be the ID of the *moved* page
     $oldid = $this->getArticleID();
     $logTitle = clone $this;
     $logEntry = new ManualLogEntry('move', $logType);
     $logEntry->setPerformer($wgUser);
     $logEntry->setTarget($logTitle);
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::target' => $nt->getPrefixedText(), '5::noredir' => $redirectContent ? '0' : '1'));
     $formatter = LogFormatter::newFromEntry($logEntry);
     $formatter->setContext(RequestContext::newExtraneousContext($this));
     $comment = $formatter->getPlainActionText();
     if ($reason) {
         $comment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason;
     }
     # Truncate for whole multibyte characters.
     $comment = $wgContLang->truncate($comment, 255);
     $dbw = wfGetDB(DB_MASTER);
     $newpage = WikiPage::factory($nt);
     if ($moveOverRedirect) {
         $newid = $nt->getArticleID();
         $newcontent = $newpage->getContent();
         # Delete the old redirect. We don't save it to history since
         # by definition if we've got here it's rather uninteresting.
         # We have to remove it so that the next step doesn't trigger
         # a conflict on the unique namespace+title index...
         $dbw->delete('page', array('page_id' => $newid), __METHOD__);
         $newpage->doDeleteUpdates($newid, $newcontent);
     }
     # Save a null revision in the page's history notifying of the move
     $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true, $wgUser);
     if (!is_object($nullRevision)) {
         throw new MWException('No valid null revision produced in ' . __METHOD__);
     }
     $nullRevision->insertOn($dbw);
     # Change the name of the target page:
     $dbw->update('page', array('page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey()), array('page_id' => $oldid), __METHOD__);
     // clean up the old title before reset article id - bug 45348
     if (!$redirectContent) {
         WikiPage::onArticleDelete($this);
     }
     $this->resetArticleID(0);
     // 0 == non existing
     $nt->resetArticleID($oldid);
     $newpage->loadPageData(WikiPage::READ_LOCKING);
     // bug 46397
     $newpage->updateRevisionOn($dbw, $nullRevision);
     wfRunHooks('NewRevisionFromEditComplete', array($newpage, $nullRevision, $nullRevision->getParentId(), $wgUser));
     $newpage->doEditUpdates($nullRevision, $wgUser, array('changed' => false));
     if (!$moveOverRedirect) {
         WikiPage::onArticleCreate($nt);
     }
     # Recreate the redirect, this time in the other direction.
     if ($redirectContent) {
         $redirectArticle = WikiPage::factory($this);
         $redirectArticle->loadFromRow(false, WikiPage::READ_LOCKING);
         // bug 46397
         $newid = $redirectArticle->insertOn($dbw);
         if ($newid) {
             // sanity
             $this->resetArticleID($newid);
             $redirectRevision = new Revision(array('title' => $this, 'page' => $newid, 'user_text' => $wgUser->getName(), 'user' => $wgUser->getId(), 'comment' => $comment, 'content' => $redirectContent));
             $redirectRevision->insertOn($dbw);
             $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
             wfRunHooks('NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false, $wgUser));
             $redirectArticle->doEditUpdates($redirectRevision, $wgUser, array('created' => true));
         }
     }
     # Log the move
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
示例#21
0
 /**
  * Process the form
  *
  * Change tags can be provided via $data['Tags'], but the calling function
  * must check if the tags can be added by the user prior to this function.
  *
  * @param array $data
  * @param IContextSource $context
  * @throws ErrorPageError
  * @return array|bool Array(message key, parameters) on failure, True on success
  */
 public static function processUnblock(array $data, IContextSource $context)
 {
     $performer = $context->getUser();
     $target = $data['Target'];
     $block = Block::newFromTarget($data['Target']);
     if (!$block instanceof Block) {
         return [['ipb_cant_unblock', $target]];
     }
     # bug 15810: blocked admins should have limited access here.  This
     # won't allow sysops to remove autoblocks on themselves, but they
     # should have ipblock-exempt anyway
     $status = SpecialBlock::checkUnblockSelf($target, $performer);
     if ($status !== true) {
         throw new ErrorPageError('badaccess', $status);
     }
     # If the specified IP is a single address, and the block is a range block, don't
     # unblock the whole range.
     list($target, $type) = SpecialBlock::getTargetAndType($target);
     if ($block->getType() == Block::TYPE_RANGE && $type == Block::TYPE_IP) {
         $range = $block->getTarget();
         return [['ipb_blocked_as_range', $target, $range]];
     }
     # If the name was hidden and the blocking user cannot hide
     # names, then don't allow any block removals...
     if (!$performer->isAllowed('hideuser') && $block->mHideName) {
         return ['unblock-hideuser'];
     }
     # Delete block
     if (!$block->delete()) {
         return ['ipb_cant_unblock', htmlspecialchars($block->getTarget())];
     }
     # Unset _deleted fields as needed
     if ($block->mHideName) {
         # Something is deeply FUBAR if this is not a User object, but who knows?
         $id = $block->getTarget() instanceof User ? $block->getTarget()->getId() : User::idFromName($block->getTarget());
         RevisionDeleteUser::unsuppressUserName($block->getTarget(), $id);
     }
     # Redact the name (IP address) for autoblocks
     if ($block->getType() == Block::TYPE_AUTO) {
         $page = Title::makeTitle(NS_USER, '#' . $block->getId());
     } else {
         $page = $block->getTarget() instanceof User ? $block->getTarget()->getUserPage() : Title::makeTitle(NS_USER, $block->getTarget());
     }
     # Make log entry
     $logEntry = new ManualLogEntry('block', 'unblock');
     $logEntry->setTarget($page);
     $logEntry->setComment($data['Reason']);
     $logEntry->setPerformer($performer);
     if (isset($data['Tags'])) {
         $logEntry->setTags($data['Tags']);
     }
     $logId = $logEntry->insert();
     $logEntry->publish($logId);
     return true;
 }
示例#22
0
 /**
  * @param User $user
  * @param string $oldModel
  * @param string $newModel
  * @param string $reason
  */
 protected function addContentModelChangeLogEntry(User $user, $oldModel, $newModel, $reason)
 {
     $log = new ManualLogEntry('contentmodel', 'change');
     $log->setPerformer($user);
     $log->setTarget($this->mTitle);
     $log->setComment($reason);
     $log->setParameters(array('4::oldmodel' => $oldModel, '5::newmodel' => $newModel));
     $logid = $log->insert();
     $log->publish($logid);
 }
示例#23
0
 /**
  * Backend implementation of doRollback(), please refer there for parameter
  * and return value documentation
  *
  * NOTE: This function does NOT check ANY permissions, it just commits the
  * rollback to the DB. Therefore, you should only call this function direct-
  * ly if you want to use custom permissions checks. If you don't, use
  * doRollback() instead.
  * @param string $fromP Name of the user whose edits to rollback.
  * @param string $summary Custom summary. Set to default summary if empty.
  * @param bool $bot If true, mark all reverted edits as bot.
  *
  * @param array $resultDetails Contains result-specific array of additional values
  * @param User $guser The user performing the rollback
  * @param array|null $tags Change tags to apply to the rollback
  * Callers are responsible for permission checks
  * (with ChangeTags::canAddTagsAccompanyingChange)
  *
  * @return array
  */
 public function commitRollback($fromP, $summary, $bot, &$resultDetails, User $guser, $tags = null)
 {
     global $wgUseRCPatrol, $wgContLang;
     $dbw = wfGetDB(DB_MASTER);
     if (wfReadOnly()) {
         return [['readonlytext']];
     }
     // Get the last editor
     $current = $this->getRevision();
     if (is_null($current)) {
         // Something wrong... no page?
         return [['notanarticle']];
     }
     $from = str_replace('_', ' ', $fromP);
     // User name given should match up with the top revision.
     // If the user was deleted then $from should be empty.
     if ($from != $current->getUserText()) {
         $resultDetails = ['current' => $current];
         return [['alreadyrolled', htmlspecialchars($this->mTitle->getPrefixedText()), htmlspecialchars($fromP), htmlspecialchars($current->getUserText())]];
     }
     // Get the last edit not by this person...
     // Note: these may not be public values
     $user = intval($current->getUser(Revision::RAW));
     $user_text = $dbw->addQuotes($current->getUserText(Revision::RAW));
     $s = $dbw->selectRow('revision', ['rev_id', 'rev_timestamp', 'rev_deleted'], ['rev_page' => $current->getPage(), "rev_user != {$user} OR rev_user_text != {$user_text}"], __METHOD__, ['USE INDEX' => 'page_timestamp', 'ORDER BY' => 'rev_timestamp DESC']);
     if ($s === false) {
         // No one else ever edited this page
         return [['cantrollback']];
     } elseif ($s->rev_deleted & Revision::DELETED_TEXT || $s->rev_deleted & Revision::DELETED_USER) {
         // Only admins can see this text
         return [['notvisiblerev']];
     }
     // Generate the edit summary if necessary
     $target = Revision::newFromId($s->rev_id, Revision::READ_LATEST);
     if (empty($summary)) {
         if ($from == '') {
             // no public user name
             $summary = wfMessage('revertpage-nouser');
         } else {
             $summary = wfMessage('revertpage');
         }
     }
     // Allow the custom summary to use the same args as the default message
     $args = [$target->getUserText(), $from, $s->rev_id, $wgContLang->timeanddate(wfTimestamp(TS_MW, $s->rev_timestamp)), $current->getId(), $wgContLang->timeanddate($current->getTimestamp())];
     if ($summary instanceof Message) {
         $summary = $summary->params($args)->inContentLanguage()->text();
     } else {
         $summary = wfMsgReplaceArgs($summary, $args);
     }
     // Trim spaces on user supplied text
     $summary = trim($summary);
     // Truncate for whole multibyte characters.
     $summary = $wgContLang->truncate($summary, 255);
     // Save
     $flags = EDIT_UPDATE | EDIT_INTERNAL;
     if ($guser->isAllowed('minoredit')) {
         $flags |= EDIT_MINOR;
     }
     if ($bot && $guser->isAllowedAny('markbotedits', 'bot')) {
         $flags |= EDIT_FORCE_BOT;
     }
     $targetContent = $target->getContent();
     $changingContentModel = $targetContent->getModel() !== $current->getContentModel();
     // Actually store the edit
     $status = $this->doEditContent($targetContent, $summary, $flags, $target->getId(), $guser, null, $tags);
     // Set patrolling and bot flag on the edits, which gets rollbacked.
     // This is done even on edit failure to have patrolling in that case (bug 62157).
     $set = [];
     if ($bot && $guser->isAllowed('markbotedits')) {
         // Mark all reverted edits as bot
         $set['rc_bot'] = 1;
     }
     if ($wgUseRCPatrol) {
         // Mark all reverted edits as patrolled
         $set['rc_patrolled'] = 1;
     }
     if (count($set)) {
         $dbw->update('recentchanges', $set, ['rc_cur_id' => $current->getPage(), 'rc_user_text' => $current->getUserText(), 'rc_timestamp > ' . $dbw->addQuotes($s->rev_timestamp)], __METHOD__);
     }
     if (!$status->isOK()) {
         return $status->getErrorsArray();
     }
     // raise error, when the edit is an edit without a new version
     $statusRev = isset($status->value['revision']) ? $status->value['revision'] : null;
     if (!$statusRev instanceof Revision) {
         $resultDetails = ['current' => $current];
         return [['alreadyrolled', htmlspecialchars($this->mTitle->getPrefixedText()), htmlspecialchars($fromP), htmlspecialchars($current->getUserText())]];
     }
     if ($changingContentModel) {
         // If the content model changed during the rollback,
         // make sure it gets logged to Special:Log/contentmodel
         $log = new ManualLogEntry('contentmodel', 'change');
         $log->setPerformer($guser);
         $log->setTarget($this->mTitle);
         $log->setComment($summary);
         $log->setParameters(['4::oldmodel' => $current->getContentModel(), '5::newmodel' => $targetContent->getModel()]);
         $logId = $log->insert($dbw);
         $log->publish($logId);
     }
     $revId = $statusRev->getId();
     Hooks::run('ArticleRollbackComplete', [$this, $guser, $target, $current]);
     $resultDetails = ['summary' => $summary, 'current' => $current, 'target' => $target, 'newid' => $revId];
     return [];
 }
 /**
  * @param string $expected Expected IRC text without colors codes
  * @param string $type Log type (move, delete, suppress, patrol ...)
  * @param string $action A log type action
  * @param array $params
  * @param string $comment (optional) A comment for the log action
  * @param string $msg (optional) A message for PHPUnit :-)
  */
 protected function assertIRCComment($expected, $type, $action, $params, $comment = null, $msg = '', $legacy = false)
 {
     $logEntry = new ManualLogEntry($type, $action);
     $logEntry->setPerformer($this->user);
     $logEntry->setTarget($this->title);
     if ($comment !== null) {
         $logEntry->setComment($comment);
     }
     $logEntry->setParameters($params);
     $logEntry->setLegacy($legacy);
     $formatter = LogFormatter::newFromEntry($logEntry);
     $formatter->setContext($this->context);
     // Apply the same transformation as done in IRCColourfulRCFeedFormatter::getLine for rc_comment
     $ircRcComment = IRCColourfulRCFeedFormatter::cleanupForIRC($formatter->getIRCActionComment());
     $this->assertEquals($expected, $ircRcComment, $msg);
 }
示例#25
0
 /**
  * Really delete the file
  *
  * @param $title Title object
  * @param File $file: file object
  * @param string $oldimage archive name
  * @param string $reason reason of the deletion
  * @param $suppress Boolean: whether to mark all deleted versions as restricted
  * @param $user User object performing the request
  * @throws MWException
  * @return bool|Status
  */
 public static function doDelete(&$title, &$file, &$oldimage, $reason, $suppress, User $user = null)
 {
     if ($user === null) {
         global $wgUser;
         $user = $wgUser;
     }
     if ($oldimage) {
         $page = null;
         $status = $file->deleteOld($oldimage, $reason, $suppress);
         if ($status->ok) {
             // Need to do a log item
             $logComment = wfMessage('deletedrevision', $oldimage)->inContentLanguage()->text();
             if (trim($reason) != '') {
                 $logComment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason;
             }
             $logtype = $suppress ? 'suppress' : 'delete';
             $logEntry = new ManualLogEntry($logtype, 'delete');
             $logEntry->setPerformer($user);
             $logEntry->setTarget($title);
             $logEntry->setComment($logComment);
             $logid = $logEntry->insert();
             $logEntry->publish($logid);
         }
     } else {
         $status = Status::newFatal('cannotdelete', wfEscapeWikiText($title->getPrefixedText()));
         $page = WikiPage::factory($title);
         $dbw = wfGetDB(DB_MASTER);
         try {
             // delete the associated article first
             $error = '';
             $deleteStatus = $page->doDeleteArticleReal($reason, $suppress, 0, false, $error, $user);
             // doDeleteArticleReal() returns a non-fatal error status if the page
             // or revision is missing, so check for isOK() rather than isGood()
             if ($deleteStatus->isOK()) {
                 $status = $file->delete($reason, $suppress);
                 if ($status->isOK()) {
                     $dbw->commit(__METHOD__);
                 } else {
                     $dbw->rollback(__METHOD__);
                 }
             }
         } catch (MWException $e) {
             // rollback before returning to prevent UI from displaying incorrect "View or restore N deleted edits?"
             $dbw->rollback(__METHOD__);
             throw $e;
         }
     }
     if ($status->isOK()) {
         wfRunHooks('FileDeleteComplete', array(&$file, &$oldimage, &$page, &$user, &$reason));
     }
     return $status;
 }
示例#26
0
 /**
  * Actually attempt the history move
  *
  * @todo if all versions of page A are moved to B and then a user
  * tries to do a reverse-merge via the "unmerge" log link, then page
  * A will still be a redirect (as it was after the original merge),
  * though it will have the old revisions back from before (as expected).
  * The user may have to "undo" the redirect manually to finish the "unmerge".
  * Maybe this should delete redirects at the source page of merges?
  *
  * @param User $user
  * @param string $reason
  * @return Status status of the history merge
  */
 public function merge(User $user, $reason = '')
 {
     $status = new Status();
     // Check validity and permissions required for merge
     $validCheck = $this->isValidMerge();
     // Check this first to check for null pages
     if (!$validCheck->isOK()) {
         return $validCheck;
     }
     $permCheck = $this->checkPermissions($user, $reason);
     if (!$permCheck->isOK()) {
         return $permCheck;
     }
     $this->dbw->update('revision', array('rev_page' => $this->dest->getArticleID()), array('rev_page' => $this->source->getArticleID(), $this->timeWhere), __METHOD__);
     // Check if this did anything
     $this->revisionsMerged = $this->dbw->affectedRows();
     if ($this->revisionsMerged < 1) {
         $status->fatal('mergehistory-fail-no-change');
         return $status;
     }
     // Make the source page a redirect if no revisions are left
     $haveRevisions = $this->dbw->selectField('revision', 'rev_timestamp', array('rev_page' => $this->source->getArticleID()), __METHOD__, array('FOR UPDATE'));
     if (!$haveRevisions) {
         if ($reason) {
             $reason = wfMessage('mergehistory-comment', $this->source->getPrefixedText(), $this->dest->getPrefixedText(), $reason)->inContentLanguage()->text();
         } else {
             $reason = wfMessage('mergehistory-autocomment', $this->source->getPrefixedText(), $this->dest->getPrefixedText())->inContentLanguage()->text();
         }
         $contentHandler = ContentHandler::getForTitle($this->source);
         $redirectContent = $contentHandler->makeRedirectContent($this->dest, wfMessage('mergehistory-redirect-text')->inContentLanguage()->plain());
         if ($redirectContent) {
             $redirectPage = WikiPage::factory($this->source);
             $redirectRevision = new Revision(array('title' => $this->source, 'page' => $this->source->getArticleID(), 'comment' => $reason, 'content' => $redirectContent));
             $redirectRevision->insertOn($this->dbw);
             $redirectPage->updateRevisionOn($this->dbw, $redirectRevision);
             // Now, we record the link from the redirect to the new title.
             // It should have no other outgoing links...
             $this->dbw->delete('pagelinks', array('pl_from' => $this->dest->getArticleID()), __METHOD__);
             $this->dbw->insert('pagelinks', array('pl_from' => $this->dest->getArticleID(), 'pl_from_namespace' => $this->dest->getNamespace(), 'pl_namespace' => $this->dest->getNamespace(), 'pl_title' => $this->dest->getDBkey()), __METHOD__);
         } else {
             // Warning if we couldn't create the redirect
             $status->warning('mergehistory-warning-redirect-not-created');
         }
     } else {
         $this->source->invalidateCache();
         // update histories
     }
     $this->dest->invalidateCache();
     // update histories
     // Update our logs
     $logEntry = new ManualLogEntry('merge', 'merge');
     $logEntry->setPerformer($user);
     $logEntry->setComment($reason);
     $logEntry->setTarget($this->source);
     $logEntry->setParameters(array('4::dest' => $this->dest->getPrefixedText(), '5::mergepoint' => $this->timestampLimit->getTimestamp(TS_MW)));
     $logId = $logEntry->insert();
     $logEntry->publish($logId);
     Hooks::run('ArticleMergeComplete', array($this->source, $this->dest));
     return $status;
 }
示例#27
0
 /**
  * Restore the given (or all) text and file revisions for the page.
  * Once restored, the items will be removed from the archive tables.
  * The deletion log will be updated with an undeletion notice.
  *
  * @param array $timestamps Pass an empty array to restore all revisions,
  *   otherwise list the ones to undelete.
  * @param string $comment
  * @param array $fileVersions
  * @param bool $unsuppress
  * @param User $user User performing the action, or null to use $wgUser
  * @return array(number of file revisions restored, number of image revisions
  *   restored, log message) on success, false on failure.
  */
 function undelete($timestamps, $comment = '', $fileVersions = array(), $unsuppress = false, User $user = null)
 {
     // If both the set of text revisions and file revisions are empty,
     // restore everything. Otherwise, just restore the requested items.
     $restoreAll = empty($timestamps) && empty($fileVersions);
     $restoreText = $restoreAll || !empty($timestamps);
     $restoreFiles = $restoreAll || !empty($fileVersions);
     if ($restoreFiles && $this->title->getNamespace() == NS_FILE) {
         $img = wfLocalFile($this->title);
         $img->load(File::READ_LATEST);
         $this->fileStatus = $img->restore($fileVersions, $unsuppress);
         if (!$this->fileStatus->isOK()) {
             return false;
         }
         $filesRestored = $this->fileStatus->successCount;
     } else {
         $filesRestored = 0;
     }
     if ($restoreText) {
         $this->revisionStatus = $this->undeleteRevisions($timestamps, $unsuppress, $comment);
         if (!$this->revisionStatus->isOK()) {
             return false;
         }
         $textRestored = $this->revisionStatus->getValue();
     } else {
         $textRestored = 0;
     }
     // Touch the log!
     if ($textRestored && $filesRestored) {
         $reason = wfMessage('undeletedrevisions-files')->numParams($textRestored, $filesRestored)->inContentLanguage()->text();
     } elseif ($textRestored) {
         $reason = wfMessage('undeletedrevisions')->numParams($textRestored)->inContentLanguage()->text();
     } elseif ($filesRestored) {
         $reason = wfMessage('undeletedfiles')->numParams($filesRestored)->inContentLanguage()->text();
     } else {
         wfDebug("Undelete: nothing undeleted...\n");
         return false;
     }
     if (trim($comment) != '') {
         $reason .= wfMessage('colon-separator')->inContentLanguage()->text() . $comment;
     }
     if ($user === null) {
         global $wgUser;
         $user = $wgUser;
     }
     $logEntry = new ManualLogEntry('delete', 'restore');
     $logEntry->setPerformer($user);
     $logEntry->setTarget($this->title);
     $logEntry->setComment($reason);
     Hooks::run('ArticleUndeleteLogEntry', array($this, &$logEntry, $user));
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
     return array($textRestored, $filesRestored, $reason);
 }
 /**
  * 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;
 }
示例#29
0
	/**
	 * Back-end article deletion
	 * Deletes the article with database consistency, writes logs, purges caches
	 *
	 * @since 1.19
	 *
	 * @param string $reason delete reason for deletion log
	 * @param $suppress boolean suppress all revisions and log the deletion in
	 *        the suppression log instead of the deletion log
	 * @param int $id article ID
	 * @param $commit boolean defaults to true, triggers transaction end
	 * @param &$error Array of errors to append to
	 * @param $user User The deleting user
	 * @return Status: Status object; if successful, $status->value is the log_id of the
	 *                 deletion log entry. If the page couldn't be deleted because it wasn't
	 *                 found, $status is a non-fatal 'cannotdelete' error
	 */
	public function doDeleteArticleReal(
		$reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
	) {
		global $wgUser, $wgContentHandlerUseDB;

		wfDebug( __METHOD__ . "\n" );

		$status = Status::newGood();

		if ( $this->mTitle->getDBkey() === '' ) {
			$status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
			return $status;
		}

		$user = is_null( $user ) ? $wgUser : $user;
		if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
			if ( $status->isOK() ) {
				// Hook aborted but didn't set a fatal status
				$status->fatal( 'delete-hook-aborted' );
			}
			return $status;
		}

		if ( $id == 0 ) {
			$this->loadPageData( 'forupdate' );
			$id = $this->getID();
			if ( $id == 0 ) {
				$status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
				return $status;
			}
		}

		// Bitfields to further suppress the content
		if ( $suppress ) {
			$bitfield = 0;
			// This should be 15...
			$bitfield |= Revision::DELETED_TEXT;
			$bitfield |= Revision::DELETED_COMMENT;
			$bitfield |= Revision::DELETED_USER;
			$bitfield |= Revision::DELETED_RESTRICTED;
		} else {
			$bitfield = 'rev_deleted';
		}

		// we need to remember the old content so we can use it to generate all deletion updates.
		$content = $this->getContent( Revision::RAW );

		$dbw = wfGetDB( DB_MASTER );
		$dbw->begin( __METHOD__ );
		// For now, shunt the revision data into the archive table.
		// Text is *not* removed from the text table; bulk storage
		// is left intact to avoid breaking block-compression or
		// immutable storage schemes.
		//
		// For backwards compatibility, note that some older archive
		// table entries will have ar_text and ar_flags fields still.
		//
		// In the future, we may keep revisions and mark them with
		// the rev_deleted field, which is reserved for this purpose.

		$row = array(
			'ar_namespace'  => 'page_namespace',
			'ar_title'      => 'page_title',
			'ar_comment'    => 'rev_comment',
			'ar_user'       => 'rev_user',
			'ar_user_text'  => 'rev_user_text',
			'ar_timestamp'  => 'rev_timestamp',
			'ar_minor_edit' => 'rev_minor_edit',
			'ar_rev_id'     => 'rev_id',
			'ar_parent_id'  => 'rev_parent_id',
			'ar_text_id'    => 'rev_text_id',
			'ar_text'       => '\'\'', // Be explicit to appease
			'ar_flags'      => '\'\'', // MySQL's "strict mode"...
			'ar_len'        => 'rev_len',
			'ar_page_id'    => 'page_id',
			'ar_deleted'    => $bitfield,
			'ar_sha1'       => 'rev_sha1',
		);

		if ( $wgContentHandlerUseDB ) {
			$row['ar_content_model'] = 'rev_content_model';
			$row['ar_content_format'] = 'rev_content_format';
		}

		$dbw->insertSelect( 'archive', array( 'page', 'revision' ),
			$row,
			array(
				'page_id' => $id,
				'page_id = rev_page'
			), __METHOD__
		);

		// Now that it's safely backed up, delete it
		$dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ );
		$ok = ( $dbw->affectedRows() > 0 ); // $id could be laggy

		if ( !$ok ) {
			$dbw->rollback( __METHOD__ );
			$status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
			return $status;
		}

		if ( !$dbw->cascadingDeletes() ) {
			$dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
		}

		$this->doDeleteUpdates( $id, $content );

		// Log the deletion, if the page was suppressed, log it at Oversight instead
		$logtype = $suppress ? 'suppress' : 'delete';

		$logEntry = new ManualLogEntry( $logtype, 'delete' );
		$logEntry->setPerformer( $user );
		$logEntry->setTarget( $this->mTitle );
		$logEntry->setComment( $reason );
		$logid = $logEntry->insert();
		$logEntry->publish( $logid );

		if ( $commit ) {
			$dbw->commit( __METHOD__ );
		}

		wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
		$status->value = $logid;
		return $status;
	}
 /**
  * @param Title $title
  * @param ForeignTitle $foreignTitle
  * @param int $revisionCount
  * @param int $successCount
  * @param array $pageInfo
  * @return void
  */
 function reportPage($title, $foreignTitle, $revisionCount, $successCount, $pageInfo)
 {
     $args = func_get_args();
     call_user_func_array($this->mOriginalPageOutCallback, $args);
     if ($title === null) {
         # Invalid or non-importable title; a notice is already displayed
         return;
     }
     $this->mPageCount++;
     if ($successCount > 0) {
         $this->getOutput()->addHTML("<li>" . Linker::linkKnown($title) . " " . $this->msg('import-revision-count')->numParams($successCount)->escaped() . "</li>\n");
         if ($this->mIsUpload) {
             $detail = $this->msg('import-logentry-upload-detail')->numParams($successCount)->inContentLanguage()->text();
             if ($this->reason) {
                 $detail .= $this->msg('colon-separator')->inContentLanguage()->text() . $this->reason;
             }
             $action = 'upload';
         } else {
             $interwiki = '[[:' . $this->mInterwiki . ':' . $foreignTitle->getFullText() . ']]';
             $detail = $this->msg('import-logentry-interwiki-detail')->numParams($successCount)->params($interwiki)->inContentLanguage()->text();
             if ($this->reason) {
                 $detail .= $this->msg('colon-separator')->inContentLanguage()->text() . $this->reason;
             }
             $action = 'interwiki';
         }
         $logEntry = new ManualLogEntry('import', $action);
         $logEntry->setTarget($title);
         $logEntry->setComment($detail);
         $logEntry->setPerformer($this->getUser());
         $logid = $logEntry->insert();
         $logEntry->publish($logid);
         $comment = $detail;
         // quick
         $dbw = wfGetDB(DB_MASTER);
         $latest = $title->getLatestRevID();
         $nullRevision = Revision::newNullRevision($dbw, $title->getArticleID(), $comment, true, $this->getUser());
         if (!is_null($nullRevision)) {
             $nullRevision->insertOn($dbw);
             $page = WikiPage::factory($title);
             # Update page record
             $page->updateRevisionOn($dbw, $nullRevision);
             Hooks::run('NewRevisionFromEditComplete', array($page, $nullRevision, $latest, $this->getUser()));
         }
     } else {
         $this->getOutput()->addHTML("<li>" . Linker::linkKnown($title) . " " . $this->msg('import-nonewrevisions')->escaped() . "</li>\n");
     }
 }