/** * Display a message to the user if (a) "blank if unapproved" is set, * (b) the page is approvable, (c) the user has 'viewlinktolatest' * permission, and (d) either the page has no approved revision, or * the user is looking at a revision that's not the latest - the * displayed message depends on which of those cases it is. * @TODO - this should probably get split up into two methods. * * @since 0.5.6 * * @param Article &$article * @param boolean $outputDone * @param boolean $useParserCache * * @return true */ public static function setArticleHeader(Article &$article, &$outputDone, &$useParserCache) { global $wgOut, $wgRequest, $egApprovedRevsBlankIfUnapproved; // For now, we only set the header if "blank if unapproved" // is set. if (!$egApprovedRevsBlankIfUnapproved) { return true; } $title = $article->getTitle(); if (!ApprovedRevs::pageIsApprovable($title)) { return true; } // If the user isn't supposed to see these kinds of // messages, exit. if (!$title->userCan('viewlinktolatest')) { return false; } // If there's an approved revision for this page, and the // user is looking at it - either by simply going to the page, // or by looking at the revision that happens to be approved - // don't display anything. $approvedRevID = ApprovedRevs::getApprovedRevID($title); if (!empty($approvedRevID) && (!$wgRequest->getCheck('oldid') || $wgRequest->getInt('oldid') == $approvedRevID)) { return true; } // Disable caching, so that if it's a specific ID being shown // that happens to be the latest, it doesn't show a blank page. $useParserCache = false; $wgOut->addHTML('<span style="margin-left: 10.75px">'); // If the user is looking at a specific revision, show an // "approve this revision" message - otherwise, it means // there's no approved revision (we would have exited out if // there were), so show a message explaining why the page is // blank, with a link to the latest revision. if ($wgRequest->getCheck('oldid')) { if (ApprovedRevs::userCanApprove($title)) { // @TODO - why is this message being shown // at all? Aren't the "approve this revision" // links in the history page always good // enough? $wgOut->addHTML(Xml::tags('span', array('id' => 'contentSub2'), Xml::element('a', array('href' => $title->getLocalUrl(array('action' => 'approve', 'oldid' => $wgRequest->getInt('oldid')))), wfMessage('approvedrevs-approvethisrev')->text()))); } } else { $wgOut->addSubtitle(htmlspecialchars(wfMessage('approvedrevs-blankpageshown')->text()) . ' ' . Xml::element('a', array('href' => $title->getLocalUrl(array('oldid' => $article->getRevIdFetched()))), wfMessage('approvedrevs-viewlatestrev')->text())); } $wgOut->addHTML('</span>'); return true; }
/** * Hook to insert things into article headers. * * @since 0.5.6 * * @param Article &$article * @param boolean $outputDone * @param boolean $useParserCache * * @return true */ public static function onArticleViewHeader(Article &$article, &$outputDone, &$useParserCache) { global $wgOut, $wgRequest, $egApprovedRevsBlankIfUnapproved; if (ApprovedRevs::pageIsApprovable($article->getTitle()) && $article->getTitle()->userCan('approverevisions')) { $approvedId = ApprovedRevs::getApprovedRevID($article->getTitle()); if ($egApprovedRevsBlankIfUnapproved && (empty($approvedId) || $wgRequest->getCheck('oldid') && $wgRequest->getInt('oldid') != $approvedId)) { $wgOut->addHTML('<span style="margin-left:10.75px">'); if ($wgRequest->getCheck('oldid')) { $wgOut->addHTML(Xml::tags('span', array('id' => 'contentSub2'), Xml::element('a', array('href' => $article->getTitle()->getLocalUrl(array('action' => 'approve', 'oldid' => $wgRequest->getInt('oldid')))), wfMsg('approvedrevs-approvethisrev')))); } else { $wgOut->appendSubtitle(htmlspecialchars(wfMsg('approvedrevs-blankpageshown')) . ' ' . Xml::element('a', array('href' => $article->getTitle()->getLocalUrl(array('oldid' => $article->getRevIdFetched()))), wfMsg('approvedrevs-viewlatestrev'))); } $wgOut->addHTML('</span>'); } } return true; }
/** * Send the edit form and related headers to $wgOut * @param callable|null $formCallback That takes an OutputPage parameter; will be called * during form output near the top, for captchas and the like. * * The $formCallback parameter is deprecated since MediaWiki 1.25. Please * use the EditPage::showEditForm:fields hook instead. */ function showEditForm($formCallback = null) { global $wgOut, $wgUser; # need to parse the preview early so that we know which templates are used, # otherwise users with "show preview after edit box" will get a blank list # we parse this near the beginning so that setHeaders can do the title # setting work instead of leaving it in getPreviewText $previewOutput = ''; if ($this->formtype == 'preview') { $previewOutput = $this->getPreviewText(); } Hooks::run('EditPage::showEditForm:initial', array(&$this, &$wgOut)); $this->setHeaders(); if ($this->showHeader() === false) { return; } $wgOut->addHTML($this->editFormPageTop); if ($wgUser->getOption('previewontop')) { $this->displayPreviewArea($previewOutput, true); } $wgOut->addHTML($this->editFormTextTop); $showToolbar = true; if ($this->wasDeletedSinceLastEdit()) { if ($this->formtype == 'save') { // Hide the toolbar and edit area, user can click preview to get it back // Add an confirmation checkbox and explanation. $showToolbar = false; } else { $wgOut->wrapWikiMsg("<div class='error mw-deleted-while-editing'>\n\$1\n</div>", 'deletedwhileediting'); } } // @todo add EditForm plugin interface and use it here! // search for textarea1 and textares2, and allow EditForm to override all uses. $wgOut->addHTML(Html::openElement('form', array('id' => self::EDITFORM_ID, 'name' => self::EDITFORM_ID, 'method' => 'post', 'action' => $this->getActionURL($this->getContextTitle()), 'enctype' => 'multipart/form-data'))); if (is_callable($formCallback)) { wfWarn('The $formCallback parameter to ' . __METHOD__ . 'is deprecated'); call_user_func_array($formCallback, array(&$wgOut)); } // Add an empty field to trip up spambots $wgOut->addHTML(Xml::openElement('div', array('id' => 'antispam-container', 'style' => 'display: none;')) . Html::rawElement('label', array('for' => 'wpAntiSpam'), wfMessage('simpleantispam-label')->parse()) . Xml::element('input', array('type' => 'text', 'name' => 'wpAntispam', 'id' => 'wpAntispam', 'value' => '')) . Xml::closeElement('div')); Hooks::run('EditPage::showEditForm:fields', array(&$this, &$wgOut)); // Put these up at the top to ensure they aren't lost on early form submission $this->showFormBeforeText(); if ($this->wasDeletedSinceLastEdit() && 'save' == $this->formtype) { $username = $this->lastDelete->user_name; $comment = $this->lastDelete->log_comment; // It is better to not parse the comment at all than to have templates expanded in the middle // TODO: can the checkLabel be moved outside of the div so that wrapWikiMsg could be used? $key = $comment === '' ? 'confirmrecreate-noreason' : 'confirmrecreate'; $wgOut->addHTML('<div class="mw-confirm-recreate">' . wfMessage($key, $username, "<nowiki>{$comment}</nowiki>")->parse() . Xml::checkLabel(wfMessage('recreate')->text(), 'wpRecreate', 'wpRecreate', false, array('title' => Linker::titleAttrib('recreate'), 'tabindex' => 1, 'id' => 'wpRecreate')) . '</div>'); } # When the summary is hidden, also hide them on preview/show changes if ($this->nosummary) { $wgOut->addHTML(Html::hidden('nosummary', true)); } # If a blank edit summary was previously provided, and the appropriate # user preference is active, pass a hidden tag as wpIgnoreBlankSummary. This will stop the # user being bounced back more than once in the event that a summary # is not required. # #### # For a bit more sophisticated detection of blank summaries, hash the # automatic one and pass that in the hidden field wpAutoSummary. if ($this->missingSummary || $this->section == 'new' && $this->nosummary) { $wgOut->addHTML(Html::hidden('wpIgnoreBlankSummary', true)); } if ($this->undidRev) { $wgOut->addHTML(Html::hidden('wpUndidRevision', $this->undidRev)); } if ($this->selfRedirect) { $wgOut->addHTML(Html::hidden('wpIgnoreSelfRedirect', true)); } if ($this->hasPresetSummary) { // If a summary has been preset using &summary= we don't want to prompt for // a different summary. Only prompt for a summary if the summary is blanked. // (Bug 17416) $this->autoSumm = md5(''); } $autosumm = $this->autoSumm ? $this->autoSumm : md5($this->summary); $wgOut->addHTML(Html::hidden('wpAutoSummary', $autosumm)); $wgOut->addHTML(Html::hidden('oldid', $this->oldid)); $wgOut->addHTML(Html::hidden('parentRevId', $this->parentRevId ?: $this->mArticle->getRevIdFetched())); $wgOut->addHTML(Html::hidden('format', $this->contentFormat)); $wgOut->addHTML(Html::hidden('model', $this->contentModel)); if ($this->section == 'new') { $this->showSummaryInput(true, $this->summary); $wgOut->addHTML($this->getSummaryPreview(true, $this->summary)); } $wgOut->addHTML($this->editFormTextBeforeContent); if (!$this->isCssJsSubpage && $showToolbar && $wgUser->getOption('showtoolbar')) { $wgOut->addHTML(EditPage::getEditToolbar($this->mTitle)); } if ($this->blankArticle) { $wgOut->addHTML(Html::hidden('wpIgnoreBlankArticle', true)); } if ($this->isConflict) { // In an edit conflict bypass the overridable content form method // and fallback to the raw wpTextbox1 since editconflicts can't be // resolved between page source edits and custom ui edits using the // custom edit ui. $this->textbox2 = $this->textbox1; $content = $this->getCurrentContent(); $this->textbox1 = $this->toEditText($content); $this->showTextbox1(); } else { $this->showContentForm(); } $wgOut->addHTML($this->editFormTextAfterContent); $this->showStandardInputs(); $this->showFormAfterText(); $this->showTosSummary(); $this->showEditTools(); $wgOut->addHTML($this->editFormTextAfterTools . "\n"); $wgOut->addHTML(Html::rawElement('div', array('class' => 'templatesUsed'), Linker::formatTemplates($this->getTemplates(), $this->preview, $this->section != ''))); $wgOut->addHTML(Html::rawElement('div', array('class' => 'hiddencats'), Linker::formatHiddenCategories($this->mArticle->getHiddenCategories()))); $wgOut->addHTML(Html::rawElement('div', array('class' => 'limitreport'), self::getPreviewLimitReport($this->mParserOutput))); $wgOut->addModules('mediawiki.action.edit.collapsibleFooter'); if ($this->isConflict) { try { $this->showConflict(); } catch (MWContentSerializationException $ex) { // this can't really happen, but be nice if it does. $msg = wfMessage('content-failed-to-parse', $this->contentModel, $this->contentFormat, $ex->getMessage()); $wgOut->addWikiText('<div class="error">' . $msg->text() . '</div>'); } } // Marker for detecting truncated form data. This must be the last // parameter sent in order to be of use, so do not move me. $wgOut->addHTML(Html::hidden('wpUltimateParam', true)); $wgOut->addHTML($this->editFormTextBottom . "\n</form>\n"); if (!$wgUser->getOption('previewontop')) { $this->displayPreviewArea($previewOutput, false); } }
/** * Get the edit's parent revision ID * * The "parent" revision is the ancestor that should be recorded in this * page's revision history. It is either the revision ID of the in-memory * article content, or in the case of a 3-way merge in order to rebase * across a recoverable edit conflict, the ID of the newer revision to * which we have rebased this page. * * @since 1.27 * @return int Revision ID */ public function getParentRevId() { if ($this->parentRevId) { return $this->parentRevId; } else { return $this->mArticle->getRevIdFetched(); } }
/** * Display a message * * @since 0.5.6 * * @param Article &$article * @param boolean $outputDone * @param boolean $useParserCache * * @return true */ public static function setArticleHeader(Article &$article, &$outputDone, &$useParserCache) { global $wgOut, $wgRequest, $egApprovedRevsBlankIfUnapproved; // For now, we only set the header if "blank if unapproved" // is set. if (!$egApprovedRevsBlankIfUnapproved) { return true; } $title = $article->getTitle(); if (!ApprovedRevs::pageIsApprovable($title)) { return true; } if (!ApprovedRevs::userCanApprove($title)) { return true; } $approvedRevID = ApprovedRevs::getApprovedRevID($title); if (!empty($approvedRevID) && !($wgRequest->getCheck('oldid') && $wgRequest->getInt('oldid') == $approvedRevID)) { return true; } // Disable caching, so that if it's a specific ID being shown // that happens to be the latest, it doesn't show a blank page. $useParserCache = false; $wgOut->addHTML('<span style="margin-left: 10.75px">'); if ($wgRequest->getCheck('oldid')) { $wgOut->addHTML(Xml::tags('span', array('id' => 'contentSub2'), Xml::element('a', array('href' => $title->getLocalUrl(array('action' => 'approve', 'oldid' => $wgRequest->getInt('oldid')))), wfMsg('approvedrevs-approvethisrev')))); } else { $wgOut->appendSubtitle(htmlspecialchars(wfMsg('approvedrevs-blankpageshown')) . ' ' . Xml::element('a', array('href' => $title->getLocalUrl(array('oldid' => $article->getRevIdFetched()))), wfMsg('approvedrevs-viewlatestrev'))); } $wgOut->addHTML('</span>'); return true; }
private function createTargetTalkPages() { for ($m = 0; $m < count($this->data); $m++) { // create talk page $talkRevids = array(); $found = false; for ($p = 0; $p < count($this->data[$m]); $p++) { if ($this->data[$m][$p]['talkrevid']) { $found = true; break; } } if ($found && !$this->data[$m][0]['talkrevid']) { $mergeTargetTalkTitle = Title::newFromText($this->data[$m][0]['title'], $this->namespace == 'Family' && $m == 0 ? NS_FAMILY_TALK : NS_PERSON_TALK); $article = new Article($mergeTargetTalkTitle, 0); if ($article) { $article->doEdit('', 'Create page in preparation for merge', EDIT_NEW); $this->data[$m][0]['talkrevid'] = $article->getRevIdFetched(); } } } }
function writeOutput($par) { global $wgUser, $wgOut, $wgLang, $wgTitle, $wgMemc, $wgDBname; global $wgRequest, $wgSitename, $wgLanguageCode; global $wgFeedClasses, $wgFilterCallback, $wgWhitelistEdit, $wgParser; wfLoadExtensionMessages('Postcomment'); $wgOut->setRobotpolicy("noindex,nofollow"); $fname = "wfSpecialPostcomment"; //echo "topic: " . $wgRequest->getVal("topic_name") . "<BR>"; //echo "title: " . $wgRequest->getVal("title") . "<BR>"; //echo "comment: " . $wgRequest->getVal("comment_text") . "<BR>"; //echo "new_topic id " . $wgRequest->getVal("new_topic") . "<BR>"; $target = !empty($par) ? $par : $wgRequest->getVal("target"); $t = Title::newFromDBKey($target); $update = true; if (!$t || !$t->userCanEdit()) { return; } if (!$wgUser->isAllowed('edit')) { return; } if ($t == null) { $wgOut->errorPage('postcomment', 'postcomment_invalidrequest'); return; } $article = new Article($t); $user = $wgUser->getName(); $real_name = User::whoIsReal($wgUser->getID()); if ($real_name == "") { $real_name = $user; } $dateStr = $wgLang->timeanddate(wfTimestampNow()); $comment = $wgRequest->getVal("comment_text"); foreach ($wgRequest->getValues() as $key => $value) { if (strpos($key, "comment_text") === 0) { $comment = $value; break; } } $topic = $wgRequest->getVal("topic_name"); //echo "$dateStr<br/>"; // remove leading space, tends to be a problem with a lot of talk page comments as it breaks the // HTML on the page $comment = preg_replace('/\\n[ ]*/', "\n", trim($comment)); // Check to see if the user is also getting a thumbs up. If so, append the thumbs message and give a thumbs up if ($wgRequest->getVal('thumb')) { $comment .= "\n\n" . wfMsg('qn_thumbs_up'); $userName = explode(":", $wgRequest->getVal('target')); ThumbsUp::quickNoteThumb($wgRequest->getVal('revold'), $wgRequest->getVal('revnew'), $wgRequest->getVal('pageid'), $userName[1]); } $formattedComment = wfMsg('postcomment_formatted_comment', $dateStr, $user, $real_name, $comment); if ($wgRequest->getVal('fromajax') == 'true') { $wgOut->setArticleBodyOnly(true); } $text = ""; $r = Revision::newFromTitle($t); if ($r) { $text = $r->getText(); } $text .= "\n\n{$formattedComment}\n\n"; $wgOut->setStatusCode(500); //echo "updating with text:<br/> $text"; //exit; $tmp = ""; if ($wgUser->isBlocked()) { $wgOut->blockedPage(); return; } if (!$wgUser->getID() && $wgWhitelistEdit) { $this->userNotLoggedInPage(); return; } if (wfReadOnly()) { $wgOut->readOnlyPage(); return; } if ($target == "Spam-Blacklist") { $wgOut->readOnlyPage(); return; } if ($wgUser->pingLimiter()) { $wgOut->rateLimited(); return; } if ($wgFilterCallback && $wgFilterCallback($t, $text, $tmp)) { # Error messages or other handling should be performed by the filter function return; } $matches = array(); $preg = "/http:\\/\\/[^] \n'\">]*/"; $mod = str_ireplace('http://www.wikihow.com', '', $comment); preg_match_all($preg, $mod, $matches); if (sizeof($matches[0]) > 2) { $wgOut->errorPage("postcomment", "postcomment_urls_limit"); return; } if (trim(strip_tags($comment)) == "") { $wgOut->errorpage("postcomment", "postcomment_nopostingtoadd"); return; } if (!$t->userCanEdit()) { $wgOut->errorpage("postcomment", "postcomment_discussionprotected"); return; } $watch = false; if ($wgUser->getID() > 0) { $watch = $wgUser->isWatched($t); } $fc = new FancyCaptcha(); $pass_captcha = $fc->passCaptcha(); if (!$pass_captcha && $wgUser->getID() == 0) { $wgOut->addHTML("Sorry, please enter the correct word. Click <a onclick='window.location.reload(true);'>here</a> to get a new one.<br/><br/>"); return; } $article->doEdit($text, ""); if ($wgRequest->getVal('jsonresponse') == 'true') { $article->loadLastEdit(true); $this->revId = $article->getRevIdFetched(); } //XX Vu added to notify users of usertalk updates if ($t->getNamespace() == NS_USER_TALK) { AuthorEmailNotification::notifyUserTalk($t->getArticleID(), $wgUser->getID(), $comment); } $wgOut->setStatusCode(200); if ($wgRequest->getVal('fromajax') == 'true') { $wgOut->redirect(''); $wgTitle = $t; $formattedComment = $wgParser->preSaveTransform($formattedComment, $t, $wgUser, new ParserOptions()); $wgOut->addHTML($wgOut->parse("\n" . $formattedComment)); return; } }
public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) { $this->dieUsageMsg(array('missingtext')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } if ($params['redirect']) { if ($titleObj->isRedirect()) { $oldTitle = $titleObj; $titles = Title::newFromRedirectArray(Revision::newFromTitle($oldTitle)->getText(Revision::FOR_THIS_USER)); $redirValues = array(); foreach ($titles as $id => $newTitle) { if (!isset($titles[$id - 1])) { $titles[$id - 1] = $oldTitle; } $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText()); $titleObj = $newTitle; } $this->getResult()->setIndexedTagName($redirValues, 'r'); $this->getResult()->addValue(null, 'redirects', $redirValues); } } // Some functions depend on $wgTitle == $ep->mTitle global $wgTitle; $wgTitle = $titleObj; if ($params['createonly'] && $titleObj->exists()) { $this->dieUsageMsg(array('createonly-exists')); } if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg(array('nocreate-missing')); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $articleObj = new Article($titleObj); $toMD5 = $params['text']; if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) { // For non-existent pages, Article::getContent() // returns an interface message rather than '' // We do want getContent()'s behavior for non-existent // MediaWiki: pages, though if ($articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI) { $content = ''; } else { $content = $articleObj->getContent(); } if (!is_null($params['section'])) { // Process the content for section edits global $wgParser; $section = intval($params['section']); $content = $wgParser->getSection($content, $section, false); if ($content === false) { $this->dieUsage("There is no section {$section}.", 'nosuchsection'); } } $params['text'] = $params['prependtext'] . $content . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } if ($params['undo'] > 0) { if ($params['undoafter'] > 0) { if ($params['undo'] < $params['undoafter']) { list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']); } $undoafterRev = Revision::newFromID($params['undoafter']); } $undoRev = Revision::newFromID($params['undo']); if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undo'])); } if ($params['undoafter'] == 0) { $undoafterRev = $undoRev->getPrevious(); } if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undoafter'])); } if ($undoRev->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText())); } if ($undoafterRev->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText())); } $newtext = $articleObj->getUndoText($undoRev, $undoafterRev); if ($newtext === false) { $this->dieUsageMsg(array('undo-failure')); } $params['text'] = $newtext; // If no summary was given and we only undid one rev, // use an autosummary if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) { $params['summary'] = wfMsgForContent('undo-summary', $params['undo'], $undoRev->getUserText()); } } // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg(array('hashcheckfailed')); } $ep = new EditPage($articleObj); // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $reqArr = array('wpTextbox1' => $params['text'], 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => ''); if (!is_null($params['summary'])) { $reqArr['wpSummary'] = $params['summary']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $reqArr['wpEdittime'] = $articleObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $reqArr['wpStarttime'] = wfTimestampNow(); // Fake wpStartime } if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) { $reqArr['wpMinoredit'] = ''; } if ($params['recreate']) { $reqArr['wpRecreate'] = ''; } if (!is_null($params['section'])) { $section = intval($params['section']); if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') { $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection"); } $reqArr['wpSection'] = $params['section']; } else { $reqArr['wpSection'] = ''; } $watch = $this->getWatchlistValue($params['watchlist'], $titleObj); // Deprecated parameters if ($params['watch']) { $watch = true; } elseif ($params['unwatch']) { $watch = false; } if ($watch) { $reqArr['wpWatchthis'] = ''; } $req = new FauxRequest($reqArr, true); $ep->importFormData($req); // Run hooks // Handle CAPTCHA parameters global $wgRequest; if (!is_null($params['captchaid'])) { $wgRequest->setVal('wpCaptchaId', $params['captchaid']); } if (!is_null($params['captchaword'])) { $wgRequest->setVal('wpCaptchaWord', $params['captchaword']); } $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = 'Failure'; $this->getResult()->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg(array('hookaborted')); } } // Do the actual save $oldRevId = $articleObj->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; global $wgMaxArticleSize; switch ($retval) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg(array('hookaborted')); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg(array('noimageredirect-anon')); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg(array('noimageredirect-logged')); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_FILTERING: $this->dieUsageMsg(array('filtered')); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg(array('blockedtext')); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg(array('noedit-anon')); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg(array('noedit')); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg(array('actionthrottledtext')); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg(array('wasdeleted')); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg(array('nocreate-loggedin')); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg(array('blankpage')); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg(array('editconflict')); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg(array('emptynewsection')); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = 'Success'; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); // HACK: We create a new Article object here because getRevIdFetched() // refuses to be run twice, and because Title::getLatestRevId() // won't fetch from the master unless we select for update, which we // don't want to do. $newArticle = new Article($titleObj); $newRevId = $newArticle->getRevIdFetched(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp()); } break; case EditPage::AS_SUMMARY_NEEDED: $this->dieUsageMsg(array('summaryrequired')); case EditPage::AS_END: // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned default: $this->dieUsageMsg(array('unknownerror', $retval)); } $this->getResult()->addValue(null, $this->getModuleName(), $r); }
public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) { $this->dieUsageMsg('missingtext'); } $pageObj = $this->getTitleOrPageId($params); $titleObj = $pageObj->getTitle(); if ($titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } if (!isset($params['contentmodel']) || $params['contentmodel'] == '') { $contentHandler = $pageObj->getContentHandler(); } else { $contentHandler = ContentHandler::getForModelID($params['contentmodel']); } // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such if (!isset($params['contentformat']) || $params['contentformat'] == '') { $params['contentformat'] = $contentHandler->getDefaultFormat(); } $contentFormat = $params['contentformat']; if (!$contentHandler->isSupportedFormat($contentFormat)) { $name = $titleObj->getPrefixedDBkey(); $model = $contentHandler->getModelID(); $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat'); } $apiResult = $this->getResult(); if ($params['redirect']) { if ($titleObj->isRedirect()) { $oldTitle = $titleObj; $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain(); // array_shift( $titles ); $redirValues = array(); foreach ($titles as $id => $newTitle) { if (!isset($titles[$id - 1])) { $titles[$id - 1] = $oldTitle; } $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText()); $titleObj = $newTitle; } $apiResult->setIndexedTagName($redirValues, 'r'); $apiResult->addValue(null, 'redirects', $redirValues); } } if ($params['createonly'] && $titleObj->exists()) { $this->dieUsageMsg('createonly-exists'); } if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg('nocreate-missing'); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $user); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $toMD5 = $params['text']; if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) { $content = $pageObj->getContent(); if (!$content) { if ($titleObj->getNamespace() == NS_MEDIAWIKI) { # If this is a MediaWiki:x message, then load the messages # and return the message value for x. $text = $titleObj->getDefaultMessageText(); if ($text === false) { $text = ''; } try { $content = ContentHandler::makeContent($text, $this->getTitle()); } catch (MWContentSerializationException $ex) { $this->dieUsage($ex->getMessage(), 'parseerror'); return; } } else { # Otherwise, make a new empty content. $content = $contentHandler->makeEmptyContent(); } } // @todo: Add support for appending/prepending to the Content interface if (!$content instanceof TextContent) { $mode = $contentHandler->getModelID(); $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported'); } if (!is_null($params['section'])) { if (!$contentHandler->supportsSections()) { $modelName = $contentHandler->getModelID(); $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported'); } // Process the content for section edits $section = intval($params['section']); $content = $content->getSection($section); if (!$content) { $this->dieUsage("There is no section {$section}.", 'nosuchsection'); } } if (!$content) { $text = ''; } else { $text = $content->serialize($contentFormat); } $params['text'] = $params['prependtext'] . $text . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } if ($params['undo'] > 0) { if ($params['undoafter'] > 0) { if ($params['undo'] < $params['undoafter']) { list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']); } $undoafterRev = Revision::newFromID($params['undoafter']); } $undoRev = Revision::newFromID($params['undo']); if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undo'])); } if ($params['undoafter'] == 0) { $undoafterRev = $undoRev->getPrevious(); } if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['undoafter'])); } if ($undoRev->getPage() != $pageObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText())); } if ($undoafterRev->getPage() != $pageObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText())); } $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev); if (!$newContent) { $this->dieUsageMsg('undo-failure'); } $params['text'] = $newContent->serialize($params['contentformat']); // If no summary was given and we only undid one rev, // use an autosummary if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) { $params['summary'] = wfMessage('undo-summary', $params['undo'], $undoRev->getUserText())->inContentLanguage()->text(); } } // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg('hashcheckfailed'); } // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => ''); if (!is_null($params['summary'])) { $requestArray['wpSummary'] = $params['summary']; } if (!is_null($params['sectiontitle'])) { $requestArray['wpSectionTitle'] = $params['sectiontitle']; } // TODO: Pass along information from 'undoafter' as well if ($params['undo'] > 0) { $requestArray['wpUndidRevision'] = $params['undo']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $requestArray['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $requestArray['wpEdittime'] = $pageObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $requestArray['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime } if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) { $requestArray['wpMinoredit'] = ''; } if ($params['recreate']) { $requestArray['wpRecreate'] = ''; } if (!is_null($params['section'])) { $section = intval($params['section']); if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') { $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection"); } $requestArray['wpSection'] = $params['section']; } else { $requestArray['wpSection'] = ''; } $watch = $this->getWatchlistValue($params['watchlist'], $titleObj); // Deprecated parameters if ($params['watch']) { $watch = true; } elseif ($params['unwatch']) { $watch = false; } if ($watch) { $requestArray['wpWatchthis'] = ''; } global $wgTitle, $wgRequest; $req = new DerivativeRequest($this->getRequest(), $requestArray, true); // Some functions depend on $wgTitle == $ep->mTitle // TODO: Make them not or check if they still do $wgTitle = $titleObj; $articleObject = new Article($titleObj); $ep = new EditPage($articleObject); // allow editing of non-textual content. $ep->allowNonTextContent = true; $ep->setContextTitle($titleObj); $ep->importFormData($req); // Run hooks // Handle APIEditBeforeSave parameters $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = 'Failure'; $apiResult->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg('hookaborted'); } } // Do the actual save $oldRevId = $articleObject->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // @todo FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $status = $ep->internalAttemptSave($result, $user->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; global $wgMaxArticleSize; switch ($status->value) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg('hookaborted'); case EditPage::AS_PARSE_ERROR: $this->dieUsage($status->getMessage(), 'parseerror'); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg('noimageredirect-anon'); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg('noimageredirect-logged'); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg('blockedtext'); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg('noedit-anon'); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg('noedit'); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg('actionthrottledtext'); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg('wasdeleted'); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg('nocreate-loggedin'); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg('blankpage'); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg('editconflict'); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg('emptynewsection'); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = 'Success'; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); $r['contentmodel'] = $titleObj->getContentModel(); $newRevId = $articleObject->getLatest(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp()); } break; case EditPage::AS_SUMMARY_NEEDED: $this->dieUsageMsg('summaryrequired'); case EditPage::AS_END: default: // $status came from WikiPage::doEdit() $errors = $status->getErrorsArray(); $this->dieUsageMsg($errors[0]); // TODO: Add new errors to message map break; } $apiResult->addValue(null, $this->getModuleName(), $r); }
/** *Integrates the operation(LogootOp) into the article via the logoot algorithm * * @param <Object> $operation * @param <String or Object> $article */ function logootIntegrate($operations, $article) { global $wgCanonicalNamespaceNames; $indexNS = 0; wfDebugLog('p2p', '@@@@@@@@@@@@@@@@@@@@@@@ - function logootIntegrate : ' . $article); $dbr = wfGetDB(DB_SLAVE); $dbr->immediateBegin(); if (is_string($article)) { //if there is a space in the title, repalce by '_' $article = str_replace(" ", "_", $article); if (strpos($article, ":") === false) { $pageid = $dbr->selectField('page', 'page_id', array('page_title' => $article)); } else { //if there is a namespace preg_match("/^(.+?)_*:_*(.*)\$/S", $article, $tmp); $articleWithoutNS = $tmp[2]; $NS = $tmp[1]; if (in_array($NS, $wgCanonicalNamespaceNames)) { foreach ($wgCanonicalNamespaceNames as $key => $value) { if ($NS == $value) { $indexNS = $key; } } } $pageid = $dbr->selectField('page', 'page_id', array('page_title' => $articleWithoutNS, 'page_namespace' => $indexNS)); } // get the page namespace $pageNameSpace = $dbr->selectField('page', 'page_namespace', array('page_id' => $pageid)); /*the ns must not be a pullfeed, pushfeed, changeset or patch namespace. If the page name is the same in different ns we can get the wrong * page id */ if ($pageNameSpace == PULLFEED || $pageNameSpace == PUSHFEED || $pageNameSpace == PATCH || $pageNameSpace == CHANGESET) { $pageid = 0; } $lastRev = Revision::loadFromPageId($dbr, $pageid); if (is_null($lastRev)) { $rev_id = 0; } else { $rev_id = $lastRev->getId(); } wfDebugLog('p2p', ' -> pageId : ' . $pageid); wfDebugLog('p2p', ' -> rev_id : ' . $rev_id); $title = Title::newFromText($article); $article = new Article($title); } else { $rev_id = $article->getRevIdFetched(); } $listOp = array(); //$blobInfo = BlobInfo::loadBlobInfo($rev_id); $model = manager::loadModel($rev_id); $logoot = manager::getNewEngine($model, DSMWSiteId::getInstance()->getSiteId()); // new logootEngine($model); foreach ($operations as $operation) { wfDebugLog('p2p', ' - operation : ' . $operation); wfDebugLog('testlog', ' - operation : ' . $operation); if (!$operation instanceof LogootOperation) { $operation = operationToLogootOp($operation); } if ($operation != false && is_object($operation)) { $listOp[] = $operation; wfDebugLog('testlog', ' -> Operation: ' . $operation->getLogootPosition()->toString()); //$blobInfo->integrateBlob($operation); } } //end foreach operations $p = new LogootPatch($rev_id, $listOp); $logoot->integrate($p); $modelAfterIntegrate = $logoot->getModel(); //$revId = utils::getNewArticleRevId(); $status = $article->doEdit($modelAfterIntegrate->getText(), $summary = ""); $revId = $status->value['revision']->getId(); manager::storeModel($revId, $sessionId = session_id(), $modelAfterIntegrate, $blobCB = 0); return array($revId, $p); }
public function buildRssNs($aParams) { global $wgRequest, $wgSitename, $wgLang, $wgDBprefix; $dbr = wfGetDB(DB_SLAVE); $_showLimit = 10; if (isset($aParams['ns'])) { $ns = $aParams['ns'] + 0; } else { $ns = $wgRequest->getInt('ns', 0); } $aNamespaces = $wgLang->getNamespaces(); $channel = RSSCreator::createChannel($wgSitename . ' - ' . wfMessage('bs-ns')->plain() . ' ' . $aNamespaces[$ns], 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], wfMessage('bs-rssstandards-desc-ns')->plain()); $res = $dbr->query("select page_id from " . $wgDBprefix . "page where page_namespace = " . $ns); $entryIds = array(); while ($row = $dbr->fetchRow($res)) { $entryIds[] = $row['page_id']; } if (count($entryIds)) { $query = "SELECT Min(r.rev_id) as rid, r.rev_page, r.rev_timestamp, r.rev_user_text FROM " . $wgDBprefix . "revision as r WHERE r.rev_page In (" . join(",", $entryIds) . ") GROUP BY r.rev_page, r.rev_timestamp, r.rev_user_text ORDER BY rid DESC"; $res = $dbr->query($query); $numberOfEntries = $dbr->numRows($res); $query .= ' LIMIT ' . $_showLimit; $res = $dbr->query($query); while ($row = $dbr->fetchRow($res)) { $title = Title::newFromID($row['rev_page']); $article = new Article($title); if (!$title->userCan('read')) { $numberOfEntries--; continue; } $_title = str_replace("_", " ", $title->getText()); $_link = $title->getFullURL(); $_tmpText = preg_replace("#\\[<a\\ href\\=\"(.*)action\\=edit(.*)\"\\ title\\=\"(.*)\">(.*)<\\/a>\\]#", "", $this->mCore->parseWikiText($article->getContent(), $this->getTitle())); if (class_exists('SecureFileStore')) { $_description = SecureFileStore::secureFilesInText($_tmpText); } else { $_description = $_tmpText; } unset($_tmpText); $item = RSSItemCreator::createItem($_title, $_link, $_description); if ($item) { $item->setPubDate(wfTimestamp(TS_UNIX, $row['rev_timestamp'])); $item->setComments($title->getTalkPage()->getFullURL()); $item->setGUID($title->getFullURL("oldid=" . $article->getRevIdFetched()), 'true'); $channel->addItem($item); } } } $dbr->freeResult($res); return $channel->buildOutput(); }
function writeOutput($par) { global $wgLang, $wgMemc, $wgDBname, $wgUser; global $wgSitename, $wgLanguageCode; global $wgFeedClasses, $wgFilterCallback, $wgWhitelistEdit, $wgParser; $this->getOutput()->setRobotpolicy("noindex,nofollow"); $target = !empty($par) ? $par : $this->getRequest()->getVal("target"); $t = Title::newFromDBKey($target); $update = true; if (!$t || !$t->userCan('edit')) { return; } if (!$this->getUser()->isAllowed('edit')) { return; } $article = new Article($t); $user = $this->getUser()->getName(); $real_name = User::whoIsReal($this->getUser()->getID()); if ($real_name == "") { $real_name = $user; } $dateStr = $wgLang->timeanddate(wfTimestampNow()); $comment = $this->getRequest()->getVal("comment_text"); foreach ($this->getRequest()->getValues() as $key => $value) { if (strpos($key, "comment_text") === 0) { $comment = $value; break; } } $topic = $this->getRequest()->getVal("topic_name"); //echo "$dateStr<br/>"; // remove leading space, tends to be a problem with a lot of talk page comments as it breaks the // HTML on the page $comment = preg_replace('/\\n[ ]*/', "\n", trim($comment)); // Check to see if the user is also getting a thumbs up. If so, append the thumbs message and give a thumbs up if ($this->getRequest()->getVal('thumb')) { $comment .= "\n\n" . wfMsg('qn_thumbs_up'); $userName = explode(":", $this->getRequest()->getVal('target')); ThumbsUp::quickNoteThumb($this->getRequest()->getVal('revold'), $this->getRequest()->getVal('revnew'), $this->getRequest()->getVal('pageid'), $userName[1]); } $formattedComment = wfMsg('postcomment_formatted_comment', $dateStr, $user, $real_name, $comment); if ($this->getRequest()->getVal('fromajax') == 'true') { $this->getOutput()->setArticleBodyOnly(true); } $text = ""; $r = Revision::newFromTitle($t); if ($r) { $text = $r->getText(); } $text .= "\n\n{$formattedComment}\n\n"; $this->getOutput()->setStatusCode(409); //echo "updating with text:<br/> $text"; //exit; $tmp = ""; if ($this->getUser()->isBlocked()) { $this->getOutput()->blockedPage(); return; } if (!$this->getUser()->getID() && $wgWhitelistEdit) { $this->userNotLoggedInPage(); return; } if (wfReadOnly()) { $this->getOutput()->readOnlyPage(); return; } if ($target == "Spam-Blacklist") { $this->getOutput()->readOnlyPage(); return; } if ($this->getUser()->pingLimiter()) { $this->getOutput()->rateLimited(); return; } $editPage = new EditPage($article); $contentModel = $t->getContentModel(); $handler = ContentHandler::getForModelID($contentModel); $contentFormat = $handler->getDefaultFormat(); $content = ContentHandler::makeContent($text, $t, $contentModel, $contentFormat); $status = Status::newGood(); if (!wfRunHooks('EditFilterMergedContent', array($this->getContext(), $content, &$status, '', $wgUser, false))) { return; } if (!$status->isGood()) { $errors = $status->getErrorsArray(true); foreach ($errors as $error) { if (is_array($error)) { $error = count($error) ? $error[0] : ''; } if (preg_match('@^spamprotection@', $error)) { $message = 'Error: found spam link'; $this->getOutput()->addHTML($message); return; } } $message = 'EditFilterMergedContent returned an error -- cannot post comment'; return; } $matches = array(); $preg = "/http:\\/\\/[^] \n'\">]*/"; $mod = str_ireplace('http://www.wikihow.com', '', $comment); preg_match_all($preg, $mod, $matches); if (sizeof($matches[0]) > 2) { $this->getOutput()->showErrorPage("postcomment", "postcomment_urls_limit"); return; } if (trim(strip_tags($comment)) == "") { $this->getOutput()->showErrorPage("postcomment", "postcomment_nopostingtoadd"); return; } if (!$t->userCan('edit')) { $this->getOutput()->showErrorPage("postcomment", "postcomment_discussionprotected"); return; } $watch = false; if ($this->getUser()->getID() > 0) { $watch = $this->getUser()->isWatched($t); } $fc = new FancyCaptcha(); $pass_captcha = $fc->passCaptcha(); if (!$pass_captcha && $this->getUser()->getID() == 0) { $this->getOutput()->addHTML("Sorry, please enter the correct word. Click <a onclick='window.location.reload(true);'>here</a> to get a new one.<br/><br/>"); return; } $article->doEdit($text, ""); if ($this->getRequest()->getVal('jsonresponse') == 'true') { $this->revId = $article->getRevIdFetched(); } // Notify users of usertalk updates if ($t->getNamespace() == NS_USER_TALK) { AuthorEmailNotification::notifyUserTalk($t->getArticleID(), $this->getUser()->getID(), $comment); } $this->getOutput()->setStatusCode(200); if ($this->getRequest()->getVal('fromajax') == 'true') { $this->getOutput()->redirect(''); $this->getContext()->setTitle($t); $formattedComment = $wgParser->preSaveTransform($formattedComment, $t, $this->getUser(), new ParserOptions()); $this->getOutput()->addHTML($this->getOutput()->parse("\n" . $formattedComment)); return; } }
public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (is_null($params['title'])) { $this->dieUsageMsg(array('missingparam', 'title')); } if (is_null($params['xpath'])) { $this->dieUsage(array('missingparam', 'xpath')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } // Some functions depend on $wgTitle == $ep->mTitle global $wgTitle; $wgTitle = $titleObj; if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg(array('nocreate-missing')); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $articleObj = new Article($titleObj); if (!is_null($params['rid'])) { $revObj = Revision::newFromID($params['rid']); if (is_null($revObj) || $revObj->isDeleted(Revision::DELETED_TEXT)) { $this->dieUsageMsg(array('nosuchrevid', $params['rid'])); } if ($revObj->getPage() != $articleObj->getID()) { $this->dieUsageMsg(array('revwrongpage', $revObj->getID(), $titleObj->getPrefixedText())); } if (!$params['force_update'] && !$revObj->isCurrent()) { $this->dieUsage("Page revision id is not current '{$titleObj->getPrefixedText()} ({$params['rid']})'", 'revnotcurrent'); } } else { $params['rid'] = 0; } $verb = $params['verb']; $xpath = $params['xpath']; try { $wom = WOMProcessor::getPageObject($titleObj, $params['rid']); $obj_ids = WOMProcessor::getObjIdByXPath2($wom, $xpath); $obj_id = null; foreach ($obj_ids as $id) { if ($id != '') { $obj_id = $id; break; } } if ($obj_id == null) { throw new MWException(__METHOD__ . ": object does not found, xpath: {$xpath}"); } if ($verb == 'remove') { $wom->removePageObject($obj_id); } elseif ($verb == 'removeall') { foreach ($obj_ids as $id) { if ($id == '') { continue; } $wom->removePageObject($id); } } else { if (is_null($params['text'])) { $this->dieUsageMsg(array('missingparam', 'text')); } $toMD5 = $params['text']; // See if the MD5 hash checks out if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) { $this->dieUsageMsg(array('hashcheckfailed')); } $text = $params['text']; if ($verb == 'insert') { $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom); // no need to parse or merge object model but use text $wom->insertPageObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'update') { $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom); $wom->updatePageObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'append') { $parent = $wom->getObject($obj_id); if (!$parent instanceof WikiObjectModelCollection) { throw new MWException(__METHOD__ . ": Object is not a collection object '{$title} ({$revision_id}) - {$obj_id}'"); } $text = WOMProcessor::getValidText($text, $parent, $wom); $wom->appendChildObject(new WOMTextModel($text), $obj_id); } elseif ($verb == 'attribute') { $obj = $wom->getObject($obj_id); $kv = explode('=', $text, 2); if (count($kv) != 2) { throw new MWException(__METHOD__ . ": value should be 'key=value' in attribute mode"); } $obj->setXMLAttribute(trim($kv[0]), trim($kv[1])); } } $ep = new EditPage($articleObj); // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $reqArr = array('wpTextbox1' => $wom->getWikiText(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '', 'wpSection' => ''); if (!is_null($params['summary'])) { $reqArr['wpSummary'] = $params['summary']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $reqArr['wpEdittime'] = $articleObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { $reqArr['wpStarttime'] = $reqArr['wpEdittime']; } // Fake wpStartime if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) { $reqArr['wpMinoredit'] = ''; } // Handle watchlist settings switch ($params['watchlist']) { case 'watch': $watch = true; break; case 'unwatch': $watch = false; break; case 'preferences': if ($titleObj->exists()) { $watch = $wgUser->getOption('watchdefault') || $titleObj->userIsWatching(); } else { $watch = $wgUser->getOption('watchcreations'); } break; case 'nochange': default: $watch = $titleObj->userIsWatching(); } // Deprecated parameters if ($params['watch']) { $watch = true; } elseif ($params['unwatch']) { $watch = false; } if ($watch) { $reqArr['wpWatchthis'] = ''; } $req = new FauxRequest($reqArr, true); $ep->importFormData($req); // Run hooks // Handle CAPTCHA parameters global $wgRequest; if (!is_null($params['captchaid'])) { $wgRequest->setVal('wpCaptchaId', $params['captchaid']); } if (!is_null($params['captchaword'])) { $wgRequest->setVal('wpCaptchaWord', $params['captchaword']); } $r = array(); if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = "Failure"; $this->getResult()->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg(array('hookaborted')); } } // Do the actual save $oldRevId = $articleObj->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; switch ($retval) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg(array('hookaborted')); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg(array('noimageredirect-anon')); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg(array('noimageredirect-logged')); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_FILTERING: $this->dieUsageMsg(array('filtered')); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg(array('blockedtext')); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: global $wgMaxArticleSize; $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg(array('noedit-anon')); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg(array('noedit')); case EditPage::AS_READ_ONLY_PAGE: $this->dieReadOnly(); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg(array('actionthrottledtext')); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg(array('wasdeleted')); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg(array('nocreate-loggedin')); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg(array('blankpage')); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg(array('editconflict')); // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg(array('emptynewsection')); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = "Success"; $r['pageid'] = intval($titleObj->getArticleID()); $r['title'] = $titleObj->getPrefixedText(); // HACK: We create a new Article object here because getRevIdFetched() // refuses to be run twice, and because Title::getLatestRevId() // won't fetch from the master unless we select for update, which we // don't want to do. $newArticle = new Article($titleObj); $newRevId = $newArticle->getRevIdFetched(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval($oldRevId); $r['newrevid'] = intval($newRevId); $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp()); } break; case EditPage::AS_END: // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned // This usually means some kind of race condition // or DB weirdness occurred. Fall through to throw an unknown // error. // This needs fixing higher up, as Article::doEdit should be // used rather than Article::updateArticle, so that specific // error conditions can be returned default: $this->dieUsageMsg(array('unknownerror', $retval)); } $this->getResult()->addValue(null, $this->getModuleName(), $r); } catch (Exception $e) { $this->dieUsage($e->getMessage(), 'WOM error'); } }
/** * @param Article $article - Article object to work on * @param string $token - Delete token (same as edit token) * @param integer $revid - revision to delete * @param string $reason - Reason for the deletion. Autogenerated if NULL * @return Title::getUserPermissionsErrors()-like array */ public function delete(&$article, $token, $revid, &$reason) { global $wgUser; $title = $article->getTitle(); $errors = self::getPermissionsError($title, $token); if (count($errors)) { return $errors; } if ($article->getRevIdFetched() == $revid) { return array(array('cannotdelete', $title->getPrefixedText())); } // Auto-generate a summary, if necessary if (is_null($reason)) { $reason = 'delete revision ' . $revid . ' of page ' . $title->getPrefixedText(); } // We have to handle the revision deletion by hand if ($this->doDeleteRevision(&$article, $revid, $reason)) { return array(); } return array(array('cannotdelete', $title->getPrefixedText())); }
/** * Grab the last good patrol * - return true if the last edit on the article was patrolled */ public static function patrolledGood($title) { // start with basic check to make sure we're dealing // with a real article if (!$title) { return false; } // get the last revision $a = new Article($title); $last_rev_id = $a->getRevIdFetched(); // get the last good revision $goodRev = self::newFromTitle($title); $last_good_rev = $goodRev->latestGood(); return $last_rev_id == $last_good_rev; }
/** * cuteCUTE **/ function execute($par) { global $wgRequest, $wgOut, $wgUser, $wgLang, $wgParser, $efType, $wgTitle; $target = isset($par) ? $par : $wgRequest->getVal('target'); wfLoadExtensionMessages('EditFinder'); self::setTemplatePath(); if ($wgUser->isBlocked()) { $wgOut->blockedPage(); return; } if ($wgUser->getID() == 0) { $wgOut->setRobotpolicy('noindex,nofollow'); $wgOut->errorpage('nosuchspecialpage', 'nospecialpagetext'); return; } $this->topicMode = strtolower($par) == 'topic' || strtolower($wgRequest->getVal('edittype')) == 'topic'; if ($wgRequest->getVal('fetchArticle')) { $wgOut->setArticleBodyOnly(true); echo json_encode($this->getNextArticle()); return; } elseif ($wgRequest->getVal('show-article')) { $wgOut->setArticleBodyOnly(true); if ($wgRequest->getInt('aid') == '') { $catsJs = $this->topicMode ? "editFinder.getThoseInterests();" : "editFinder.getThoseCats();"; $catsTxt = $this->topicMode ? "interests" : "categories"; $wgOut->addHTML('<div class="article_inner">No articles found. <a href="#" onclick="' . $catsJs . '">Select more ' . $catsTxt . '</a> and try again.</div>'); return; } $t = Title::newFromID($wgRequest->getInt('aid')); $articleTitleLink = $t->getLocalURL(); $articleTitle = $t->getText(); //$edittype = $a['edittype']; //get article $a = new Article($t); $r = Revision::newFromTitle($t); $popts = $wgOut->parserOptions(); $popts->setTidy(true); $popts->enableLimitReport(); $parserOutput = $wgParser->parse($r->getText(), $t, $popts, true, true, $a->getRevIdFetched()); $popts->setTidy(false); $popts->enableLimitReport(false); $html = WikihowArticleHTML::processArticleHTML($parserOutput->getText(), array('no-ads', 'ns' => NS_MAIN)); $wgOut->addHTML($html); return; } elseif ($wgRequest->getVal('edit-article')) { // SHOW THE EDIT FORM $wgOut->setArticleBodyOnly(true); $t = Title::newFromID($wgRequest->getInt('aid')); $a = new Article($t); $editor = new EditPage($a); $editor->edit(); return; } elseif ($wgRequest->getVal('action') == 'submit') { $wgOut->setArticleBodyOnly(true); $efType = strtolower($wgRequest->getVal('type')); $t = Title::newFromID($wgRequest->getInt('aid')); $a = new Article($t); //log it $params = array($efType); $log = new LogPage('EF_' . substr($efType, 0, 7), false); // false - dont show in recentchanges $log->addEntry('', $t, 'Repaired an article -- ' . strtoupper($efType) . '.', $params); $text = $wgRequest->getVal('wpTextbox1'); $sum = $wgRequest->getVal('wpSummary'); //save the edit $a->doEdit($text, $sum, EDIT_UPDATE); wfRunHooks("EditFinderArticleSaveComplete", array($a, $text, $sum, $wgUser, $efType)); return; } elseif ($wgRequest->getVal('confirmation')) { $wgOut->setArticleBodyOnly(true); echo $this->confirmationModal($wgRequest->getVal('type'), $wgRequest->getInt('aid')); wfProfileOut(__METHOD__); return; } elseif ($wgRequest->getVal('cancel-confirmation')) { $wgOut->setArticleBodyOnly(true); echo $this->cancelConfirmationModal($wgRequest->getInt('aid')); wfProfileOut(__METHOD__); return; } else { //default view (same as most of the views) $sk = $wgUser->getSkin(); $wgOut->setArticleBodyOnly(false); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('mousetrap.min.js', 'jquery.cookie.js'), 'extensions/wikihow/common', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('preview.js'), 'skins/common', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('clientscript.js', 'preview.js'), 'skins/common', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('editfinder.js'), 'extensions/wikihow/editfinder', false)); $efType = strtolower($target); if (strpos($efType, '/') !== false) { $efType = substr($efType, 0, strpos($efType, '/')); } if ($efType == '') { //no type specified? send 'em to format... $wgOut->redirect('/Special:EditFinder/Format'); } $wgOut->addHTML('<script>var g_eftype = "' . $target . '";</script>'); //add main article info $vars = array('pagetitle' => wfMsg('app-name') . ': ' . wfMsg($efType), 'question' => wfMsg('editfinder-question'), 'yep' => wfMsg('editfinder_yes'), 'nope' => wfMsg('editfinder_no'), 'helparticle' => wfMsg('help_' . $efType)); $vars['uc_categories'] = $this->topicMode ? 'Interests' : 'Categories'; $vars['lc_categories'] = $this->topicMode ? 'interests' : 'categories'; $vars['editfinder_edit_title'] = wfMsg('editfinder_edit_title'); $vars['editfinder_skip_title'] = wfMsg('editfinder_skip_title'); $vars['css'] = HtmlSnips::makeUrlTags('css', array('editfinder.css'), 'extensions/wikihow/editfinder', false); $vars['css'] .= HtmlSnips::makeUrlTags('css', array('suggestedtopics.css'), 'extensions/wikihow', false); $html = EasyTemplate::html('editfinder_main', $vars); $wgOut->addHTML($html); $wgOut->setHTMLTitle(wfMsg('app-name') . ': ' . wfMsg($efType) . ' - wikiHow'); $wgOut->setPageTitle(wfMsg('app-name') . ': ' . wfMsg($efType) . ' - wikiHow'); } $stats = new EditFinderStandingsIndividual($efType); $stats->addStatsWidget(); $standings = new EditFinderStandingsGroup($efType); $standings->addStandingsWidget(); }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; $page = $params['page']; $pageid = $params['pageid']; $oldid = $params['oldid']; if (!is_null($page) && (!is_null($text) || $title != 'API')) { $this->dieUsage('The page parameter cannot be used together with the text and title parameters', 'params'); } $prop = array_flip($params['prop']); if (isset($params['section'])) { $this->section = $params['section']; } else { $this->section = false; } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* global $wgParser, $wgUser, $wgTitle, $wgLang; // Currently unnecessary, code to act as a safeguard against any change in current behaviour of uselang breaks $oldLang = null; if (isset($params['uselang']) && $params['uselang'] != $wgLang->getCode()) { $oldLang = $wgLang; // Backup wgLang $wgLang = Language::factory($params['uselang']); } $popts = new ParserOptions(); $popts->setTidy(true); $popts->enableLimitReport(!$params['disablepp']); $redirValues = null; // Return result $result = $this->getResult(); if (!is_null($oldid) || !is_null($pageid) || !is_null($page)) { if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromID($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT)) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $titleObj = $rev->getTitle(); $wgTitle = $titleObj; // If for some reason the "oldid" is actually the current revision, it may be cached if ($titleObj->getLatestRevID() === intval($oldid)) { $articleObj = new Article($titleObj, 0); $p_result = $this->getParsedSectionOrText($articleObj, $titleObj, $popts, $pageid, isset($prop['wikitext'])); } else { // This is an old revision, so get the text differently $this->text = $rev->getText(Revision::FOR_THIS_USER); $wgTitle = $titleObj; if ($this->section !== false) { $this->text = $this->getSectionText($this->text, 'r' . $rev->getId()); } $p_result = $wgParser->parse($this->text, $titleObj, $popts); } } else { // Not $oldid if ($params['redirects']) { $reqParams = array('action' => 'query', 'redirects' => ''); if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; } else { // $page $reqParams['titles'] = $page; } $req = new FauxRequest($reqParams); $main = new ApiMain($req); $main->execute(); $data = $main->getResultData(); $redirValues = isset($data['query']['redirects']) ? $data['query']['redirects'] : array(); $to = $page; foreach ((array) $redirValues as $r) { $to = $r['to']; } $titleObj = Title::newFromText($to); } else { if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; $titleObj = Title::newFromID($pageid); } else { // $page $to = $page; $titleObj = Title::newFromText($to); } } if (!is_null($pageid)) { if (!$titleObj) { // Still throw nosuchpageid error if pageid was provided $this->dieUsageMsg(array('nosuchpageid', $pageid)); } } elseif (!$titleObj || !$titleObj->exists()) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $wgTitle = $titleObj; $articleObj = new Article($titleObj, 0); if (isset($prop['revid'])) { $oldid = $articleObj->getRevIdFetched(); } $p_result = $this->getParsedSectionOrText($articleObj, $titleObj, $popts, $pageid, isset($prop['wikitext'])); } } else { // Not $oldid, $pageid, $page. Hence based on $text $this->text = $text; $titleObj = Title::newFromText($title); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $title)); } $wgTitle = $titleObj; if ($this->section !== false) { $this->text = $this->getSectionText($this->text, $titleObj->getText()); } if ($params['pst'] || $params['onlypst']) { $this->pstText = $wgParser->preSaveTransform($this->text, $titleObj, $wgUser, $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array['text'] = array(); $result->setContent($result_array['text'], $this->pstText); if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->text); } $result->addValue(null, $this->getModuleName(), $result_array); return; } $p_result = $wgParser->parse($params['pst'] ? $this->pstText : $this->text, $titleObj, $popts); } $result_array = array(); $result_array['title'] = $titleObj->getPrefixedText(); if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if (isset($prop['text'])) { $result_array['text'] = array(); $result->setContent($result_array['text'], $p_result->getText()); } if (!is_null($params['summary'])) { $result_array['parsedsummary'] = array(); $result->setContent($result_array['parsedsummary'], $wgUser->getSkin()->formatComment($params['summary'], $titleObj)); } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks()); } if (isset($prop['languageshtml'])) { $languagesHtml = $this->languagesHtml($p_result->getLanguageLinks()); $result_array['languageshtml'] = array(); $result->setContent($result_array['languageshtml'], $languagesHtml); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['categorieshtml'])) { $categoriesHtml = $this->categoriesHtml($p_result->getCategories()); $result_array['categorieshtml'] = array(); $result->setContent($result_array['categorieshtml'], $categoriesHtml); } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems']) || isset($prop['headhtml'])) { $context = new RequestContext(); $context->getOutput()->addParserOutputNoText($p_result); if (isset($prop['headitems'])) { $headItems = $this->formatHeadItems($p_result->getHeadItems()); $context->getSkin()->setupUserCss($context->getOutput()); $css = $this->formatCss($context->getOutput()->buildCssLinksArray()); $scripts = array($context->getOutput()->getHeadScripts($context->getSkin())); $result_array['headitems'] = array_merge($headItems, $css, $scripts); } if (isset($prop['headhtml'])) { $result_array['headhtml'] = array(); $result->setContent($result_array['headhtml'], $context->getOutput()->headElement($context->getSkin())); } } if (isset($prop['iwlinks'])) { $result_array['iwlinks'] = $this->formatIWLinks($p_result->getInterwikiLinks()); } if (isset($prop['wikitext'])) { $result_array['wikitext'] = array(); $result->setContent($result_array['wikitext'], $this->text); if (!is_null($this->pstText)) { $result_array['psttext'] = array(); $result->setContent($result_array['psttext'], $this->pstText); } } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'iwlinks' => 'iw', 'sections' => 's', 'headitems' => 'hi'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); if (!is_null($oldLang)) { $wgLang = $oldLang; // Reset $wgLang to $oldLang } }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; $page = $params['page']; $oldid = $params['oldid']; if (!is_null($page) && (!is_null($text) || $title != "API")) { $this->dieUsage("The page parameter cannot be used together with the text and title parameters", 'params'); } $prop = array_flip($params['prop']); $revid = false; // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* global $wgParser, $wgUser, $wgTitle, $wgEnableParserCache; $popts = new ParserOptions(); $popts->setTidy(true); $popts->enableLimitReport(); $redirValues = null; if (!is_null($oldid) || !is_null($page)) { if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromID($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT)) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $text = $rev->getText(Revision::FOR_THIS_USER); $titleObj = $rev->getTitle(); $wgTitle = $titleObj; $p_result = $wgParser->parse($text, $titleObj, $popts); } else { if ($params['redirects']) { $req = new FauxRequest(array('action' => 'query', 'redirects' => '', 'titles' => $page)); $main = new ApiMain($req); $main->execute(); $data = $main->getResultData(); $redirValues = @$data['query']['redirects']; $to = $page; foreach ((array) $redirValues as $r) { $to = $r['to']; } } else { $to = $page; } $titleObj = Title::newFromText($to); if (!$titleObj) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $articleObj = new Article($titleObj); if (isset($prop['revid'])) { $oldid = $articleObj->getRevIdFetched(); } // Try the parser cache first $p_result = false; $pcache = ParserCache::singleton(); if ($wgEnableParserCache) { $p_result = $pcache->get($articleObj, $wgUser); } if (!$p_result) { $p_result = $wgParser->parse($articleObj->getContent(), $titleObj, $popts); if ($wgEnableParserCache) { $pcache->save($p_result, $articleObj, $popts); } } } } else { $titleObj = Title::newFromText($title); if (!$titleObj) { $titleObj = Title::newFromText("API"); } $wgTitle = $titleObj; if ($params['pst'] || $params['onlypst']) { $text = $wgParser->preSaveTransform($text, $titleObj, $wgUser, $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array['text'] = array(); $this->getResult()->setContent($result_array['text'], $text); $this->getResult()->addValue(null, $this->getModuleName(), $result_array); return; } $p_result = $wgParser->parse($text, $titleObj, $popts); } // Return result $result = $this->getResult(); $result_array = array(); if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if (isset($prop['text'])) { $result_array['text'] = array(); $result->setContent($result_array['text'], $p_result->getText()); } if (!is_null($params['summary'])) { $result_array['parsedsummary'] = array(); $result->setContent($result_array['parsedsummary'], $wgUser->getSkin()->formatComment($params['summary'], $titleObj)); } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks()); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems'])) { $result_array['headitems'] = $this->formatHeadItems($p_result->getHeadItems()); } if (isset($prop['headhtml'])) { $out = new OutputPage(); $out->addParserOutputNoText($p_result); $result_array['headhtml'] = array(); $result->setContent($result_array['headhtml'], $out->headElement($wgUser->getSkin())); } if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'sections' => 's', 'headitems' => 'hi'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); }
public function execute() { global $wgUser; $this->getMain()->requestWriteMode(); $params = $this->extractRequestParams(); if (is_null($params['title'])) { $this->dieUsageMsg(array('missingparam', 'title')); } if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext'])) { $this->dieUsageMsg(array('missingtext')); } if (is_null($params['token'])) { $this->dieUsageMsg(array('missingparam', 'token')); } if (!$wgUser->matchEditToken($params['token'])) { $this->dieUsageMsg(array('sessionfailure')); } $titleObj = Title::newFromText($params['title']); if (!$titleObj) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } if ($params['createonly'] && $titleObj->exists()) { $this->dieUsageMsg(array('createonly-exists')); } if ($params['nocreate'] && !$titleObj->exists()) { $this->dieUsageMsg(array('nocreate-missing')); } // Now let's check whether we're even allowed to do this $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser); if (!$titleObj->exists()) { $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser)); } if (count($errors)) { $this->dieUsageMsg($errors[0]); } $articleObj = new Article($titleObj); $toMD5 = $params['text']; if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) { $content = $articleObj->getContent(); $params['text'] = $params['prependtext'] . $content . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } # See if the MD5 hash checks out if (isset($params['md5'])) { if (md5($toMD5) !== $params['md5']) { $this->dieUsageMsg(array('hashcheckfailed')); } } $ep = new EditPage($articleObj); // EditPage wants to parse its stuff from a WebRequest // That interface kind of sucks, but it's workable $reqArr = array('wpTextbox1' => $params['text'], 'wpEdittoken' => $params['token'], 'wpIgnoreBlankSummary' => ''); if (!is_null($params['summary'])) { $reqArr['wpSummary'] = $params['summary']; } # Watch out for basetimestamp == '' # wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') { $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']); } else { $reqArr['wpEdittime'] = $articleObj->getTimestamp(); } if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') { $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']); } else { # Fake wpStartime $reqArr['wpStarttime'] = $reqArr['wpEdittime']; } if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) { $reqArr['wpMinoredit'] = ''; } if ($params['recreate']) { $reqArr['wpRecreate'] = ''; } if (!is_null($params['section'])) { $section = intval($params['section']); if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') { $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection"); } $reqArr['wpSection'] = $params['section']; } else { $reqArr['wpSection'] = ''; } if ($params['watch']) { $watch = true; } else { if ($params['unwatch']) { $watch = false; } else { if ($titleObj->userIsWatching()) { $watch = true; } else { if ($wgUser->getOption('watchdefault')) { $watch = true; } else { if ($wgUser->getOption('watchcreations') && !$titleObj->exists()) { $watch = true; } else { $watch = false; } } } } } if ($watch) { $reqArr['wpWatchthis'] = ''; } $req = new FauxRequest($reqArr, true); $ep->importFormData($req); # Run hooks # Handle CAPTCHA parameters global $wgRequest; if (isset($params['captchaid'])) { $wgRequest->setVal('wpCaptchaId', $params['captchaid']); } if (isset($params['captchaword'])) { $wgRequest->setVal('wpCaptchaWord', $params['captchaword']); } $r = array(); if (!wfRunHooks('APIEditBeforeSave', array(&$ep, $ep->textbox1, &$r))) { if (count($r)) { $r['result'] = "Failure"; $this->getResult()->addValue(null, $this->getModuleName(), $r); return; } else { $this->dieUsageMsg(array('hookaborted')); } } # Do the actual save $oldRevId = $articleObj->getRevIdFetched(); $result = null; # *Something* is setting $wgTitle to a title corresponding to "Msg", # but that breaks API mode detection through is_null($wgTitle) global $wgTitle; $wgTitle = null; # Fake $wgRequest for some hooks inside EditPage # FIXME: This interface SUCKS $oldRequest = $wgRequest; $wgRequest = $req; $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']); $wgRequest = $oldRequest; switch ($retval) { case EditPage::AS_HOOK_ERROR: case EditPage::AS_HOOK_ERROR_EXPECTED: $this->dieUsageMsg(array('hookaborted')); case EditPage::AS_IMAGE_REDIRECT_ANON: $this->dieUsageMsg(array('noimageredirect-anon')); case EditPage::AS_IMAGE_REDIRECT_LOGGED: $this->dieUsageMsg(array('noimageredirect-logged')); case EditPage::AS_SPAM_ERROR: $this->dieUsageMsg(array('spamdetected', $result['spam'])); case EditPage::AS_FILTERING: $this->dieUsageMsg(array('filtered')); case EditPage::AS_BLOCKED_PAGE_FOR_USER: $this->dieUsageMsg(array('blockedtext')); case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: case EditPage::AS_CONTENT_TOO_BIG: global $wgMaxArticleSize; $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize)); case EditPage::AS_READ_ONLY_PAGE_ANON: $this->dieUsageMsg(array('noedit-anon')); case EditPage::AS_READ_ONLY_PAGE_LOGGED: $this->dieUsageMsg(array('noedit')); case EditPage::AS_READ_ONLY_PAGE: $this->dieUsageMsg(array('readonlytext')); case EditPage::AS_RATE_LIMITED: $this->dieUsageMsg(array('actionthrottledtext')); case EditPage::AS_ARTICLE_WAS_DELETED: $this->dieUsageMsg(array('wasdeleted')); case EditPage::AS_NO_CREATE_PERMISSION: $this->dieUsageMsg(array('nocreate-loggedin')); case EditPage::AS_BLANK_ARTICLE: $this->dieUsageMsg(array('blankpage')); case EditPage::AS_CONFLICT_DETECTED: $this->dieUsageMsg(array('editconflict')); #case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary #case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary case EditPage::AS_TEXTBOX_EMPTY: $this->dieUsageMsg(array('emptynewsection')); case EditPage::AS_END: # This usually means some kind of race condition # or DB weirdness occurred. Throw an unknown error here. $this->dieUsageMsg(array('unknownerror')); case EditPage::AS_SUCCESS_NEW_ARTICLE: $r['new'] = ''; case EditPage::AS_SUCCESS_UPDATE: $r['result'] = "Success"; $r['pageid'] = $titleObj->getArticleID(); $r['title'] = $titleObj->getPrefixedText(); # HACK: We create a new Article object here because getRevIdFetched() # refuses to be run twice, and because Title::getLatestRevId() # won't fetch from the master unless we select for update, which we # don't want to do. $newArticle = new Article($titleObj); $newRevId = $newArticle->getRevIdFetched(); if ($newRevId == $oldRevId) { $r['nochange'] = ''; } else { $r['oldrevid'] = $oldRevId; $r['newrevid'] = $newRevId; } break; default: $this->dieUsageMsg(array('unknownerror', $retval)); } $this->getResult()->addValue(null, $this->getModuleName(), $r); }