Index: trunk/extensions/CentralAuth/centralauth.js |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +cursor = { x : 0, y : 0 }; |
| 3 | +function updateCursorPosition(e) { |
| 4 | + e = e || window.event; |
| 5 | + cursor.x = e.clientX + ( document.documentElement.scrollLeft || document.body.scrollLeft ) - document.documentElement.clientLeft; |
| 6 | + cursor.y = e.clientY + ( document.documentElement.scrollTop || document.body.scrollTop ) - document.documentElement.clientTop; |
| 7 | +} |
| 8 | +document.onmousemove = updateCursorPosition; |
| 9 | + |
| 10 | +methodHint = null; |
| 11 | +function showMethodHint( methodName ) { |
| 12 | + hideMethodHint(); |
| 13 | + |
| 14 | + method = wgMergeMethodDescriptions[methodName]; |
| 15 | + helpHtml = "<p class='merge-method-help-name'>" + method.short + "</p>" + method.desc; |
| 16 | + |
| 17 | + methodHint = document.createElement( 'div' ); |
| 18 | + methodHint.innerHTML = helpHtml; |
| 19 | + methodHint.setAttribute( 'class', 'merge-method-help-div' ); |
| 20 | + methodHint.style.left = cursor.x + 'px'; |
| 21 | + methodHint.style.top = cursor.y + 'px'; |
| 22 | + methodHint.setAttribute( 'onclick', 'hideMethodHint()' ); |
| 23 | + document.getElementById( 'globalWrapper' ).appendChild( methodHint ); |
| 24 | +} |
| 25 | +function hideMethodHint() { |
| 26 | + if( methodHint ) { |
| 27 | + methodHint.parentNode.removeChild( methodHint ); |
| 28 | + methodHint = null; |
| 29 | + } |
| 30 | +} |
Property changes on: trunk/extensions/CentralAuth/centralauth.js |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 31 | + native |
Index: trunk/extensions/CentralAuth/db_patches/patch-gu_hidden.sql |
— | — | @@ -0,0 +1,17 @@ |
| 2 | +-- This patch switches gu_hidden from boolean to string (so multiple hiding |
| 3 | +-- levels may be applied). It also creates indexes on those columns so we can easily |
| 4 | +-- get a list of hidden or locked users. |
| 5 | +-- Victor Vasiliev, January 2010. |
| 6 | + |
| 7 | +ALTER TABLE globaluser |
| 8 | + MODIFY COLUMN gu_hidden VARBINARY(255) NOT NULL DEFAULT ''; |
| 9 | + |
| 10 | +-- Not hidden (was 0) |
| 11 | +UPDATE globaluser SET gu_hidden = '' WHERE gu_hidden = '0'; |
| 12 | +-- Hidden from public lists, but remains visible in Special:CentralSuth log |
| 13 | +UPDATE globaluser SET gu_hidden = 'lists' WHERE gu_hidden = '1'; |
| 14 | +-- There's also "suppressed" level, which wasn't used before this schema change |
| 15 | + |
| 16 | +ALTER TABLE globaluser |
| 17 | + ADD INDEX gu_locked( gu_locked ), |
| 18 | + ADD INDEX gu_hidden( gu_hidden(255) ); |
Property changes on: trunk/extensions/CentralAuth/db_patches/patch-gu_hidden.sql |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 19 | + native |
Index: trunk/extensions/CentralAuth/CentralAuthUser.php |
— | — | @@ -18,7 +18,7 @@ |
19 | 19 | */ |
20 | 20 | /*private*/ var $mName; |
21 | 21 | /*private*/ var $mStateDirty = false; |
22 | | - /*private*/ var $mVersion = 3; |
| 22 | + /*private*/ var $mVersion = 4; |
23 | 23 | /*private*/ var $mDelayInvalidation = 0; |
24 | 24 | |
25 | 25 | static $mCacheVars = array( |
— | — | @@ -42,6 +42,10 @@ |
43 | 43 | 'mVersion', |
44 | 44 | ); |
45 | 45 | |
| 46 | + const HIDDEN_NONE = ''; |
| 47 | + const HIDDEN_LISTS = 'lists'; |
| 48 | + const HIDDEN_OVERSIGHT = 'suppressed'; |
| 49 | + |
46 | 50 | function __construct( $username ) { |
47 | 51 | $this->mName = $username; |
48 | 52 | $this->resetState(); |
— | — | @@ -216,7 +220,7 @@ |
217 | 221 | $this->mIsAttached = false; |
218 | 222 | $this->mFromMaster = $fromMaster; |
219 | 223 | $this->mLocked = false; |
220 | | - $this->mHidden = false; |
| 224 | + $this->mHidden = ''; |
221 | 225 | } |
222 | 226 | } |
223 | 227 | |
— | — | @@ -362,6 +366,8 @@ |
363 | 367 | } |
364 | 368 | |
365 | 369 | /** |
| 370 | + * Returns whether the account is |
| 371 | + * locked. |
366 | 372 | * @return bool |
367 | 373 | */ |
368 | 374 | public function isLocked() { |
— | — | @@ -370,6 +376,8 @@ |
371 | 377 | } |
372 | 378 | |
373 | 379 | /** |
| 380 | + * Returns whether user name should not |
| 381 | + * be shown in public lists. |
374 | 382 | * @return bool |
375 | 383 | */ |
376 | 384 | public function isHidden() { |
— | — | @@ -378,6 +386,31 @@ |
379 | 387 | } |
380 | 388 | |
381 | 389 | /** |
| 390 | + * Returns whether user's name should |
| 391 | + * be hidden from all public views because |
| 392 | + * of privacy issues. |
| 393 | + * @return bool |
| 394 | + */ |
| 395 | + public function isOversighted() { |
| 396 | + $this->loadState(); |
| 397 | + return $this->mHidden == self::HIDDEN_OVERSIGHT; |
| 398 | + } |
| 399 | + |
| 400 | + /** |
| 401 | + * Returns the hidden level of |
| 402 | + * the account. |
| 403 | + */ |
| 404 | + public function getHiddenLevel() { |
| 405 | + $this->loadState(); |
| 406 | + |
| 407 | + // b/c-failsafe. Should never happen |
| 408 | + if( $this->mHidden === '0' ) |
| 409 | + $this->mHidden = ''; |
| 410 | + |
| 411 | + return $this->mHidden; |
| 412 | + } |
| 413 | + |
| 414 | + /** |
382 | 415 | * @return string timestamp |
383 | 416 | */ |
384 | 417 | public function getRegistration() { |
— | — | @@ -413,7 +446,7 @@ |
414 | 447 | 'gu_password' => $hash, |
415 | 448 | |
416 | 449 | 'gu_locked' => 0, |
417 | | - 'gu_hidden' => 0, |
| 450 | + 'gu_hidden' => '', |
418 | 451 | |
419 | 452 | 'gu_registration' => $dbw->timestamp(), |
420 | 453 | ), |
— | — | @@ -477,6 +510,8 @@ |
478 | 511 | 'gu_email' => $email, |
479 | 512 | 'gu_email_authenticated' => $dbw->timestampOrNull( $emailAuth ), |
480 | 513 | 'gu_registration' => $dbw->timestamp(), // hmmmm |
| 514 | + 'gu_locked' => 0, |
| 515 | + 'gu_hidden' => '', |
481 | 516 | ), |
482 | 517 | __METHOD__, |
483 | 518 | array( 'IGNORE' ) ); |
— | — | @@ -958,43 +993,143 @@ |
959 | 994 | |
960 | 995 | /** |
961 | 996 | * Hide a global account |
| 997 | + * @deprecated Use adminSetHidden |
962 | 998 | */ |
963 | 999 | function adminHide() { |
964 | | - $dbw = self::getCentralDB(); |
965 | | - $dbw->begin(); |
966 | | - $dbw->update( 'globaluser', array( 'gu_hidden' => 1 ), |
967 | | - array( 'gu_name' => $this->mName ), __METHOD__ ); |
968 | | - if ( !$dbw->affectedRows() ) { |
969 | | - $dbw->commit(); |
970 | | - return Status::newFatal( 'centralauth-admin-hide-nonexistent', $this->mName ); |
971 | | - } |
972 | | - $dbw->commit(); |
973 | | - |
974 | | - $this->invalidateCache(); |
975 | | - |
976 | | - return Status::newGood(); |
| 1000 | + $this->adminSetHidden( self::HIDDEN_LISTS ); |
977 | 1001 | } |
978 | 1002 | |
979 | 1003 | /** |
980 | 1004 | * Unhide a global account |
| 1005 | + * @deprecated Use adminSetHidden |
981 | 1006 | */ |
982 | 1007 | function adminUnhide() { |
| 1008 | + $this->adminSetHidden( self::HIDDEN_NONE ); |
| 1009 | + } |
| 1010 | + |
| 1011 | + /** |
| 1012 | + * Change account hiding level. |
| 1013 | + */ |
| 1014 | + function adminSetHidden( $level ) { |
983 | 1015 | $dbw = self::getCentralDB(); |
984 | 1016 | $dbw->begin(); |
985 | | - $dbw->update( 'globaluser', array( 'gu_hidden' => 0 ), |
| 1017 | + $dbw->update( 'globaluser', array( 'gu_hidden' => $level ), |
986 | 1018 | array( 'gu_name' => $this->mName ), __METHOD__ ); |
987 | 1019 | if ( !$dbw->affectedRows() ) { |
988 | 1020 | $dbw->commit(); |
989 | 1021 | return Status::newFatal( 'centralauth-admin-unhide-nonexistent', $this->mName ); |
990 | 1022 | } |
991 | 1023 | $dbw->commit(); |
992 | | - |
| 1024 | + |
993 | 1025 | $this->invalidateCache(); |
994 | | - |
| 1026 | + |
995 | 1027 | return Status::newGood(); |
996 | 1028 | } |
997 | 1029 | |
998 | 1030 | /** |
| 1031 | + * Suppresses all user accounts in all wikis. |
| 1032 | + */ |
| 1033 | + function suppress( $reason ) { |
| 1034 | + global $wgUser; |
| 1035 | + $this->doCrosswikiSuppression( true, $wgUser->getName(), $reason ); |
| 1036 | + } |
| 1037 | + |
| 1038 | + /** |
| 1039 | + * Unsuppresses all user accounts in all wikis. |
| 1040 | + */ |
| 1041 | + function unsuppress( $reason ) { |
| 1042 | + global $wgUser; |
| 1043 | + $this->doCrosswikiSuppression( false, $wgUser->getName(), $reason ); |
| 1044 | + } |
| 1045 | + |
| 1046 | + protected function doCrosswikiSuppression( $suppress, $by, $reason ) { |
| 1047 | + global $wgCentralAuthWikisPerSuppressJob; |
| 1048 | + $this->loadAttached(); |
| 1049 | + if( count( $this->mAttachedArray ) <= $wgCentralAuthWikisPerSuppressJob ) { |
| 1050 | + foreach( $this->mAttachedArray as $wiki ) { |
| 1051 | + $this->doLocalSuppression( $suppress, $wiki, $by, $reason ); |
| 1052 | + } |
| 1053 | + } else { |
| 1054 | + $jobParams = array( |
| 1055 | + 'username' => $this->getName(), |
| 1056 | + 'suppress' => $suppress, |
| 1057 | + 'by' => $by, |
| 1058 | + 'reason' => $reason, |
| 1059 | + ); |
| 1060 | + $jobs = array(); |
| 1061 | + $step = $wgCentralAuthWikisPerSuppressJob; |
| 1062 | + for( $jobCount = 0; $jobCount < count( $this->mAttachedArray ); $jobCount += $step ) { |
| 1063 | + $length = $jobCount + $step > count( $this->mAttachedArray ) ? |
| 1064 | + $jobCount - $step : $step; |
| 1065 | + $jobParams['wikis'] = array_slice( $this->mAttachedArray, $jobCount, $length ); |
| 1066 | + $jobs[] = Job::factory( |
| 1067 | + 'crosswikiSuppressUser', |
| 1068 | + Title::makeTitleSafe( NS_USER, $this->getName() ), |
| 1069 | + $jobParams ); |
| 1070 | + } |
| 1071 | + Job::batchInsert( $jobs ); |
| 1072 | + } |
| 1073 | + } |
| 1074 | + |
| 1075 | + /** |
| 1076 | + * Suppresses a local account of a user. |
| 1077 | + */ |
| 1078 | + public function doLocalSuppression( $suppress, $wiki, $by, $reason ) { |
| 1079 | + global $wgConf, $wgLanguageNames; |
| 1080 | + |
| 1081 | + $lb = wfGetLB( $wiki ); |
| 1082 | + $dbw = $lb->getConnection( DB_MASTER, array(), $wiki ); |
| 1083 | + $data = $this->localUserData( $wiki ); |
| 1084 | + |
| 1085 | + if( $suppress ) { |
| 1086 | + list( $site, $lang ) = $wgConf->siteFromDB( $wiki ); |
| 1087 | + $lang = isset( $wgLanguageNames[$lang] ) ? $lang : 'en'; |
| 1088 | + $blockReason = wfMsgReal( 'centralauth-admin-suppressreason', |
| 1089 | + array( $by, $reason ), true, $lang ); |
| 1090 | + |
| 1091 | + $ipbID = $dbw->nextSequenceValue( 'ipblocks_ipb_id_seq' ); |
| 1092 | + $dbw->insert( 'ipblocks', |
| 1093 | + array( |
| 1094 | + 'ipb_id' => $ipbID, |
| 1095 | + 'ipb_address' => $this->mName, |
| 1096 | + 'ipb_user' => $data['id'], |
| 1097 | + 'ipb_by' => 0, |
| 1098 | + 'ipb_by_text' => $by, |
| 1099 | + 'ipb_reason' => $blockReason, |
| 1100 | + 'ipb_timestamp' => $dbw->timestamp( wfTimestampNow() ), |
| 1101 | + 'ipb_auto' => false, |
| 1102 | + 'ipb_anon_only' => false, |
| 1103 | + 'ipb_create_account' => true, |
| 1104 | + 'ipb_enable_autoblock' => false, |
| 1105 | + 'ipb_expiry' => Block::infinity(), |
| 1106 | + 'ipb_range_start' => '', |
| 1107 | + 'ipb_range_end' => '', |
| 1108 | + 'ipb_deleted' => true, |
| 1109 | + 'ipb_block_email' => true, |
| 1110 | + 'ipb_allow_usertalk' => false |
| 1111 | + ), __METHOD__, array( 'IGNORE' ) |
| 1112 | + ); |
| 1113 | + |
| 1114 | + IPBlockForm::suppressUserName( $this->mName, $data['id'], $dbw ); |
| 1115 | + } else { |
| 1116 | + $dbw->delete( |
| 1117 | + 'ipblocks', |
| 1118 | + array( |
| 1119 | + 'ipb_user' => $data['id'], |
| 1120 | + 'ipb_by' => 0, // Check whether this block was imposed globally |
| 1121 | + 'ipb_deleted' => true, |
| 1122 | + ), |
| 1123 | + __METHOD__ |
| 1124 | + ); |
| 1125 | + |
| 1126 | + // Unsuppress only if unblocked |
| 1127 | + if( $dbw->affectedRows() ) { |
| 1128 | + IPBlockForm::unsuppressUserName( $this->mName, $data['id'], $dbw ); |
| 1129 | + } |
| 1130 | + } |
| 1131 | + } |
| 1132 | + |
| 1133 | + /** |
999 | 1134 | * Add a local account record for the given wiki to the central database. |
1000 | 1135 | * @param string $wikiID |
1001 | 1136 | * @param int $localid |
— | — | @@ -1033,7 +1168,7 @@ |
1034 | 1169 | $wgCentralAuthUDPAddress, $wgCentralAuthNew2UDPPrefix ); |
1035 | 1170 | } |
1036 | 1171 | } |
1037 | | - |
| 1172 | + |
1038 | 1173 | /** |
1039 | 1174 | * Generate an IRC line corresponding to user unification/creation |
1040 | 1175 | * @param Title $userpage |
— | — | @@ -1065,15 +1200,15 @@ |
1066 | 1201 | return "no user"; |
1067 | 1202 | } |
1068 | 1203 | |
1069 | | - list($salt,$crypt) = $this->getPasswordHash(); |
1070 | | - $locked = $this->isLocked(); |
| 1204 | + // Don't allow users to autocreate if they are oversighted. |
| 1205 | + // If they do, their name will appear on local user list |
| 1206 | + // (and since it contains private info, its inacceptable). |
| 1207 | + // FIXME: this will give users "password incorrect" error. |
| 1208 | + // Giving correct message requires AuthPlugin and SpecialUserlogin |
| 1209 | + // rewriting. |
| 1210 | + if( !User::idFromName( $this->getName() ) && $this->isOversighted() ) |
| 1211 | + return "locked"; |
1071 | 1212 | |
1072 | | - if( $locked ) { |
1073 | | - wfDebugLog( 'CentralAuth', |
1074 | | - "authentication for '$this->mName' failed due to lock" ); |
1075 | | - return "locked"; |
1076 | | - } |
1077 | | - |
1078 | 1213 | return true; |
1079 | 1214 | } |
1080 | 1215 | |
Index: trunk/extensions/CentralAuth/CentralAuth.php |
— | — | @@ -122,11 +122,29 @@ |
123 | 123 | */ |
124 | 124 | $wgCentralAuthCreateOnView = false; |
125 | 125 | |
126 | | -// UDP logging stuff |
| 126 | +/** |
| 127 | + * UPD-transmissed RC settings |
| 128 | + */ |
127 | 129 | $wgCentralAuthUDPAddress = false; |
128 | 130 | $wgCentralAuthNew2UDPPrefix = ''; |
129 | 131 | |
130 | 132 | /** |
| 133 | + * A CSS file version. Change each time centralauth.css is changed. |
| 134 | + */ |
| 135 | +$wgCentralAuthStyleVersion = 1; |
| 136 | + |
| 137 | +/** |
| 138 | + * List of local pages global users may edit while being globally locked. |
| 139 | + */ |
| 140 | +$wgCentralAuthLockedCanEdit = array(); |
| 141 | + |
| 142 | +/** |
| 143 | + * Size of wikis handled in one suppress user job. |
| 144 | + * Keep in mind that one wiki requires ~10 queries. |
| 145 | + */ |
| 146 | +$wgCentralAuthWikisPerSuppressJob = 10; |
| 147 | + |
| 148 | +/** |
131 | 149 | * Initialization of the autoloaders, and special extension pages. |
132 | 150 | */ |
133 | 151 | $caBase = dirname( __FILE__ ); |
— | — | @@ -136,6 +154,7 @@ |
137 | 155 | $wgAutoloadClasses['CentralAuthUser'] = "$caBase/CentralAuthUser.php"; |
138 | 156 | $wgAutoloadClasses['CentralAuthPlugin'] = "$caBase/CentralAuthPlugin.php"; |
139 | 157 | $wgAutoloadClasses['CentralAuthHooks'] = "$caBase/CentralAuthHooks.php"; |
| 158 | +$wgAutoloadClasses['CentralAuthSuppressUserJob'] = "$caBase/SuppressUserJob.php"; |
140 | 159 | $wgAutoloadClasses['WikiSet'] = "$caBase/WikiSet.php"; |
141 | 160 | $wgAutoloadClasses['SpecialAutoLogin'] = "$caBase/SpecialAutoLogin.php"; |
142 | 161 | $wgAutoloadClasses['CentralAuthUserArray'] = "$caBase/CentralAuthUserArray.php"; |
— | — | @@ -149,6 +168,8 @@ |
150 | 169 | $wgExtensionMessagesFiles['SpecialCentralAuth'] = "$caBase/CentralAuth.i18n.php"; |
151 | 170 | $wgExtensionAliasesFiles['SpecialCentralAuth'] = "$caBase/CentralAuth.alias.php"; |
152 | 171 | |
| 172 | +$wgJobClasses['crosswikiSuppressUser'] = 'CentralAuthSuppressUserJob'; |
| 173 | + |
153 | 174 | $wgHooks['AuthPluginSetup'][] = 'CentralAuthHooks::onAuthPluginSetup'; |
154 | 175 | $wgHooks['AddNewAccount'][] = 'CentralAuthHooks::onAddNewAccount'; |
155 | 176 | $wgHooks['GetPreferences'][] = 'CentralAuthHooks::onGetPreferences'; |
— | — | @@ -178,11 +199,15 @@ |
179 | 200 | // For SecurePoll |
180 | 201 | $wgHooks['SecurePoll_GetUserParams'][] = 'CentralAuthHooks::onSecurePoll_GetUserParams'; |
181 | 202 | |
182 | | -$wgAvailableRights[] = 'centralauth-admin'; |
183 | 203 | $wgAvailableRights[] = 'centralauth-merge'; |
| 204 | +$wgAvailableRights[] = 'centralauth-unmerge'; |
| 205 | +$wgAvailableRights[] = 'centralauth-lock'; |
| 206 | +$wgAvailableRights[] = 'centralauth-oversight'; |
184 | 207 | $wgAvailableRights[] = 'globalgrouppermissions'; |
185 | 208 | $wgAvailableRights[] = 'globalgroupmembership'; |
186 | | -$wgGroupPermissions['steward']['centralauth-admin'] = true; |
| 209 | +$wgGroupPermissions['steward']['centralauth-unmerge'] = true; |
| 210 | +$wgGroupPermissions['steward']['centralauth-lock'] = true; |
| 211 | +$wgGroupPermissions['steward']['centralauth-oversight'] = true; |
187 | 212 | $wgGroupPermissions['*']['centralauth-merge'] = true; |
188 | 213 | |
189 | 214 | $wgSpecialPages['CentralAuth'] = 'SpecialCentralAuth'; |
— | — | @@ -211,6 +236,7 @@ |
212 | 237 | $wgLogActions['globalauth/unhide'] = 'centralauth-log-entry-unhide'; |
213 | 238 | $wgLogActions['globalauth/lockandhid'] = 'centralauth-log-entry-lockandhide'; |
214 | 239 | $wgLogActions['globalauth/setstatus'] = 'centralauth-log-entry-chgstatus'; |
| 240 | +$wgLogActions['suppress/setstatus'] = 'centralauth-log-entry-chgstatus'; |
215 | 241 | |
216 | 242 | $wgLogTypes[] = 'gblrights'; |
217 | 243 | $wgLogNames['gblrights'] = 'centralauth-rightslog-name'; |
Index: trunk/extensions/CentralAuth/SpecialCentralAuth.php |
— | — | @@ -1,36 +1,31 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | class SpecialCentralAuth extends SpecialPage { |
| 5 | + var $mUserName, $mCanUnmerge, $mCanLock, $mCanOversight, $mCanEdit; |
| 6 | + var $mGlobalUser, $mAttachedLocalAccounts, $mUnattachedLocalAccounts; |
5 | 7 | |
6 | 8 | function __construct() { |
7 | 9 | wfLoadExtensionMessages('SpecialCentralAuth'); |
8 | | - parent::__construct( 'CentralAuth', 'centralauth-admin' ); |
| 10 | + parent::__construct( 'CentralAuth' ); |
9 | 11 | } |
10 | 12 | |
11 | 13 | function execute( $subpage ) { |
12 | 14 | global $wgOut, $wgRequest, $wgUser; |
| 15 | + global $wgExtensionAssetsPath, $wgCentralAuthStyleVersion; |
| 16 | + global $wgUser, $wgRequest; |
13 | 17 | $this->setHeaders(); |
14 | 18 | |
15 | | - if( !$wgUser->isLoggedIn() ) { |
16 | | - $wgOut->addWikiText( |
17 | | - wfMsg( 'centralauth-merge-notlogged' ) . |
18 | | - "\n\n" . |
19 | | - wfMsg( 'centralauth-readmore-text' ) ); |
| 19 | + $this->mCanUnmerge = $wgUser->isAllowed( 'centralauth-unmerge' ); |
| 20 | + $this->mCanLock = $wgUser->isAllowed( 'centralauth-lock' ); |
| 21 | + $this->mCanOversight = $wgUser->isAllowed( 'centralauth-oversight' ); |
| 22 | + $this->mCanEdit = $this->mCanUnmerge || $this->mCanLock || $this->mCanOversight; |
20 | 23 | |
21 | | - return; |
22 | | - } |
| 24 | + $wgOut->addExtensionStyle( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.css?" . |
| 25 | + $wgCentralAuthStyleVersion ); |
| 26 | + $wgOut->addScriptFile( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.js?" . |
| 27 | + $wgCentralAuthStyleVersion ); |
| 28 | + $this->addMergeMethodDescriptions(); |
23 | 29 | |
24 | | - global $wgUser, $wgRequest; |
25 | | - $this->mUserName = $wgUser->getName(); |
26 | | - |
27 | | - if( !$wgUser->isAllowed( 'centralauth-admin' ) ) { |
28 | | - $wgOut->addWikiText( |
29 | | - wfMsg( 'centralauth-admin-permission' ) . |
30 | | - "\n\n" . |
31 | | - wfMsg( 'centralauth-readmore-text' ) ); |
32 | | - return; |
33 | | - } |
34 | | - |
35 | 30 | $this->mUserName = |
36 | 31 | trim( |
37 | 32 | str_replace( '_', ' ', |
— | — | @@ -38,7 +33,6 @@ |
39 | 34 | |
40 | 35 | $this->mPosted = $wgRequest->wasPosted(); |
41 | 36 | $this->mMethod = $wgRequest->getVal( 'wpMethod' ); |
42 | | - $this->mPassword = $wgRequest->getVal( 'wpPassword' ); |
43 | 37 | $this->mWikis = (array)$wgRequest->getArray( 'wpWikis' ); |
44 | 38 | |
45 | 39 | // Possible demo states |
— | — | @@ -61,22 +55,30 @@ |
62 | 56 | |
63 | 57 | $this->mGlobalUser = $globalUser = new CentralAuthUser( $this->mUserName ); |
64 | 58 | |
65 | | - if ( !$globalUser->exists() ) { |
| 59 | + if ( !$globalUser->exists() || |
| 60 | + ( $globalUser->isOversighted() && !$this->mCanOversight ) ) { |
66 | 61 | $this->showError( 'centralauth-admin-nonexistent', $this->mUserName ); |
67 | 62 | $this->showUsernameForm(); |
68 | 63 | return; |
69 | 64 | } |
70 | 65 | |
71 | 66 | $continue = true; |
72 | | - if( $this->mPosted ) { |
| 67 | + if( $this->mCanEdit && $this->mPosted ) { |
73 | 68 | $continue = $this->doSubmit(); |
74 | 69 | } |
75 | 70 | |
| 71 | + $this->mAttachedLocalAccounts = $this->mGlobalUser->queryAttached(); |
| 72 | + $this->mUnattachedLocalAccounts = $this->mGlobalUser->queryUnattached(); |
| 73 | + |
76 | 74 | $this->showUsernameForm(); |
77 | 75 | if ( $continue ) { |
78 | 76 | $this->showInfo(); |
79 | | - $this->showStatusForm(); |
80 | | - $this->showActionForm( 'delete' ); |
| 77 | + if( $this->mCanLock ) |
| 78 | + $this->showStatusForm(); |
| 79 | + if( $this->mCanUnmerge ) |
| 80 | + $this->showActionForm( 'delete' ); |
| 81 | + if( $this->mCanEdit ) |
| 82 | + $this->showLogExtract(); |
81 | 83 | $this->showWikiLists(); |
82 | 84 | } |
83 | 85 | } |
— | — | @@ -88,7 +90,7 @@ |
89 | 91 | global $wgUser, $wgOut, $wgRequest; |
90 | 92 | if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) { |
91 | 93 | $this->showError( 'centralauth-token-mismatch' ); |
92 | | - } elseif( $this->mMethod == 'unmerge' ) { |
| 94 | + } elseif( $this->mMethod == 'unmerge' && $this->mCanUnmerge ) { |
93 | 95 | $status = $globalUser->adminUnattach( $this->mWikis ); |
94 | 96 | if ( !$status->isGood() ) { |
95 | 97 | $this->showStatusError( $status->getWikiText() ); |
— | — | @@ -98,7 +100,7 @@ |
99 | 101 | $wgLang->formatNum( $status->successCount ), |
100 | 102 | /* deprecated */ $status->successCount ); |
101 | 103 | } |
102 | | - } elseif ( $this->mMethod == 'delete' ) { |
| 104 | + } elseif ( $this->mMethod == 'delete' && $this->mCanUnmerge ) { |
103 | 105 | $status = $globalUser->adminDelete(); |
104 | 106 | if ( !$status->isGood() ) { |
105 | 107 | $this->showStatusError( $status->getWikiText() ); |
— | — | @@ -108,15 +110,23 @@ |
109 | 111 | $deleted = true; |
110 | 112 | $this->logAction( 'delete', $this->mUserName, $wgRequest->getVal( 'reason' ) ); |
111 | 113 | } |
112 | | - } elseif ( $this->mMethod == 'set-status' ) { |
| 114 | + } elseif ( $this->mMethod == 'set-status' && $this->mCanLock ) { |
113 | 115 | $setLocked = $wgRequest->getBool( 'wpStatusLocked' ); |
114 | | - $setHidden = $wgRequest->getBool( 'wpStatusHidden' ); |
| 116 | + $setHidden = $wgRequest->getVal( 'wpStatusHidden' ); |
115 | 117 | $isLocked = $globalUser->isLocked(); |
116 | | - $isHidden = $globalUser->isHidden(); |
| 118 | + $oldHiddenLevel = $globalUser->getHiddenLevel(); |
117 | 119 | $lockStatus = $hideStatus = null; |
118 | 120 | $added = array(); |
119 | 121 | $removed = array(); |
120 | | - |
| 122 | + |
| 123 | + // Sanitizing input value... |
| 124 | + $hiddenLevels = array( |
| 125 | + CentralAuthUser::HIDDEN_NONE, |
| 126 | + CentralAuthUser::HIDDEN_LISTS, |
| 127 | + CentralAuthUser::HIDDEN_OVERSIGHT ); |
| 128 | + if( !in_array( $setHidden, $hiddenLevels ) ) |
| 129 | + $setHidden = ''; |
| 130 | + |
121 | 131 | if ( !$isLocked && $setLocked ) { |
122 | 132 | $lockStatus = $globalUser->adminLock(); |
123 | 133 | $added[] = wfMsgForContent( 'centralauth-log-status-locked' ); |
— | — | @@ -124,13 +134,39 @@ |
125 | 135 | $lockStatus = $globalUser->adminUnlock(); |
126 | 136 | $removed[] = wfMsgForContent( 'centralauth-log-status-locked' ); |
127 | 137 | } |
| 138 | + |
| 139 | + $reason = $wgRequest->getText( 'wpReasonList' ); |
| 140 | + $reasonDetail = $wgRequest->getText( 'wpReason' ); |
| 141 | + if( $reason == 'other' ) { |
| 142 | + $reason = $reasonDetail; |
| 143 | + } elseif( $reasonDetail ) { |
| 144 | + $reason .= wfMsgForContent( 'colon-separator' ) . $reasonDetail; |
| 145 | + } |
128 | 146 | |
129 | | - if ( !$isHidden && $setHidden ) { |
130 | | - $hideStatus = $globalUser->adminHide(); |
131 | | - $added[] = wfMsgForContent( 'centralauth-log-status-hidden' ); |
132 | | - } elseif( $isHidden && !$setHidden ) { |
133 | | - $hideStatus = $globalUser->adminUnhide(); |
134 | | - $removed[] = wfMsgForContent( 'centralauth-log-status-hidden' ); |
| 147 | + if ( $oldHiddenLevel != $setHidden ) { |
| 148 | + $hideStatus = $globalUser->adminSetHidden( $setHidden ); |
| 149 | + switch( $setHidden ) { |
| 150 | + case CentralAuthUser::HIDDEN_NONE: |
| 151 | + $removed[] = $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT ? |
| 152 | + wfMsgForContent( 'centralauth-log-status-oversighted' ) : |
| 153 | + wfMsgForContent( 'centralauth-log-status-hidden' ); |
| 154 | + break; |
| 155 | + case CentralAuthUser::HIDDEN_LISTS: |
| 156 | + $added[] = wfMsgForContent( 'centralauth-log-status-hidden' ); |
| 157 | + if( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT ) |
| 158 | + $removed[] = wfMsgForContent( 'centralauth-log-status-oversighted' ); |
| 159 | + break; |
| 160 | + case CentralAuthUser::HIDDEN_OVERSIGHT: |
| 161 | + $added[] = wfMsgForContent( 'centralauth-log-status-oversighted' ); |
| 162 | + if( $oldHiddenLevel == CentralAuthUser::HIDDEN_LISTS ) |
| 163 | + $removed[] = wfMsgForContent( 'centralauth-log-status-hidden' ); |
| 164 | + break; |
| 165 | + } |
| 166 | + |
| 167 | + if( $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT ) |
| 168 | + $globalUser->suppress( $reason ); |
| 169 | + elseif( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT ) |
| 170 | + $globalUser->unsuppress( $reason ); |
135 | 171 | } |
136 | 172 | |
137 | 173 | $good = |
— | — | @@ -143,13 +179,13 @@ |
144 | 180 | implode( ', ', $added ) : wfMsgForContent( 'centralauth-log-status-none' ); |
145 | 181 | $removed = count($removed) ? |
146 | 182 | implode( ', ', $removed ) : wfMsgForContent( 'centralauth-log-status-none' ); |
147 | | - |
148 | | - $reason = $wgRequest->getText( 'wpReason' ); |
| 183 | + |
149 | 184 | $this->logAction( |
150 | 185 | 'setstatus', |
151 | 186 | $this->mUserName, |
152 | 187 | $reason, |
153 | | - array( $added, $removed ) |
| 188 | + array( $added, $removed ), |
| 189 | + $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT |
154 | 190 | ); |
155 | 191 | $this->showSuccess( 'centralauth-admin-setstatus-success', $this->mUserName ); |
156 | 192 | } elseif (!$good) { |
— | — | @@ -187,6 +223,9 @@ |
188 | 224 | |
189 | 225 | function showUsernameForm() { |
190 | 226 | global $wgOut, $wgScript; |
| 227 | + $lookup = $this->mCanEdit ? |
| 228 | + wfMsg( 'centralauth-admin-lookup-rw' ) : |
| 229 | + wfMsg( 'centralauth-admin-lookup-ro' ); |
191 | 230 | $wgOut->addHTML( |
192 | 231 | Xml::openElement( 'form', array( |
193 | 232 | 'method' => 'get', |
— | — | @@ -199,7 +238,7 @@ |
200 | 239 | 'target', 'target', 25, $this->mUserName ) . |
201 | 240 | '</p>' . |
202 | 241 | '<p>' . |
203 | | - Xml::submitButton( wfMsg( 'centralauth-admin-lookup' ) ) . |
| 242 | + Xml::submitButton( $lookup ) . |
204 | 243 | '</p>' . |
205 | 244 | '</fieldset>' . |
206 | 245 | '</form>' |
— | — | @@ -222,71 +261,48 @@ |
223 | 262 | } |
224 | 263 | return wfMsgExt( "centralauth-$unit-ago", 'parsemag', $span ); |
225 | 264 | } |
226 | | - |
227 | | - function showWikiLists() { |
228 | | - global $wgOut; |
229 | | - $merged = $this->mGlobalUser->queryAttached(); |
230 | | - $remainder = $this->mGlobalUser->queryUnattached(); |
231 | | - |
232 | | - $wgOut->addHTML( |
233 | | - Xml::tags( 'h2', null, wfMsgExt( 'centralauth-admin-attached', 'parseinline' ) ) |
234 | | - ); |
235 | | - $wgOut->addHTML( $this->listMerged( $merged ) ); |
236 | 265 | |
237 | | - $wgOut->addHTML( |
238 | | - Xml::tags( 'h2', null, wfMsgExt( 'centralauth-admin-unattached', 'parseinline' ) ) |
239 | | - ); |
240 | | - |
241 | | - if( $remainder ) { |
242 | | - $wgOut->addHTML( $this->listRemainder( $remainder ) ); |
243 | | - } else { |
244 | | - $wgOut->addWikiMsg( 'centralauth-admin-no-unattached' ); |
245 | | - } |
246 | | - } |
247 | | - |
248 | 266 | function showInfo() { |
249 | 267 | $globalUser = $this->mGlobalUser; |
250 | 268 | |
251 | | - $id = $globalUser->exists() ? $globalUser->getId() : "unified account not registered"; |
252 | | - |
253 | 269 | global $wgOut, $wgLang; |
254 | | - if( $globalUser->exists() ) { |
255 | | - $reg = $globalUser->getRegistration(); |
256 | | - $age = $this->prettyTimespan( wfTimestamp( TS_UNIX ) - wfTimestamp( TS_UNIX, $reg ) ); |
257 | | - $attribs = array( |
258 | | - 'id' => $globalUser->getId(), |
259 | | - 'registered' => $wgLang->timeanddate( $reg ) . " ($age)", |
260 | | - 'locked' => $globalUser->isLocked() ? wfMsg( 'centralauth-admin-yes' ) : wfMsg( 'centralauth-admin-no' ), |
261 | | - 'hidden' => $globalUser->isHidden() ? wfMsg( 'centralauth-admin-yes' ) : wfMsg( 'centralauth-admin-no' ) ); |
262 | | - $out = '<ul id="mw-centralauth-info">'; |
263 | | - foreach( $attribs as $tag => $data ) { |
264 | | - $out .= Xml::element( 'li', array(), wfMsg( "centralauth-admin-info-$tag" ) . ' ' . $data ); |
265 | | - } |
266 | | - $out .= '</ul>'; |
267 | | - $wgOut->addHTML( $out ); |
268 | | - } else { |
269 | | - $wgOut->addWikiText( wfMsg( 'centralauth-admin-no-unified' ) ); |
| 270 | + $reg = $globalUser->getRegistration(); |
| 271 | + $age = $this->prettyTimespan( wfTimestamp( TS_UNIX ) - wfTimestamp( TS_UNIX, $reg ) ); |
| 272 | + $attribs = array( |
| 273 | + 'id' => $globalUser->getId(), |
| 274 | + 'registered' => $wgLang->timeanddate( $reg ) . " ($age)", |
| 275 | + 'home' => $this->determineHomeWiki(), |
| 276 | + 'editcount' => $this->evaluateTotalEditcount(), |
| 277 | + 'locked' => $globalUser->isLocked() ? wfMsg( 'centralauth-admin-yes' ) : wfMsg( 'centralauth-admin-no' ), |
| 278 | + 'hidden' => $this->formatHiddenLevel( $globalUser->getHiddenLevel() ) ); |
| 279 | + $out = '<fieldset id="mw-centralauth-info">'; |
| 280 | + $out .= '<legend>' . wfMsgHtml( 'centralauth-admin-info-header' ) . '</legend>'; |
| 281 | + foreach( $attribs as $tag => $data ) { |
| 282 | + $out .= '<p><strong>' . wfMsg( "centralauth-admin-info-$tag" ) . '</strong> ' . $data . '</p>'; |
270 | 283 | } |
| 284 | + $out .= '</fieldset>'; |
| 285 | + $wgOut->addHTML( $out ); |
271 | 286 | } |
272 | 287 | |
273 | | - function listMerged( $list ) { |
274 | | - return $this->listForm( $list, 'listMergedWikiItem', |
275 | | - 'unmerge', wfMsg( 'centralauth-admin-unmerge' ) ); |
276 | | - } |
| 288 | + function showWikiLists() { |
| 289 | + global $wgOut; |
| 290 | + $merged = $this->mAttachedLocalAccounts; |
| 291 | + $remainder = $this->mUnattachedLocalAccounts; |
277 | 292 | |
278 | | - function listRemainder( $list ) { |
279 | | - ksort( $list ); |
280 | | - $s = '<ul id="mw-centralauth-unattached">'; |
281 | | - foreach ( $list as $row ) { |
282 | | - $s .= '<li>' . $this->foreignUserLink( $row['wiki'] ) . "</li>\n"; |
283 | | - } |
284 | | - $s .= '</ul>'; |
285 | | - return $s; |
| 293 | + $legend = $this->mCanUnmerge ? |
| 294 | + wfMsg( 'centralauth-admin-list-legend-rw' ) : |
| 295 | + wfMsg( 'centralauth-admin-list-legend-ro' ); |
| 296 | + |
| 297 | + $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" ); |
| 298 | + $wgOut->addHTML( $this->listHeader() ); |
| 299 | + $wgOut->addHTML( $this->listMerged( $merged ) ); |
| 300 | + if( $remainder ) |
| 301 | + $wgOut->addHTML( $this->listRemainder( $remainder ) ); |
| 302 | + $wgOut->addHTML( $this->listFooter() ); |
286 | 303 | } |
287 | 304 | |
288 | | - function listForm( $list, $listMethod, $action, $buttonText ) { |
| 305 | + function listHeader() { |
289 | 306 | global $wgUser; |
290 | | - ksort( $list ); |
291 | 307 | return |
292 | 308 | Xml::openElement( 'form', |
293 | 309 | array( |
— | — | @@ -294,53 +310,76 @@ |
295 | 311 | 'action' => |
296 | 312 | $this->getTitle( $this->mUserName )->getLocalUrl( 'action=submit' ), |
297 | 313 | 'id' => 'mw-centralauth-merged' ) ) . |
298 | | - Xml::hidden( 'wpMethod', $action ) . |
| 314 | + Xml::hidden( 'wpMethod', 'unmerge' ) . |
299 | 315 | Xml::hidden( 'wpEditToken', $wgUser->editToken() ) . |
300 | | - '<table>' . |
301 | | - '<thead>' . |
302 | | - $this->tableRow( 'th', |
303 | | - array( |
304 | | - '', |
305 | | - wfMsgHtml( 'centralauth-admin-list-localwiki' ), |
306 | | - wfMsgHtml( 'centralauth-admin-list-attached-on' ), |
307 | | - wfMsgHtml( 'centralauth-admin-list-method' ), |
308 | | - wfMsgHtml( 'centralauth-admin-list-blocked' ), |
309 | | - wfMsgHtml( 'centralauth-admin-list-editcount' ), |
310 | | - ) |
311 | | - ) . |
312 | | - '</thead>' . |
313 | | - '<tbody>' . |
314 | | - implode( "\n", |
315 | | - array_map( array( $this, $listMethod ), |
316 | | - $list ) ) . |
317 | | - '<tr>' . |
318 | | - '<td></td>' . |
319 | | - '<td>' . |
320 | | - Xml::submitButton( $buttonText ) . |
321 | | - '</td>' . |
322 | | - '</tr>' . |
323 | | - '</tbody>' . |
324 | | - '</table>' . |
325 | | - Xml::closeElement( 'form' ); |
| 316 | + '<table id="mw-wikis-list">' . |
| 317 | + '<thead><tr>' . |
| 318 | + ( $this->mCanUnmerge ? '<th></th>' : '' ) . |
| 319 | + '<th>' . wfMsgHtml( 'centralauth-admin-list-localwiki' ) . '</th>'. |
| 320 | + '<th>' . wfMsgHtml( 'centralauth-admin-list-attached-on' ) . '</th>' . |
| 321 | + '<th>' . wfMsgHtml( 'centralauth-admin-list-method' ) . '</th>' . |
| 322 | + '<th>' . wfMsgHtml( 'centralauth-admin-list-blocked' ) . '</th>' . |
| 323 | + '<th>' . wfMsgHtml( 'centralauth-admin-list-editcount' ) . '</th>'. |
| 324 | + '</tr></thead>' . |
| 325 | + '<tbody>'; |
326 | 326 | } |
327 | 327 | |
| 328 | + function listFooter() { |
| 329 | + $footer = ''; |
| 330 | + if( $this->mCanUnmerge ) |
| 331 | + $footer .= |
| 332 | + '<tr>' . |
| 333 | + '<td style="border-right: none"></td>' . |
| 334 | + '<td style="border-left: none" colspan="5">' . |
| 335 | + Xml::submitButton( wfMsg( 'centralauth-admin-unmerge' ) ) . |
| 336 | + '</td>' . |
| 337 | + '</tr>'; |
| 338 | + $footer .= '</tbody></table></form>'; |
| 339 | + return $footer; |
| 340 | + } |
| 341 | + |
| 342 | + function listMerged( $list ) { |
| 343 | + ksort( $list ); |
| 344 | + return implode( "\n", array_map( array( $this, 'listMergedWikiItem' ), $list ) ); |
| 345 | + } |
| 346 | + |
| 347 | + function listRemainder( $list ) { |
| 348 | + ksort( $list ); |
| 349 | + $notMerged = wfMsg( 'centralauth-admin-unattached' ); |
| 350 | + $rows = array(); |
| 351 | + foreach ( $list as $row ) { |
| 352 | + $rows[] = '<tr class="unattached-row"><td>' . |
| 353 | + ( $this->mCanUnmerge ? '</td><td>' : '' ) . |
| 354 | + $this->foreignUserLink( $row['wiki'] ) . |
| 355 | + "</td><td colspan='4'>{$notMerged}</td></tr>\n"; |
| 356 | + } |
| 357 | + return implode( $rows ); |
| 358 | + } |
| 359 | + |
328 | 360 | function listMergedWikiItem( $row ) { |
329 | 361 | global $wgLang; |
330 | | - return $this->tableRow( 'td', |
331 | | - array( |
332 | | - $this->adminCheck( $row['wiki'] ), |
333 | | - $this->foreignUserLink( $row['wiki'] ), |
334 | | - htmlspecialchars( $wgLang->timeanddate( $row['attachedTimestamp'] ) ), |
335 | | - htmlspecialchars( wfMsg( 'centralauth-merge-method-' . $row['attachedMethod'] ) ), |
336 | | - $this->showBlockStatus( $row ), |
337 | | - intval( $row['editCount'] ) |
338 | | - ) |
339 | | - ); |
| 362 | + return '<tr>' . |
| 363 | + ( $this->mCanUnmerge ? '<td>' . $this->adminCheck( $row['wiki'] ) . '</td>' : '' ). |
| 364 | + '<td>' . $this->foreignUserLink( $row['wiki'] ) . '</td>' . |
| 365 | + '<td>' . htmlspecialchars( $wgLang->timeanddate( $row['attachedTimestamp'] ) ) . '</td>' . |
| 366 | + '<td style="text-align: center">' . $this->formatMergeMethod( $row['attachedMethod'] ) . '</td>' . |
| 367 | + '<td>' . $this->formatBlockStatus( $row ) . '</td>' . |
| 368 | + '<td>' . $this->formatEditcount( $row ) . '</td>' . |
| 369 | + '</tr>'; |
340 | 370 | } |
341 | | - |
342 | | - function showBlockStatus( $row ) { |
343 | | - if ($row['blocked']) { |
344 | | - if ($row['block-expiry'] == 'infinity') { |
| 371 | + |
| 372 | + function formatMergeMethod( $method ) { |
| 373 | + global $wgExtensionAssetsPath; |
| 374 | + |
| 375 | + $img = "{$wgExtensionAssetsPath}/CentralAuth/icons/merged-{$method}.png"; |
| 376 | + $brief = wfMsgHtml( "centralauth-merge-method-{$method}" ); |
| 377 | + return "<img src=\"{$img}\" alt=\"{$brief}\" />" . |
| 378 | + "<span class=\"merge-method-help\" title=\"{$brief}\" onclick=\"showMethodHint('{$method}')\">(?)</span>"; |
| 379 | + } |
| 380 | + |
| 381 | + function formatBlockStatus( $row ) { |
| 382 | + if( $row['blocked'] ) { |
| 383 | + if( $row['block-expiry'] == 'infinity' ) { |
345 | 384 | $reason = $row['block-reason']; |
346 | 385 | return wfMsgExt( 'centralauth-admin-blocked-indef', 'parseinline', array( $reason ) ); |
347 | 386 | } else { |
— | — | @@ -350,38 +389,73 @@ |
351 | 390 | $expiryt = $wgLang->time( $row['block-expiry'] ); |
352 | 391 | $reason = $row['block-reason']; |
353 | 392 | |
354 | | - return wfMsgExt( 'centralauth-admin-blocked', 'parseinline', array( $expiry, $reason, $expiryd, $expiryt ) ); |
| 393 | + $text = wfMsgExt( 'centralauth-admin-blocked', 'parseinline', array( $expiry, $reason, $expiryd, $expiryt ) ); |
355 | 394 | } |
356 | 395 | } else { |
357 | | - return wfMsgExt( 'centralauth-admin-notblocked', 'parseinline' ); |
| 396 | + $text = wfMsgExt( 'centralauth-admin-notblocked', 'parseinline' ); |
358 | 397 | } |
| 398 | + |
| 399 | + return $this->foreignLink( |
| 400 | + $row['wiki'], |
| 401 | + 'Special:Log/block', |
| 402 | + $text, |
| 403 | + wfMsg( 'centralauth-admin-blocklog' ), |
| 404 | + 'page=User:' . urlencode( $this->mUserName ) ); |
359 | 405 | } |
360 | 406 | |
| 407 | + function formatEditcount( $row ) { |
| 408 | + return $this->foreignLink( |
| 409 | + $row['wiki'], |
| 410 | + 'Special:Contributions/' . $this->mUserName, |
| 411 | + intval( $row['editCount'] ), |
| 412 | + 'contributions' ); |
| 413 | + } |
| 414 | + |
| 415 | + function formatHiddenLevel( $level ) { |
| 416 | + switch( $level ) { |
| 417 | + case CentralAuthUser::HIDDEN_NONE: |
| 418 | + return wfMsg( 'centralauth-admin-no' ); |
| 419 | + case CentralAuthUser::HIDDEN_LISTS: |
| 420 | + return wfMsg( 'centralauth-admin-hidden-list' ); |
| 421 | + case CentralAuthUser::HIDDEN_OVERSIGHT: |
| 422 | + return wfMsg( 'centralauth-admin-hidden-oversight' ); |
| 423 | + } |
| 424 | + } |
| 425 | + |
361 | 426 | function tableRow( $element, $cols ) { |
362 | 427 | return "<tr><$element>" . |
363 | 428 | implode( "</$element><$element>", $cols ) . |
364 | 429 | "</$element></tr>"; |
365 | 430 | } |
366 | 431 | |
367 | | - function foreignUserLink( $wikiID ) { |
| 432 | + function foreignLink( $wikiID, $title, $text, $hint = '', $params = '' ) { |
368 | 433 | $wiki = WikiMap::getWiki( $wikiID ); |
369 | 434 | if( !$wiki ) { |
370 | | - throw new MWException( "no wiki for $wikiID" ); |
| 435 | + throw new MWException( "Invalid wiki: $wikiID" ); |
371 | 436 | } |
372 | 437 | |
373 | | - $hostname = $wiki->getDisplayName(); |
374 | | - $userPageName = 'User:' . $this->mUserName; |
375 | | - $url = $wiki->getUrl( $userPageName ); |
| 438 | + $url = $wiki->getUrl( $title ); |
| 439 | + if( $params ) |
| 440 | + $url .= '?' . $params; |
376 | 441 | return Xml::element( 'a', |
377 | 442 | array( |
378 | 443 | 'href' => $url, |
379 | | - 'title' => wfMsg( 'centralauth-foreign-link', |
380 | | - $this->mUserName, |
381 | | - $hostname ), |
| 444 | + 'title' => $hint, |
382 | 445 | ), |
383 | | - $hostname ); |
| 446 | + $text ); |
384 | 447 | } |
385 | 448 | |
| 449 | + function foreignUserLink( $wikiID ) { |
| 450 | + $wiki = WikiMap::getWiki( $wikiID ); |
| 451 | + $wikiname = $wiki->getDisplayName(); |
| 452 | + return $this->foreignLink( |
| 453 | + $wikiID, |
| 454 | + 'User:' . $this->mUserName, |
| 455 | + $wikiname, |
| 456 | + wfMsg( 'centralauth-foreign-link', $this->mUserName, $wikiname ) ); |
| 457 | + |
| 458 | + } |
| 459 | + |
386 | 460 | function adminCheck( $wikiID ) { |
387 | 461 | return |
388 | 462 | Xml::check( 'wpWikis[]', false, array( 'value' => $wikiID ) ); |
— | — | @@ -390,7 +464,7 @@ |
391 | 465 | function showActionForm( $action ) { |
392 | 466 | global $wgOut, $wgUser; |
393 | 467 | $wgOut->addHTML( |
394 | | - Xml::element( 'h2', array(), wfMsg( "centralauth-admin-{$action}-title" ) ) . |
| 468 | + Xml::fieldset( wfMsg( "centralauth-admin-{$action}-title" ) ) . |
395 | 469 | Xml::openElement( 'form', array( |
396 | 470 | 'method' => 'POST', |
397 | 471 | 'action' => $this->getTitle()->getFullUrl( 'target=' . urlencode( $this->mUserName ) ), |
— | — | @@ -398,51 +472,76 @@ |
399 | 473 | Xml::hidden( 'wpMethod', $action ) . |
400 | 474 | Xml::hidden( 'wpEditToken', $wgUser->editToken() ) . |
401 | 475 | wfMsgExt( "centralauth-admin-{$action}-description", 'parse' ) . |
402 | | - '<p>' . |
403 | | - Xml::label( wfMsgHtml( 'centralauth-admin-reason' ), "{$action}-reason" ) . ' ' . |
404 | | - Xml::input( 'reason', false, false, array( 'id' => "{$action}-reason" ) ) . |
405 | | - '</p>' . |
406 | | - '<p>' . |
407 | | - Xml::submitButton( wfMsg( "centralauth-admin-{$action}-button" ) ) . |
408 | | - '</p>' . |
409 | | - '</form>' ); |
| 476 | + Xml::buildForm( |
| 477 | + array( 'centralauth-admin-reason' => Xml::input( 'reason', |
| 478 | + false, false, array( 'id' => "{$action}-reason" ) ) ), |
| 479 | + "centralauth-admin-{$action}-button" |
| 480 | + ) . |
| 481 | + '</form></fieldset>' ); |
410 | 482 | } |
411 | 483 | |
412 | 484 | function showStatusForm() { |
413 | 485 | // Allows locking, hiding, locking and hiding. |
414 | 486 | global $wgUser, $wgOut; |
415 | 487 | $form = ''; |
416 | | - $form .= Xml::element( 'h2', array(), wfMsg( 'centralauth-admin-status' ) ); |
| 488 | + $form .= Xml::fieldset( wfMsg( 'centralauth-admin-status' ) ); |
417 | 489 | $form .= Xml::hidden( 'wpMethod', 'set-status' ); |
418 | 490 | $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken() ); |
419 | 491 | $form .= wfMsgExt( 'centralauth-admin-status-intro', 'parse' ); |
420 | 492 | |
421 | | - // Checkboxen |
422 | | - $lockedLabel = wfMsg( 'centralauth-admin-status-locked' ); |
423 | | - $checkLocked = Xml::checkLabel( $lockedLabel, |
424 | | - 'wpStatusLocked', |
425 | | - 'mw-centralauth-status-locked', |
426 | | - $this->mGlobalUser->isLocked() ); |
427 | | - $hiddenLabel = wfMsg( 'centralauth-admin-status-hidden' ); |
428 | | - $checkHidden = Xml::checkLabel( $hiddenLabel, |
429 | | - 'wpStatusHidden', |
430 | | - 'mw-centralauth-status-hidden', |
431 | | - $this->mGlobalUser->isHidden() ); |
432 | | - |
433 | | - $form .= Xml::tags( 'p', null, $checkLocked ) . |
434 | | - Xml::tags( 'p', null, $checkHidden ); |
435 | | - |
| 493 | + // Radio buttons |
| 494 | + $radioLocked = |
| 495 | + Xml::radioLabel( |
| 496 | + wfMsg( 'centralauth-admin-status-locked-no' ), |
| 497 | + 'wpStatusLocked', |
| 498 | + '0', |
| 499 | + 'mw-centralauth-status-locked-no', |
| 500 | + !$this->mGlobalUser->isLocked() ) . |
| 501 | + '<br/>' . |
| 502 | + Xml::radioLabel( |
| 503 | + wfMsg( 'centralauth-admin-status-locked-yes' ), |
| 504 | + 'wpStatusLocked', |
| 505 | + '1', |
| 506 | + 'mw-centralauth-status-locked-yes', |
| 507 | + $this->mGlobalUser->isLocked() ); |
| 508 | + $radioHidden = |
| 509 | + Xml::radioLabel( |
| 510 | + wfMsg( 'centralauth-admin-status-hidden-no' ), |
| 511 | + 'wpStatusHidden', |
| 512 | + CentralAuthUser::HIDDEN_NONE, |
| 513 | + 'mw-centralauth-status-hidden-no', |
| 514 | + $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_NONE ) . |
| 515 | + '<br/>' . |
| 516 | + Xml::radioLabel( |
| 517 | + wfMsg( 'centralauth-admin-status-hidden-list' ), |
| 518 | + 'wpStatusHidden', |
| 519 | + CentralAuthUser::HIDDEN_LISTS, |
| 520 | + 'mw-centralauth-status-hidden-list', |
| 521 | + $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_LISTS ) . |
| 522 | + '<br/>'; |
| 523 | + if( $this->mCanOversight ) |
| 524 | + $radioHidden .= Xml::radioLabel( |
| 525 | + wfMsg( 'centralauth-admin-status-hidden-oversight' ), |
| 526 | + 'wpStatusHidden', |
| 527 | + CentralAuthUser::HIDDEN_OVERSIGHT, |
| 528 | + 'mw-centralauth-status-hidden-oversight', |
| 529 | + $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_OVERSIGHT ); |
| 530 | + |
436 | 531 | // Reason |
437 | | - $reasonLabel = wfMsg( 'centralauth-admin-reason' ); |
438 | | - $reasonField = Xml::inputLabel( $reasonLabel, |
439 | | - 'wpReason', |
440 | | - 'mw-centralauth-reason', |
441 | | - 45 ); |
442 | | - $form .= Xml::tags( 'p', null, $reasonField ); |
443 | | - |
444 | | - $form .= Xml::tags( 'p', null, |
445 | | - Xml::submitButton( wfMsg( 'centralauth-admin-status-submit' ) ) |
446 | | - ); |
| 532 | + $reasonList = Xml::listDropDown( 'wpReasonList', |
| 533 | + wfMsgForContent( 'centralauth-admin-status-reasons' ), |
| 534 | + wfMsgForContent( 'ipbreasonotherlist' ) ); |
| 535 | + $reasonField = Xml::input( 'wpReason', 45, false ); |
| 536 | + |
| 537 | + $form .= Xml::buildForm( |
| 538 | + array( |
| 539 | + 'centralauth-admin-status-locked' => $radioLocked, |
| 540 | + 'centralauth-admin-status-hidden' => $radioHidden, |
| 541 | + 'centralauth-admin-reason' => $reasonList, |
| 542 | + 'centralauth-admin-reason-other' => $reasonField ), |
| 543 | + 'centralauth-admin-status-submit' ); |
| 544 | + |
| 545 | + $form .= '</fieldset>'; |
447 | 546 | $form = Xml::tags( 'form', |
448 | 547 | array( 'method' => 'POST', |
449 | 548 | 'action' => |
— | — | @@ -455,8 +554,55 @@ |
456 | 555 | $wgOut->addHTML( $form ); |
457 | 556 | } |
458 | 557 | |
459 | | - function logAction( $action, $target, $reason = '', $params = array() ) { |
460 | | - $log = new LogPage( 'globalauth' ); //Not centralauth because of some weird length limitiations |
| 558 | + function showLogExtract() { |
| 559 | + global $wgOut; |
| 560 | + $user = $this->mGlobalUser->getName(); |
| 561 | + $text = ''; |
| 562 | + $numRows = LogEventsList::showLogExtract( |
| 563 | + $text, |
| 564 | + array( 'globalauth', 'suppress' ), |
| 565 | + Title::newFromText( "User:{$user}@global" )->getPrefixedText(), |
| 566 | + '', |
| 567 | + array( 'showIfEmpty' => true ) ); |
| 568 | + if( $numRows ) { |
| 569 | + $wgOut->addHTML( Xml::fieldset( wfMsg( 'centralauth-admin-logsnippet' ), $text ) ); |
| 570 | + } |
| 571 | + } |
| 572 | + |
| 573 | + function determineHomeWiki() { |
| 574 | + foreach( $this->mAttachedLocalAccounts as $wiki => $acc ) { |
| 575 | + if( $acc['attachedMethod'] == 'primary' || $acc['attachedMethod'] == 'new' ) { |
| 576 | + return $wiki; |
| 577 | + } |
| 578 | + } |
| 579 | + |
| 580 | + // Should not happen. |
| 581 | + return ''; |
| 582 | + } |
| 583 | + |
| 584 | + function evaluateTotalEditcount() { |
| 585 | + $total = 0; |
| 586 | + foreach( $this->mAttachedLocalAccounts as $acc ) { |
| 587 | + $total += $acc['editCount']; |
| 588 | + } |
| 589 | + return $total; |
| 590 | + } |
| 591 | + |
| 592 | + function addMergeMethodDescriptions() { |
| 593 | + global $wgOut, $wgLang; |
| 594 | + $js = "wgMergeMethodDescriptions = {\n"; |
| 595 | + foreach( array( 'primary', 'new', 'empty', 'password', 'mail', 'admin', 'login' ) as $method ) { |
| 596 | + $short = Xml::encodeJsVar( $wgLang->ucFirst( wfMsgHtml( "centralauth-merge-method-{$method}" ) ) ); |
| 597 | + $desc = Xml::encodeJsVar( wfMsgWikiHtml( "centralauth-merge-method-{$method}-desc" ) ); |
| 598 | + $js .= "\t'{$method}' : { 'short' : {$short}, 'desc' : {$desc} },\n"; |
| 599 | + } |
| 600 | + $js .= "}"; |
| 601 | + $wgOut->addInlineScript( $js ); |
| 602 | + } |
| 603 | + |
| 604 | + function logAction( $action, $target, $reason = '', $params = array(), $suppressLog = false ) { |
| 605 | + $logType = $suppressLog ? 'suppress' : 'globalauth'; // Not centralauth because of some weird length limitiations |
| 606 | + $log = new LogPage( $logType ); |
461 | 607 | $log->addEntry( $action, Title::newFromText( "User:{$target}@global" ), $reason, $params ); |
462 | 608 | } |
463 | 609 | } |
Index: trunk/extensions/CentralAuth/centralauth.css |
— | — | @@ -0,0 +1,36 @@ |
| 2 | +#mw-wikis-list { |
| 3 | + margin: 1em 1em 1em 0; |
| 4 | + background: #f9f9f9; |
| 5 | + border: 1px #aaa solid; |
| 6 | + border-collapse: collapse; |
| 7 | +} |
| 8 | +#mw-wikis-list td { |
| 9 | + border: 1px #aaa solid; |
| 10 | + padding: 0.2em; |
| 11 | +} |
| 12 | +#mw-wikis-list th { |
| 13 | + background: #f2f2f2; |
| 14 | + text-align: center; |
| 15 | +} |
| 16 | + |
| 17 | +.merge-method-help { |
| 18 | + color: #aaa; |
| 19 | + cursor: pointer; |
| 20 | + font-size: 7pt; |
| 21 | + padding: 3px; |
| 22 | +} |
| 23 | + |
| 24 | +.merge-method-help-div { |
| 25 | + position: absolute; |
| 26 | + z-index: 3; |
| 27 | + cursor: pointer; |
| 28 | + |
| 29 | + width: 15em; |
| 30 | + border: 1px solid black; |
| 31 | + background-color: #ff9; |
| 32 | + padding: 0.5em; |
| 33 | +} |
| 34 | + |
| 35 | +.merge-method-help-name { |
| 36 | + font-weight: bold; |
| 37 | +} |
Property changes on: trunk/extensions/CentralAuth/centralauth.css |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 38 | + native |
Index: trunk/extensions/CentralAuth/CentralAuthHooks.php |
— | — | @@ -444,7 +444,6 @@ |
445 | 445 | return false; |
446 | 446 | } |
447 | 447 | |
448 | | - |
449 | 448 | // Checks passed, create the user |
450 | 449 | wfDebug( __METHOD__.": creating new user\n" ); |
451 | 450 | $user->loadDefaults( $userName ); |
— | — | @@ -565,6 +564,8 @@ |
566 | 565 | } |
567 | 566 | |
568 | 567 | static function onGetUserPermissionsErrorsExpensive( $title, $user, $action, &$result ) { |
| 568 | + global $wgCentralAuthLockedCanEdit; |
| 569 | + |
569 | 570 | if( $action == 'read' || $user->isAnon() ) { |
570 | 571 | return true; |
571 | 572 | } |
— | — | @@ -572,7 +573,10 @@ |
573 | 574 | if( !($centralUser->exists() && $centralUser->isAttached()) ) { |
574 | 575 | return true; |
575 | 576 | } |
576 | | - if( $centralUser->isLocked() ) { |
| 577 | + if( |
| 578 | + $centralUser->isOversighted() || // Oversighted users should *never* be able to edit |
| 579 | + ( $centralUser->isLocked() && !in_array( $title->getPrefixedText(), $wgCentralAuthLockedCanEdit ) ) |
| 580 | + ) { |
577 | 581 | $result = 'centralauth-error-locked'; |
578 | 582 | return false; |
579 | 583 | } |
Index: trunk/extensions/CentralAuth/SuppressUserJob.php |
— | — | @@ -0,0 +1,37 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * A job to do crosswiki suppression in batches, rather than |
| 6 | + * in one request. Size of batch is changed by changing |
| 7 | + * $wgCentralAuthWikisPerSuppressJob. |
| 8 | + */ |
| 9 | +class CentralAuthSuppressUserJob extends Job { |
| 10 | + /** |
| 11 | + * Constructor |
| 12 | + * |
| 13 | + * @param Title $title Associated title |
| 14 | + * @param array $params Job parameters |
| 15 | + */ |
| 16 | + public function __construct( $title, $params ) { |
| 17 | + parent::__construct( 'crosswikiSuppressUser', $title, $params ); |
| 18 | + } |
| 19 | + |
| 20 | + /** |
| 21 | + * Execute the job |
| 22 | + * |
| 23 | + * @return bool |
| 24 | + */ |
| 25 | + public function run() { |
| 26 | + extract( $this->params ); |
| 27 | + $user = new CentralAuthUser( $username ); |
| 28 | + if( !$user->exists() ) { |
| 29 | + wfDebugLog( 'suppressjob', "Requested to suppress non-existent user {$username} by {$by}." ); |
| 30 | + } |
| 31 | + |
| 32 | + foreach( $wikis as $wiki ) { |
| 33 | + $user->doLocalSuppression( $suppress, $wiki, $by, $reason ); |
| 34 | + wfDebugLog( 'suppressjob', ( $suppress ? 'S' : 'Uns' ) . "uppressed {$username} at {$wiki} by {$by} via job queue." ); |
| 35 | + } |
| 36 | + return true; |
| 37 | + } |
| 38 | +} |
Property changes on: trunk/extensions/CentralAuth/SuppressUserJob.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 39 | + native |
Index: trunk/extensions/CentralAuth/SpecialGlobalUsers.php |
— | — | @@ -73,7 +73,7 @@ |
74 | 74 | |
75 | 75 | function getQueryInfo() { |
76 | 76 | $localwiki = wfWikiID(); |
77 | | - $conds = array( 'gu_hidden' => 0 ); |
| 77 | + $conds = array( 'gu_hidden' => CentralAuthUser::HIDDEN_NONE ); |
78 | 78 | |
79 | 79 | if( $this->mGroup ) |
80 | 80 | $conds['gug_group'] = $this->mGroup; |
Index: trunk/extensions/CentralAuth/icons/LICENSE |
— | — | @@ -0,0 +1,165 @@ |
| 2 | + GNU LESSER GENERAL PUBLIC LICENSE |
| 3 | + Version 3, 29 June 2007 |
| 4 | + |
| 5 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
| 6 | + Everyone is permitted to copy and distribute verbatim copies |
| 7 | + of this license document, but changing it is not allowed. |
| 8 | + |
| 9 | + |
| 10 | + This version of the GNU Lesser General Public License incorporates |
| 11 | +the terms and conditions of version 3 of the GNU General Public |
| 12 | +License, supplemented by the additional permissions listed below. |
| 13 | + |
| 14 | + 0. Additional Definitions. |
| 15 | + |
| 16 | + As used herein, "this License" refers to version 3 of the GNU Lesser |
| 17 | +General Public License, and the "GNU GPL" refers to version 3 of the GNU |
| 18 | +General Public License. |
| 19 | + |
| 20 | + "The Library" refers to a covered work governed by this License, |
| 21 | +other than an Application or a Combined Work as defined below. |
| 22 | + |
| 23 | + An "Application" is any work that makes use of an interface provided |
| 24 | +by the Library, but which is not otherwise based on the Library. |
| 25 | +Defining a subclass of a class defined by the Library is deemed a mode |
| 26 | +of using an interface provided by the Library. |
| 27 | + |
| 28 | + A "Combined Work" is a work produced by combining or linking an |
| 29 | +Application with the Library. The particular version of the Library |
| 30 | +with which the Combined Work was made is also called the "Linked |
| 31 | +Version". |
| 32 | + |
| 33 | + The "Minimal Corresponding Source" for a Combined Work means the |
| 34 | +Corresponding Source for the Combined Work, excluding any source code |
| 35 | +for portions of the Combined Work that, considered in isolation, are |
| 36 | +based on the Application, and not on the Linked Version. |
| 37 | + |
| 38 | + The "Corresponding Application Code" for a Combined Work means the |
| 39 | +object code and/or source code for the Application, including any data |
| 40 | +and utility programs needed for reproducing the Combined Work from the |
| 41 | +Application, but excluding the System Libraries of the Combined Work. |
| 42 | + |
| 43 | + 1. Exception to Section 3 of the GNU GPL. |
| 44 | + |
| 45 | + You may convey a covered work under sections 3 and 4 of this License |
| 46 | +without being bound by section 3 of the GNU GPL. |
| 47 | + |
| 48 | + 2. Conveying Modified Versions. |
| 49 | + |
| 50 | + If you modify a copy of the Library, and, in your modifications, a |
| 51 | +facility refers to a function or data to be supplied by an Application |
| 52 | +that uses the facility (other than as an argument passed when the |
| 53 | +facility is invoked), then you may convey a copy of the modified |
| 54 | +version: |
| 55 | + |
| 56 | + a) under this License, provided that you make a good faith effort to |
| 57 | + ensure that, in the event an Application does not supply the |
| 58 | + function or data, the facility still operates, and performs |
| 59 | + whatever part of its purpose remains meaningful, or |
| 60 | + |
| 61 | + b) under the GNU GPL, with none of the additional permissions of |
| 62 | + this License applicable to that copy. |
| 63 | + |
| 64 | + 3. Object Code Incorporating Material from Library Header Files. |
| 65 | + |
| 66 | + The object code form of an Application may incorporate material from |
| 67 | +a header file that is part of the Library. You may convey such object |
| 68 | +code under terms of your choice, provided that, if the incorporated |
| 69 | +material is not limited to numerical parameters, data structure |
| 70 | +layouts and accessors, or small macros, inline functions and templates |
| 71 | +(ten or fewer lines in length), you do both of the following: |
| 72 | + |
| 73 | + a) Give prominent notice with each copy of the object code that the |
| 74 | + Library is used in it and that the Library and its use are |
| 75 | + covered by this License. |
| 76 | + |
| 77 | + b) Accompany the object code with a copy of the GNU GPL and this license |
| 78 | + document. |
| 79 | + |
| 80 | + 4. Combined Works. |
| 81 | + |
| 82 | + You may convey a Combined Work under terms of your choice that, |
| 83 | +taken together, effectively do not restrict modification of the |
| 84 | +portions of the Library contained in the Combined Work and reverse |
| 85 | +engineering for debugging such modifications, if you also do each of |
| 86 | +the following: |
| 87 | + |
| 88 | + a) Give prominent notice with each copy of the Combined Work that |
| 89 | + the Library is used in it and that the Library and its use are |
| 90 | + covered by this License. |
| 91 | + |
| 92 | + b) Accompany the Combined Work with a copy of the GNU GPL and this license |
| 93 | + document. |
| 94 | + |
| 95 | + c) For a Combined Work that displays copyright notices during |
| 96 | + execution, include the copyright notice for the Library among |
| 97 | + these notices, as well as a reference directing the user to the |
| 98 | + copies of the GNU GPL and this license document. |
| 99 | + |
| 100 | + d) Do one of the following: |
| 101 | + |
| 102 | + 0) Convey the Minimal Corresponding Source under the terms of this |
| 103 | + License, and the Corresponding Application Code in a form |
| 104 | + suitable for, and under terms that permit, the user to |
| 105 | + recombine or relink the Application with a modified version of |
| 106 | + the Linked Version to produce a modified Combined Work, in the |
| 107 | + manner specified by section 6 of the GNU GPL for conveying |
| 108 | + Corresponding Source. |
| 109 | + |
| 110 | + 1) Use a suitable shared library mechanism for linking with the |
| 111 | + Library. A suitable mechanism is one that (a) uses at run time |
| 112 | + a copy of the Library already present on the user's computer |
| 113 | + system, and (b) will operate properly with a modified version |
| 114 | + of the Library that is interface-compatible with the Linked |
| 115 | + Version. |
| 116 | + |
| 117 | + e) Provide Installation Information, but only if you would otherwise |
| 118 | + be required to provide such information under section 6 of the |
| 119 | + GNU GPL, and only to the extent that such information is |
| 120 | + necessary to install and execute a modified version of the |
| 121 | + Combined Work produced by recombining or relinking the |
| 122 | + Application with a modified version of the Linked Version. (If |
| 123 | + you use option 4d0, the Installation Information must accompany |
| 124 | + the Minimal Corresponding Source and Corresponding Application |
| 125 | + Code. If you use option 4d1, you must provide the Installation |
| 126 | + Information in the manner specified by section 6 of the GNU GPL |
| 127 | + for conveying Corresponding Source.) |
| 128 | + |
| 129 | + 5. Combined Libraries. |
| 130 | + |
| 131 | + You may place library facilities that are a work based on the |
| 132 | +Library side by side in a single library together with other library |
| 133 | +facilities that are not Applications and are not covered by this |
| 134 | +License, and convey such a combined library under terms of your |
| 135 | +choice, if you do both of the following: |
| 136 | + |
| 137 | + a) Accompany the combined library with a copy of the same work based |
| 138 | + on the Library, uncombined with any other library facilities, |
| 139 | + conveyed under the terms of this License. |
| 140 | + |
| 141 | + b) Give prominent notice with the combined library that part of it |
| 142 | + is a work based on the Library, and explaining where to find the |
| 143 | + accompanying uncombined form of the same work. |
| 144 | + |
| 145 | + 6. Revised Versions of the GNU Lesser General Public License. |
| 146 | + |
| 147 | + The Free Software Foundation may publish revised and/or new versions |
| 148 | +of the GNU Lesser General Public License from time to time. Such new |
| 149 | +versions will be similar in spirit to the present version, but may |
| 150 | +differ in detail to address new problems or concerns. |
| 151 | + |
| 152 | + Each version is given a distinguishing version number. If the |
| 153 | +Library as you received it specifies that a certain numbered version |
| 154 | +of the GNU Lesser General Public License "or any later version" |
| 155 | +applies to it, you have the option of following the terms and |
| 156 | +conditions either of that published version or of any later version |
| 157 | +published by the Free Software Foundation. If the Library as you |
| 158 | +received it does not specify a version number of the GNU Lesser |
| 159 | +General Public License, you may choose any version of the GNU Lesser |
| 160 | +General Public License ever published by the Free Software Foundation. |
| 161 | + |
| 162 | + If the Library as you received it specifies that a proxy can decide |
| 163 | +whether future versions of the GNU Lesser General Public License shall |
| 164 | +apply, that proxy's public statement of acceptance of any version is |
| 165 | +permanent authorization for you to choose that version for the |
| 166 | +Library. |
Index: trunk/extensions/CentralAuth/icons/merged-empty.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-empty.png |
___________________________________________________________________ |
Name: svn:mime-type |
1 | 167 | + image/png |
Index: trunk/extensions/CentralAuth/icons/merged-mail.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-mail.png |
___________________________________________________________________ |
Name: svn:mime-type |
2 | 168 | + image/png |
Index: trunk/extensions/CentralAuth/icons/merged-password.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-password.png |
___________________________________________________________________ |
Name: svn:mime-type |
3 | 169 | + image/png |
Index: trunk/extensions/CentralAuth/icons/merged-primary.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-primary.png |
___________________________________________________________________ |
Name: svn:mime-type |
4 | 170 | + image/png |
Index: trunk/extensions/CentralAuth/icons/merged-admin.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-admin.png |
___________________________________________________________________ |
Name: svn:mime-type |
5 | 171 | + image/png |
Index: trunk/extensions/CentralAuth/icons/merged-login.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-login.png |
___________________________________________________________________ |
Name: svn:mime-type |
6 | 172 | + image/png |
Index: trunk/extensions/CentralAuth/icons/README |
— | — | @@ -0,0 +1,11 @@ |
| 2 | +Icons present in this folder are mostly icons from Nuvola icons set by David Vignoni: |
| 3 | +* Nuvola_apps_agent.png |
| 4 | +* Nuvola_apps_kgpg.png |
| 5 | +* Nuvola_filesystems_folder_home.png |
| 6 | +* Nuvola_apps_email.png |
| 7 | +Those files are distributed under GNU Lesser General Public License. Its text may be found in LICENSE file. |
| 8 | + |
| 9 | +Other files included are: |
| 10 | +* Recycling_symbol.svg (by Krdan Ielalir, public domain) |
| 11 | +* Symbol_support_vote.svg (by Zachary Harden, public domain) |
| 12 | + |
Index: trunk/extensions/CentralAuth/icons/merged-new.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/CentralAuth/icons/merged-new.png |
___________________________________________________________________ |
Name: svn:mime-type |
1 | 13 | + image/png |
Name: svn:executable |
2 | 14 | + * |
Index: trunk/extensions/CentralAuth/CentralAuth.i18n.php |
— | — | @@ -95,9 +95,21 @@ |
96 | 96 | 'centralauth-merge-method-empty' => 'no contributions', |
97 | 97 | 'centralauth-merge-method-mail' => 'confirmed by e-mail', |
98 | 98 | 'centralauth-merge-method-password' => 'confirmed by password', |
99 | | - 'centralauth-merge-method-admin' => 'admin merged account', |
| 99 | + 'centralauth-merge-method-admin' => 'admin-merged account', |
100 | 100 | 'centralauth-merge-method-new' => 'new account', |
101 | | - 'centralauth-merge-method-login' => 'confirmed by login', |
| 101 | + 'centralauth-merge-method-login' => 'created on login', |
| 102 | + 'centralauth-merge-method-primary-desc' => 'This is the wiki at which the account was initially merged. |
| 103 | +Note that it may differ from the real home wiki of that user.', |
| 104 | + 'centralauth-merge-method-empty-desc' => 'Indicates that the local account was merged because it had no edits.', |
| 105 | + 'centralauth-merge-method-mail-desc' => 'Indicates that the local account was merged because its email address matched |
| 106 | +the email address of the main account', |
| 107 | + 'centralauth-merge-method-password-desc' => 'Indicates that the local account was merged because user specified a valid |
| 108 | +password for it.', |
| 109 | + 'centralauth-merge-method-admin-desc' => 'Indicates that the local account was merged manually by stewards. That feature |
| 110 | +is disabled now because of security reasons.', |
| 111 | + 'centralauth-merge-method-new-desc' => 'Indicates that the global account was created automatically when that local |
| 112 | +account was created.', |
| 113 | + 'centralauth-merge-method-login-desc' => 'Indicates that the local account was created automatically when user logged in.', |
102 | 114 | |
103 | 115 | // When not complete, offer to finish... |
104 | 116 | 'centralauth-finish-title' => 'Finish merge', |
— | — | @@ -122,30 +134,37 @@ |
123 | 135 | 'centralauth-attach-success' => 'The account was migrated to the unified account.', |
124 | 136 | |
125 | 137 | // Administrator's console |
126 | | - 'centralauth' => 'Unified login administration', |
| 138 | + 'centralauth' => 'Global user manager', |
127 | 139 | 'centralauth-admin-intro' => 'This interface can be used for administration of global accounts.', |
128 | 140 | 'centralauth-admin-manage' => 'Manage user data', |
129 | 141 | 'centralauth-admin-username' => 'User name:', |
130 | | - 'centralauth-admin-lookup' => 'View or edit user data', |
| 142 | + 'centralauth-admin-lookup-ro' => 'View user info', |
| 143 | + 'centralauth-admin-lookup-rw' => 'Manage user account', |
131 | 144 | 'centralauth-admin-permission' => "Only stewards may merge other people's accounts for them.", |
132 | 145 | 'centralauth-admin-no-unified' => 'No unified account for this username.', |
| 146 | + 'centralauth-admin-info-header' => 'Global user info', |
133 | 147 | 'centralauth-admin-info-id' => 'User ID:', |
134 | 148 | 'centralauth-admin-info-registered' => 'Registered:', |
| 149 | + 'centralauth-admin-info-home' => 'Home wiki:', |
| 150 | + 'centralauth-admin-info-editcount' => 'Total editcount:', |
135 | 151 | 'centralauth-admin-info-locked' => 'Locked:', |
136 | | - 'centralauth-admin-info-hidden' => 'Hidden:', |
| 152 | + 'centralauth-admin-info-hidden' => 'Hidden level:', |
137 | 153 | 'centralauth-admin-yes' => 'yes', |
138 | 154 | 'centralauth-admin-no' => 'no', |
139 | | - 'centralauth-admin-attached' => 'Fully merged accounts', |
140 | | - 'centralauth-admin-unattached' => 'Unattached accounts', |
141 | | - 'centralauth-admin-no-unattached' => 'No unmerged accounts remain.', |
142 | | - 'centralauth-admin-notblocked' => 'Not blocked', |
| 155 | + 'centralauth-admin-hidden-list' => 'from public lists', |
| 156 | + 'centralauth-admin-hidden-oversight' => 'oversighted', |
| 157 | + 'centralauth-admin-list-legend-ro' => 'List of local accounts', |
| 158 | + 'centralauth-admin-list-legend-rw' => 'Unmerge local accounts', |
| 159 | + 'centralauth-admin-unattached' => 'not attached', |
| 160 | + 'centralauth-admin-notblocked' => '—', |
143 | 161 | 'centralauth-admin-blocked' => 'Blocked, expires $3 at $4. Reason: $2', |
144 | 162 | 'centralauth-admin-blocked-indef' => 'Blocked indefinitely. Reason: $1', |
| 163 | + 'centralauth-admin-blocklog' => 'block log', |
145 | 164 | 'centralauth-admin-list-localwiki' => 'Local wiki', |
146 | 165 | 'centralauth-admin-list-attached-on' => 'Attached on', |
147 | 166 | 'centralauth-admin-list-method' => 'Method', |
148 | 167 | 'centralauth-admin-list-editcount' => 'Edit count', |
149 | | - 'centralauth-admin-list-blocked' => 'Blocked status', |
| 168 | + 'centralauth-admin-list-blocked' => 'Blocked', |
150 | 169 | 'centralauth-admin-unmerge' => 'Unmerge selected', |
151 | 170 | 'centralauth-admin-merge' => 'Merge selected', |
152 | 171 | 'centralauth-admin-bad-input' => 'Invalid merge selection', |
— | — | @@ -162,15 +181,29 @@ |
163 | 182 | 'centralauth-admin-delete-nonexistent' => 'Error: the global account "<nowiki>$1</nowiki>" does not exist.', |
164 | 183 | 'centralauth-token-mismatch' => 'Sorry, we could not process your form submission due to a loss of session data.', |
165 | 184 | 'centralauth-admin-reason' => 'Reason:', |
| 185 | + 'centralauth-admin-reason-other' => 'Other/additional reason:', |
166 | 186 | 'centralauth-admin-status' => 'Set global account status', |
167 | | - 'centralauth-admin-status-intro' => 'You can use this form to change the status of this global account', |
168 | | - 'centralauth-admin-status-locked' => 'Locked', |
169 | | - 'centralauth-admin-status-hidden' => 'Hidden', |
| 187 | + 'centralauth-admin-status-intro' => 'You can use this form to change the status of this global account.', |
| 188 | + 'centralauth-admin-status-locked' => 'Locked:', |
| 189 | + 'centralauth-admin-status-locked-no' => 'Account is not locked', |
| 190 | + 'centralauth-admin-status-locked-yes' => 'Account is locked from editing', |
| 191 | + 'centralauth-admin-status-hidden' => 'Hidden:', |
| 192 | + 'centralauth-admin-status-hidden-no' => 'Account is not hidden', |
| 193 | + 'centralauth-admin-status-hidden-list' => 'Account is hidden from public lists', |
| 194 | + 'centralauth-admin-status-hidden-oversight' => 'Account is hidden completely', |
170 | 195 | 'centralauth-admin-status-submit' => 'Set status', |
171 | 196 | 'centralauth-admin-status-nonexistent' => 'Error: the global account "<nowiki>$1</nowiki>" does not exist.', |
172 | 197 | 'centralauth-admin-setstatus-success' => 'You have successfully changed the status of this global account.', |
173 | | - |
| 198 | + 'centralauth-admin-status-reasons' => '* Common lock reasons |
| 199 | +** vandalism-only account |
| 200 | +** spam-only account |
| 201 | +* Common lock-and-hide reasons |
| 202 | +** abusive user name |
| 203 | +** inappropriate personal information', |
| 204 | + 'centralauth-admin-logsnippet' => 'Previous global account changes', |
| 205 | + 'centralauth-admin-suppressreason' => 'Globally suppressed by $1 for following reason: $2', |
174 | 206 | |
| 207 | + |
175 | 208 | // List of global users |
176 | 209 | 'globalusers' => 'Global user list', |
177 | 210 | 'centralauth-listusers-locked' => 'locked', |
— | — | @@ -208,19 +241,21 @@ |
209 | 242 | 'centralauth-logout-progress' => 'Logging you out from other projects of {{int:Centralauth-groupname}}:', |
210 | 243 | 'centralauth-login-no-others' => 'You have been automatically logged into other projects of {{int:Centralauth-groupname}}.', |
211 | 244 | 'centralauth-logout-no-others' => 'You have been automatically logged out of other projects of {{int:Centralauth-groupname}}.', |
| 245 | + 'centralauth-hidden-blockreason' => 'globally hidden by $1 at $2 with following reason: $3', |
212 | 246 | |
213 | 247 | // Logging |
214 | 248 | 'centralauth-log-name' => 'Global account log', |
215 | 249 | 'centralauth-log-header' => 'This log contains operations under global accounts: deletions, locking and unlocking.', |
216 | | - 'centralauth-log-entry-delete' => 'deleted global account "<nowiki>$1</nowiki>"', |
217 | | - 'centralauth-log-entry-lock' => 'locked global account "<nowiki>$1</nowiki>"', |
218 | | - 'centralauth-log-entry-unlock' => 'unlocked global account "<nowiki>$1</nowiki>"', |
219 | | - 'centralauth-log-entry-hide' => 'hid global account "<nowiki>$1</nowiki>"', |
220 | | - 'centralauth-log-entry-unhide' => 'unhid global account "<nowiki>$1</nowiki>"', |
221 | | - 'centralauth-log-entry-lockandhide' => 'locked and hid global account "<nowiki>$1</nowiki>"', |
222 | | - 'centralauth-log-entry-chgstatus' => 'changed status for global account "<nowiki>$1</nowiki>": Set $2; Unset $3', |
223 | | - 'centralauth-log-status-locked' => 'locked', |
224 | | - 'centralauth-log-status-hidden' => 'hidden', |
| 250 | + 'centralauth-log-entry-delete' => 'deleted global account "$1"', |
| 251 | + 'centralauth-log-entry-lock' => 'locked global account "$1"', |
| 252 | + 'centralauth-log-entry-unlock' => 'unlocked global account "$1"', |
| 253 | + 'centralauth-log-entry-hide' => 'hid global account "$1"', |
| 254 | + 'centralauth-log-entry-unhide' => 'unhid global account "$1"', |
| 255 | + 'centralauth-log-entry-lockandhide' => 'locked and hid global account "$1"', |
| 256 | + 'centralauth-log-entry-chgstatus' => 'changed status for global account "$1": Set $2; Unset $3', |
| 257 | + 'centralauth-log-status-locked' => 'locked', |
| 258 | + 'centralauth-log-status-hidden' => 'hidden', |
| 259 | + 'centralauth-log-status-oversighted' => 'oversighted', |
225 | 260 | 'centralauth-log-status-none' => '(none)', |
226 | 261 | |
227 | 262 | 'centralauth-rightslog-name' => 'Global rights log', |
— | — | @@ -313,7 +348,9 @@ |
314 | 349 | |
315 | 350 | // User rights |
316 | 351 | 'right-globalgroupmembership' => 'Edit membership to global groups', |
317 | | - 'right-centralauth-admin' => 'Administrate global accounts', |
| 352 | + 'right-centralauth-unmerge' => 'Unmerge global account', |
| 353 | + 'right-centralauth-lock' => 'Lock or hide global account', |
| 354 | + 'right-centralauth-oversight' => 'Suppress global account', |
318 | 355 | 'right-centralauth-merge' => 'Merge their account', |
319 | 356 | 'right-globalgrouppermissions' => 'Manage global groups', |
320 | 357 | ); |
— | — | @@ -15853,6 +15890,7 @@ |
15854 | 15891 | 'centralauth-admin-status-submit' => 'Установить статус', |
15855 | 15892 | 'centralauth-admin-status-nonexistent' => 'Ошибка. Глобальной учётной записи «<nowiki>$1</nowiki>» не существует.', |
15856 | 15893 | 'centralauth-admin-setstatus-success' => 'Вы успешно изменили статус этой глобальной учётной записи.', |
| 15894 | + 'centralauth-admin-suppressreason' => 'Глобально скрыт $1 со следующим обоснованием: $2', |
15857 | 15895 | 'globalusers' => 'Глобальный список участников', |
15858 | 15896 | 'centralauth-listusers-locked' => 'заморозить', |
15859 | 15897 | 'centralauth-listusers-attached' => 'существует локально', |