/** * Insert the captcha prompt into an edit form. * @param EditPage $editPage */ function editShowCaptcha($editPage) { $context = $editPage->getArticle()->getContext(); $page = $editPage->getArticle()->getPage(); $out = $context->getOutput(); if (isset($page->ConfirmEdit_ActivateCaptcha) || $this->showEditCaptcha || $this->shouldCheck($page, '', '', false)) { $out->addWikiText($this->getMessage($this->action)); $out->addHTML($this->getForm()); } unset($page->ConfirmEdit_ActivateCaptcha); }
/** * Monitors edit page usage */ public static function onEditForm(EditPage $editPage) { global $wgUser, $wgEditPageTrackingRegistrationCutoff, $wgMemc; // Anonymous users if ($wgUser->isAnon()) { return true; } if ($wgEditPageTrackingRegistrationCutoff && $wgUser->getRegistration() < $wgEditPageTrackingRegistrationCutoff) { // User registered before the cutoff return true; } if (EditPageTracking::getFirstEditPage($wgUser)) { // Already stored. return true; } // Record it $dbw = wfGetDB(DB_MASTER); $title = $editPage->getArticle()->getTitle(); $timestamp = wfTimestampNow(); $row = array('ept_user' => $wgUser->getId(), 'ept_namespace' => $title->getNamespace(), 'ept_title' => $title->getDBkey(), 'ept_timestamp' => $dbw->timestamp($timestamp)); $dbw->insert('edit_page_tracking', $row, __METHOD__); $wgUser->mFirstEditPage = $timestamp; $cacheKey = wfMemcKey('first-edit-page', $wgUser->getId()); $wgMemc->set($cacheKey, $timestamp, 86400); return true; }
/** * @desc Redirects to Special:CSS if this is a try of edition of Wikia.css * * @param EditPage $editPage * @return bool */ public static function onAlternateEdit(EditPage $editPage) { wfProfileIn(__METHOD__); $app = F::app(); $model = new SpecialCssModel(); if (static::shouldRedirect($app, $model, $editPage->getArticle()->getTitle())) { $oldid = $app->wg->Request->getIntOrNull('oldid'); $app->wg->Out->redirect($model->getSpecialCssUrl(false, $oldid ? array('oldid' => $oldid) : null)); } wfProfileOut(__METHOD__); return true; }
/** * Guess the rev ID the text of this form is based off * Note: baseRevId trusted for Reviewers - check text for others. * @return int */ protected static function getBaseRevId(EditPage $editPage, WebRequest $request) { if (!isset($editPage->fr_baseRevId)) { $article = $editPage->getArticle(); // convenience $latestId = $article->getLatest(); // current rev $undo = $request->getIntOrNull('undo'); # Undoing consecutive top edits... if ($undo && $undo === $latestId) { # Treat this like a revert to a base revision. # We are undoing all edits *after* some rev ID (undoafter). # If undoafter is not given, then it is the previous rev ID. $revId = $request->getInt('undoafter', $article->getTitle()->getPreviousRevisionID($latestId, Title::GAID_FOR_UPDATE)); # Undoing other edits... } elseif ($undo) { $revId = $latestId; // current rev is the base rev # Other edits... } else { # If we are editing via oldid=X, then use that rev ID. # Otherwise, check if the client specified the ID (bug 23098). $revId = $article->getOldID() ? $article->getOldID() : $request->getInt('baseRevId'); // e.g. "show changes"/"preview" } # Zero oldid => draft revision if (!$revId) { $revId = $latestId; } $editPage->fr_baseRevId = $revId; } return $editPage->fr_baseRevId; }
/** * Appends a preview of the actual form, when a page in the "Form" * namespace is previewed. * * @author Solitarius * @since 2.4 * * @param EditPage $editpage * @param WebRequest $request * * @return true */ public static function showFormPreview(EditPage $editpage, WebRequest $request) { global $wgOut, $sfgFormPrinter; wfDebug(__METHOD__ . ": enter.\n"); wfProfileIn(__METHOD__); // Exit if we're not in preview mode. if (!$editpage->preview) { wfProfileOut(__METHOD__); return true; } // Exit if we aren't in the "Form" namespace. if ($editpage->getArticle()->getTitle()->getNamespace() != SF_NS_FORM) { wfProfileOut(__METHOD__); return true; } $editpage->previewTextAfterContent .= Html::element('h2', null, wfMessage('sf-preview-header')->text()) . "\n" . '<div class="previewnote" style="font-weight: bold">' . $wgOut->parse(wfMessage('sf-preview-note')->text()) . "</div>\n<hr />\n"; $form_definition = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $editpage->textbox1); list($form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name) = $sfgFormPrinter->formHTML($form_definition, null, false, null, null, "Semantic Forms form preview dummy title", null); SFUtils::addJavascriptAndCSS(); $editpage->previewTextAfterContent .= '<div style="margin-top: 15px">' . $form_text . "</div>"; wfProfileOut(__METHOD__); return true; }
/** * This is attached to the MediaWiki 'EditPage::attemptSave:after' hook. * * @param EditPage $editPage * @param Status $status * @return boolean */ public static function editPageAttemptSaveAfter(EditPage $editPage, Status $status) { $article = $editPage->getArticle(); $request = $article->getContext()->getRequest(); if ($request->getVal('editingStatsId')) { $data = array(); $data['editingSessionId'] = $request->getVal('editingStatsId'); if ($status->isOK()) { $action = 'saveSuccess'; } else { $action = 'saveFailure'; $errors = $status->getErrorsArray(); if (isset($errors[0][0])) { $data['action.saveFailure.message'] = $errors[0][0]; } if ($status->value === EditPage::AS_CONFLICT_DETECTED) { $data['action.saveFailure.type'] = 'editConflict'; } elseif ($status->value === EditPage::AS_ARTICLE_WAS_DELETED) { $data['action.saveFailure.type'] = 'editPageDeleted'; } elseif (isset($errors[0][0]) && $errors[0][0] === 'abusefilter-disallowed') { $data['action.saveFailure.type'] = 'extensionAbuseFilter'; } elseif (isset($editPage->getArticle()->getPage()->ConfirmEdit_ActivateCaptcha)) { // TODO: :( $data['action.saveFailure.type'] = 'extensionCaptcha'; } elseif (isset($errors[0][0]) && $errors[0][0] === 'spamprotectiontext') { $data['action.saveFailure.type'] = 'extensionSpamBlacklist'; } else { // Catch everything else... We don't seem to get userBadToken or // userNewUser through this hook. $data['action.saveFailure.type'] = 'responseUnknown'; } } self::doEventLogging($action, $article, $data); } return true; }
/** * @param EditPage $editpage * @return string */ private static function editBoxes(EditPage $editpage) { $context = $editpage->getArticle()->getContext(); $request = $context->getRequest(); $groupId = $request->getText('loadgroup', ''); $th = new TranslationHelpers($editpage->getTitle(), $groupId); if ($editpage->firsttime && !$request->getCheck('oldid') && !$request->getCheck('undo')) { $editpage->textbox1 = (string) $th->getTranslation(); } else { $th->setTranslation($editpage->textbox1); } TranslationHelpers::addModules($context->getOutput()); return $th->getBoxes(); }
protected function doStore(EditPage $editor) { $title = $editor->getTitle(); // If they used redlink=1 and the page exists, redirect to the main article and send notice if ($this->getRequest()->getBool('redlink') && $title->exists()) { $this->logMessage(wfMessage('sf_autoedit_redlinkexists')->parse(), self::WARNING); } $permErrors = $title->getUserPermissionsErrors('edit', $this->getUser()); // if this title needs to be created, user needs create rights if (!$title->exists()) { $permErrors = array_merge($permErrors, wfArrayDiff2($title->getUserPermissionsErrors('create', $this->getUser()), $permErrors)); } if ($permErrors) { // Auto-block user's IP if the account was "hard" blocked $this->getUser()->spreadAnyEditBlock(); foreach ($permErrors as $error) { $this->logMessage(call_user_func_array('wfMessage', $error)->parse()); } return; } $resultDetails = false; # Allow bots to exempt some edits from bot flagging $bot = $this->getUser()->isAllowed('bot') && $editor->bot; $request = $editor->sfFauxRequest; if ($editor->tokenOk($request)) { $ctx = RequestContext::getMain(); $tempTitle = $ctx->getTitle(); $ctx->setTitle($title); $status = $editor->internalAttemptSave($resultDetails, $bot); $ctx->setTitle($tempTitle); } else { throw new MWException(wfMessage('session_fail_preview')->parse()); } switch ($status->value) { case EditPage::AS_HOOK_ERROR_EXPECTED: // A hook function returned an error // show normal Edit page // remove Preview and Diff standard buttons from editor page Hooks::register('EditPageBeforeEditButtons', function (&$editor, &$buttons, &$tabindex) { foreach (array_keys($buttons) as $key) { if ($key !== 'save') { unset($buttons[$key]); } } }); // Context title needed for correct Cancel link $editor->setContextTitle($title); $editor->showEditForm(); return false; // success // success case EditPage::AS_CONTENT_TOO_BIG: // Content too big (> $wgMaxArticleSize) // Content too big (> $wgMaxArticleSize) case EditPage::AS_ARTICLE_WAS_DELETED: // article was deleted while editting and param wpRecreate == false or form was not posted // article was deleted while editting and param wpRecreate == false or form was not posted case EditPage::AS_CONFLICT_DETECTED: // (non-resolvable) edit conflict // (non-resolvable) edit conflict case EditPage::AS_SUMMARY_NEEDED: // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false // no edit summary given and the user has forceeditsummary set and the user is not editting in his own userspace or talkspace and wpIgnoreBlankSummary == false case EditPage::AS_TEXTBOX_EMPTY: // user tried to create a new section without content // user tried to create a new section without content case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: // article is too big (> $wgMaxArticleSize), after merging in the new section // article is too big (> $wgMaxArticleSize), after merging in the new section case EditPage::AS_END: // WikiPage::doEdit() was unsuccessfull throw new MWException(wfMessage('sf_autoedit_fail', $this->mOptions['target'])->parse()); case EditPage::AS_HOOK_ERROR: // Article update aborted by a hook function $this->logMessage('Article update aborted by a hook function', self::DEBUG); return false; // success // TODO: This error code only exists from 1.21 onwards. It is // suitably handled by the default branch, but really should get its // own branch. Uncomment once compatibility to pre1.21 is dropped. // case EditPage::AS_PARSE_ERROR: // can't parse content // // throw new MWException( $status->getHTML() ); // return true; // fail // success // TODO: This error code only exists from 1.21 onwards. It is // suitably handled by the default branch, but really should get its // own branch. Uncomment once compatibility to pre1.21 is dropped. // case EditPage::AS_PARSE_ERROR: // can't parse content // // throw new MWException( $status->getHTML() ); // return true; // fail case EditPage::AS_SUCCESS_NEW_ARTICLE: // Article successfully created $query = $resultDetails['redirect'] ? 'redirect=no' : ''; $anchor = isset($resultDetails['sectionanchor']) ? $resultDetails['sectionanchor'] : ''; $this->getOutput()->redirect($title->getFullURL($query) . $anchor); $this->getResult()->addValue(NULL, 'redirect', $title->getFullURL($query) . $anchor); return false; // success // success case EditPage::AS_SUCCESS_UPDATE: // Article successfully updated $extraQuery = ''; $sectionanchor = $resultDetails['sectionanchor']; // Give extensions a chance to modify URL query on update Hooks::run('ArticleUpdateBeforeRedirect', array($editor->getArticle(), &$sectionanchor, &$extraQuery)); if ($resultDetails['redirect']) { if ($extraQuery == '') { $extraQuery = 'redirect=no'; } else { $extraQuery = 'redirect=no&' . $extraQuery; } } $this->getOutput()->redirect($title->getFullURL($extraQuery) . $sectionanchor); $this->getResult()->addValue(NULL, 'redirect', $title->getFullURL($extraQuery) . $sectionanchor); return false; // success // success case EditPage::AS_BLANK_ARTICLE: // user tried to create a blank page $this->logMessage('User tried to create a blank page', self::DEBUG); $this->getOutput()->redirect($editor->getContextTitle()->getFullURL()); $this->getResult()->addValue(NULL, 'redirect', $editor->getContextTitle()->getFullURL()); return false; // success // success case EditPage::AS_SPAM_ERROR: // summary contained spam according to one of the regexes in $wgSummarySpamRegex $match = $resultDetails['spam']; if (is_array($match)) { $match = $this->getLanguage()->listToText($match); } throw new MWException(wfMessage('spamprotectionmatch', wfEscapeWikiText($match))->parse()); // FIXME: Include better error message // FIXME: Include better error message case EditPage::AS_BLOCKED_PAGE_FOR_USER: // User is blocked from editting editor page throw new UserBlockedError($this->getUser()->getBlock()); case EditPage::AS_IMAGE_REDIRECT_ANON: // anonymous user is not allowed to upload (User::isAllowed('upload') == false) // anonymous user is not allowed to upload (User::isAllowed('upload') == false) case EditPage::AS_IMAGE_REDIRECT_LOGGED: // logged in user is not allowed to upload (User::isAllowed('upload') == false) throw new PermissionsError('upload'); case EditPage::AS_READ_ONLY_PAGE_ANON: // editor anonymous user is not allowed to edit editor page // editor anonymous user is not allowed to edit editor page case EditPage::AS_READ_ONLY_PAGE_LOGGED: // editor logged in user is not allowed to edit editor page throw new PermissionsError('edit'); case EditPage::AS_READ_ONLY_PAGE: // wiki is in readonly mode (wfReadOnly() == true) throw new ReadOnlyError(); case EditPage::AS_RATE_LIMITED: // rate limiter for action 'edit' was tripped throw new ThrottledError(); case EditPage::AS_NO_CREATE_PERMISSION: // user tried to create editor page, but is not allowed to do that ( Title->usercan('create') == false ) $permission = $title->isTalkPage() ? 'createtalk' : 'createpage'; throw new PermissionsError($permission); default: // We don't recognize $status->value. The only way that can happen // is if an extension hook aborted from inside ArticleSave. // Render the status object into $editor->hookError $editor->hookError = '<div class="error">' . $status->getWikitext() . '</div>'; throw new MWException($status->getHTML()); } }
/** * Guess the alternative rev ID the text of this form is based off. * When undoing the top X edits, the base can be though of as either * the current or the edit X edits prior to the latest. * Note: baseRevId trusted for Reviewers - check text for others. * @param EditPage $editPage * @param WebRequest $request * @return int */ protected static function getAltBaseRevId(EditPage $editPage, WebRequest $request) { if ($editPage->isConflict) { return 0; // throw away these values (bug 33481) } if (!isset($editPage->fr_altBaseRevId)) { $article = $editPage->getArticle(); // convenience $latestId = $article->getLatest(); // current rev $undo = $request->getIntOrNull('undo'); # Undoing consecutive top edits... if ($undo && $undo === $latestId) { # Treat this like a revert to a base revision. # We are undoing all edits *after* some rev ID (undoafter). # If undoafter is not given, then it is the previous rev ID. $revId = $request->getInt('undoafter', $article->getTitle()->getPreviousRevisionID($latestId, Title::GAID_FOR_UPDATE)); } else { $revId = $request->getInt('altBaseRevId'); } $editPage->fr_altBaseRevId = $revId; } return $editPage->fr_altBaseRevId; }
/** * This function is called when an article is modified via the Mediawiki API. * The article's name is stored for later update with the IAI bot * (see iaifArticleSaveComplete). * * @param EditPage $editPage * @param string $text * @param array $resultArr * @return bool true */ function iaifAPIEditBeforeSave(&$editPage, $text, &$resultArr) { iaifStartLog("iaifAPIEditBeforeSave"); global $iaigIP; global $iaigUpdateWithBot; $t = $editPage->getArticle()->getTitle()->getFullText(); $iaigUpdateWithBot[] = $t; global $iaigLog, $iaigStartTime; fprintf($iaigLog, "iaifAPIEditBeforeSave: %f (ms)\n", (microtime(true) - $iaigStartTime) / 1000); iaifEndLog("iaifAPIEditBeforeSave"); return true; }
/** * Display header on 'Task:' pages (dummy hook for edit pages) * @param EditPage $editPage */ public static function onEditPageShowEditFormInitial(&$editPage) { # Checked for HTML and MySQL insertion attacks return self::onArticleViewHeader($editPage->getArticle()); }
/** * EditPageBeforeEditButtons hook * Add draft saving controls */ public static function onEditPageBeforeEditButtons(EditPage $editpage, $buttons, &$tabindex) { global $egDraftsAutoSaveWait, $egDraftsAutoSaveTimeout, $egDraftsAutoSaveInputBased; $context = $editpage->getArticle()->getContext(); $user = $context->getUser(); if (!$user->getOption('extensionDrafts_enable', 'true')) { return true; } // Check permissions if ($user->isAllowed('edit') && $user->isLoggedIn()) { $request = $context->getRequest(); // Build XML $buttons['savedraft'] = Xml::openElement('script', array('type' => 'text/javascript', 'language' => 'javascript')); $buttonAttribs = array('id' => 'wpDraftSave', 'name' => 'wpDraftSave', 'class' => 'button secondary disabled', 'tabindex' => ++$tabindex, 'value' => $context->msg('drafts-save-save')->text()); $attribs = Linker::tooltipAndAccesskeyAttribs('drafts-save'); if (isset($attribs['accesskey'])) { $buttonAttribs['accesskey'] = $attribs['accesskey']; } if (isset($attribs['tooltip'])) { $buttonAttribs['title'] = $attribs['title']; } $ajaxButton = Xml::escapeJsString(Xml::element('input', array('type' => 'submit') + $buttonAttribs + ($request->getText('action') !== 'submit' ? array('disabled' => 'disabled') : array()))); $buttons['savedraft'] .= "document.write( '{$ajaxButton}' );"; $buttons['savedraft'] .= Xml::closeElement('script'); $buttons['savedraft'] .= Xml::openElement('noscript'); $buttons['savedraft'] .= Xml::element('input', array('type' => 'submit') + $buttonAttribs); $buttons['savedraft'] .= Xml::closeElement('noscript'); $buttons['savedraft'] .= Xml::element('input', array('type' => 'hidden', 'name' => 'wpDraftToken', 'value' => MWCryptRand::generateHex(32))); $buttons['savedraft'] .= Xml::element('input', array('type' => 'hidden', 'name' => 'wpDraftID', 'value' => $request->getInt('draft', ''))); $buttons['savedraft'] .= Xml::element('input', array('type' => 'hidden', 'name' => 'wpDraftTitle', 'value' => $context->getTitle()->getPrefixedText())); } // Continue return true; }