Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlowAction
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 6
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 show
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 showForAction
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
42
 getRedirectUrl
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace Flow\Actions;
4
5use Action;
6use Article;
7use ErrorPageError;
8use Flow\Container;
9use Flow\Data\ManagerGroup;
10use Flow\Exception\FlowException;
11use Flow\Exception\InvalidDataException;
12use Flow\Model\UUID;
13use Flow\Model\Workflow;
14use Flow\View;
15use Flow\WorkflowLoaderFactory;
16use IContextSource;
17use MediaWiki\Output\OutputPage;
18use MediaWiki\Request\WebRequest;
19use MediaWiki\Title\Title;
20use MWExceptionRenderer;
21
22class FlowAction extends Action {
23    /**
24     * @var string
25     */
26    protected $actionName;
27
28    /**
29     * @param Article $article
30     * @param IContextSource $source
31     * @param string $actionName
32     */
33    public function __construct( Article $article, IContextSource $source, $actionName ) {
34        parent::__construct( $article, $source );
35        $this->actionName = $actionName;
36    }
37
38    public function doesWrites() {
39        return true;
40    }
41
42    /**
43     * @return string
44     */
45    public function getName() {
46        return $this->actionName;
47    }
48
49    public function show() {
50        $this->showForAction( $this->getName() );
51    }
52
53    /**
54     * @param string $action
55     * @param OutputPage|null $output
56     * @throws ErrorPageError
57     * @throws FlowException
58     */
59    public function showForAction( $action, OutputPage $output = null ) {
60        $container = Container::getContainer();
61        $output ??= $this->context->getOutput();
62        $title = $this->getTitle();
63
64        $titleContentModel = $title->getContentModel();
65        if ( $titleContentModel !== CONTENT_MODEL_FLOW_BOARD ) {
66            // If we make it to this method, something thinks it's Flow.
67            // However, if we get here the Title class thinks otherwise.
68
69            // This may mean it is a non-Flow page in a Flow namespace, if
70            // page_content_model is populated but rev_content_model is not.
71
72            throw new ErrorPageError( 'nosuchaction', 'flow-action-wrong-title-content-model', [ $titleContentModel ] );
73        }
74
75        // @todo much of this seems to duplicate BoardContent::getParserOutput
76        $view = new View(
77            $container['url_generator'],
78            $container['lightncandy'],
79            $output,
80            $container['flow_actions']
81        );
82
83        $request = $this->context->getRequest();
84
85        // BC for urls pre july 2014 with workflow query parameter
86        $redirect = $this->getRedirectUrl( $request, $title );
87        if ( $redirect ) {
88            $output->redirect( $redirect );
89            return;
90        }
91
92        $action = $request->getVal( 'action', 'view' );
93        try {
94            /** @var WorkflowLoaderFactory $factory */
95            $factory = $container['factory.loader.workflow'];
96            $loader = $factory->createWorkflowLoader( $title );
97
98            if ( $title->getNamespace() === NS_TOPIC && $loader->getWorkflow()->getType() !== 'topic' ) {
99                // @todo better error handling
100                throw new FlowException( 'Invalid title: uuid is not a topic' );
101            }
102
103            $view->show( $loader, $action );
104        } catch ( InvalidDataException $e ) {
105            // FIXME: This isn't a real solution to the problem.
106            // Pretend that we aren't generating 500 errors here by swallowing the
107            // error, removing some log spam and avoiding pings to SRE and others
108            // looking at the production logs.
109            // The actual fix would be to prevent users from getting in a stuck
110            // position with their user talk pages.
111            MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
112        }
113    }
114
115    /**
116     * Flow used to output some permalink urls with workflow ids in them. Each
117     * workflow now has its own page, so those have been deprecated. This checks
118     * a web request for the old workflow parameter and returns a url to redirect
119     * to if necessary.
120     *
121     * @param WebRequest $request
122     * @param Title $title
123     * @return string URL to redirect to or blank string for no redirect
124     */
125    protected function getRedirectUrl( WebRequest $request, Title $title ) {
126        $workflow = $request->getVal( 'workflow', null );
127        $workflowId = $workflow !== null ? UUID::create( strtolower( $workflow ) ) : null;
128        if ( !$workflowId ) {
129            return '';
130        }
131
132        /** @var ManagerGroup $storage */
133        $storage = Container::get( 'storage' );
134        /** @var Workflow $workflow */
135        $workflow = $storage->get( 'Workflow', $workflowId );
136
137        // The uuid points to a non-existant workflow
138        if ( !$workflow ) {
139            return '';
140        }
141
142        // The uuid points to the current page
143        $redirTitle = $workflow->getArticleTitle();
144        if ( $redirTitle->equals( $title ) ) {
145            return '';
146        }
147
148        // We need to redirect
149        return $redirTitle->getLinkURL(
150            array_diff_key( $request->getValues(), [ 'title' => '', 'workflow' => '' ] )
151        );
152    }
153}