function validateTarget($target) { if (!$target) { return wfMsgExt('lqt_move_nodestination', 'parseinline'); } $title = Title::newFromText($target); if (!$title || !LqtDispatch::isLqtPage($title)) { return wfMsgExt('lqt_move_thread_bad_destination', 'parseinline'); } if ($title->equals($this->mThread->getTitle())) { return wfMsgExt('lqt_move_samedestination', 'parseinline'); } return true; }
/** * Creates a flow board. * Archives any pre-existing wikitext talk page. * * @param array $data Form data * @return Status Status indicating result */ public function onSubmit(array $data) { $page = $data['page']; $title = Title::newFromText($page); if (!$title) { return Status::newFatal('flow-special-enableflow-invalid-title', $page); } // Canonicalize so the error or confirmation message looks nicer (no underscores). $page = $title->getPrefixedText(); if ($this->occupationController->isTalkpageOccupied($title, true)) { return Status::newFatal('flow-special-enableflow-board-already-exists', $page); } $status = Status::newGood(); if ($title->exists(Title::GAID_FOR_UPDATE)) { if (class_exists('LqtDispatch') && \LqtDispatch::isLqtPage($title)) { return Status::newFatal('flow-special-enableflow-page-is-liquidthreads', $page); } $logger = Container::get('default_logger'); $converter = new Converter(wfGetDB(DB_MASTER), Container::get('importer'), $logger, $this->occupationController->getTalkpageManager(), new EnableFlowWikitextConversionStrategy(Container::get('parser'), new NullImportSourceStore(), $logger, array(), $data['header'])); try { $converter->convert($title); } catch (\Exception $e) { \MWExceptionHandler::logException($e); $status->fatal('flow-error-external', $e->getMessage()); } } else { $allowCreationStatus = $this->occupationController->allowCreation($title, $this->getUser(), false); if (!$allowCreationStatus->isGood()) { return Status::newFatal('flow-special-enableflow-board-creation-not-allowed', $page); } $loader = $this->loaderFactory->createWorkflowLoader($title); $blocks = $loader->getBlocks(); $action = 'edit-header'; $params = array('header' => array('content' => $data['header'], 'format' => 'wikitext')); $blocksToCommit = $loader->handleSubmit($this->getContext(), $action, $params); foreach ($blocks as $block) { if ($block->hasErrors()) { $errors = $block->getErrors(); foreach ($errors as $errorKey) { $status->fatal($block->getErrorMessage($errorKey)); } } } $loader->commit($blocksToCommit); } $this->page = $data['page']; return $status; }
/** * @param $thread Thread * @param $levelNum int * @param $totalInLevel int * @param $options array * @throws Exception */ function showThread($thread, $levelNum = 1, $totalInLevel = 1, $options = array()) { // Safeguard if ($thread->type() & Threads::TYPE_DELETED || !$thread->root()) { return; } $this->threadNestingLevel++; // Figure out which threads *need* to be shown because they're involved in an // operation $mustShowOption = array(); if (isset($options['mustShowThreads'])) { $mustShowOption = $options['mustShowThreads']; } $mustShowThreads = $this->getMustShowThreads($mustShowOption); // For cascading. $options['mustShowThreads'] = $mustShowThreads; // Don't show blank posts unless we have to $content = ''; if ($thread->root()) { $content = $thread->root()->getContent(); } if (trim($content) == '' && $thread->type() != Threads::TYPE_MOVED && !self::threadContainsRepliesWithContent($thread) && !array_key_exists($thread->id(), $mustShowThreads)) { $this->threadNestingLevel--; return; } // Grab options if (isset($options['maxDepth'])) { $maxDepth = $options['maxDepth']; } else { $maxDepth = $this->user->getOption('lqtdisplaydepth'); } if (isset($options['maxCount'])) { $maxCount = $options['maxCount']; } else { $maxCount = $this->user->getOption('lqtdisplaycount'); } if (isset($options['startAt'])) { $startAt = $options['startAt']; } else { $startAt = 0; } // Figure out if we have replies to show or not. $showThreads = $maxDepth == -1 || $this->threadNestingLevel <= $maxDepth; $mustShowThreadIds = array_keys($mustShowThreads); $subthreadIds = array_keys($thread->replies()); $mustShowSubthreadIds = array_intersect($mustShowThreadIds, $subthreadIds); $hasSubthreads = self::threadContainsRepliesWithContent($thread); $hasSubthreads = $hasSubthreads || count($mustShowSubthreadIds); // Show subthreads if one of the subthreads is on the must-show list $showThreads = $showThreads || count(array_intersect(array_keys($mustShowThreads), array_keys($thread->replies()))); $replyTo = $this->methodAppliesToThread('reply', $thread); $this->output->addModules('ext.liquidThreads'); $html = ''; Hooks::run('EditPageBeforeEditToolbar', array(&$html)); $class = $this->threadDivClass($thread); if ($levelNum == 1) { $class .= ' lqt-thread-first'; } elseif ($levelNum == $totalInLevel) { $class .= ' lqt-thread-last'; } if ($hasSubthreads && $showThreads) { $class .= ' lqt-thread-with-subthreads'; } else { $class .= ' lqt-thread-no-subthreads'; } if (!$thread->title()->quickUserCan('edit') || !LqtDispatch::isLqtPage($thread->getTitle())) { $class .= ' lqt-thread-uneditable'; } $class .= ' lqt-thread-wrapper'; $html .= Xml::openElement('div', array('class' => $class, 'id' => 'lqt_thread_id_' . $thread->id())); $html .= Xml::element('a', array('name' => $this->anchorName($thread)), ' '); $html .= $this->showThreadHeading($thread); // Metadata stuck in the top of the lqt_thread div. // Modified time for topmost threads... if ($thread->isTopmostThread()) { $html .= Html::hidden('lqt-thread-modified-' . $thread->id(), wfTimestamp(TS_MW, $thread->modified()), array('id' => 'lqt-thread-modified-' . $thread->id(), 'class' => 'lqt-thread-modified')); $html .= Html::hidden('lqt-thread-sortkey', $thread->sortkey(), array('id' => 'lqt-thread-sortkey-' . $thread->id())); $html .= Html::hidden('lqt-thread-talkpage-' . $thread->id(), $thread->article()->getTitle()->getPrefixedText(), array('class' => 'lqt-thread-talkpage-metadata')); } if (!$thread->title()) { throw new Exception("Thread " . $thread->id() . " has null title"); } // Add the thread's title $html .= Html::hidden('lqt-thread-title-' . $thread->id(), $thread->title()->getPrefixedText(), array('id' => 'lqt-thread-title-' . $thread->id(), 'class' => 'lqt-thread-title-metadata')); // Flush output to display thread $this->output->addHTML($html); $this->output->addHTML(Xml::openElement('div', array('class' => 'lqt-post-wrapper'))); $this->showSingleThread($thread); $this->output->addHTML(Xml::closeElement('div')); $cascadeOptions = $options; unset($cascadeOptions['startAt']); $replyInterruption = $levelNum < $totalInLevel; if ($hasSubthreads && $showThreads) { // If the thread has subthreads, and we want to show them, we should do so. $this->showThreadReplies($thread, $startAt, $maxCount, $showThreads, $cascadeOptions, $replyInterruption); } elseif ($hasSubthreads && !$showThreads) { // If the thread has subthreads, but we don't want to show them, then // show the reply form if necessary, and add the "Show X replies" link. if ($replyTo) { $this->showReplyForm($thread); } // Add a "show subthreads" link. $link = $this->getShowReplies($thread); $this->output->addHTML($link); if ($levelNum < $totalInLevel) { $this->output->addHTML(Xml::tags('div', array('class' => 'lqt-post-sep'), ' ')); } } elseif ($levelNum < $totalInLevel) { // If we have no replies, and we're not at the end of this level, add the post separator // and a reply box if necessary. $this->output->addHTML(Xml::tags('div', array('class' => 'lqt-post-sep'), ' ')); if ($replyTo) { $class = 'lqt-thread-replies lqt-thread-replies-' . $this->threadNestingLevel; $html = Xml::openElement('div', array('class' => $class)); $this->output->addHTML($html); $this->showReplyForm($thread); $finishDiv = Xml::tags('div', array('class' => 'lqt-replies-finish'), ' '); // Layout plus close div.lqt-thread-replies $finishHTML = Xml::closeElement('div'); // lqt-reply-form $finishHTML .= $finishDiv; // Layout $finishHTML .= Xml::closeElement('div'); // lqt-thread-replies $this->output->addHTML($finishHTML); } } elseif (!$hasSubthreads && $replyTo) { // If we have no replies, we're at the end of this level, and we want to reply, // show the reply box. $class = 'lqt-thread-replies lqt-thread-replies-' . $this->threadNestingLevel; $html = Xml::openElement('div', array('class' => $class)); $this->output->addHTML($html); $this->showReplyForm($thread); $html = Xml::tags('div', array('class' => 'lqt-replies-finish'), Xml::tags('div', array('class' => 'lqt-replies-finish-corner'), ' ')); $html .= Xml::closeElement('div'); $this->output->addHTML($html); } // I don't remember why this is here, commenting out. // if ( $this->threadNestingLevel == 1 ) { // if ( !( $hasSubthreads && $showThreads && !$replyTo ) ) { // $this->showReplyBox( $thread ); // $finishDiv = ''; // $finishDiv .= Xml::tags( 'div', array( 'class' => 'lqt-replies-finish' ), // Xml::tags( 'div', array( 'class' => 'lqt-replies-finish-corner' ), ' ' ) ); // // $this->output->addHTML( $finishDiv ); // } // } $this->output->addHTML(Xml::closeElement('div')); $this->threadNestingLevel--; }
function doLazyUpdates() { if ($this->isHistorical()) { return; } // Don't do lazy updates on stored historical threads. // This is an invocation guard to avoid infinite recursion when fixing a // missing ancestor. static $doingUpdates = false; if ($doingUpdates) { return; } $doingUpdates = true; // Fix missing ancestry information. // (there was a bug where this was not saved properly) if ($this->parentId && !$this->ancestorId) { $this->fixMissingAncestor(); } $ancestor = $this->topmostThread(); $set = array(); // Fix missing subject information // (this information only started to be added later) if (!$this->subject && $this->root()) { $detectedSubject = $this->root()->getTitle()->getText(); $parts = self::splitIncrementFromSubject($detectedSubject); $this->subject = $detectedSubject = $parts[1]; // Update in the DB $set['thread_subject'] = $detectedSubject; } // Fix inconsistent subject information // (in some intermediate versions this was not updated when the subject was changed) if ($this->subject() != $ancestor->subject()) { $set['thread_subject'] = $ancestor->subject(); $this->subject = $ancestor->subject(); } // Fix missing authorship information // (this information only started to be added later) if (!$this->authorName) { $author = $this->loadOriginalAuthorFromRevision(); $this->authorId = $author->getId(); $this->authorName = $author->getName(); $set['thread_author_name'] = $this->authorName; $set['thread_author_id'] = $this->authorId; } // Check for article being in subject, not talk namespace. // If the page is non-LiquidThreads and it's in subject-space, we'll assume it's meant // to be on the corresponding talk page, but only if the talk-page is a LQT page. // (Previous versions stored the subject page, for some totally bizarre reason) // Old versions also sometimes store the thread page for trace threads as the // article, not as the root. // Trying not to exacerbate this by moving it to be the 'Thread talk' page. $articleTitle = $this->getTitle(); global $wgLiquidThreadsMigrate; if (!LqtDispatch::isLqtPage($articleTitle) && !$articleTitle->isTalkPage() && LqtDispatch::isLqtPage($articleTitle->getTalkPage()) && $articleTitle->getNamespace() != NS_LQT_THREAD && $wgLiquidThreadsMigrate) { $newTitle = $articleTitle->getTalkPage(); $newArticle = new Article($newTitle); $set['thread_article_namespace'] = $newTitle->getNamespace(); $set['thread_article_title'] = $newTitle->getDbKey(); $this->articleNamespace = $newTitle->getNamespace(); $this->articleTitle = $newTitle->getDbKey(); $this->articleId = $newTitle->getArticleId(); $this->article = $newArticle; } // Check for article corruption from incomplete thread moves. // (thread moves only updated this on immediate replies, not replies to replies etc) if (!$ancestor->getTitle()->equals($this->getTitle())) { $title = $ancestor->getTitle(); $set['thread_article_namespace'] = $title->getNamespace(); $set['thread_article_title'] = $title->getDbKey(); $this->articleNamespace = $title->getNamespace(); $this->articleTitle = $title->getDbKey(); $this->articleId = $title->getArticleId(); $this->article = $ancestor->article(); } // Check for invalid/missing articleId $articleTitle = null; $dbTitle = Title::makeTitleSafe($this->articleNamespace, $this->articleTitle); if ($this->articleId && isset(self::$titleCacheById[$this->articleId])) { // If it corresponds to a title, the article obviously exists. $articleTitle = self::$titleCacheById[$this->articleId]; $this->article = new Article($articleTitle); } elseif ($this->articleId) { $articleTitle = Title::newFromID($this->articleId); } // If still unfilled, the article ID referred to is no longer valid. Re-fill it // from the namespace/title pair if an article ID is provided if (!$articleTitle && ($this->articleId != 0 || $dbTitle->getArticleId() != 0)) { $articleTitle = $dbTitle; $this->articleId = $articleTitle->getArticleId(); $this->article = new Article($dbTitle); $set['thread_article_id'] = $this->articleId; wfDebug("Unfilled or non-existent thread_article_id, refilling to {$this->articleId}\n"); // There are probably problems on the rest of the article, trigger a small update Threads::synchroniseArticleData($this->article, 100, 'cascade'); } elseif ($articleTitle && !$articleTitle->equals($dbTitle)) { // The page was probably moved and this was probably not updated. wfDebug("Article ID/Title discrepancy, resetting NS/Title to article provided by ID\n"); $this->articleNamespace = $articleTitle->getNamespace(); $this->articleTitle = $articleTitle->getDBkey(); $set['thread_article_namespace'] = $articleTitle->getNamespace(); $set['thread_article_title'] = $articleTitle->getDBkey(); // There are probably problems on the rest of the article, trigger a small update Threads::synchroniseArticleData($this->article, 100, 'cascade'); } // Check for unfilled signature field. This field hasn't existed until // recently. if (is_null($this->signature)) { // Grab our signature. $sig = LqtView::getUserSignature($this->author()); $set['thread_signature'] = $sig; $this->setSignature($sig); } if (count($set)) { $dbw = wfGetDB(DB_MASTER); $dbw->update('thread', $set, array('thread_id' => $this->id()), __METHOD__); } // Done $doingUpdates = false; }
/** * If the page we recieve is a LiquidThreads page of any kind, process it * as needed and return True. If it's a normal, non-liquid page, return false. * @param $output OutputPage * @param $article Article * @param $title Title * @param $user User * @param $request WebRequest * @return bool */ static function tryPage($output, $article, $title, $user, $request) { if (LqtDispatch::isLqtPage($title)) { // LiquidThreads pages, Talk:X etc return self::talkpageMain($output, $article, $title, $user, $request); } elseif ($title->getNamespace() == NS_LQT_THREAD) { // Thread permalink pages, Thread:X return self::threadPermalinkMain($output, $article, $title, $user, $request); } elseif ($title->getNamespace() == NS_LQT_SUMMARY) { // Summary pages, Summary:X return self::threadSummaryMain($output, $article, $title, $user, $request); } return true; }
public function actionNewThread($threads, $params) { // Validate talkpage parameters if (!count($params['talkpage'])) { $this->dieUsageMsg(array('missingparam', 'talkpage')); } $talkpageTitle = Title::newFromText($params['talkpage']); if (!$talkpageTitle || !LqtDispatch::isLqtPage($talkpageTitle)) { $this->dieUsage('The talkpage you specified is invalid, or does not ' . 'have discussion threading enabled.', 'invalid-talkpage'); } $talkpage = new Article($talkpageTitle, 0); // Check if we can post. $user = $this->getUser(); if (Thread::canUserPost($user, $talkpage) !== true) { $this->dieUsage('You cannot post to the specified talkpage, ' . 'because it is protected from new posts', 'talkpage-protected'); } // Validate subject, generate a title if (empty($params['subject'])) { $this->dieUsageMsg(array('missingparam', 'subject')); } $subject = $params['subject']; $title = null; $subjectOk = Thread::validateSubject($subject, $title, null, $talkpage); if (!$subjectOk) { $this->dieUsage('The subject you specified is not valid', 'invalid-subject'); } $article = new Article($title, 0); // Check for text if (empty($params['text'])) { $this->dieUsage('You must include text in your post', 'no-text'); } $text = $params['text']; // Generate or pull summary $summary = wfMessage('lqt-newpost-summary', $subject)->inContentLanguage()->text(); if (!empty($params['reason'])) { $summary = $params['reason']; } $signature = null; if (isset($params['signature'])) { $signature = $params['signature']; } // Inform hooks what we're doing LqtHooks::$editTalkpage = $talkpage; LqtHooks::$editArticle = $article; LqtHooks::$editThread = null; LqtHooks::$editType = 'new'; LqtHooks::$editAppliesTo = null; $token = $params['token']; // All seems in order. Construct an API edit request $requestData = array('action' => 'edit', 'title' => $title->getPrefixedText(), 'text' => $text, 'summary' => $summary, 'token' => $token, 'basetimestamp' => wfTimestampNow(), 'minor' => 0, 'format' => 'json'); if ($user->isAllowed('bot')) { $requestData['bot'] = true; } $editReq = new DerivativeRequest($this->getRequest(), $requestData, true); $internalApi = new ApiMain($editReq, true); $internalApi->execute(); if (defined('ApiResult::META_CONTENT')) { $editResult = $internalApi->getResult()->getResultData(); } else { $editResult = $internalApi->getResultData(); } if ($editResult['edit']['result'] != 'Success') { $result = array('result' => 'EditFailure', 'details' => $editResult); $this->getResult()->addValue(null, $this->getModuleName(), $result); return; } $articleId = $editResult['edit']['pageid']; $article->getTitle()->resetArticleID($articleId); $title->resetArticleID($articleId); $thread = LqtView::newPostMetadataUpdates(array('root' => $article, 'talkpage' => $talkpage, 'subject' => $subject, 'signature' => $signature, 'summary' => $summary, 'text' => $text)); $result = array('result' => 'Success', 'thread-id' => $thread->id(), 'thread-title' => $title->getPrefixedText(), 'modified' => $thread->modified()); if (!empty($params['render'])) { $result['html'] = $this->renderThreadPostAction($thread); } $result = array('thread' => $result); $this->getResult()->addValue(null, $this->getModuleName(), $result); }
/** * Checks whether the current page should be Reflected. First, only LQT pages * can be Reflected. Second, either Reflect must be enabled for all pages, or * the current page must belong to a subset of pages Reflect is enabled on. * * @param $title Title of current page. * * @return Returns whether the current page should have Reflect added. */ private static function isReflectPage($title) { global $wgReflectPages, $wgReflectTalkPages; $isReflectPage = LqtDispatch::isLqtPage($title) && ($wgReflectTalkPages || in_array($title->getPrefixedText(), $wgReflectPages)); return $isReflectPage; }
/** * Execute the requested Api actions. * @todo: Write some unit tests for API results */ public function execute() { // Logged-in users' parser options depend on preferences $this->getMain()->setCacheMode('anon-public-user-private'); // Enough '*' keys in JSON!!! $isXml = $this->getMain()->isInternalMode() || $this->getMain()->getPrinter()->getFormat() == 'XML'; $textElement = $isXml ? '*' : 'text'; $params = $this->extractRequestParams(); $prop = array_flip($params['prop']); $sectionProp = array_flip($params['sectionprop']); $this->variant = $params['variant']; $this->followRedirects = $params['redirect'] == 'yes'; $this->noHeadings = $params['noheadings']; $this->noTransform = $params['notransform']; $onlyRequestedSections = $params['onlyrequestedsections']; $this->offset = $params['offset']; $this->maxlen = $params['maxlen']; if ($this->offset === 0 && $this->maxlen === 0) { $this->offset = -1; // Disable text splitting } elseif ($this->maxlen === 0) { $this->maxlen = PHP_INT_MAX; } $title = $this->makeTitle($params['page']); // See whether the actual page (or if enabled, the redirect target) is the main page $this->mainPage = $this->isMainPage($title); if ($this->mainPage && $this->noHeadings) { $this->noHeadings = false; $this->setWarning("``noheadings'' makes no sense on the main page, ignoring"); } if (isset($prop['normalizedtitle']) && $title->getPrefixedText() != $params['page']) { $this->getResult()->addValue(null, $this->getModuleName(), array('normalizedtitle' => $title->getPageLanguage()->convert($title->getPrefixedText()))); } $data = $this->getData($title, $params['noimages']); // Bug 73109: #getData will return an empty array if the title redirects to // a page in a virtual namespace (NS_SPECIAL, NS_MEDIA), so make sure that // the requested data exists too. if (isset($prop['lastmodified']) && isset($data['lastmodified'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('lastmodified' => $data['lastmodified'])); } if (isset($prop['lastmodifiedby']) && isset($data['lastmodifiedby'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('lastmodifiedby' => $data['lastmodifiedby'])); } if (isset($prop['revision']) && isset($data['revision'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('revision' => $data['revision'])); } if (isset($prop['id']) && isset($data['id'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('id' => $data['id'])); } if (isset($prop['languagecount']) && isset($data['languagecount'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('languagecount' => $data['languagecount'])); } if (isset($prop['hasvariants']) && isset($data['hasvariants'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('hasvariants' => $data['hasvariants'])); } if (isset($prop['displaytitle']) && isset($data['displaytitle'])) { $this->getResult()->addValue(null, $this->getModuleName(), array('displaytitle' => $data['displaytitle'])); } if (isset($prop['pageprops'])) { $propNames = $params['pageprops']; if ($propNames == '*' && isset($data['pageprops'])) { $pageProps = $data['pageprops']; } else { $propNames = explode('|', $propNames); $pageProps = array_intersect_key($data['pageprops'], array_flip($propNames)); } $this->getResult()->addValue(null, $this->getModuleName(), array('pageprops' => $pageProps)); } if (isset($prop['description']) && isset($data['pageprops']['wikibase_item'])) { $desc = ExtMobileFrontend::getWikibaseDescription($data['pageprops']['wikibase_item']); if ($desc) { $this->getResult()->addValue(null, $this->getModuleName(), array('description' => $desc)); } } if ($this->usePageImages) { $this->addPageImage($data, $params, $prop); } $result = array(); $missingSections = array(); if ($this->mainPage) { if ($onlyRequestedSections) { $requestedSections = self::parseSections($params['sections'], $data, $missingSections); } else { $requestedSections = array(0); } $this->getResult()->addValue(null, $this->getModuleName(), array('mainpage' => '')); } elseif (isset($params['sections'])) { $requestedSections = self::parseSections($params['sections'], $data, $missingSections); } else { $requestedSections = array(); } if (isset($data['sections'])) { if (isset($prop['sections'])) { $sectionCount = count($data['sections']); for ($i = 0; $i <= $sectionCount; $i++) { if (!isset($requestedSections[$i]) && $onlyRequestedSections) { continue; } $section = array(); if ($i > 0) { $section = array_intersect_key($data['sections'][$i - 1], $sectionProp); } $section['id'] = $i; if (isset($prop['text']) && isset($requestedSections[$i]) && isset($data['text'][$i])) { $section[$textElement] = $this->stringSplitter($this->prepareSection($data['text'][$i])); unset($requestedSections[$i]); } if (isset($data['refsections'][$i])) { $section['references'] = ''; } $result[] = $section; } $missingSections = array_keys($requestedSections); } else { foreach (array_keys($requestedSections) as $index) { $section = array('id' => $index); if (isset($data['text'][$index])) { $section[$textElement] = $this->stringSplitter($this->prepareSection($data['text'][$index])); } else { $missingSections[] = $index; } $result[] = $section; } } $this->getResult()->setIndexedTagName($result, 'section'); $this->getResult()->addValue(null, $this->getModuleName(), array('sections' => $result)); } if (isset($prop['protection'])) { $this->addProtection($title); } if (isset($prop['editable'])) { $user = $this->getUser(); if ($user->isAnon()) { // HACK: Anons receive cached information, so don't check blocked status for them // to avoid them receiving false positives. Currently there is no way to check // all permissions except blocked status from the Title class. $req = new FauxRequest(); $req->setIP('127.0.0.1'); $user = User::newFromSession($req); } $editable = $title->quickUserCan('edit', $user); if ($isXml) { $editable = intval($editable); } $this->getResult()->addValue(null, $this->getModuleName(), array('editable' => $editable)); } // https://bugzilla.wikimedia.org/show_bug.cgi?id=51586 // Inform ppl if the page is infested with LiquidThreads but that's the // only thing we support about it. if (class_exists('LqtDispatch') && LqtDispatch::isLqtPage($title)) { $this->getResult()->addValue(null, $this->getModuleName(), array('liquidthreads' => '')); } if (count($missingSections) && isset($prop['text'])) { $this->setWarning('Section(s) ' . implode(', ', $missingSections) . ' not found'); } if ($this->maxlen < 0) { // There is more data available $this->getResult()->addValue(null, $this->getModuleName(), array('continue-offset' => $params['offset'] + $params['maxlen'])); } }
public static function onInfoAction($context, $pageInfo) { if (LqtDispatch::isLqtPage($context->getTitle())) { $pageInfo['header-basic'][] = array(wfMessage('pageinfo-usinglqt'), wfMessage('pageinfo-usinglqt-yes')); } return true; }
function show() { $this->output->addModules('ext.liquidThreads'); $article = $this->talkpage; if (!LqtDispatch::isLqtPage($article->getTitle())) { $this->output->addWikiMsg('lqt-not-discussion-page'); return false; } $this->output->setPageTitle($this->title->getPrefixedText()); // Expose feed links. global $wgFeedClasses; $apiParams = array('action' => 'feedthreads', 'type' => 'replies|newthreads', 'talkpage' => $this->title->getPrefixedText()); $urlPrefix = wfScript('api') . '?'; foreach ($wgFeedClasses as $format => $class) { $theseParams = $apiParams + array('feedformat' => $format); $url = $urlPrefix . wfArrayToCgi($theseParams); $this->output->addFeedLink($format, $url); } if ($this->request->getBool('lqt_inline')) { $this->doInlineEditForm(); return false; } $this->output->addHTML(Xml::openElement('div', array('class' => 'lqt-talkpage'))); // Search! if ($this->request->getCheck('lqt_search')) { $q = $this->request->getText('lqt_search'); $q .= ' ondiscussionpage:' . $article->getTitle()->getPrefixedText(); $params = array('search' => $q, 'fulltext' => 1, 'ns' . NS_LQT_THREAD => 1, 'srbackend' => 'LuceneSearch'); $t = SpecialPage::getTitleFor('Search'); $url = $t->getLocalURL(wfArrayToCgi($params)); $this->output->redirect($url); return true; } if ($this->shouldShow('header')) { $this->showHeader(); } global $wgLang; // This closes the div of mw-content-ltr/rtl containing lang and dir attributes $this->output->addHTML(Html::closeElement('div') . Html::openElement('div', array('class' => 'lqt-talkpage', 'lang' => $wgLang->getCode(), 'dir' => $wgLang->getDir()))); $html = ''; // Set up a per-page header for new threads, search box, and sorting stuff. $talkpageHeader = ''; if (Thread::canUserPost($this->user, $this->talkpage)) { $newThreadText = wfMessage('lqt_new_thread')->parse(); $newThreadLink = Linker::link($this->title, $newThreadText, array('lqt_talkpage' => $this->talkpage->getTitle()->getPrefixedText()), array('lqt_method' => 'talkpage_new_thread'), array('known')); $newThreadLink = Xml::tags('strong', array('class' => 'lqt_start_discussion'), $newThreadLink); $talkpageHeader .= $newThreadLink; } global $wgSearchTypeAlternatives, $wgSearchType; if ($wgSearchType == "LuceneSearch" || in_array("LuceneSearch", $wgSearchTypeAlternatives ?: array())) { $talkpageHeader .= $this->getSearchBox(); } $talkpageHeader .= $this->showTalkpageViewOptions($article); $talkpageHeader = Xml::tags('div', array('class' => 'lqt-talkpage-header'), $talkpageHeader); if ($this->shouldShow('options')) { $this->output->addHTML($talkpageHeader); } elseif ($this->shouldShow('simplenew')) { $this->output->addHTML($newThreadLink); } if ($this->methodApplies('talkpage_new_thread')) { $this->showNewThreadForm($this->talkpage); } else { $this->output->addHTML(Xml::tags('div', array('class' => 'lqt-new-thread lqt-edit-form'), '')); } $pager = $this->getPager(); $threads = $this->getPageThreads($pager); if (count($threads) > 0 && $this->shouldShow('toc')) { $html .= $this->getTOC($threads); } elseif (count($threads) == 0) { $html .= Xml::tags('div', array('class' => 'lqt-no-threads'), wfMessage('lqt-no-threads')->parse()); } $html .= $pager->getNavigationBar(); $html .= Xml::openElement('div', array('class' => 'lqt-threads lqt-talkpage-threads')); $this->output->addHTML($html); foreach ($threads as $t) { $this->showThread($t); } $this->output->addHTML(Xml::closeElement('div') . $pager->getNavigationBar() . Xml::closeElement('div')); return false; }
/** * {@inheritDoc} */ public function shouldConvert(Title $sourceTitle) { // If we have LiquidThreads filter out any pages with that enabled. They should // be converted separately. if (class_exists('LqtDispatch')) { if (\LqtDispatch::isLqtPage($sourceTitle)) { $this->logger->info("Skipping LQT enabled page, conversion must be done with convertLqtPagesWithProp.php or convertLqtPageOnLocalWiki.php: {$sourceTitle}"); return false; } } if (!$this->meetsSubpageRequirements($sourceTitle) || $this->hasNoConvertTemplate($sourceTitle)) { return false; } return true; }
/** * Send a message to a user * Modified from the TranslationNotification extension * * @return bool */ function sendMessage() { $title = $this->normalizeTitle($this->title); if ($title === null) { return true; // Skip it } $this->title = $title; if (self::isOptedOut($this->title)) { $this->logLocalSkip('skipoptout'); return true; // Oh well. } // If we're sending to a User:/User talk: page, make sure the user exists. // Redirects are automatically followed in getLocalTargets if ($title->getNamespace() == NS_USER || $title->getNamespace() == NS_USER_TALK) { $user = User::newFromName($title->getBaseText()); if (!$user->getId()) { // Does not exist $this->logLocalSkip('skipnouser'); return true; } } // See if we should use LiquidThreads if (class_exists('LqtDispatch') && LqtDispatch::isLqtPage($title)) { // This is the same check that LQT uses internally $this->addLQTThread(); } else { $this->editPage(); } return true; }
/** * @param $title Title * @param $types * @return bool */ static function getProtectionTypes($title, &$types) { $isLqtPage = LqtDispatch::isLqtPage($title); $isThread = $title->getNamespace() == NS_LQT_THREAD; if (!$isLqtPage && !$isThread) { return true; } if ($isLqtPage) { $types[] = 'newthread'; $types[] = 'reply'; } if ($isThread) { $types[] = 'reply'; } return true; }
function show() { $this->output->addModules('ext.liquidThreads'); $article = $this->talkpage; if (!LqtDispatch::isLqtPage($article->getTitle())) { $this->output->addWikiMsg('lqt-not-discussion-page'); return false; } $this->output->setPageTitle($this->title->getPrefixedText()); // Expose feed links. global $wgFeedClasses; $apiParams = array('action' => 'feedthreads', 'type' => 'replies|newthreads', 'talkpage' => $this->title->getPrefixedText()); $urlPrefix = wfScript('api') . '?'; foreach ($wgFeedClasses as $format => $class) { $theseParams = $apiParams + array('feedformat' => $format); $url = $urlPrefix . wfArrayToCGI($theseParams); $this->output->addFeedLink($format, $url); } $linker = class_exists('DummyLinker') ? new DummyLinker() : new Linker(); if ($this->request->getBool('lqt_inline')) { $this->doInlineEditForm(); return false; } $this->output->addHTML(Xml::openElement('div', array('class' => 'lqt-talkpage'))); // Search! if ($this->request->getCheck('lqt_search')) { $q = $this->request->getText('lqt_search'); $q .= ' ondiscussionpage:' . $article->getTitle()->getPrefixedText(); $params = array('search' => $q, 'fulltext' => 1, 'ns' . NS_LQT_THREAD => 1); $t = SpecialPage::getTitleFor('Search'); $url = $t->getLocalURL(wfArrayToCGI($params)); $this->output->redirect($url); return true; } if ($this->shouldShow('header')) { $this->showHeader(); } global $wgLang, $wgBetterDirectionality; if ($wgBetterDirectionality) { // This closes the div of mw-content-ltr/rtl containing lang and dir attributes $this->output->addHTML(Html::closeElement('div') . Html::openElement('div', array('class' => 'lqt-talkpage', 'lang' => $wgLang->getCode(), 'dir' => wfUILang()->getDir()))); } $html = ''; // Set up a per-page header for new threads, search box, and sorting stuff. $talkpageHeader = ''; if (Thread::canUserPost($this->user, $this->talkpage)) { $newThreadText = wfMsgExt('lqt_new_thread', 'parseinline'); $newThreadLink = $linker->link($this->title, $newThreadText, array('lqt_talkpage' => $this->talkpage->getTitle()->getPrefixedText()), array('lqt_method' => 'talkpage_new_thread'), array('known')); $newThreadLink = Xml::tags('strong', array('class' => 'lqt_start_discussion'), $newThreadLink); $talkpageHeader .= $newThreadLink; } $talkpageHeader .= $this->getSearchBox(); $talkpageHeader .= $this->showTalkpageViewOptions($article); $talkpageHeader = Xml::tags('div', array('class' => 'lqt-talkpage-header'), $talkpageHeader); if ($this->shouldShow('options')) { $this->output->addHTML($talkpageHeader); } elseif ($this->shouldShow('simplenew')) { $this->output->addHTML($newThreadLink); } if ($this->methodApplies('talkpage_new_thread')) { $params = array('class' => 'lqt-new-thread lqt-edit-form'); $this->output->addHTML(Xml::openElement('div', $params)); $this->showNewThreadForm($this->talkpage); $this->output->addHTML(Xml::closeElement('div')); } else { $this->output->addHTML(Xml::tags('div', array('class' => 'lqt-new-thread lqt-edit-form'), '')); } $pager = $this->getPager(); $threads = $this->getPageThreads($pager); if (count($threads) > 0 && $this->shouldShow('toc')) { $html .= $this->getTOC($threads); } elseif (count($threads) == 0) { $html .= Xml::tags('div', array('class' => 'lqt-no-threads'), wfMsgExt('lqt-no-threads', 'parseinline')); } $html .= $pager->getNavigationBar(); $html .= Xml::openElement('div', array('class' => 'lqt-threads lqt-talkpage-threads')); $this->output->addHTML($html); foreach ($threads as $t) { $this->showThread($t); } $this->output->addHTML(Xml::closeElement('div') . $pager->getNavigationBar() . Xml::closeElement('div')); // Workaround for bug 25077 global $wgOut, $wgUser; # Skin::setTitle was removed in 1.18, it already shares the same source of title with $wgOut. if (method_exists('Skin', 'setTitle')) { $sk = $wgUser->getSkin(); $sk->setTitle($wgOut->getTitle()); } return false; }