Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 155 |
|
0.00% |
0 / 24 |
CRAP | |
0.00% |
0 / 1 |
WikiSet | |
0.00% |
0 / 155 |
|
0.00% |
0 / 24 |
1640 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
exists | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getWikisRaw | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setWikisRaw | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setType | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
newFromRow | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
newFromName | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
12 | |||
newFromID | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
12 | |||
getDataForCache | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
loadFromCachedData | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
saveToDB | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
6 | |||
delete | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
purge | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getPerIdCacheKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPerNameCacheKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getWikis | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
inSet | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getRestrictedGroups | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
getAllWikiSets | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
getWikiSetForGroup | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Extension\CentralAuth; |
22 | |
23 | use MediaWiki\MediaWikiServices; |
24 | use MediaWiki\WikiMap\WikiMap; |
25 | use stdClass; |
26 | use WANObjectCache; |
27 | use Wikimedia\Rdbms\Database; |
28 | |
29 | class WikiSet { |
30 | public const OPTIN = 'optin'; |
31 | public const OPTOUT = 'optout'; |
32 | |
33 | private const VERSION = 1; |
34 | |
35 | /** @var int ID of the group */ |
36 | private $mId; |
37 | /** @var string Display name of the group */ |
38 | private $mName; |
39 | /** @var string Opt-in based or opt-out based */ |
40 | private $mType; |
41 | /** @var string[] List of wikis */ |
42 | private $mWikis; |
43 | |
44 | /** @var string[] */ |
45 | private static $mCacheVars = [ |
46 | 'mId', |
47 | 'mName', |
48 | 'mType', |
49 | 'mWikis', |
50 | ]; |
51 | |
52 | /** |
53 | * @param string $name |
54 | * @param string $type |
55 | * @param string[] $wikis |
56 | * @param int $id |
57 | */ |
58 | public function __construct( $name = '', $type = self::OPTIN, $wikis = [], $id = 0 ) { |
59 | $this->mId = $id; |
60 | $this->mName = $name; |
61 | $this->mType = $type; |
62 | $this->mWikis = $wikis; |
63 | } |
64 | |
65 | /** |
66 | * @return int |
67 | */ |
68 | public function getId() { |
69 | return $this->mId; |
70 | } |
71 | |
72 | /** |
73 | * @return bool |
74 | */ |
75 | public function exists() { |
76 | return (bool)$this->getID(); |
77 | } |
78 | |
79 | /** |
80 | * @return string |
81 | */ |
82 | public function getName() { |
83 | return $this->mName; |
84 | } |
85 | |
86 | /** |
87 | * @param string $name |
88 | */ |
89 | public function setName( $name ) { |
90 | $this->mName = $name; |
91 | } |
92 | |
93 | /** |
94 | * @return string[] |
95 | */ |
96 | public function getWikisRaw() { |
97 | return $this->mWikis; |
98 | } |
99 | |
100 | /** |
101 | * @param string[] $wikis |
102 | */ |
103 | public function setWikisRaw( $wikis ) { |
104 | $this->mWikis = $wikis; |
105 | } |
106 | |
107 | /** |
108 | * @return string |
109 | */ |
110 | public function getType() { |
111 | return $this->mType; |
112 | } |
113 | |
114 | /** |
115 | * @param string $type |
116 | */ |
117 | public function setType( $type ) { |
118 | if ( !in_array( $type, [ self::OPTIN, self::OPTOUT ] ) ) { |
119 | return; |
120 | } |
121 | $this->mType = $type; |
122 | } |
123 | |
124 | /** |
125 | * @param stdClass|bool $row |
126 | * @return null|WikiSet |
127 | */ |
128 | public static function newFromRow( $row ) { |
129 | if ( !$row ) { |
130 | return null; |
131 | } |
132 | return new WikiSet( |
133 | $row->ws_name, |
134 | $row->ws_type, |
135 | explode( ',', $row->ws_wikis ), |
136 | $row->ws_id |
137 | ); |
138 | } |
139 | |
140 | /** |
141 | * @param string $name |
142 | * @return null|WikiSet |
143 | */ |
144 | public static function newFromName( $name ) { |
145 | $cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); |
146 | $fname = __METHOD__; |
147 | |
148 | $data = $cache->getWithSetCallback( |
149 | self::getPerNameCacheKey( $cache, $name ), |
150 | $cache::TTL_INDEFINITE, |
151 | function ( $oldValue, &$ttl, &$setOpts ) use ( $name, $fname ) { |
152 | $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB(); |
153 | $setOpts += Database::getCacheSetOptions( $dbr ); |
154 | |
155 | $row = $dbr->newSelectQueryBuilder() |
156 | ->select( '*' ) |
157 | ->from( 'wikiset' ) |
158 | ->where( [ 'ws_name' => $name ] ) |
159 | ->caller( $fname ) |
160 | ->fetchRow(); |
161 | |
162 | $wikiSet = self::newFromRow( $row ); |
163 | if ( $wikiSet ) { |
164 | $value = $wikiSet->getDataForCache(); |
165 | } else { |
166 | // cache negatives |
167 | $ttl = WANObjectCache::TTL_MINUTE; |
168 | $value = null; |
169 | } |
170 | |
171 | return $value; |
172 | }, |
173 | [ 'version' => self::VERSION ] |
174 | ); |
175 | |
176 | if ( !$data ) { |
177 | return null; |
178 | } |
179 | |
180 | $wikiSet = new WikiSet(); |
181 | $wikiSet->loadFromCachedData( $data ); |
182 | |
183 | return $wikiSet; |
184 | } |
185 | |
186 | /** |
187 | * @param string|int $id |
188 | * @return null|WikiSet |
189 | */ |
190 | public static function newFromID( $id ) { |
191 | $cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); |
192 | $fname = __METHOD__; |
193 | |
194 | $data = $cache->getWithSetCallback( |
195 | self::getPerIdCacheKey( $cache, $id ), |
196 | $cache::TTL_INDEFINITE, |
197 | function ( $oldValue, &$ttl, &$setOpts ) use ( $id, $fname ) { |
198 | $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB(); |
199 | $setOpts += Database::getCacheSetOptions( $dbr ); |
200 | |
201 | $row = $dbr->newSelectQueryBuilder() |
202 | ->select( '*' ) |
203 | ->from( 'wikiset' ) |
204 | ->where( [ 'ws_id' => $id ] ) |
205 | ->caller( $fname ) |
206 | ->fetchRow(); |
207 | |
208 | $wikiSet = self::newFromRow( $row ); |
209 | if ( $wikiSet ) { |
210 | $value = $wikiSet->getDataForCache(); |
211 | } else { |
212 | // cache negatives |
213 | $ttl = WANObjectCache::TTL_MINUTE; |
214 | $value = null; |
215 | } |
216 | |
217 | return $value; |
218 | }, |
219 | [ 'version' => self::VERSION ] |
220 | ); |
221 | |
222 | if ( !$data ) { |
223 | return null; |
224 | } |
225 | |
226 | $wikiSet = new WikiSet(); |
227 | $wikiSet->loadFromCachedData( $data ); |
228 | |
229 | return $wikiSet; |
230 | } |
231 | |
232 | /** |
233 | * @return array |
234 | */ |
235 | private function getDataForCache() { |
236 | $data = []; |
237 | foreach ( self::$mCacheVars as $var ) { |
238 | if ( isset( $this->$var ) ) { |
239 | $data[$var] = $this->$var; |
240 | } |
241 | } |
242 | |
243 | return $data; |
244 | } |
245 | |
246 | /** |
247 | * @param array $data |
248 | */ |
249 | private function loadFromCachedData( array $data ) { |
250 | foreach ( $data as $key => $val ) { |
251 | $this->$key = $val; |
252 | } |
253 | } |
254 | |
255 | /** |
256 | * @return bool |
257 | */ |
258 | public function saveToDB() { |
259 | $dbw = CentralAuthServices::getDatabaseManager()->getCentralPrimaryDB(); |
260 | $dbw->startAtomic( __METHOD__ ); |
261 | $dbw->newReplaceQueryBuilder() |
262 | ->replaceInto( 'wikiset' ) |
263 | ->uniqueIndexFields( 'ws_id' ) |
264 | ->row( [ |
265 | 'ws_id' => $this->mId, |
266 | 'ws_name' => $this->mName, |
267 | 'ws_type' => $this->mType, |
268 | 'ws_wikis' => implode( ',', $this->mWikis ), |
269 | ] ) |
270 | ->caller( __METHOD__ ) |
271 | ->execute(); |
272 | if ( !$this->mId ) { |
273 | $this->mId = $dbw->insertId(); |
274 | } |
275 | $dbw->endAtomic( __METHOD__ ); |
276 | $this->purge(); |
277 | return (bool)$dbw->affectedRows(); |
278 | } |
279 | |
280 | /** |
281 | * @return bool |
282 | */ |
283 | public function delete() { |
284 | $dbw = CentralAuthServices::getDatabaseManager()->getCentralPrimaryDB(); |
285 | $dbw->newDeleteQueryBuilder() |
286 | ->deleteFrom( 'wikiset' ) |
287 | ->where( [ 'ws_id' => $this->mId ] ) |
288 | ->caller( __METHOD__ ) |
289 | ->execute(); |
290 | $this->purge(); |
291 | return (bool)$dbw->affectedRows(); |
292 | } |
293 | |
294 | public function purge() { |
295 | $cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); |
296 | $cache->delete( self::getPerIdCacheKey( $cache, $this->mId ) ); |
297 | $cache->delete( self::getPerNameCacheKey( $cache, $this->mName ) ); |
298 | } |
299 | |
300 | /** |
301 | * @param WANObjectCache $cache |
302 | * @param string|int $id |
303 | * @return string |
304 | */ |
305 | private static function getPerIdCacheKey( WANObjectCache $cache, $id ) { |
306 | return $cache->makeGlobalKey( __CLASS__, 'id', $id ); |
307 | } |
308 | |
309 | /** |
310 | * @param WANObjectCache $cache |
311 | * @param string $name |
312 | * @return string |
313 | */ |
314 | private static function getPerNameCacheKey( WANObjectCache $cache, $name ) { |
315 | return $cache->makeGlobalKey( __CLASS__, 'name', md5( $name ) ); |
316 | } |
317 | |
318 | /** |
319 | * @return string[] |
320 | */ |
321 | public function getWikis() { |
322 | if ( $this->mType == self::OPTIN ) { |
323 | return $this->mWikis; |
324 | } else { |
325 | $wikiList = CentralAuthServices::getWikiListService()->getWikiList(); |
326 | return array_diff( $wikiList, $this->mWikis ); |
327 | } |
328 | } |
329 | |
330 | /** |
331 | * @param string $wiki |
332 | * @return bool |
333 | */ |
334 | public function inSet( $wiki = '' ) { |
335 | if ( !$wiki ) { |
336 | $wiki = WikiMap::getCurrentWikiId(); |
337 | } |
338 | return in_array( $wiki, $this->getWikis() ); |
339 | } |
340 | |
341 | /** |
342 | * @return string[] |
343 | */ |
344 | public function getRestrictedGroups() { |
345 | $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB(); |
346 | return $dbr->newSelectQueryBuilder() |
347 | ->select( 'ggr_group' ) |
348 | ->from( 'global_group_restrictions' ) |
349 | ->where( [ 'ggr_set' => $this->mId ] ) |
350 | ->caller( __METHOD__ ) |
351 | ->fetchFieldValues(); |
352 | } |
353 | |
354 | /** |
355 | * @param string|null $from The wiki set name to start from (result is ordered by name) |
356 | * @param int|null $limit Limit for the selection (0 or null = no limit) |
357 | * @param bool $orderByName Order the result by name? |
358 | * @return self[] |
359 | */ |
360 | public static function getAllWikiSets( $from = null, $limit = null, $orderByName = false ) { |
361 | $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB(); |
362 | |
363 | $qb = $dbr->newSelectQueryBuilder() |
364 | ->select( '*' ) |
365 | ->from( 'wikiset' ) |
366 | ->caller( __METHOD__ ); |
367 | |
368 | if ( $from != null ) { |
369 | $qb->where( $dbr->expr( 'ws_name', '>=', $from ) ); |
370 | $orderByName = true; |
371 | } |
372 | |
373 | if ( $limit ) { |
374 | $qb->limit( intval( $limit ) ); |
375 | } |
376 | |
377 | if ( $orderByName ) { |
378 | $qb->orderBy( 'ws_name' ); |
379 | } |
380 | |
381 | $res = $qb->fetchResultSet(); |
382 | |
383 | $result = []; |
384 | foreach ( $res as $row ) { |
385 | $result[] = self::newFromRow( $row ); |
386 | } |
387 | return $result; |
388 | } |
389 | |
390 | /** |
391 | * @param string $group |
392 | * @return int |
393 | */ |
394 | public static function getWikiSetForGroup( $group ) { |
395 | $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB(); |
396 | return (int)$dbr->newSelectQueryBuilder() |
397 | ->select( 'ggr_set' ) |
398 | ->from( 'global_group_restrictions' ) |
399 | ->where( [ 'ggr_group' => $group ] ) |
400 | ->caller( __METHOD__ ) |
401 | ->fetchField(); |
402 | } |
403 | |
404 | } |