Index: branches/REL1_18/phase3/RELEASE-NOTES-1.18 |
— | — | @@ -81,7 +81,6 @@ |
82 | 82 | hooks have been removed. |
83 | 83 | * New hook "Collation::factory" to allow extensions to create custom |
84 | 84 | category collations. |
85 | | -* $wgGroupPermissions now supports per namespace permissions. |
86 | 85 | |
87 | 86 | === New features in 1.18 === |
88 | 87 | * BREAKING CHANGE: action=watch / action=unwatch now requires a token. |
Index: branches/REL1_18/phase3/tests/phpunit/includes/ArticleTablesTest.php |
— | — | @@ -11,7 +11,7 @@ |
12 | 12 | $title = Title::newFromText("Bug 14404"); |
13 | 13 | $article = new Article( $title ); |
14 | 14 | $wgUser = new User(); |
15 | | - $wgUser->mRights['*'] = array( 'createpage', 'edit', 'purge' ); |
| 15 | + $wgUser->mRights = array( 'createpage', 'edit', 'purge' ); |
16 | 16 | $wgLanguageCode = 'es'; |
17 | 17 | $wgContLang = Language::factory( 'es' ); |
18 | 18 | |
Index: branches/REL1_18/phase3/tests/phpunit/includes/UserTest.php |
— | — | @@ -1,11 +1,7 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -define( 'NS_UNITTEST', 5600 ); |
5 | | -define( 'NS_UNITTEST_TALK', 5601 ); |
6 | | - |
7 | 4 | class UserTest extends MediaWikiTestCase { |
8 | 5 | protected $savedGroupPermissions, $savedRevokedPermissions; |
9 | | - protected $user; |
10 | 6 | |
11 | 7 | public function setUp() { |
12 | 8 | parent::setUp(); |
— | — | @@ -14,40 +10,24 @@ |
15 | 11 | $this->savedRevokedPermissions = $GLOBALS['wgRevokePermissions']; |
16 | 12 | |
17 | 13 | $this->setUpPermissionGlobals(); |
18 | | - $this->setUpUser(); |
19 | 14 | } |
20 | 15 | private function setUpPermissionGlobals() { |
21 | 16 | global $wgGroupPermissions, $wgRevokePermissions; |
22 | 17 | |
23 | | - # Data for regular $wgGroupPermissions test |
24 | 18 | $wgGroupPermissions['unittesters'] = array( |
25 | | - 'test' => true, |
26 | 19 | 'runtest' => true, |
27 | 20 | 'writetest' => false, |
28 | 21 | 'nukeworld' => false, |
29 | 22 | ); |
30 | 23 | $wgGroupPermissions['testwriters'] = array( |
31 | | - 'test' => true, |
32 | 24 | 'writetest' => true, |
33 | 25 | 'modifytest' => true, |
34 | 26 | ); |
35 | | - # Data for regular $wgRevokePermissions test |
| 27 | + |
36 | 28 | $wgRevokePermissions['formertesters'] = array( |
37 | 29 | 'runtest' => true, |
38 | 30 | ); |
39 | | - |
40 | | - # Data for namespace based $wgGroupPermissions test |
41 | | - $wgGroupPermissions['unittesters']['writedocumentation'] = array( |
42 | | - NS_MAIN => false, NS_UNITTEST => true, |
43 | | - ); |
44 | | - $wgGroupPermissions['testwriters']['writedocumentation'] = true; |
45 | | - |
46 | 31 | } |
47 | | - private function setUpUser() { |
48 | | - $this->user = new User; |
49 | | - $this->user->addGroup( 'unittesters' ); |
50 | | - } |
51 | | - |
52 | 32 | public function tearDown() { |
53 | 33 | parent::tearDown(); |
54 | 34 | |
— | — | @@ -75,90 +55,4 @@ |
76 | 56 | $this->assertNotContains( 'modifytest', $rights ); |
77 | 57 | $this->assertNotContains( 'nukeworld', $rights ); |
78 | 58 | } |
79 | | - |
80 | | - public function testNamespaceGroupPermissions() { |
81 | | - $rights = User::getGroupPermissions( array( 'unittesters' ) ); |
82 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
83 | | - |
84 | | - $rights = User::getGroupPermissions( array( 'unittesters' ) , NS_MAIN ); |
85 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
86 | | - $this->assertNotContains( 'modifytest', $rights ); |
87 | | - |
88 | | - $rights = User::getGroupPermissions( array( 'unittesters' ), NS_HELP ); |
89 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
90 | | - $this->assertNotContains( 'modifytest', $rights ); |
91 | | - |
92 | | - $rights = User::getGroupPermissions( array( 'unittesters' ), NS_UNITTEST ); |
93 | | - $this->assertContains( 'writedocumentation', $rights ); |
94 | | - |
95 | | - $rights = User::getGroupPermissions( |
96 | | - array( 'unittesters', 'testwriters' ), NS_MAIN ); |
97 | | - $this->assertContains( 'writedocumentation', $rights ); |
98 | | - } |
99 | | - |
100 | | - public function testUserPermissions() { |
101 | | - $rights = $this->user->getRights(); |
102 | | - $this->assertContains( 'runtest', $rights ); |
103 | | - $this->assertNotContains( 'writetest', $rights ); |
104 | | - $this->assertNotContains( 'modifytest', $rights ); |
105 | | - $this->assertNotContains( 'nukeworld', $rights ); |
106 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
107 | | - |
108 | | - $rights = $this->user->getRights( NS_MAIN ); |
109 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
110 | | - $this->assertNotContains( 'modifytest', $rights ); |
111 | | - |
112 | | - $rights = $this->user->getRights( NS_HELP ); |
113 | | - $this->assertNotContains( 'writedocumentation', $rights ); |
114 | | - $this->assertNotContains( 'modifytest', $rights ); |
115 | | - |
116 | | - $rights = $this->user->getRights( NS_UNITTEST ); |
117 | | - $this->assertContains( 'writedocumentation', $rights ); |
118 | | - } |
119 | | - |
120 | | - /** |
121 | | - * @dataProvider provideGetGroupsWithPermission |
122 | | - */ |
123 | | - public function testGetGroupsWithPermission( $expected, $right, $ns ) { |
124 | | - $result = User::getGroupsWithPermission( $right, $ns ); |
125 | | - sort( $result ); |
126 | | - sort( $expected ); |
127 | | - |
128 | | - $this->assertEquals( $expected, $result, "Groups with permission $right" . |
129 | | - ( is_null( $ns ) ? '' : "in namespace $ns" ) ); |
130 | | - } |
131 | | - public function provideGetGroupsWithPermission() { |
132 | | - return array( |
133 | | - array( |
134 | | - array( 'unittesters', 'testwriters' ), |
135 | | - 'test', |
136 | | - null |
137 | | - ), |
138 | | - array( |
139 | | - array( 'unittesters' ), |
140 | | - 'runtest', |
141 | | - null |
142 | | - ), |
143 | | - array( |
144 | | - array( 'testwriters' ), |
145 | | - 'writetest', |
146 | | - null |
147 | | - ), |
148 | | - array( |
149 | | - array( 'testwriters' ), |
150 | | - 'modifytest', |
151 | | - null |
152 | | - ), |
153 | | - array( |
154 | | - array( 'testwriters' ), |
155 | | - 'writedocumentation', |
156 | | - NS_MAIN |
157 | | - ), |
158 | | - array( |
159 | | - array( 'unittesters', 'testwriters' ), |
160 | | - 'writedocumentation', |
161 | | - NS_UNITTEST |
162 | | - ), |
163 | | - ); |
164 | | - } |
165 | 59 | } |
\ No newline at end of file |
Index: branches/REL1_18/phase3/tests/phpunit/includes/TitlePermissionTest.php |
— | — | @@ -56,17 +56,11 @@ |
57 | 57 | } |
58 | 58 | |
59 | 59 | function setUserPerm( $perm ) { |
60 | | - // Setting member variables is evil!!! |
61 | | - |
62 | | - if ( !is_array( $perm ) ) { |
63 | | - $perm = array( $perm ); |
| 60 | + if ( is_array( $perm ) ) { |
| 61 | + $this->user->mRights = $perm; |
| 62 | + } else { |
| 63 | + $this->user->mRights = array( $perm ); |
64 | 64 | } |
65 | | - for ($i = 0; $i < 100; $i++) { |
66 | | - $this->user->mRights[$i] = $perm; |
67 | | - } |
68 | | - |
69 | | - // Hack, hack hack ... |
70 | | - $this->user->mRights['*'] = $perm; |
71 | 65 | } |
72 | 66 | |
73 | 67 | function setTitle( $ns, $title = "Main_Page" ) { |
Index: branches/REL1_18/phase3/includes/User.php |
— | — | @@ -2252,29 +2252,16 @@ |
2253 | 2253 | |
2254 | 2254 | /** |
2255 | 2255 | * Get the permissions this user has. |
2256 | | - * @param $ns int If numeric, get permissions for this namespace |
2257 | 2256 | * @return Array of String permission names |
2258 | 2257 | */ |
2259 | | - public function getRights( $ns = null ) { |
2260 | | - $key = is_null( $ns ) ? '*' : intval( $ns ); |
2261 | | - |
| 2258 | + function getRights() { |
2262 | 2259 | if ( is_null( $this->mRights ) ) { |
2263 | | - $this->mRights = array(); |
2264 | | - } |
2265 | | - |
2266 | | - if ( !isset( $this->mRights[$key] ) ) { |
2267 | | - $this->mRights[$key] = self::getGroupPermissions( $this->getEffectiveGroups(), $ns ); |
2268 | | - wfRunHooks( 'UserGetRights', array( $this, &$this->mRights[$key], $ns ) ); |
| 2260 | + $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() ); |
| 2261 | + wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) ); |
2269 | 2262 | // Force reindexation of rights when a hook has unset one of them |
2270 | | - $this->mRights[$key] = array_values( $this->mRights[$key] ); |
| 2263 | + $this->mRights = array_values( $this->mRights ); |
2271 | 2264 | } |
2272 | | - if ( is_null( $ns ) ) { |
2273 | | - return $this->mRights[$key]; |
2274 | | - } else { |
2275 | | - // Merge non namespace specific rights |
2276 | | - return array_merge( $this->mRights[$key], $this->getRights() ); |
2277 | | - } |
2278 | | - |
| 2265 | + return $this->mRights; |
2279 | 2266 | } |
2280 | 2267 | |
2281 | 2268 | /** |
— | — | @@ -2398,7 +2385,7 @@ |
2399 | 2386 | } |
2400 | 2387 | $this->loadGroups(); |
2401 | 2388 | $this->mGroups[] = $group; |
2402 | | - $this->mRights = null; |
| 2389 | + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) ); |
2403 | 2390 | |
2404 | 2391 | $this->invalidateCache(); |
2405 | 2392 | } |
— | — | @@ -2428,7 +2415,7 @@ |
2429 | 2416 | } |
2430 | 2417 | $this->loadGroups(); |
2431 | 2418 | $this->mGroups = array_diff( $this->mGroups, array( $group ) ); |
2432 | | - $this->mRights = null; |
| 2419 | + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) ); |
2433 | 2420 | |
2434 | 2421 | $this->invalidateCache(); |
2435 | 2422 | } |
— | — | @@ -2485,10 +2472,9 @@ |
2486 | 2473 | /** |
2487 | 2474 | * Internal mechanics of testing a permission |
2488 | 2475 | * @param $action String |
2489 | | - * @param $ns int|null Namespace optional |
2490 | 2476 | * @return bool |
2491 | 2477 | */ |
2492 | | - public function isAllowed( $action = '', $ns = null ) { |
| 2478 | + public function isAllowed( $action = '' ) { |
2493 | 2479 | if ( $action === '' ) { |
2494 | 2480 | return true; // In the spirit of DWIM |
2495 | 2481 | } |
— | — | @@ -2500,7 +2486,7 @@ |
2501 | 2487 | } |
2502 | 2488 | # Use strict parameter to avoid matching numeric 0 accidentally inserted |
2503 | 2489 | # by misconfiguration: 0 == 'foo' |
2504 | | - return in_array( $action, $this->getRights( $ns ), true ); |
| 2490 | + return in_array( $action, $this->getRights(), true ); |
2505 | 2491 | } |
2506 | 2492 | |
2507 | 2493 | /** |
— | — | @@ -3452,53 +3438,30 @@ |
3453 | 3439 | * |
3454 | 3440 | * @return Array of Strings List of permission key names for given groups combined |
3455 | 3441 | */ |
3456 | | - public static function getGroupPermissions( $groups, $ns = null ) { |
| 3442 | + public static function getGroupPermissions( $groups ) { |
3457 | 3443 | global $wgGroupPermissions, $wgRevokePermissions; |
3458 | 3444 | $rights = array(); |
3459 | 3445 | |
3460 | 3446 | // Grant every granted permission first |
3461 | 3447 | foreach( $groups as $group ) { |
3462 | 3448 | if( isset( $wgGroupPermissions[$group] ) ) { |
3463 | | - $rights = array_merge( $rights, self::extractRights( |
3464 | | - $wgGroupPermissions[$group], $ns ) ); |
| 3449 | + $rights = array_merge( $rights, |
| 3450 | + // array_filter removes empty items |
| 3451 | + array_keys( array_filter( $wgGroupPermissions[$group] ) ) ); |
3465 | 3452 | } |
3466 | 3453 | } |
3467 | 3454 | |
3468 | 3455 | // Revoke the revoked permissions |
3469 | 3456 | foreach( $groups as $group ) { |
3470 | 3457 | if( isset( $wgRevokePermissions[$group] ) ) { |
3471 | | - $rights = array_diff( $rights, self::extractRights( |
3472 | | - $wgRevokePermissions[$group], $ns ) ); |
| 3458 | + $rights = array_diff( $rights, |
| 3459 | + array_keys( array_filter( $wgRevokePermissions[$group] ) ) ); |
3473 | 3460 | } |
3474 | 3461 | } |
3475 | 3462 | return array_unique( $rights ); |
3476 | 3463 | } |
3477 | 3464 | |
3478 | 3465 | /** |
3479 | | - * Helper for User::getGroupPermissions |
3480 | | - * @param $list array |
3481 | | - * @param $ns int |
3482 | | - * @return array |
3483 | | - */ |
3484 | | - private static function extractRights( $list, $ns ) { |
3485 | | - $rights = array(); |
3486 | | - foreach( $list as $right => $value ) { |
3487 | | - if ( is_array( $value ) ) { |
3488 | | - # This is a list of namespaces where the permission applies |
3489 | | - if ( !is_null( $ns ) && !empty( $value[$ns] ) ) { |
3490 | | - $rights[] = $right; |
3491 | | - } |
3492 | | - } else { |
3493 | | - # This is a boolean indicating that the permission applies |
3494 | | - if ( $value ) { |
3495 | | - $rights[] = $right; |
3496 | | - } |
3497 | | - } |
3498 | | - } |
3499 | | - return $rights; |
3500 | | - } |
3501 | | - |
3502 | | - /** |
3503 | 3466 | * Get all the groups who have a given permission |
3504 | 3467 | * |
3505 | 3468 | * @param $role String Role to check |
— | — | @@ -3507,11 +3470,11 @@ |
3508 | 3471 | * |
3509 | 3472 | * @return Array of Strings List of internal group names with the given permission |
3510 | 3473 | */ |
3511 | | - public static function getGroupsWithPermission( $role, $ns = null ) { |
| 3474 | + public static function getGroupsWithPermission( $role ) { |
3512 | 3475 | global $wgGroupPermissions; |
3513 | 3476 | $allowedGroups = array(); |
3514 | 3477 | foreach ( $wgGroupPermissions as $group => $rights ) { |
3515 | | - if ( in_array( $role, self::getGroupPermissions( array( $group ), $ns ), true ) ) { |
| 3478 | + if ( isset( $rights[$role] ) && $rights[$role] ) { |
3516 | 3479 | $allowedGroups[] = $group; |
3517 | 3480 | } |
3518 | 3481 | } |
Index: branches/REL1_18/phase3/includes/Title.php |
— | — | @@ -1239,33 +1239,34 @@ |
1240 | 1240 | * @return Array list of errors |
1241 | 1241 | */ |
1242 | 1242 | private function checkQuickPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) { |
1243 | | - $ns = $this->getNamespace(); |
1244 | | - |
1245 | 1243 | if ( $action == 'create' ) { |
1246 | | - if ( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk', $ns ) ) || |
1247 | | - ( !$this->isTalkPage() && !$user->isAllowed( 'createpage', $ns ) ) ) { |
| 1244 | + if ( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) || |
| 1245 | + ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) { |
1248 | 1246 | $errors[] = $user->isAnon() ? array( 'nocreatetext' ) : array( 'nocreate-loggedin' ); |
1249 | 1247 | } |
1250 | 1248 | } elseif ( $action == 'move' ) { |
1251 | | - if ( !$user->isAllowed( 'move-rootuserpages', $ns ) |
1252 | | - && $ns == NS_USER && !$this->isSubpage() ) { |
| 1249 | + if ( !$user->isAllowed( 'move-rootuserpages' ) |
| 1250 | + && $this->mNamespace == NS_USER && !$this->isSubpage() ) { |
1253 | 1251 | // Show user page-specific message only if the user can move other pages |
1254 | 1252 | $errors[] = array( 'cant-move-user-page' ); |
1255 | 1253 | } |
1256 | 1254 | |
1257 | 1255 | // Check if user is allowed to move files if it's a file |
1258 | | - if ( $ns == NS_FILE && !$user->isAllowed( 'movefile', $ns ) ) { |
| 1256 | + if ( $this->mNamespace == NS_FILE && !$user->isAllowed( 'movefile' ) ) { |
1259 | 1257 | $errors[] = array( 'movenotallowedfile' ); |
1260 | 1258 | } |
1261 | 1259 | |
1262 | | - if ( !$user->isAllowed( 'move', $ns) ) { |
| 1260 | + if ( !$user->isAllowed( 'move' ) ) { |
1263 | 1261 | // User can't move anything |
1264 | | - |
1265 | | - $userCanMove = in_array( 'move', User::getGroupPermissions( |
1266 | | - array( 'user' ), $ns ), true ); |
1267 | | - $autoconfirmedCanMove = in_array( 'move', User::getGroupPermissions( |
1268 | | - array( 'autoconfirmed' ), $ns ), true ); |
1269 | | - |
| 1262 | + global $wgGroupPermissions; |
| 1263 | + $userCanMove = false; |
| 1264 | + if ( isset( $wgGroupPermissions['user']['move'] ) ) { |
| 1265 | + $userCanMove = $wgGroupPermissions['user']['move']; |
| 1266 | + } |
| 1267 | + $autoconfirmedCanMove = false; |
| 1268 | + if ( isset( $wgGroupPermissions['autoconfirmed']['move'] ) ) { |
| 1269 | + $autoconfirmedCanMove = $wgGroupPermissions['autoconfirmed']['move']; |
| 1270 | + } |
1270 | 1271 | if ( $user->isAnon() && ( $userCanMove || $autoconfirmedCanMove ) ) { |
1271 | 1272 | // custom message if logged-in users without any special rights can move |
1272 | 1273 | $errors[] = array( 'movenologintext' ); |
— | — | @@ -1274,20 +1275,20 @@ |
1275 | 1276 | } |
1276 | 1277 | } |
1277 | 1278 | } elseif ( $action == 'move-target' ) { |
1278 | | - if ( !$user->isAllowed( 'move', $ns ) ) { |
| 1279 | + if ( !$user->isAllowed( 'move' ) ) { |
1279 | 1280 | // User can't move anything |
1280 | 1281 | $errors[] = array( 'movenotallowed' ); |
1281 | | - } elseif ( !$user->isAllowed( 'move-rootuserpages', $ns ) |
1282 | | - && $ns == NS_USER && !$this->isSubpage() ) { |
| 1282 | + } elseif ( !$user->isAllowed( 'move-rootuserpages' ) |
| 1283 | + && $this->mNamespace == NS_USER && !$this->isSubpage() ) { |
1283 | 1284 | // Show user page-specific message only if the user can move other pages |
1284 | 1285 | $errors[] = array( 'cant-move-to-user-page' ); |
1285 | 1286 | } |
1286 | | - } elseif ( !$user->isAllowed( $action, $ns ) ) { |
| 1287 | + } elseif ( !$user->isAllowed( $action ) ) { |
1287 | 1288 | // We avoid expensive display logic for quickUserCan's and such |
1288 | 1289 | $groups = false; |
1289 | 1290 | if ( !$short ) { |
1290 | 1291 | $groups = array_map( array( 'User', 'makeGroupLinkWiki' ), |
1291 | | - User::getGroupsWithPermission( $action, $ns ) ); |
| 1292 | + User::getGroupsWithPermission( $action ) ); |
1292 | 1293 | } |
1293 | 1294 | |
1294 | 1295 | if ( $groups ) { |
— | — | @@ -1439,9 +1440,9 @@ |
1440 | 1441 | if ( $right == 'sysop' ) { |
1441 | 1442 | $right = 'protect'; |
1442 | 1443 | } |
1443 | | - if ( $right != '' && !$user->isAllowed( $right, $this->mNamespace ) ) { |
| 1444 | + if ( $right != '' && !$user->isAllowed( $right ) ) { |
1444 | 1445 | // Users with 'editprotected' permission can edit protected pages |
1445 | | - if ( $action == 'edit' && $user->isAllowed( 'editprotected', $this->mNamespace ) ) { |
| 1446 | + if ( $action == 'edit' && $user->isAllowed( 'editprotected' ) ) { |
1446 | 1447 | // Users with 'editprotected' permission cannot edit protected pages |
1447 | 1448 | // with cascading option turned on. |
1448 | 1449 | if ( $this->mCascadeRestriction ) { |
— | — | @@ -1482,7 +1483,7 @@ |
1483 | 1484 | if ( isset( $restrictions[$action] ) ) { |
1484 | 1485 | foreach ( $restrictions[$action] as $right ) { |
1485 | 1486 | $right = ( $right == 'sysop' ) ? 'protect' : $right; |
1486 | | - if ( $right != '' && !$user->isAllowed( $right, $this->mNamespace ) ) { |
| 1487 | + if ( $right != '' && !$user->isAllowed( $right ) ) { |
1487 | 1488 | $pages = ''; |
1488 | 1489 | foreach ( $cascadingSources as $page ) |
1489 | 1490 | $pages .= '* [[:' . $page->getPrefixedText() . "]]\n"; |
— | — | @@ -1518,9 +1519,7 @@ |
1519 | 1520 | if( $title_protection['pt_create_perm'] == 'sysop' ) { |
1520 | 1521 | $title_protection['pt_create_perm'] = 'protect'; // B/C |
1521 | 1522 | } |
1522 | | - if( $title_protection['pt_create_perm'] == '' || |
1523 | | - !$user->isAllowed( $title_protection['pt_create_perm'], |
1524 | | - $this->mNamespace ) ) { |
| 1523 | + if( $title_protection['pt_create_perm'] == '' || !$user->isAllowed( $title_protection['pt_create_perm'] ) ) { |
1525 | 1524 | $errors[] = array( 'titleprotected', User::whoIs( $title_protection['pt_user'] ), $title_protection['pt_reason'] ); |
1526 | 1525 | } |
1527 | 1526 | } |
Index: branches/REL1_18/phase3/includes/DefaultSettings.php |
— | — | @@ -3304,10 +3304,6 @@ |
3305 | 3305 | * unable to perform certain essential tasks or access new functionality |
3306 | 3306 | * when new permissions are introduced and default grants established. |
3307 | 3307 | * |
3308 | | - * If set to an array instead of a boolean, it is assumed that the array is in |
3309 | | - * NS => bool form in order to support per-namespace permissions. Note that |
3310 | | - * this feature does not fully work for all permission types. |
3311 | | - * |
3312 | 3308 | * Functionality to make pages inaccessible has not been extensively tested |
3313 | 3309 | * for security. Use at your own risk! |
3314 | 3310 | * |