public function testSortByOption()
 {
     $user = User::newFromId(1);
     $user->setOption('flow-topiclist-sortby', '');
     // reset flow state, so everything ($container['permissions'])
     // uses this particular $user
     \FlowHooks::resetFlowExtension();
     Container::reset();
     $container = Container::getContainer();
     $container['user'] = $user;
     $ctx = $this->getMock('IContextSource');
     $ctx->expects($this->any())->method('getUser')->will($this->returnValue($user));
     $workflow = Workflow::create('discussion', Title::newFromText('Talk:Flow_QA'));
     $block = new TopicListBlock($workflow, Container::get('storage'));
     $block->init($ctx, 'view');
     $res = $block->renderApi(array());
     $this->assertEquals('newest', $res['sortby'], 'With no sortby defaults to newest');
     $res = $block->renderApi(array('sortby' => 'foo'));
     $this->assertEquals('newest', $res['sortby'], 'With invalid sortby defaults to newest');
     $res = $block->renderApi(array('sortby' => 'updated'));
     $this->assertEquals('updated', $res['sortby'], 'With sortby updated output changes to updated');
     $res = $block->renderApi(array());
     $this->assertEquals('newest', $res['sortby'], 'Sort still defaults to newest');
     $res = $block->renderApi(array('sortby' => 'updated', 'savesortby' => '1'));
     $this->assertEquals('updated', $res['sortby'], 'Request saving sortby option');
     $res = $block->renderApi(array());
     $this->assertEquals('updated', $res['sortby'], 'Default sortby now changed to updated');
     $res = $block->renderApi(array('sortby' => ''));
     $this->assertEquals('updated', $res['sortby'], 'Default sortby with blank sortby still uses user default');
 }
 public function setUp()
 {
     parent::setUp();
     // reset flow state, so everything ($container['permissions'])
     // uses this particular $user
     \FlowHooks::resetFlowExtension();
     Container::reset();
     $container = Container::getContainer();
     $container['user'] = User::newFromName('127.0.0.1', false);
 }
 protected function doDBUpdates()
 {
     // get "User:" namespace prefix in wiki language
     global $wgContLang;
     $namespaces = $wgContLang->getFormattedNamespaces();
     $title = Title::newFromText(wfMessage('flow-ve-mention-template-title')->inContentLanguage()->plain(), NS_TEMPLATE);
     $article = new Article($title);
     $page = $article->getPage();
     if ($page->getRevision() !== null) {
         // template already exists, don't overwrite it
         return true;
     }
     $status = $page->doEditContent(new WikitextContent('@[[' . $namespaces[NS_USER] . ':{{{1|Example}}}|{{{2|{{{1|Example}}}}}}]]'), '/* Automatically created by Flow */', EDIT_FORCE_BOT | EDIT_SUPPRESS_RC, false, FlowHooks::getOccupationController()->getTalkpageManager());
     return $status->isOK();
 }
 public function execute()
 {
     global $wgLang, $wgParser;
     $provided = $this->getArg(0);
     $namespace = $wgLang->getNsIndex($provided);
     if (!$namespace) {
         $this->error("Invalid namespace provided: {$provided}");
         return;
     }
     $namespaceName = $wgLang->getNsText($namespace);
     if (!MWNamespace::hasSubpages($namespace)) {
         $this->error("Subpages are not enabled in the {$namespaceName} namespace.");
         $this->error("In order to convert this namespace to Flow, you must enable subpages using:");
         $this->error("\$wgNamespacesWithSubpages[{$namespace}] = true;");
         return;
     }
     $noConvertTemplates = explode(',', $this->getOption('no-convert-templates', ''));
     if ($noConvertTemplates === array('')) {
         // explode( ',', '' ) returns array( '' )
         $noConvertTemplates = array();
     }
     // Convert to Title objects
     foreach ($noConvertTemplates as &$template) {
         $title = Title::newFromText($template, NS_TEMPLATE);
         if (!$title) {
             $this->error("Invalid template name: {$template}");
             return;
         }
         $template = $title;
     }
     // @todo send to prod logger?
     $logger = new MaintenanceDebugLogger($this);
     $dbw = wfGetDB(DB_MASTER);
     $converter = new \Flow\Import\Converter($dbw, Flow\Container::get('importer'), $logger, FlowHooks::getOccupationController()->getTalkpageManager(), new Flow\Import\Wikitext\ConversionStrategy($wgParser, new Flow\Import\NullImportSourceStore(), $logger, $noConvertTemplates, $this->getOption('archive-pattern', null)));
     $logger->info("Starting conversion of {$namespaceName} namespace");
     // Iterate over all existing pages of the namespace.
     $it = new NamespaceIterator($dbw, $namespace);
     // NamespaceIterator is an IteratorAggregate. Get an Iterator
     // so we can wrap that.
     $it = $it->getIterator();
     $converter->convertAll($it);
     $logger->info("Finished conversion of {$namespaceName} namespace");
 }
 public function execute()
 {
     $logger = new MaintenanceDebugLogger($this);
     if ($this->getOption('debug')) {
         $logger->setMaximumLevel(LogLevel::DEBUG);
     } else {
         $logger->setMaximumLevel(LogLevel::INFO);
     }
     $importer = Flow\Container::get('importer');
     $talkpageManagerUser = FlowHooks::getOccupationController()->getTalkpageManager();
     $dbw = wfGetDB(DB_MASTER);
     $strategy = new ConversionStrategy($dbw, new FileImportSourceStore($this->getOption('logfile')), new LocalApiBackend($talkpageManagerUser), Container::get('url_generator'), $talkpageManagerUser, Container::get('controller.notification'));
     $converter = new \Flow\Import\Converter($dbw, $importer, $logger, $talkpageManagerUser, $strategy);
     $startId = $this->getOption('startId');
     $stopId = $this->getOption('stopId');
     $logger->info("Starting full wiki LQT conversion of all pages with use-liquid-threads property");
     $titles = new PagesWithPropertyIterator($dbw, 'use-liquid-threads', $startId, $stopId);
     $converter->convertAll($titles);
     $logger->info("Finished conversion");
 }
 /**
  * @param string $action
  * @param OutputPage|null $output
  * @throws ErrorPageError
  * @throws FlowException
  */
 public function showForAction($action, OutputPage $output = null)
 {
     $container = Container::getContainer();
     $occupationController = \FlowHooks::getOccupationController();
     if ($output === null) {
         $output = $this->context->getOutput();
     }
     // Check if this is actually a Flow page.
     if (!$this->page instanceof WikiPage && !$this->page instanceof Article) {
         throw new ErrorPageError('nosuchaction', 'flow-action-unsupported');
     }
     $title = $this->page->getTitle();
     if (!$occupationController->isTalkpageOccupied($title)) {
         throw new ErrorPageError('nosuchaction', 'flow-action-unsupported');
     }
     // @todo much of this seems to duplicate BoardContent::getParserOutput
     $view = new View($container['url_generator'], $container['lightncandy'], $output, $container['flow_actions']);
     $request = $this->context->getRequest();
     // BC for urls pre july 2014 with workflow query parameter
     $redirect = $this->getRedirectUrl($request, $title);
     if ($redirect) {
         $output->redirect($redirect);
         return;
     }
     $action = $request->getVal('action', 'view');
     try {
         /** @var WorkflowLoaderFactory $factory */
         $factory = $container['factory.loader.workflow'];
         $loader = $factory->createWorkflowLoader($title);
         if ($title->getNamespace() === NS_TOPIC && $loader->getWorkflow()->getType() !== 'topic') {
             // @todo better error handling
             throw new FlowException('Invalid title: uuid is not a topic');
         }
         $view->show($loader, $action);
     } catch (FlowException $e) {
         $e->setOutput($output);
         throw $e;
     }
 }
 public function execute()
 {
     $cacheDir = $this->getOption('cacheremoteapidir');
     if (!is_dir($cacheDir)) {
         if (!mkdir($cacheDir)) {
             throw new Flow\Exception\FlowException('Provided dir for caching remote api calls is not creatable.');
         }
     }
     if (!is_writable($cacheDir)) {
         throw new Flow\Exception\FlowException('Provided dir for caching remote api calls is not writable.');
     }
     $api = new RemoteApiBackend($this->getOption('remoteapi'), $cacheDir);
     $importer = Flow\Container::get('importer');
     $importer->setAllowUnknownUsernames(true);
     $talkPageManagerUser = \FlowHooks::getOccupationController()->getTalkpageManager();
     $srcPageName = $this->getOption('srcpage');
     if ($this->hasOption('dstpage')) {
         $dstPageName = $this->getOption('dstpage');
     } else {
         $dstPageName = $srcPageName;
     }
     $dstTitle = Title::newFromText($dstPageName);
     $source = new LiquidThreadsApiImportSource($api, $srcPageName, $talkPageManagerUser);
     $logFilename = $this->getOption('logfile');
     $sourceStore = new FileImportSourceStore($logFilename);
     $logger = new MaintenanceDebugLogger($this);
     if ($this->getOption('debug')) {
         $logger->setMaximumLevel(LogLevel::DEBUG);
     } else {
         $logger->setMaximumLevel(LogLevel::INFO);
     }
     $importer->setLogger($logger);
     $api->setLogger($logger);
     $logger->info("Starting LQT conversion of page {$srcPageName}");
     $importer->import($source, $dstTitle, $sourceStore);
     $logger->info("Finished LQT conversion of page {$srcPageName}");
 }
 public function execute()
 {
     $talkPageManagerUser = \FlowHooks::getOccupationController()->getTalkpageManager();
     $api = new LocalApiBackend($talkPageManagerUser);
     $importer = Container::get('importer');
     $srcPageName = $this->getOption('srcpage');
     $logFilename = $this->getOption('logfile');
     $sourceStore = new FileImportSourceStore($logFilename);
     $dbw = wfGetDB(DB_MASTER);
     $logger = new MaintenanceDebugLogger($this);
     if ($this->getOption('debug')) {
         $logger->setMaximumLevel(LogLevel::DEBUG);
     } else {
         $logger->setMaximumLevel(LogLevel::INFO);
     }
     $strategy = new LiquidThreadsApiConversionStrategy($dbw, $sourceStore, $api, Container::get('url_generator'), $talkPageManagerUser, Container::get('controller.notification'));
     $importer->setLogger($logger);
     $api->setLogger($logger);
     $converter = new \Flow\Import\Converter($dbw, $importer, $logger, $talkPageManagerUser, $strategy);
     $logger->info("Starting LQT conversion of page {$srcPageName}");
     $srcTitle = \Title::newFromText($srcPageName);
     $converter->convertAll(array($srcTitle));
     $logger->info("Finished LQT conversion of page {$srcPageName}");
 }
