Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
31.82% |
14 / 44 |
|
25.00% |
2 / 8 |
CRAP | |
0.00% |
0 / 1 |
ApiCrossWiki | |
31.82% |
14 / 44 |
|
25.00% |
2 / 8 |
76.12 | |
0.00% |
0 / 1 |
getFromForeign | |
25.00% |
3 / 12 |
|
0.00% |
0 / 1 |
6.80 | |||
getForeignQueryParams | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
allowCrossWikiNotifications | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRequestedWikis | |
60.00% |
6 / 10 |
|
0.00% |
0 / 1 |
3.58 | |||
getRequestedForeignWikis | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getForeignNotifications | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getForeignWikisWithUnreadNotifications | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCrossWikiParams | |
20.00% |
3 / 15 |
|
0.00% |
0 / 1 |
4.05 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\Notifications\Api; |
4 | |
5 | // @phan-file-suppress PhanUndeclaredMethod This is a trait, and phan is confused by $this |
6 | use Exception; |
7 | use MediaWiki\Extension\Notifications\ForeignNotifications; |
8 | use MediaWiki\Extension\Notifications\ForeignWikiRequest; |
9 | use MediaWiki\WikiMap\WikiMap; |
10 | use Wikimedia\ParamValidator\ParamValidator; |
11 | |
12 | /** |
13 | * Trait that adds cross-wiki functionality to an API module. For mixing into ApiBase subclasses. |
14 | * |
15 | * In addition to mixing in this trait, you have to do the following in your API module: |
16 | * - In your getAllowedParams() method, merge in the return value of getCrossWikiParams() |
17 | * - In your execute() method, call getFromForeign() somewhere and do something with the result |
18 | * - Optionally, override getForeignQueryParams() to customize what is sent to the foreign wikis |
19 | */ |
20 | trait ApiCrossWiki { |
21 | /** |
22 | * @var ForeignNotifications |
23 | */ |
24 | protected $foreignNotifications; |
25 | |
26 | /** |
27 | * This will take the current API call (with all of its params) and execute |
28 | * it on all foreign wikis, returning an array of results per wiki. |
29 | * |
30 | * @param array|null $wikis List of wikis to query. Defaults to the result of getRequestedForeignWikis(). |
31 | * @param array $paramOverrides Request parameter overrides |
32 | * @return array[] |
33 | * @throws Exception |
34 | */ |
35 | protected function getFromForeign( array $wikis = null, array $paramOverrides = [] ) { |
36 | $wikis ??= $this->getRequestedForeignWikis(); |
37 | if ( $wikis === [] ) { |
38 | return []; |
39 | } |
40 | $tokenType = $this->needsToken(); |
41 | $foreignReq = new ForeignWikiRequest( |
42 | $this->getUser(), |
43 | $paramOverrides + $this->getForeignQueryParams(), |
44 | $wikis, |
45 | $this->getModulePrefix() . 'wikis', |
46 | $tokenType !== false ? $tokenType : null |
47 | ); |
48 | return $foreignReq->execute( $this->getRequest() ); |
49 | } |
50 | |
51 | /** |
52 | * Get the query parameters to use for the foreign API requests. |
53 | * Implementing classes should override this if they need to customize |
54 | * the parameters. |
55 | * @return array Query parameters |
56 | */ |
57 | protected function getForeignQueryParams() { |
58 | return $this->getRequest()->getValues(); |
59 | } |
60 | |
61 | /** |
62 | * @return bool |
63 | */ |
64 | protected function allowCrossWikiNotifications() { |
65 | global $wgEchoCrossWikiNotifications; |
66 | return $wgEchoCrossWikiNotifications; |
67 | } |
68 | |
69 | /** |
70 | * This is basically equivalent to $params['wikis'], but some added checks: |
71 | * - `*` will expand to "all wikis with unread notifications" |
72 | * - if `$wgEchoCrossWikiNotifications` is off, foreign wikis will be excluded |
73 | * |
74 | * @return string[] |
75 | */ |
76 | protected function getRequestedWikis() { |
77 | $params = $this->extractRequestParams(); |
78 | |
79 | // if wiki is omitted from params, that's because crosswiki is/was not |
80 | // available, and it'll default to current wiki |
81 | $wikis = $params['wikis'] ?? [ WikiMap::getCurrentWikiId() ]; |
82 | |
83 | if ( in_array( '*', $wikis ) ) { |
84 | // expand `*` to all foreign wikis with unread notifications + local |
85 | $wikis = array_merge( |
86 | [ WikiMap::getCurrentWikiId() ], |
87 | $this->getForeignWikisWithUnreadNotifications() |
88 | ); |
89 | } |
90 | |
91 | if ( !$this->allowCrossWikiNotifications() ) { |
92 | // exclude foreign wikis if x-wiki is not enabled |
93 | $wikis = array_intersect_key( [ WikiMap::getCurrentWikiId() ], $wikis ); |
94 | } |
95 | |
96 | return $wikis; |
97 | } |
98 | |
99 | /** |
100 | * @return string[] Wiki names |
101 | */ |
102 | protected function getRequestedForeignWikis() { |
103 | return array_diff( $this->getRequestedWikis(), [ WikiMap::getCurrentWikiId() ] ); |
104 | } |
105 | |
106 | /** |
107 | * @return ForeignNotifications |
108 | */ |
109 | protected function getForeignNotifications() { |
110 | if ( $this->foreignNotifications === null ) { |
111 | $this->foreignNotifications = new ForeignNotifications( $this->getUser() ); |
112 | } |
113 | return $this->foreignNotifications; |
114 | } |
115 | |
116 | /** |
117 | * @return string[] Wiki names |
118 | */ |
119 | protected function getForeignWikisWithUnreadNotifications() { |
120 | return $this->getForeignNotifications()->getWikis(); |
121 | } |
122 | |
123 | /** |
124 | * @return array[] |
125 | */ |
126 | public function getCrossWikiParams() { |
127 | global $wgConf; |
128 | |
129 | $params = []; |
130 | |
131 | if ( $this->allowCrossWikiNotifications() ) { |
132 | $params += [ |
133 | // fetch notifications from multiple wikis |
134 | 'wikis' => [ |
135 | ParamValidator::PARAM_ISMULTI => true, |
136 | ParamValidator::PARAM_DEFAULT => WikiMap::getCurrentWikiId(), |
137 | // `*` will let you immediately fetch from all wikis that have |
138 | // unread notifications, without having to look them up first |
139 | ParamValidator::PARAM_TYPE => array_unique( |
140 | array_merge( |
141 | $wgConf->wikis, |
142 | [ WikiMap::getCurrentWikiId(), '*' ] |
143 | ) |
144 | ), |
145 | ], |
146 | ]; |
147 | } |
148 | |
149 | return $params; |
150 | } |
151 | } |