/** * Constructor. * * @param IContextSource $context * @param array $conds * @param string $className */ public function __construct(IContextSource $context, array $conds, $className) { $this->conds = $conds; $this->className = $className; $this->context = $context; $this->mDefaultDirection = true; parent::__construct($context); $this->context->getOutput()->addModules('ep.pager'); }
/** * Display a pager with articles. * * @since 0.1 * * @param IContextSource $context * @param array $conditions */ public static function displayPager(IContextSource $context, array $conditions = array()) { $pager = new EPArticlePager($context, $conditions); if ($pager->getNumRows()) { $context->getOutput()->addHTML($pager->getFilterControl() . $pager->getNavigationBar() . $pager->getBody() . $pager->getNavigationBar() . $pager->getMultipleItemControl()); } else { $context->getOutput()->addHTML($pager->getFilterControl(true)); $context->getOutput()->addWikiMsg('ep-articles-noresults'); } }
public function includeAssets() { TranslationHelpers::addModules($this->context->getOutput()); $pages = array(); foreach ($this->collection->getTitles() as $title) { $pages[] = $title->getPrefixedDBKey(); } $vars = array('trlKeys' => $pages); $this->context->getOutput()->addScript(Skin::makeVariablesScript($vars)); }
/** * @param $context IContextSource * @param $pageType */ public static function addNavigationLinks(IContextSource $context, $pageType) { $linkDefs = array('home' => 'Special:AbuseFilter', 'recentchanges' => 'Special:AbuseFilter/history', 'examine' => 'Special:AbuseFilter/examine', 'log' => 'Special:AbuseLog'); if ($context->getUser()->isAllowed('abusefilter-modify')) { $linkDefs = array_merge($linkDefs, array('test' => 'Special:AbuseFilter/test', 'tools' => 'Special:AbuseFilter/tools', 'import' => 'Special:AbuseFilter/import')); } // Save some translator work $msgOverrides = array('recentchanges' => 'abusefilter-filter-log'); $links = array(); foreach ($linkDefs as $name => $page) { // Give grep a chance to find the usages: // abusefilter-topnav-home, abusefilter-topnav-test, abusefilter-topnav-examine // abusefilter-topnav-log, abusefilter-topnav-tools, abusefilter-topnav-import $msgName = "abusefilter-topnav-{$name}"; if (isset($msgOverrides[$name])) { $msgName = $msgOverrides[$name]; } $msg = wfMessage($msgName)->parse(); $title = Title::newFromText($page); if ($name == $pageType) { $links[] = Xml::tags('strong', null, $msg); } else { $links[] = Linker::link($title, $msg); } } $linkStr = wfMessage('parentheses', $context->getLanguage()->pipeList($links))->text(); $linkStr = wfMessage('abusefilter-topnav')->parse() . " {$linkStr}"; $linkStr = Xml::tags('div', array('class' => 'mw-abusefilter-navigation'), $linkStr); $context->getOutput()->setSubtitle($linkStr); }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $request->getVal('action', 'view') == 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_MAIN, 'AJAX'); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; if ($wgUseFileCache && $title->getNamespace() >= 0) { wfProfileIn('main-try-filecache'); if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = HTMLFileCache::newFromTitle($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } $this->performRequest(); // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction wfGetLBFactory()->commitMasterChanges(); // Output everything! $this->context->getOutput()->output(); wfProfileOut(__METHOD__); }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $request->getVal('action', 'view') == 'ajax') { // Set a dummy title, because $wgTitle == null might break things // Wikia change - start // @author macbre, wladek $title = Wikia::createTitleFromRequest($request); // Wikia change - end $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; if ($wgUseFileCache && $title->getNamespace() >= 0) { wfProfileIn('main-try-filecache'); if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = HTMLFileCache::newFromTitle($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } $this->performRequest(); $this->finalCleanup(); wfProfileOut(__METHOD__); }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); # Set title from request parameters $wgTitle = $this->getTitle(); $action = $this->getAction(); $user = $this->context->getUser(); # Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $action == 'ajax') { $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } if ($wgUseFileCache && $wgTitle->getNamespace() != NS_SPECIAL) { wfProfileIn('main-try-filecache'); // Raw pages should handle cache control on their own, // even when using file cache. This reduces hits from clients. if (HTMLFileCache::useFileCache()) { /* Try low-level file cache hit */ $cache = new HTMLFileCache($wgTitle, $action); if ($cache->isFileCacheGood()) { /* Check incoming headers to see if client has this cached */ $timestamp = $cache->fileCacheTime(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache(); } # Do any stats increment/watchlist stuff $article = WikiPage::factory($wgTitle); $article->doViewUpdates($user); # Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } $this->performRequest(); $this->finalCleanup(); wfProfileOut(__METHOD__); }
/** * @param IContextSource $context * * @return string HTML */ public function getHtml(IContextSource $context) { $context->getOutput()->addModules('ext.translate.statsbar'); $total = $this->stats[MessageGroupStats::TOTAL]; $proofread = $this->stats[MessageGroupStats::PROOFREAD]; $translated = $this->stats[MessageGroupStats::TRANSLATED]; $fuzzy = $this->stats[MessageGroupStats::FUZZY]; if (!$total) { $untranslated = null; $wproofread = $wtranslated = $wfuzzy = $wuntranslated = 0; } else { // Proofread is subset of translated $untranslated = $total - $translated - $fuzzy; $wproofread = round(100 * $proofread / $total, 2); $wtranslated = round(100 * ($translated - $proofread) / $total, 2); $wfuzzy = round(100 * $fuzzy / $total, 2); $wuntranslated = round(100 - $wproofread - $wtranslated - $wfuzzy, 2); } return Html::rawElement('div', array('class' => 'tux-statsbar', 'data-total' => $total, 'data-group' => $this->group, 'data-language' => $this->language), Html::element('span', array('class' => 'tux-proofread', 'style' => "width: {$wproofread}%", 'data-proofread' => $proofread)) . Html::element('span', array('class' => 'tux-translated', 'style' => "width: {$wtranslated}%", 'data-translated' => $translated)) . Html::element('span', array('class' => 'tux-fuzzy', 'style' => "width: {$wfuzzy}%", 'data-fuzzy' => $fuzzy)) . Html::element('span', array('class' => 'tux-untranslated', 'style' => "width: {$wuntranslated}%", 'data-untranslated' => $untranslated))); }
private function main() { global $wgUseFileCache, $wgTitle, $wgUseAjax; wfProfileIn(__METHOD__); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($wgUseAjax && $request->getVal('action', 'view') == 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_MAIN, 'AJAX'); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher(); $dispatcher->performAction(); wfProfileOut(__METHOD__); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; // If the user has forceHTTPS set to true, or if the user // is in a group requiring HTTPS, or if they have the HTTPS // preference set, redirect them to HTTPS. // Note: Do this after $wgTitle is setup, otherwise the hooks run from // isLoggedIn() will do all sorts of weird stuff. if (($request->getCookie('forceHTTPS', '') || $request->getCookie('forceHTTPS') || $this->context->getUser()->isLoggedIn() && $this->context->getUser()->requiresHTTPS()) && $request->getProtocol() == 'http') { $oldUrl = $request->getFullRequestURL(); $redirUrl = str_replace('http://', 'https://', $oldUrl); if ($request->wasPosted()) { // This is weird and we'd hope it almost never happens. This // means that a POST came in via HTTP and policy requires us // redirecting to HTTPS. It's likely such a request is going // to fail due to post data being lost, but let's try anyway // and just log the instance. // // @todo @fixme See if we could issue a 307 or 308 here, need // to see how clients (automated & browser) behave when we do wfDebugLog('RedirectedPosts', "Redirected from HTTP to HTTPS: {$oldUrl}"); } // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText(NS_MAIN, 'REDIR'); $this->context->setTitle($title); $output = $this->context->getOutput(); // Since we only do this redir to change proto, always send a vary header $output->addVaryHeader('X-Forwarded-Proto'); $output->redirect($redirUrl); $output->output(); wfProfileOut(__METHOD__); return; } if ($wgUseFileCache && $title->getNamespace() >= 0) { wfProfileIn('main-try-filecache'); if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = HTMLFileCache::newFromTitle($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff // Assume we're viewing the latest revision (this should always be the case with file cache) $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); wfProfileOut('main-try-filecache'); wfProfileOut(__METHOD__); return; } } wfProfileOut('main-try-filecache'); } // Actually do the work of the request and build up any output $this->performRequest(); // Either all DB and deferred updates should happen or none. // The later should not be cancelled due to client disconnect. ignore_user_abort(true); // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction wfGetLBFactory()->commitMasterChanges(); // Output everything! $this->context->getOutput()->output(); wfProfileOut(__METHOD__); }
/** * Get the OutputPage being used for this instance. * IndexPager extends ContextSource as of 1.19. * * @since 0.1 * * @return OutputPage */ public function getOutput() { return $this->context->getOutput(); }
private function main() { global $wgTitle; $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($this->config->get('UseAjax') && $request->getVal('action') === 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_SPECIAL, 'Badtitle/performing an AJAX call in ' . __METHOD__); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher($this->config); $dispatcher->performAction($this->context->getUser()); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; $trxProfiler = Profiler::instance()->getTransactionProfiler(); $trxProfiler->setLogger(LoggerFactory::getInstance('DBPerformance')); // Aside from rollback, master queries should not happen on GET requests. // Periodic or "in passing" updates on GET should use the job queue. if (!$request->wasPosted() && in_array($action, array('view', 'edit', 'history'))) { $trxProfiler->setExpectation('masterConns', 0, __METHOD__); $trxProfiler->setExpectation('writes', 0, __METHOD__); } else { $trxProfiler->setExpectation('maxAffected', 500, __METHOD__); } // If the user has forceHTTPS set to true, or if the user // is in a group requiring HTTPS, or if they have the HTTPS // preference set, redirect them to HTTPS. // Note: Do this after $wgTitle is setup, otherwise the hooks run from // isLoggedIn() will do all sorts of weird stuff. if ($request->getProtocol() == 'http' && ($request->getCookie('forceHTTPS', '') || $request->getCookie('forceHTTPS') || $this->context->getUser()->isLoggedIn() && $this->context->getUser()->requiresHTTPS())) { $oldUrl = $request->getFullRequestURL(); $redirUrl = preg_replace('#^http://#', 'https://', $oldUrl); // ATTENTION: This hook is likely to be removed soon due to overall design of the system. if (Hooks::run('BeforeHttpsRedirect', array($this->context, &$redirUrl))) { if ($request->wasPosted()) { // This is weird and we'd hope it almost never happens. This // means that a POST came in via HTTP and policy requires us // redirecting to HTTPS. It's likely such a request is going // to fail due to post data being lost, but let's try anyway // and just log the instance. // // @todo FIXME: See if we could issue a 307 or 308 here, need // to see how clients (automated & browser) behave when we do wfDebugLog('RedirectedPosts', "Redirected from HTTP to HTTPS: {$oldUrl}"); } // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText('REDIR', NS_MAIN); $this->context->setTitle($title); $output = $this->context->getOutput(); // Since we only do this redir to change proto, always send a vary header $output->addVaryHeader('X-Forwarded-Proto'); $output->redirect($redirUrl); $output->output(); return; } } if ($this->config->get('UseFileCache') && $title->getNamespace() >= 0) { if (HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = new HTMLFileCache($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$this->context->getOutput()->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff // Assume we're viewing the latest revision (this should always be the case with file cache) $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $this->context->getOutput()->disable(); return; } } } // Actually do the work of the request and build up any output $this->performRequest(); // Either all DB and deferred updates should happen or none. // The later should not be cancelled due to client disconnect. ignore_user_abort(true); // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction wfGetLBFactory()->commitMasterChanges(); // Output everything! $this->context->getOutput()->output(); }
/** * Just like executePath() but will override global variables and execute * the page in "inclusion" mode. Returns true if the execution was * successful or false if there was no such special page, or a title object * if it was a redirect. * * Also saves the current $wgTitle, $wgOut, $wgRequest, $wgUser and $wgLang * variables so that the special page will get the context it'd expect on a * normal request, and then restores them to their previous values after. * * @param $title Title * @param $context IContextSource * * @return String: HTML fragment */ static function capturePath(Title $title, IContextSource $context) { global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang; // Save current globals $oldTitle = $wgTitle; $oldOut = $wgOut; $oldRequest = $wgRequest; $oldUser = $wgUser; $oldLang = $wgLang; // Set the globals to the current context $wgTitle = $title; $wgOut = $context->getOutput(); $wgRequest = $context->getRequest(); $wgUser = $context->getUser(); $wgLang = $context->getLanguage(); // The useful part $ret = self::executePath($title, $context, true); // And restore the old globals $wgTitle = $oldTitle; $wgOut = $oldOut; $wgRequest = $oldRequest; $wgUser = $oldUser; $wgLang = $oldLang; return $ret; }
/** * Adds a control to add a term org to the provided context. * Additional arguments can be provided to set the default values for the control fields. * * @since 0.1 * * @param IContextSource $context * @param array $args * * @return boolean */ public static function displayAddNewControl(IContextSource $context, array $args) { if (!$context->getUser()->isAllowed('ep-course')) { return false; } $out = $context->getOutput(); $out->addModules('ep.addcourse'); $out->addHTML(Html::openElement('form', array('method' => 'post', 'action' => self::getTitleFor('NAME_PLACEHOLDER')->getLocalURL(array('action' => 'edit'))))); $out->addHTML('<fieldset>'); $out->addHTML('<legend>' . wfMsgHtml('ep-courses-addnew') . '</legend>'); $out->addElement('p', array(), wfMsg('ep-courses-namedoc')); $out->addElement('label', array('for' => 'neworg'), wfMsg('ep-courses-neworg')); $select = new XmlSelect('neworg', 'neworg', array_key_exists('org', $args) ? $args['org'] : false); $select->addOptions(EPOrg::getOrgOptions()); $out->addHTML($select->getHTML()); $out->addHTML(' ' . Xml::inputLabel(wfMsg('ep-courses-newname'), 'newname', 'newname', 20, array_key_exists('name', $args) ? $args['name'] : false)); $out->addHTML(' ' . Xml::inputLabel(wfMsg('ep-courses-newterm'), 'newterm', 'newterm', 10, array_key_exists('term', $args) ? $args['term'] : false)); $out->addHTML(' ' . Html::input('addnewcourse', wfMsg('ep-courses-add'), 'submit', array('disabled' => 'disabled', 'class' => 'ep-course-add'))); $out->addHTML(Html::hidden('isnew', 1)); $out->addHTML('</fieldset></form>'); return true; }
/** * Adds a navigation menu with the provided links. * Links should be provided in an array with: * label => Title (object) * * @since 0.1 * * @param IContextSource $context * @param array $items */ public static function displayNavigation(IContextSource $context, array $items = array()) { $links = array(); foreach ($items as $label => $data) { if (is_array($data)) { $target = array_shift($data); $attribs = $data; } else { $target = $data; $attribs = array(); } $links[] = Linker::linkKnown($target, htmlspecialchars($label), $attribs); } $context->getOutput()->addHTML(Html::rawElement('p', array(), $context->getLanguage()->pipeList($links))); }
/** * Returns the tool links for this mentor. * * @since 0.1 * * @param IContextSource $context * @param EPCourse|null $course * * @return string */ public function getToolLinks(IContextSource $context, EPCourse $course = null) { $links = array(); $links[] = Linker::userTalkLink($this->getUser()->getId(), $this->getUser()->getName()); $links[] = Linker::link(SpecialPage::getTitleFor('Contributions', $this->getUser()->getName()), wfMsgHtml('contribslink')); if (!is_null($course) && ($context->getUser()->isAllowed('ep-instructor') || $this->getUser()->getId() == $context->getUser()->getId())) { $links[] = Html::element('a', array('href' => '#', 'class' => 'ep-instructor-remove', 'data-courseid' => $course->getId(), 'data-coursename' => $course->getField('name'), 'data-userid' => $this->getUser()->getId(), 'data-username' => $this->getUser()->getName(), 'data-bestname' => $this->getName()), wfMsg('ep-instructor-remove')); $context->getOutput()->addModules('ep.instructor'); } return ' <span class="mw-usertoollinks">(' . $context->getLanguage()->pipeList($links) . ')</span>'; }
/** * Hook to provide syntax highlighting for API pretty-printed output * * @param IContextSource $context * @param string $text * @param string $mime * @param string $format * @since MW 1.24 */ public static function onApiFormatHighlight(IContextSource $context, $text, $mime, $format) { if (!isset(self::$mimeLexers[$mime])) { return true; } $lexer = self::$mimeLexers[$mime]; $status = self::highlight($text, $lexer); if (!$status->isOK()) { return true; } $out = $status->getValue(); if (preg_match('/^<pre([^>]*)>/i', $out, $m)) { $attrs = Sanitizer::decodeTagAttributes($m[1]); $attrs['class'] .= ' api-pretty-content'; $encodedAttrs = Sanitizer::safeEncodeTagAttributes($attrs); $out = '<pre' . $encodedAttrs . '>' . substr($out, strlen($m[0])); } $output = $context->getOutput(); $output->addModuleStyles('ext.pygments'); $output->addHTML('<div dir="ltr">' . $out . '</div>'); // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. return false; }
/** * Save submitted protection form * * @return bool Success */ function save() { # Permission check! if ($this->disabled) { $this->show(); return false; } $request = $this->mContext->getRequest(); $user = $this->mContext->getUser(); $out = $this->mContext->getOutput(); $token = $request->getVal('wpEditToken'); if (!$user->matchEditToken($token, ['protect', $this->mTitle->getPrefixedDBkey()])) { $this->show(['sessionfailure']); return false; } # Create reason string. Use list and/or custom string. $reasonstr = $this->mReasonSelection; if ($reasonstr != 'other' && $this->mReason != '') { // Entry from drop down menu + additional comment $reasonstr .= $this->mContext->msg('colon-separator')->text() . $this->mReason; } elseif ($reasonstr == 'other') { $reasonstr = $this->mReason; } $expiry = []; foreach ($this->mApplicableTypes as $action) { $expiry[$action] = $this->getExpiry($action); if (empty($this->mRestrictions[$action])) { continue; // unprotected } if (!$expiry[$action]) { $this->show(['protect_expiry_invalid']); return false; } if ($expiry[$action] < wfTimestampNow()) { $this->show(['protect_expiry_old']); return false; } } $this->mCascade = $request->getBool('mwProtect-cascade'); $status = $this->mArticle->doUpdateRestrictions($this->mRestrictions, $expiry, $this->mCascade, $reasonstr, $user); if (!$status->isOK()) { $this->show($out->parseInline($status->getWikiText())); return false; } /** * Give extensions a change to handle added form items * * @since 1.19 you can (and you should) return false to abort saving; * you can also return an array of message name and its parameters */ $errorMsg = ''; if (!Hooks::run('ProtectionForm::save', [$this->mArticle, &$errorMsg, $reasonstr])) { if ($errorMsg == '') { $errorMsg = ['hookaborted']; } } if ($errorMsg != '') { $this->show($errorMsg); return false; } WatchAction::doWatchOrUnwatch($request->getCheck('mwProtectWatch'), $this->mTitle, $user); return true; }
/** * Hook to provide syntax highlighting for API pretty-printed output * * @param IContextSource $context * @param string $text * @param string $mime * @param string $format * @since MW 1.24 */ public static function apiFormatHighlight(IContextSource $context, $text, $mime, $format) { switch ($mime) { case 'text/javascript': case 'application/json': $lang = 'javascript'; break; case 'text/xml': $lang = 'xml'; break; default: // Don't know how to handle this return true; } $geshi = self::prepare($text, $lang); if ($geshi instanceof GeSHi) { $out = $geshi->parse_code(); if (!$geshi->error()) { if (preg_match('/^<pre([^>]*)>/i', $out, $m)) { $attrs = Sanitizer::decodeTagAttributes($m[1]); $attrs['class'] .= ' api-pretty-content'; $out = '<pre' . Sanitizer::safeEncodeTagAttributes($attrs) . '>' . substr($out, strlen($m[0])); } $output = $context->getOutput(); $output->addModuleStyles(array("ext.geshi.language.{$lang}", 'ext.geshi.local')); $output->addHTML("<div dir=\"ltr\">{$out}</div>"); // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. return false; } } // Bottle out return true; }
private function main() { global $wgTitle; $output = $this->context->getOutput(); $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ($this->config->get('UseAjax') && $request->getVal('action') === 'ajax') { // Set a dummy title, because $wgTitle == null might break things $title = Title::makeTitle(NS_SPECIAL, 'Badtitle/performing an AJAX call in ' . __METHOD__); $this->context->setTitle($title); $wgTitle = $title; $dispatcher = new AjaxDispatcher($this->config); $dispatcher->performAction($this->context->getUser()); return; } // Get title from request parameters, // is set on the fly by parseTitle the first time. $title = $this->getTitle(); $action = $this->getAction(); $wgTitle = $title; // Set DB query expectations for this HTTP request $trxLimits = $this->config->get('TrxProfilerLimits'); $trxProfiler = Profiler::instance()->getTransactionProfiler(); $trxProfiler->setLogger(LoggerFactory::getInstance('DBPerformance')); if ($request->hasSafeMethod()) { $trxProfiler->setExpectations($trxLimits['GET'], __METHOD__); } else { $trxProfiler->setExpectations($trxLimits['POST'], __METHOD__); } // If the user has forceHTTPS set to true, or if the user // is in a group requiring HTTPS, or if they have the HTTPS // preference set, redirect them to HTTPS. // Note: Do this after $wgTitle is setup, otherwise the hooks run from // isLoggedIn() will do all sorts of weird stuff. if ($request->getProtocol() == 'http' && preg_match('#^https://#', wfExpandUrl($request->getRequestURL(), PROTO_HTTPS)) && ($request->getSession()->shouldForceHTTPS() || $request->getCookie('forceHTTPS', '') || $request->getCookie('forceHTTPS') || $this->context->getUser()->isLoggedIn() && $this->context->getUser()->requiresHTTPS())) { $oldUrl = $request->getFullRequestURL(); $redirUrl = preg_replace('#^http://#', 'https://', $oldUrl); // ATTENTION: This hook is likely to be removed soon due to overall design of the system. if (Hooks::run('BeforeHttpsRedirect', [$this->context, &$redirUrl])) { if ($request->wasPosted()) { // This is weird and we'd hope it almost never happens. This // means that a POST came in via HTTP and policy requires us // redirecting to HTTPS. It's likely such a request is going // to fail due to post data being lost, but let's try anyway // and just log the instance. // @todo FIXME: See if we could issue a 307 or 308 here, need // to see how clients (automated & browser) behave when we do wfDebugLog('RedirectedPosts', "Redirected from HTTP to HTTPS: {$oldUrl}"); } // Setup dummy Title, otherwise OutputPage::redirect will fail $title = Title::newFromText('REDIR', NS_MAIN); $this->context->setTitle($title); // Since we only do this redir to change proto, always send a vary header $output->addVaryHeader('X-Forwarded-Proto'); $output->redirect($redirUrl); $output->output(); return; } } if ($title->canExist() && HTMLFileCache::useFileCache($this->context)) { // Try low-level file cache hit $cache = new HTMLFileCache($title, $action); if ($cache->isCacheGood()) { // Check incoming headers to see if client has this cached $timestamp = $cache->cacheTimestamp(); if (!$output->checkLastModified($timestamp)) { $cache->loadFromFileCache($this->context); } // Do any stats increment/watchlist stuff, assuming user is viewing the // latest revision (which should always be the case for file cache) $this->context->getWikiPage()->doViewUpdates($this->context->getUser()); // Tell OutputPage that output is taken care of $output->disable(); return; } } // Actually do the work of the request and build up any output $this->performRequest(); // GUI-ify and stash the page output in MediaWiki::doPreOutputCommit() while // ChronologyProtector synchronizes DB positions or slaves accross all datacenters. $buffer = null; $outputWork = function () use($output, &$buffer) { if ($buffer === null) { $buffer = $output->output(true); } return $buffer; }; // Now commit any transactions, so that unreported errors after // output() don't roll back the whole DB transaction and so that // we avoid having both success and error text in the response $this->doPreOutputCommit($outputWork); // Now send the actual output print $outputWork(); }
/** * Read from cache to context output * @param IContextSource $context * @param integer $mode One of the HTMLFileCache::MODE_* constants * @return void */ public function loadFromFileCache(IContextSource $context, $mode = self::MODE_NORMAL) { global $wgContLang; $config = MediaWikiServices::getInstance()->getMainConfig(); wfDebug(__METHOD__ . "()\n"); $filename = $this->cachePath(); if ($mode === self::MODE_OUTAGE) { // Avoid DB errors for queries in sendCacheControl() $context->getTitle()->resetArticleID(0); } $context->getOutput()->sendCacheControl(); header("Content-Type: {$config->get('MimeType')}; charset=UTF-8"); header("Content-Language: {$wgContLang->getHtmlCode()}"); if ($this->useGzip()) { if (wfClientAcceptsGzip()) { header('Content-Encoding: gzip'); readfile($filename); } else { /* Send uncompressed */ wfDebug(__METHOD__ . " uncompressing cache file and sending it\n"); readgzfile($filename); } } else { readfile($filename); } $context->getOutput()->disable(); // tell $wgOut that output is taken care of }
/** * Read from cache to context output * @param $context IContextSource * @return void */ public function loadFromFileCache(IContextSource $context) { global $wgMimeType, $wgLanguageCode; wfDebug(__METHOD__ . "()\n"); $filename = $this->cachePath(); $context->getOutput()->sendCacheControl(); header("Content-Type: {$wgMimeType}; charset=UTF-8"); header("Content-Language: {$wgLanguageCode}"); if ($this->useGzip()) { if (wfClientAcceptsGzip()) { header('Content-Encoding: gzip'); readfile($filename); } else { /* Send uncompressed */ wfDebug(__METHOD__ . " uncompressing cache file and sending it\n"); readgzfile($filename); } } else { readfile($filename); } $context->getOutput()->disable(); // tell $wgOut that output is taken care of }
/** * Adds a control to add a term org to the provided context. * Additional arguments can be provided to set the default values for the control fields. * * @since 0.1 * * @param IContextSource $context * @param array $args * * @return boolean */ public static function displayAddNewControl(IContextSource $context, array $args) { if (!$context->getUser()->isAllowed('ep-term')) { return false; } $out = $context->getOutput(); $out->addHTML(Html::openElement('form', array('method' => 'post', 'action' => SpecialPage::getTitleFor('EditTerm')->getLocalURL()))); $out->addHTML('<fieldset>'); $out->addHTML('<legend>' . wfMsgHtml('ep-terms-addnew') . '</legend>'); $out->addHTML(Html::element('p', array(), wfMsg('ep-terms-namedoc'))); $out->addHTML(Html::element('label', array('for' => 'newcourse'), wfMsg('ep-terms-newcourse'))); $select = new XmlSelect('newcourse', 'newcourse', array_key_exists('course', $args) ? $args['course'] : false); $select->addOptions(EPCourse::getCourseOptions()); $out->addHTML($select->getHTML()); $out->addHTML(' ' . Xml::inputLabel(wfMsg('ep-terms-newyear'), 'newyear', 'newyear', 10)); $out->addHTML(' ' . Html::input('addnewterm', wfMsg('ep-terms-add'), 'submit')); $out->addHTML(Html::hidden('isnew', 1)); $out->addHTML('</fieldset></form>'); return true; }
/** * Just like executePath() but will override global variables and execute * the page in "inclusion" mode. Returns true if the execution was * successful or false if there was no such special page, or a title object * if it was a redirect. * * Also saves the current $wgTitle, $wgOut, $wgRequest, $wgUser and $wgLang * variables so that the special page will get the context it'd expect on a * normal request, and then restores them to their previous values after. * * @param Title $title * @param IContextSource $context * @return string HTML fragment */ public static function capturePath(Title $title, IContextSource $context) { global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang; $main = RequestContext::getMain(); // Save current globals and main context $glob = ['title' => $wgTitle, 'output' => $wgOut, 'request' => $wgRequest, 'user' => $wgUser, 'language' => $wgLang]; $ctx = ['title' => $main->getTitle(), 'output' => $main->getOutput(), 'request' => $main->getRequest(), 'user' => $main->getUser(), 'language' => $main->getLanguage()]; // Override $wgTitle = $title; $wgOut = $context->getOutput(); $wgRequest = $context->getRequest(); $wgUser = $context->getUser(); $wgLang = $context->getLanguage(); $main->setTitle($title); $main->setOutput($context->getOutput()); $main->setRequest($context->getRequest()); $main->setUser($context->getUser()); $main->setLanguage($context->getLanguage()); // The useful part $ret = self::executePath($title, $context, true); // Restore old globals and context $wgTitle = $glob['title']; $wgOut = $glob['output']; $wgRequest = $glob['request']; $wgUser = $glob['user']; $wgLang = $glob['language']; $main->setTitle($ctx['title']); $main->setOutput($ctx['output']); $main->setRequest($ctx['request']); $main->setUser($ctx['user']); $main->setLanguage($ctx['language']); return $ret; }
/** * Attempt to validate and submit this data to the DB * @param $context IContextSource * @return array( true or error key string, html error msg or null ) */ public function submit(IContextSource $context) { global $wgAuth, $wgAccountRequestThrottle, $wgMemc, $wgContLang; global $wgConfirmAccountRequestFormItems; $formConfig = $wgConfirmAccountRequestFormItems; // convience $reqUser = $this->requester; # Make sure that basic permissions are checked $block = ConfirmAccount::getAccountRequestBlock($reqUser); if ($block) { return array('accountreq_permission_denied', $context->msg('badaccess-group0')->escaped()); } elseif (wfReadOnly()) { return array('accountreq_readonly', $context->msg('badaccess-group0')->escaped()); } # Now create a dummy user ($u) and check if it is valid if ($this->userName === '') { return array('accountreq_no_name', $context->msg('noname')->escaped()); } $u = User::newFromName($this->userName, 'creatable'); if (!$u) { return array('accountreq_invalid_name', $context->msg('noname')->escaped()); } # No request spamming... if ($wgAccountRequestThrottle && $reqUser->isPingLimitable()) { $key = wfMemcKey('acctrequest', 'ip', $this->ip); $value = (int) $wgMemc->get($key); if ($value > $wgAccountRequestThrottle) { return array('accountreq_throttled', $context->msg('acct_request_throttle_hit', $wgAccountRequestThrottle)->text()); } } # Make sure user agrees to policy here if ($formConfig['TermsOfService']['enabled'] && !$this->tosAccepted) { return array('acct_request_skipped_tos', $context->msg('requestaccount-agree')->escaped()); } # Validate email address if (!Sanitizer::validateEmail($this->email)) { return array('acct_request_invalid_email', $context->msg('invalidemailaddress')->escaped()); } # Check if biography is long enough if ($formConfig['Biography']['enabled'] && str_word_count($this->bio) < $formConfig['Biography']['minWords']) { $minWords = $formConfig['Biography']['minWords']; return array('acct_request_short_bio', $context->msg('requestaccount-tooshort')->numParams($minWords)->text()); } # Per security reasons, file dir cannot be pulled from client, # so ask them to resubmit it then... # If the extra fields are off, then uploads are off $allowFiles = $formConfig['CV']['enabled']; if ($allowFiles && $this->attachmentPrevName && !$this->attachmentSrcName) { # If the user is submitting forgotAttachment as true with no file, # then they saw the notice and choose not to re-select the file. # Assume that they don't want to send one anymore. if (!$this->attachmentDidNotForget) { $this->attachmentPrevName = ''; $this->attachmentDidNotForget = 0; return array(false, $context->msg('requestaccount-resub')->escaped()); } } # Check if already in use if (0 != $u->idForName() || $wgAuth->userExists($u->getName())) { return array('accountreq_username_exists', $context->msg('userexists')->escaped()); } # Set email and real name $u->setEmail($this->email); $u->setRealName($this->realName); $dbw = wfGetDB(DB_MASTER); $dbw->begin(); // ready to acquire locks # Check pending accounts for name use if (!UserAccountRequest::acquireUsername($u->getName())) { $dbw->rollback(); return array('accountreq_username_pending', $context->msg('requestaccount-inuse')->escaped()); } # Check if someone else has an account request with the same email if (!UserAccountRequest::acquireEmail($u->getEmail())) { $dbw->rollback(); return array('acct_request_email_exists', $context->msg('requestaccount-emaildup')->escaped()); } # Process upload... if ($allowFiles && $this->attachmentSrcName) { global $wgAccountRequestExts, $wgConfirmAccountFSRepos; $ext = explode('.', $this->attachmentSrcName); $finalExt = $ext[count($ext) - 1]; # File must have size. if (trim($this->attachmentSrcName) == '' || empty($this->attachmentSize)) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_empty_file', $context->msg('emptyfile')->escaped()); } # Look at the contents of the file; if we can recognize the # type but it's corrupt or data of the wrong type, we should # probably not accept it. if (!in_array($finalExt, $wgAccountRequestExts)) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_bad_file_ext', $context->msg('requestaccount-exts')->escaped()); } $veri = ConfirmAccount::verifyAttachment($this->attachmentTempPath, $finalExt); if (!$veri->isGood()) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_corrupt_file', $context->msg('verification-error')->escaped()); } # Start a transaction, move file from temp to account request directory. $repo = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $key = sha1_file($this->attachmentTempPath) . '.' . $finalExt; $pathRel = UserAccountRequest::relPathFromKey($key); $triplet = array($this->attachmentTempPath, 'public', $pathRel); $status = $repo->storeBatch(array($triplet), FSRepo::OVERWRITE_SAME); // save! if (!$status->isOk()) { $dbw->rollback(); return array('acct_request_file_store_error', $context->msg('filecopyerror', $this->attachmentTempPath, $pathRel)->escaped()); } } $expires = null; // passed by reference $token = ConfirmAccount::getConfirmationToken($u, $expires); # Insert into pending requests... $req = UserAccountRequest::newFromArray(array('name' => $u->getName(), 'email' => $u->getEmail(), 'real_name' => $u->getRealName(), 'registration' => $this->registration, 'bio' => $this->bio, 'notes' => $this->notes, 'urls' => $this->urls, 'filename' => isset($this->attachmentSrcName) ? $this->attachmentSrcName : null, 'type' => $this->type, 'areas' => $this->areas, 'storage_key' => isset($key) ? $key : null, 'comment' => '', 'email_token' => md5($token), 'email_token_expires' => $expires, 'ip' => $this->ip, 'xff' => $this->xff, 'agent' => $this->agent)); $req->insertOn(); # Send confirmation, required! $result = ConfirmAccount::sendConfirmationMail($u, $this->ip, $token, $expires); if (!$result->isOK()) { $dbw->rollback(); // nevermind if (isset($repo) && isset($pathRel)) { // remove attachment $repo->cleanupBatch(array(array('public', $pathRel))); } $param = $context->getOutput()->parse($result->getWikiText()); return array('acct_request_mail_failed', $context->msg('mailerror')->rawParams($param)->escaped()); } $dbw->commit(); # Clear cache for notice of how many account requests there are ConfirmAccount::clearAccountRequestCountCache(); # No request spamming... if ($wgAccountRequestThrottle && $reqUser->isPingLimitable()) { $ip = $context->getRequest()->getIP(); $key = wfMemcKey('acctrequest', 'ip', $ip); $value = $wgMemc->incr($key); if (!$value) { $wgMemc->set($key, 1, 86400); } } # Done! return array(true, null); }
protected function acceptRequest(IContextSource $context) { global $wgAuth, $wgAccountRequestTypes, $wgConfirmAccountSaveInfo; global $wgAllowAccountRequestFiles, $wgConfirmAccountFSRepos; $accReq = $this->accountReq; // convenience # Now create user and check if the name is valid $user = User::newFromName($this->userName, 'creatable'); if (!$user) { return array('accountconf_invalid_name', wfMsgHtml('noname')); } # Check if account name is already in use if (0 != $user->idForName() || $wgAuth->userExists($user->getName())) { return array('accountconf_user_exists', wfMsgHtml('userexists')); } $dbw = wfGetDB(DB_MASTER); $dbw->begin(); # Make a random password $p = User::randomPassword(); # Insert the new user into the DB... $tokenExpires = $accReq->getEmailTokenExpires(); $authenticated = $accReq->getEmailAuthTimestamp(); $params = array('real_name' => $accReq->getRealName(), 'newpassword' => User::crypt($p), 'email' => $accReq->getEmail(), 'email_authenticated' => $dbw->timestampOrNull($authenticated), 'email_token_expires' => $dbw->timestamp($tokenExpires), 'email_token' => $accReq->getEmailToken()); $user = User::createNew($user->getName(), $params); # Grant any necessary rights (exclude blank or dummy groups) $group = self::getGroupFromType($this->type); if ($group != '' && $group != 'user' && $group != '*') { $user->addGroup($group); } $acd_id = null; // used for rollback cleanup # Save account request data to credentials system if ($wgConfirmAccountSaveInfo) { $key = $accReq->getFileStorageKey(); # Copy any attached files to new storage group if ($wgAllowAccountRequestFiles && $key) { $repoOld = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $repoNew = new FSRepo($wgConfirmAccountFSRepos['accountcreds']); $pathRel = UserAccountRequest::relPathFromKey($key); $oldPath = $repoOld->getZonePath('public') . '/' . $pathRel; $triplet = array($oldPath, 'public', $pathRel); $status = $repoNew->storeBatch(array($triplet)); // copy! if (!$status->isOK()) { $dbw->rollback(); # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback($dbw, $user->getId(), $acd_id); return array('accountconf_copyfailed', $context->getOutput()->parse($status->getWikiText())); } } $acd_id = $dbw->nextSequenceValue('account_credentials_acd_id_seq'); # Move request data into a separate table $dbw->insert('account_credentials', array('acd_user_id' => $user->getID(), 'acd_real_name' => $accReq->getRealName(), 'acd_email' => $accReq->getEmail(), 'acd_email_authenticated' => $dbw->timestampOrNull($authenticated), 'acd_bio' => $accReq->getBio(), 'acd_notes' => $accReq->getNotes(), 'acd_urls' => $accReq->getUrls(), 'acd_ip' => $accReq->getIP(), 'acd_filename' => $accReq->getFileName(), 'acd_storage_key' => $accReq->getFileStorageKey(), 'acd_areas' => $accReq->getAreas('flat'), 'acd_registration' => $dbw->timestamp($accReq->getRegistration()), 'acd_accepted' => $dbw->timestamp(), 'acd_user' => $this->admin->getID(), 'acd_comment' => $this->reason, 'acd_id' => $acd_id), __METHOD__); if (is_null($acd_id)) { $acd_id = $dbw->insertId(); // set $acd_id to ID inserted } } # Add to global user login system (if there is one) if (!$wgAuth->addUser($user, $p, $accReq->getEmail(), $accReq->getRealName())) { $dbw->rollback(); # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback($dbw, $user->getId(), $acd_id); return array('accountconf_externaldberror', wfMsgHtml('externaldberror')); } # OK, now remove the request from the queue $accReq->remove(); # Commit this if we make past the CentralAuth system # and the groups are added. Next step is sending out an # email, which we cannot take back... $dbw->commit(); # Prepare a temporary password email... if ($this->reason != '') { $msg = "confirmaccount-email-body2-pos{$this->type}"; # If the user is in a group and there is a welcome for that group, use it if ($group && !wfEmptyMsg($msg)) { $ebody = wfMsgExt($msg, array('parsemag', 'content'), $user->getName(), $p, $this->reason); # Use standard if none found... } else { $ebody = wfMsgExt('confirmaccount-email-body2', array('parsemag', 'content'), $user->getName(), $p, $this->reason); } } else { $msg = "confirmaccount-email-body-pos{$this->type}"; # If the user is in a group and there is a welcome for that group, use it if ($group && !wfEmptyMsg($msg)) { $ebody = wfMsgExt($msg, array('parsemag', 'content'), $user->getName(), $p, $this->reason); # Use standard if none found... } else { $ebody = wfMsgExt('confirmaccount-email-body', array('parsemag', 'content'), $user->getName(), $p, $this->reason); } } # Actually send out the email (@TODO: rollback on failure including $wgAuth) $result = $user->sendMail(wfMsgForContent('confirmaccount-email-subj'), $ebody); /* if ( !$result->isOk() ) { # DELETE new rows in case there was a COMMIT somewhere $this->acceptRequest_rollback( $dbw, $user->getId(), $acd_id ); return array( 'accountconf_mailerror', wfMsg( 'mailerror', $context->getOutput()->parse( $result->getWikiText() ) ) ); } */ # Update user count $ssUpdate = new SiteStatsUpdate(0, 0, 0, 0, 1); $ssUpdate->doUpdate(); # Safe to hook/log now... wfRunHooks('AddNewAccount', array($user, false)); $user->addNewUserLogEntry(); # Clear cache for notice of how many account requests there are ConfirmAccount::clearAccountRequestCountCache(); # Delete any attached file and don't stop the whole process if this fails if ($wgAllowAccountRequestFiles) { $key = $accReq->getFileStorageKey(); if ($key) { $repoOld = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $pathRel = UserAccountRequest::relPathFromKey($key); $oldPath = $repoOld->getZonePath('public') . '/' . $pathRel; if (file_exists($oldPath)) { unlink($oldPath); // delete! } } } # Start up the user's userpages if set to do so. # Will not append, so previous content will be blanked. $this->createUserPage($user); # Greet the new user if set to do so. $this->createUserTalkPage($user); return array(true, null); }
/** * Build the input form * * @return string HTML form */ function buildForm() { $user = $this->mContext->getUser(); $output = $this->mContext->getOutput(); $lang = $this->mContext->getLanguage(); $cascadingRestrictionLevels = $this->mContext->getConfig()->get('CascadingRestrictionLevels'); $out = ''; if (!$this->disabled) { $output->addModules('mediawiki.legacy.protect'); $output->addJsConfigVars('wgCascadeableLevels', $cascadingRestrictionLevels); $out .= Xml::openElement('form', array('method' => 'post', 'action' => $this->mTitle->getLocalURL('action=protect'), 'id' => 'mw-Protect-Form')); } $out .= Xml::openElement('fieldset') . Xml::element('legend', null, wfMessage('protect-legend')->text()) . Xml::openElement('table', array('id' => 'mwProtectSet')) . Xml::openElement('tbody'); $scExpiryOptions = wfMessage('protect-expiry-options')->inContentLanguage()->text(); $showProtectOptions = $scExpiryOptions !== '-' && !$this->disabled; // Not all languages have V_x <-> N_x relation foreach ($this->mRestrictions as $action => $selected) { // Messages: // restriction-edit, restriction-move, restriction-create, restriction-upload $msg = wfMessage('restriction-' . $action); $out .= "<tr><td>" . Xml::openElement('fieldset') . Xml::element('legend', null, $msg->exists() ? $msg->text() : $action) . Xml::openElement('table', array('id' => "mw-protect-table-{$action}")) . "<tr><td>" . $this->buildSelector($action, $selected) . "</td></tr><tr><td>"; $mProtectexpiry = Xml::label(wfMessage('protectexpiry')->text(), "mwProtectExpirySelection-{$action}"); $mProtectother = Xml::label(wfMessage('protect-othertime')->text(), "mwProtect-{$action}-expires"); $expiryFormOptions = ''; if ($this->mExistingExpiry[$action] && $this->mExistingExpiry[$action] != 'infinity') { $timestamp = $lang->timeanddate($this->mExistingExpiry[$action], true); $d = $lang->date($this->mExistingExpiry[$action], true); $t = $lang->time($this->mExistingExpiry[$action], true); $expiryFormOptions .= Xml::option(wfMessage('protect-existing-expiry', $timestamp, $d, $t)->text(), 'existing', $this->mExpirySelection[$action] == 'existing') . "\n"; } $expiryFormOptions .= Xml::option(wfMessage('protect-othertime-op')->text(), "othertime") . "\n"; foreach (explode(',', $scExpiryOptions) as $option) { if (strpos($option, ":") === false) { $show = $value = $option; } else { list($show, $value) = explode(":", $option); } $show = htmlspecialchars($show); $value = htmlspecialchars($value); $expiryFormOptions .= Xml::option($show, $value, $this->mExpirySelection[$action] === $value) . "\n"; } # Add expiry dropdown if ($showProtectOptions && !$this->disabled) { $out .= "\n\t\t\t\t\t<table><tr>\n\t\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t\t{$mProtectexpiry}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class='mw-input'>" . Xml::tags('select', array('id' => "mwProtectExpirySelection-{$action}", 'name' => "wpProtectExpirySelection-{$action}", 'tabindex' => '2') + $this->disabledAttrib, $expiryFormOptions) . "</td>\n\t\t\t\t\t</tr></table>"; } # Add custom expiry field $attribs = array('id' => "mwProtect-{$action}-expires") + $this->disabledAttrib; $out .= "<table><tr>\n\t\t\t\t\t<td class='mw-label'>" . $mProtectother . '</td> <td class="mw-input">' . Xml::input("mwProtect-expiry-{$action}", 50, $this->mExpiry[$action], $attribs) . '</td> </tr></table>'; $out .= "</td></tr>" . Xml::closeElement('table') . Xml::closeElement('fieldset') . "</td></tr>"; } # Give extensions a chance to add items to the form wfRunHooks('ProtectionForm::buildForm', array($this->mArticle, &$out)); $out .= Xml::closeElement('tbody') . Xml::closeElement('table'); // JavaScript will add another row with a value-chaining checkbox if ($this->mTitle->exists()) { $out .= Xml::openElement('table', array('id' => 'mw-protect-table2')) . Xml::openElement('tbody'); $out .= '<tr> <td></td> <td class="mw-input">' . Xml::checkLabel(wfMessage('protect-cascade')->text(), 'mwProtect-cascade', 'mwProtect-cascade', $this->mCascade, $this->disabledAttrib) . "</td>\n\t\t\t\t</tr>\n"; $out .= Xml::closeElement('tbody') . Xml::closeElement('table'); } # Add manual and custom reason field/selects as well as submit if (!$this->disabled) { $mProtectreasonother = Xml::label(wfMessage('protectcomment')->text(), 'wpProtectReasonSelection'); $mProtectreason = Xml::label(wfMessage('protect-otherreason')->text(), 'mwProtect-reason'); $reasonDropDown = Xml::listDropDown('wpProtectReasonSelection', wfMessage('protect-dropdown')->inContentLanguage()->text(), wfMessage('protect-otherreason-op')->inContentLanguage()->text(), $this->mReasonSelection, 'mwProtect-reason', 4); $out .= Xml::openElement('table', array('id' => 'mw-protect-table3')) . Xml::openElement('tbody'); $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t{$mProtectreasonother}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class='mw-input'>\n\t\t\t\t\t\t{$reasonDropDown}\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t{$mProtectreason}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class='mw-input'>" . Xml::input('mwProtect-reason', 60, $this->mReason, array('type' => 'text', 'id' => 'mwProtect-reason', 'maxlength' => 180)) . "</td>\n\t\t\t\t</tr>"; # Disallow watching is user is not logged in if ($user->isLoggedIn()) { $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td></td>\n\t\t\t\t\t<td class='mw-input'>" . Xml::checkLabel(wfMessage('watchthis')->text(), 'mwProtectWatch', 'mwProtectWatch', $user->isWatched($this->mTitle) || $user->getOption('watchdefault')) . "</td>\n\t\t\t\t</tr>"; } $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td></td>\n\t\t\t\t\t<td class='mw-submit'>" . Xml::submitButton(wfMessage('confirm')->text(), array('id' => 'mw-Protect-submit')) . "</td>\n\t\t\t\t</tr>\n"; $out .= Xml::closeElement('tbody') . Xml::closeElement('table'); } $out .= Xml::closeElement('fieldset'); if ($user->isAllowed('editinterface')) { $title = Title::makeTitle(NS_MEDIAWIKI, 'Protect-dropdown'); $link = Linker::link($title, wfMessage('protect-edit-reasonlist')->escaped(), array(), array('action' => 'edit')); $out .= '<p class="mw-protect-editreasons">' . $link . '</p>'; } if (!$this->disabled) { $out .= Html::hidden('wpEditToken', $user->getEditToken(array('protect', $this->mTitle->getPrefixedDBkey()))); $out .= Xml::closeElement('form'); } return $out; }
/** * Generate help for the specified modules * * Help is placed into the OutputPage object returned by * $context->getOutput(). * * Recognized options include: * - headerlevel: (int) Header tag level * - nolead: (bool) Skip the inclusion of api-help-lead * - noheader: (bool) Skip the inclusion of the top-level section headers * - submodules: (bool) Include help for submodules of the current module * - recursivesubmodules: (bool) Include help for submodules recursively * - helptitle: (string) Title to link for additional modules' help. Should contain $1. * - toc: (bool) Include a table of contents * * @param IContextSource $context * @param ApiBase[]|ApiBase $modules * @param array $options Formatting options (described above) * @return string */ public static function getHelp(IContextSource $context, $modules, array $options) { global $wgContLang; if (!is_array($modules)) { $modules = array($modules); } $out = $context->getOutput(); $out->addModuleStyles('mediawiki.hlist'); $out->addModuleStyles('mediawiki.apihelp'); if (!empty($options['toc'])) { $out->addModules('mediawiki.toc'); } $out->setPageTitle($context->msg('api-help-title')); $cache = ObjectCache::getMainWANInstance(); $cacheKey = null; if (count($modules) == 1 && $modules[0] instanceof ApiMain && $options['recursivesubmodules'] && $context->getLanguage() === $wgContLang) { $cacheHelpTimeout = $context->getConfig()->get('APICacheHelpTimeout'); if ($cacheHelpTimeout > 0) { // Get help text from cache if present $cacheKey = wfMemcKey('apihelp', $modules[0]->getModulePath(), (int) (!empty($options['toc'])), str_replace(' ', '_', SpecialVersion::getVersion('nodb'))); $cached = $cache->get($cacheKey); if ($cached) { $out->addHTML($cached); return; } } } if ($out->getHTML() !== '') { // Don't save to cache, there's someone else's content in the page // already $cacheKey = null; } $options['recursivesubmodules'] = !empty($options['recursivesubmodules']); $options['submodules'] = $options['recursivesubmodules'] || !empty($options['submodules']); // Prepend lead if (empty($options['nolead'])) { $msg = $context->msg('api-help-lead'); if (!$msg->isDisabled()) { $out->addHTML($msg->parseAsBlock()); } } $haveModules = array(); $html = self::getHelpInternal($context, $modules, $options, $haveModules); if (!empty($options['toc']) && $haveModules) { $out->addHTML(Linker::generateTOC($haveModules, $context->getLanguage())); } $out->addHTML($html); $helptitle = isset($options['helptitle']) ? $options['helptitle'] : null; $html = self::fixHelpLinks($out->getHTML(), $helptitle, $haveModules); $out->clearHTML(); $out->addHTML($html); if ($cacheKey !== null) { $cache->set($cacheKey, $out->getHTML(), $cacheHelpTimeout); } }
/** * Execute a special page path. * The path may contain parameters, e.g. Special:Name/Params * Extracts the special page name and call the execute method, passing the parameters * * Returns a title object if the page is redirected, false if there was no such special * page, and true if it was successful. * * @param $title Title object * @param $context IContextSource * @param $including Bool output is being captured for use in {{special:whatever}} * * @return bool */ public static function executePath(Title &$title, IContextSource &$context, $including = false) { wfProfileIn(__METHOD__); // @todo FIXME: Redirects broken due to this call $bits = explode('/', $title->getDBkey(), 2); $name = $bits[0]; if (!isset($bits[1])) { // bug 2087 $par = null; } else { $par = $bits[1]; } $page = self::getPage($name); // Nonexistent? if (!$page) { $context->getOutput()->setArticleRelated(false); $context->getOutput()->setRobotPolicy('noindex,nofollow'); $context->getOutput()->setStatusCode(404); $context->getOutput()->showErrorPage('nosuchspecialpage', 'nospecialpagetext'); wfProfileOut(__METHOD__); return false; } // Page exists, set the context $page->setContext($context); if (!$including) { // Redirect to canonical alias for GET commands // Not for POST, we'd lose the post data, so it's best to just distribute // the request. Such POST requests are possible for old extensions that // generate self-links without being aware that their default name has // changed. if ($name != $page->getLocalName() && !$context->getRequest()->wasPosted()) { $query = $context->getRequest()->getQueryValues(); unset($query['title']); $query = wfArrayToCGI($query); $title = $page->getTitle($par); $url = $title->getFullUrl($query); $context->getOutput()->redirect($url); wfProfileOut(__METHOD__); return $title; } else { $context->setTitle($page->getTitle($par)); } } elseif (!$page->isIncludable()) { wfProfileOut(__METHOD__); return false; } $page->including($including); // Execute special page $profName = 'Special:' . $page->getName(); wfProfileIn($profName); $page->execute($par); wfProfileOut($profName); wfProfileOut(__METHOD__); return true; }