$c['factory.loader.workflow'] = function ($c) {
    global $wgFlowDefaultWorkflow;
    return new Flow\WorkflowLoaderFactory($c['storage'], $c['factory.block'], $c['submission_handler'], $wgFlowDefaultWorkflow);
};
// Initialized in FlowHooks to facilitate only loading the flow container
// when flow is specifically requested to run. Extension initialization
// must always happen before calling flow code.
$c['occupation_controller'] = FlowHooks::getOccupationController();
$c['controller.notification'] = function ($c) {
    global $wgContLang;
    return new Flow\NotificationController($wgContLang);
};
// Initialized in FlowHooks to faciliate only loading the flow container
// when flow is specifically requested to run. Extension initialization
// must always happen before calling flow code.
$c['controller.abusefilter'] = FlowHooks::getAbuseFilter();
$c['controller.spamregex'] = function ($c) {
    return new Flow\SpamFilter\SpamRegex();
};
$c['controller.spamblacklist'] = function ($c) {
    return new Flow\SpamFilter\SpamBlacklist();
};
$c['controller.confirmedit'] = function ($c) {
    return new Flow\SpamFilter\ConfirmEdit();
};
$c['controller.contentlength'] = function ($c) {
    global $wgMaxArticleSize;
    // wgMaxArticleSize is in kilobytes,
    // whereas this really is characters (it uses
    // mb_strlen), so it's not the exact same limit.
    $maxCharCount = $wgMaxArticleSize * 1024;
 /**
  * Blocks topics from being deleted using the core deletion process, since it
  * doesn't work.
  *
  * @param WikiPage &$article Page the user requested to delete
  * @param User &$user User who requested to delete the article
  * @param string &$reason Reason given for deletion
  * @param string &$error Error explaining why we are not allowing the deletion
  * @return bool False if it is a Topic (to block it); otherwise, true
  */
 public static function onArticleDelete(WikiPage &$article, User &$user, &$reason, &$error)
 {
     $title = $article->getTitle();
     if ($title->inNamespace(NS_TOPIC)) {
         $error = FlowHooks::getTopicDeletionError($title);
         return false;
     }
     return true;
 }
 /**
  * @dataProvider onIRCLineUrlProvider
  */
 public function testOnIRCLineUrl($message, $metadataGen, $expectedQuery)
 {
     $user = User::newFromName('127.0.0.1', false);
     // reset flow state, so everything ($container['permissions'])
     // uses this particular $user
     \FlowHooks::resetFlowExtension();
     Container::reset();
     $container = Container::getContainer();
     $container['user'] = $user;
     $rc = new RecentChange();
     $rc->mAttribs = array('rc_namespace' => 0, 'rc_title' => 'Main Page', 'rc_source' => RecentChangesListener::SRC_FLOW);
     $metadata = $metadataGen($user);
     Container::get('formatter.irclineurl')->associate($rc, $metadata);
     $url = 'unset';
     $query = 'unset';
     $this->assertTrue(FlowHooks::onIRCLineURL($url, $query, $rc));
     $expectedQuery['title'] = $metadata['workflow']->getArticleTitle()->getPrefixedDBkey();
     $parts = parse_url($url);
     $this->assertArrayHasKey('query', $parts, $url);
     parse_str($parts['query'], $queryParts);
     foreach ($expectedQuery as $key => $value) {
         $this->assertEquals($value, $queryParts[$key], "Query part {$key}");
     }
     $this->assertEquals('', $query, $message);
 }