Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialCode
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 6
930
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSubpagesForPrefixSearch
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 execute
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 getViewFrom
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
380
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isListed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\CodeReview\UI;
4
5use MediaWiki\Extension\CodeReview\Backend\CodeRepository;
6use SpecialPage;
7
8/**
9 * Main UI entry point. This calls the appropriate CodeView subclass and runs it
10 */
11class SpecialCode extends SpecialPage {
12    public function __construct() {
13        parent::__construct( 'Code', 'codereview-use' );
14    }
15
16    /**
17     * Return an array of subpages that this special page will accept.
18     *
19     * @return string[] subpages
20     */
21    public function getSubpagesForPrefixSearch() {
22        $repos = CodeRepository::getRepoList();
23        if ( count( $repos ) ) {
24            $retVal = [];
25            foreach ( $repos as $repo ) {
26                $retVal[] = $repo->getName();
27            }
28            sort( $retVal );
29            return $retVal;
30        }
31        return [];
32    }
33
34    /**
35     * @param string $subpage
36     */
37    public function execute( $subpage ) {
38        $this->checkPermissions();
39
40        $this->setHeaders();
41        // Base styles used for all code review UI actions.
42        $out = $this->getOutput();
43        $out->addModules( 'ext.codereview' );
44        $out->addModules( 'ext.codereview.tooltips' );
45        $out->addModuleStyles( 'ext.codereview.styles' );
46
47        // Load [[MediaWiki:CodeReview.css]] (bug #16049) if site CSS is enabled
48        if ( $this->getConfig()->get( 'UseSiteCss' ) ) {
49            $out->addModuleStyles( 'ext.codereview.local' );
50        }
51
52        $view = $this->getViewFrom( $subpage );
53        if ( $view ) {
54            $view->execute();
55        } else {
56            $out->addWikiMsg( 'nosuchactiontext' );
57            $out->returnToMain( null, $this->getPageTitle() );
58            return;
59        }
60
61        // Add subtitle for easy navigation
62        if ( $view instanceof CodeView ) {
63            $repo = $view->getRepo();
64
65            if ( $repo ) {
66                $out->setSubtitle(
67                    $this->msg(
68                        'codereview-subtitle',
69                        CodeRepoListView::getNavItem( $repo, $this->getUser() )
70                    )->parseAsBlock()
71                );
72            }
73        }
74    }
75
76    /**
77     * Get a view object from a sub page path.
78     * @param string|null $subpage
79     * @return CodeView|CodeRepoListView|null - Null if no valid action could be found
80     */
81    private function getViewFrom( $subpage ) {
82        // Defines the classes to use for each view type.
83        // The first class name is used if no additional parameters are provided.
84        // The second, if defined, is used if there is an additional parameter. If
85        // there is no second class defined, then the first class is used in both
86        // cases.
87        static $paramClasses = [
88            'tag' => [ CodeTagListView::class, CodeRevisionTagView::class, ],
89            'author' => [ CodeAuthorListView::class, CodeRevisionAuthorView::class ],
90            'status' => [ CodeStatusListView::class, CodeRevisionStatusView::class ],
91            'comments' => [ CodeCommentsListView::class ],
92            'statuschanges' => [ CodeStatusChangeListView::class ],
93            'releasenotes' => [ CodeReleaseNotes::class ],
94            'stats' => [ CodeRepoStatsView::class ],
95        ];
96
97        $request = $this->getRequest();
98        # Remove stray slashes
99        $subpage = preg_replace( '/\/$/', '', $subpage ?? '' );
100        if ( $subpage == '' ) {
101            $view = new CodeRepoListView();
102        } else {
103            $params = explode( '/', $subpage );
104
105            $repo = CodeRepository::newFromName( $params[0] );
106            // If a repository was specified, but it does not exist, redirect to the
107            // repository list with an appropriate message.
108            if ( !$repo ) {
109                $view = new CodeRepoListView();
110                $this->getOutput()->addWikiMsg( 'code-repo-not-found', wfEscapeWikiText( $params[0] ) );
111                return $view;
112            }
113
114            $user = $this->getUser();
115
116            switch ( count( $params ) ) {
117            case 1:
118                $view = new CodeRevisionListView( $repo );
119                break;
120            case 2:
121                // drop through...
122            case 3:
123                if ( isset( $paramClasses[$params[1]] ) ) {
124                    $row = $paramClasses[$params[1]];
125                    if ( isset( $params[2] ) && isset( $row[1] ) ) {
126                        $view = new $row[1]( $repo, $params[2] );
127                    } else {
128                        $view = new $row[0]( $repo );
129                    }
130                } elseif ( $request->wasPosted() && !$request->getCheck( 'wpPreview' ) ) {
131                    # This is not really a view, but we return it nonetheless.
132                    # Add any tags, Set status, Adds comments
133                    // @phan-suppress-next-line PhanTypeMismatchArgumentReal
134                    $view = new CodeRevisionCommitter( $repo, $user, $params[1] );
135                } elseif ( empty( $params[1] ) ) {
136                    $view = new CodeRevisionListView( $repo );
137                } else {
138                    $view = new CodeRevisionView( $repo, $params[1], $user );
139                }
140                break;
141            case 4:
142                if ( $params[1] === 'author' && $params[3] === 'link' ) {
143                    $view = new CodeRevisionAuthorLink( $repo, $params[2], $this->getUser() );
144                    break;
145                } elseif ( $params[1] === 'comments' ) {
146                    $view = new CodeCommentsAuthorListView( $repo, $params[3] );
147                    break;
148                } elseif ( $params[1] === 'statuschanges' ) {
149                    $view = new CodeStatusChangeAuthorListView( $repo, $params[3] );
150                    break;
151                }
152                // @todo FIXME: Fall through or not?
153            default:
154                if ( $params[2] == 'reply' ) {
155                    $view = new CodeRevisionView( $repo, $params[1], $user, $params[3] );
156                    break;
157                }
158                return null;
159            }
160        }
161        return $view;
162    }
163
164    protected function getGroupName() {
165        return 'developer';
166    }
167
168    /**
169     * Only list me on Special:SpecialPages when configured.
170     * @return bool
171     */
172    public function isListed() {
173        return $this->getConfig()->get( 'CodeReviewListSpecialPage' );
174    }
175}