Index: trunk/phase3/includes/User.php |
— | — | @@ -206,7 +206,6 @@ |
207 | 207 | # Can't load from ID, user is anonymous |
208 | 208 | return false; |
209 | 209 | } |
210 | | - |
211 | 210 | $this->saveToCache(); |
212 | 211 | } else { |
213 | 212 | wfDebug( "Got user {$this->mId} from cache\n" ); |
— | — | @@ -223,6 +222,7 @@ |
224 | 223 | */ |
225 | 224 | function saveToCache() { |
226 | 225 | $this->load(); |
| 226 | + $this->loadGroups(); |
227 | 227 | if ( $this->isAnon() ) { |
228 | 228 | // Anonymous users are uncached |
229 | 229 | return; |
— | — | @@ -314,6 +314,16 @@ |
315 | 315 | } |
316 | 316 | |
317 | 317 | /** |
| 318 | + * Create a new user object from a user row. |
| 319 | + * The row should have all fields from the user table in it. |
| 320 | + */ |
| 321 | + static function newFromRow( $row ) { |
| 322 | + $user = new User; |
| 323 | + $user->loadFromRow( $row ); |
| 324 | + return $user; |
| 325 | + } |
| 326 | + |
| 327 | + /** |
318 | 328 | * Get username given an id. |
319 | 329 | * @param integer $id Database user id |
320 | 330 | * @return string Nickname of a user |
— | — | @@ -788,23 +798,50 @@ |
789 | 799 | |
790 | 800 | if ( $s !== false ) { |
791 | 801 | # Initialise user table data |
792 | | - $this->mName = $s->user_name; |
793 | | - $this->mRealName = $s->user_real_name; |
794 | | - $this->mPassword = $s->user_password; |
795 | | - $this->mNewpassword = $s->user_newpassword; |
796 | | - $this->mNewpassTime = wfTimestampOrNull( TS_MW, $s->user_newpass_time ); |
797 | | - $this->mEmail = $s->user_email; |
798 | | - $this->decodeOptions( $s->user_options ); |
799 | | - $this->mTouched = wfTimestamp(TS_MW,$s->user_touched); |
800 | | - $this->mToken = $s->user_token; |
801 | | - $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $s->user_email_authenticated ); |
802 | | - $this->mEmailToken = $s->user_email_token; |
803 | | - $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $s->user_email_token_expires ); |
804 | | - $this->mRegistration = wfTimestampOrNull( TS_MW, $s->user_registration ); |
805 | | - $this->mEditCount = $s->user_editcount; |
| 802 | + $this->loadFromRow( $s ); |
| 803 | + $this->mGroups = null; // deferred |
806 | 804 | $this->getEditCount(); // revalidation for nulls |
| 805 | + return true; |
| 806 | + } else { |
| 807 | + # Invalid user_id |
| 808 | + $this->mId = 0; |
| 809 | + $this->loadDefaults(); |
| 810 | + return false; |
| 811 | + } |
| 812 | + } |
807 | 813 | |
808 | | - # Load group data |
| 814 | + /** |
| 815 | + * Initialise the user object from a row from the user table |
| 816 | + */ |
| 817 | + function loadFromRow( $row ) { |
| 818 | + $this->mDataLoaded = true; |
| 819 | + |
| 820 | + if ( isset( $row->user_id ) ) { |
| 821 | + $this->mId = $row->user_id; |
| 822 | + } |
| 823 | + $this->mName = $row->user_name; |
| 824 | + $this->mRealName = $row->user_real_name; |
| 825 | + $this->mPassword = $row->user_password; |
| 826 | + $this->mNewpassword = $row->user_newpassword; |
| 827 | + $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time ); |
| 828 | + $this->mEmail = $row->user_email; |
| 829 | + $this->decodeOptions( $row->user_options ); |
| 830 | + $this->mTouched = wfTimestamp(TS_MW,$row->user_touched); |
| 831 | + $this->mToken = $row->user_token; |
| 832 | + $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated ); |
| 833 | + $this->mEmailToken = $row->user_email_token; |
| 834 | + $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires ); |
| 835 | + $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration ); |
| 836 | + $this->mEditCount = $row->user_editcount; |
| 837 | + } |
| 838 | + |
| 839 | + /** |
| 840 | + * Load the groups from the database if they aren't already loaded |
| 841 | + * @private |
| 842 | + */ |
| 843 | + function loadGroups() { |
| 844 | + if ( is_null( $this->mGroups ) ) { |
| 845 | + $dbr = wfGetDB( DB_MASTER ); |
809 | 846 | $res = $dbr->select( 'user_groups', |
810 | 847 | array( 'ug_group' ), |
811 | 848 | array( 'ug_user' => $this->mId ), |
— | — | @@ -813,12 +850,6 @@ |
814 | 851 | while( $row = $dbr->fetchObject( $res ) ) { |
815 | 852 | $this->mGroups[] = $row->ug_group; |
816 | 853 | } |
817 | | - return true; |
818 | | - } else { |
819 | | - # Invalid user_id |
820 | | - $this->mId = 0; |
821 | | - $this->loadDefaults(); |
822 | | - return false; |
823 | 854 | } |
824 | 855 | } |
825 | 856 | |
— | — | @@ -1529,17 +1560,20 @@ |
1530 | 1561 | |
1531 | 1562 | function getEmail() { |
1532 | 1563 | $this->load(); |
| 1564 | + wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) ); |
1533 | 1565 | return $this->mEmail; |
1534 | 1566 | } |
1535 | 1567 | |
1536 | 1568 | function getEmailAuthenticationTimestamp() { |
1537 | 1569 | $this->load(); |
| 1570 | + wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) ); |
1538 | 1571 | return $this->mEmailAuthenticated; |
1539 | 1572 | } |
1540 | 1573 | |
1541 | 1574 | function setEmail( $str ) { |
1542 | 1575 | $this->load(); |
1543 | 1576 | $this->mEmail = $str; |
| 1577 | + wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) ); |
1544 | 1578 | } |
1545 | 1579 | |
1546 | 1580 | function getRealName() { |
— | — | @@ -1657,10 +1691,9 @@ |
1658 | 1692 | */ |
1659 | 1693 | function getEffectiveGroups( $recache = false ) { |
1660 | 1694 | if ( $recache || is_null( $this->mEffectiveGroups ) ) { |
1661 | | - $this->load(); |
1662 | | - $this->mEffectiveGroups = $this->mGroups; |
| 1695 | + $this->mEffectiveGroups = $this->getGroups(); |
1663 | 1696 | $this->mEffectiveGroups[] = '*'; |
1664 | | - if( $this->mId ) { |
| 1697 | + if( $this->getId() ) { |
1665 | 1698 | $this->mEffectiveGroups[] = 'user'; |
1666 | 1699 | |
1667 | 1700 | $this->mEffectiveGroups = array_unique( array_merge( |
— | — | @@ -1695,7 +1728,6 @@ |
1696 | 1729 | * @param string $group |
1697 | 1730 | */ |
1698 | 1731 | function addGroup( $group ) { |
1699 | | - $this->load(); |
1700 | 1732 | $dbw = wfGetDB( DB_MASTER ); |
1701 | 1733 | if( $this->getId() ) { |
1702 | 1734 | $dbw->insert( 'user_groups', |
— | — | @@ -1707,6 +1739,7 @@ |
1708 | 1740 | array( 'IGNORE' ) ); |
1709 | 1741 | } |
1710 | 1742 | |
| 1743 | + $this->loadGroups(); |
1711 | 1744 | $this->mGroups[] = $group; |
1712 | 1745 | $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) ); |
1713 | 1746 | |
— | — | @@ -1728,6 +1761,7 @@ |
1729 | 1762 | ), |
1730 | 1763 | 'User::removeGroup' ); |
1731 | 1764 | |
| 1765 | + $this->loadGroups(); |
1732 | 1766 | $this->mGroups = array_diff( $this->mGroups, array( $group ) ); |
1733 | 1767 | $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups( true ) ); |
1734 | 1768 | |
— | — | @@ -2044,10 +2078,10 @@ |
2045 | 2079 | 'user_id' => $this->mId |
2046 | 2080 | ), __METHOD__ |
2047 | 2081 | ); |
| 2082 | + wfRunHooks( 'UserSaveSettings', array( $this ) ); |
2048 | 2083 | $this->clearSharedCache(); |
2049 | 2084 | } |
2050 | 2085 | |
2051 | | - |
2052 | 2086 | /** |
2053 | 2087 | * Checks if a user with the given name exists, returns the ID. |
2054 | 2088 | */ |
— | — | @@ -2398,6 +2432,9 @@ |
2399 | 2433 | * Generate a new e-mail confirmation token and send a confirmation/invalidation |
2400 | 2434 | * mail to the user's given address. |
2401 | 2435 | * |
| 2436 | + * Call saveSettings() after calling this function to commit the confirmation |
| 2437 | + * token to the database. |
| 2438 | + * |
2402 | 2439 | * @return mixed True on success, a WikiError object on failure. |
2403 | 2440 | */ |
2404 | 2441 | function sendConfirmationMail() { |
— | — | @@ -2438,6 +2475,10 @@ |
2439 | 2476 | /** |
2440 | 2477 | * Generate, store, and return a new e-mail confirmation code. |
2441 | 2478 | * A hash (unsalted since it's used as a key) is stored. |
| 2479 | + * |
| 2480 | + * Call saveSettings() after calling this function to commit |
| 2481 | + * this change to the database. |
| 2482 | + * |
2442 | 2483 | * @param &$expiration mixed output: accepts the expiration time |
2443 | 2484 | * @return string |
2444 | 2485 | * @private |
— | — | @@ -2451,7 +2492,6 @@ |
2452 | 2493 | $this->load(); |
2453 | 2494 | $this->mEmailToken = $hash; |
2454 | 2495 | $this->mEmailTokenExpires = $expiration; |
2455 | | - $this->saveSettings(); |
2456 | 2496 | return $token; |
2457 | 2497 | } |
2458 | 2498 | |
— | — | @@ -2477,28 +2517,35 @@ |
2478 | 2518 | } |
2479 | 2519 | |
2480 | 2520 | /** |
2481 | | - * Mark the e-mail address confirmed and save. |
| 2521 | + * Mark the e-mail address confirmed. |
| 2522 | + * |
| 2523 | + * Call saveSettings() after calling this function to commit the change. |
2482 | 2524 | */ |
2483 | 2525 | function confirmEmail() { |
2484 | | - $this->load(); |
2485 | | - $this->mEmailAuthenticated = wfTimestampNow(); |
2486 | | - $this->saveSettings(); |
| 2526 | + $this->setEmailAuthenticationTimestamp( wfTimestampNow() ); |
2487 | 2527 | return true; |
2488 | 2528 | } |
2489 | 2529 | |
2490 | 2530 | /** |
2491 | 2531 | * Invalidate the user's email confirmation, unauthenticate the email |
2492 | | - * if it was already confirmed and save. |
| 2532 | + * if it was already confirmed. |
| 2533 | + * |
| 2534 | + * Call saveSettings() after calling this function to commit the change. |
2493 | 2535 | */ |
2494 | 2536 | function invalidateEmail() { |
2495 | 2537 | $this->load(); |
2496 | 2538 | $this->mEmailToken = null; |
2497 | 2539 | $this->mEmailTokenExpires = null; |
2498 | | - $this->mEmailAuthenticated = null; |
2499 | | - $this->saveSettings(); |
| 2540 | + $this->setEmailAuthenticationTimestamp( null ); |
2500 | 2541 | return true; |
2501 | 2542 | } |
2502 | 2543 | |
| 2544 | + function setEmailAuthenticationTimestamp( $timestamp ) { |
| 2545 | + $this->load(); |
| 2546 | + $this->mEmailAuthenticated = $timestamp; |
| 2547 | + wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) ); |
| 2548 | + } |
| 2549 | + |
2503 | 2550 | /** |
2504 | 2551 | * Is this user allowed to send e-mails within limits of current |
2505 | 2552 | * site configuration? |
Index: trunk/phase3/includes/SpecialUserlogin.php |
— | — | @@ -158,8 +158,7 @@ |
159 | 159 | if( $wgLoginLanguageSelector && $this->mLanguage ) |
160 | 160 | $u->setOption( 'language', $this->mLanguage ); |
161 | 161 | |
162 | | - # Save user settings and send out an email authentication message if needed |
163 | | - $u->saveSettings(); |
| 162 | + # Send out an email authentication message if needed |
164 | 163 | if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) { |
165 | 164 | global $wgOut; |
166 | 165 | $error = $u->sendConfirmationMail(); |
— | — | @@ -170,6 +169,9 @@ |
171 | 170 | } |
172 | 171 | } |
173 | 172 | |
| 173 | + # Save settings (including confirmation token) |
| 174 | + $u->saveSettings(); |
| 175 | + |
174 | 176 | # If not logged in, assume the new account as the current one and set session cookies |
175 | 177 | # then show a "welcome" message or a "need cookies" message as needed |
176 | 178 | if( $wgUser->isAnon() ) { |
— | — | @@ -420,6 +422,7 @@ |
421 | 423 | // |
422 | 424 | if( !$u->isEmailConfirmed() ) { |
423 | 425 | $u->confirmEmail(); |
| 426 | + $u->saveSettings(); |
424 | 427 | } |
425 | 428 | |
426 | 429 | // At this point we just return an appropriate code |
Index: trunk/phase3/includes/UserMailer.php |
— | — | @@ -362,16 +362,17 @@ |
363 | 363 | } |
364 | 364 | $dbr = wfGetDB( DB_SLAVE ); |
365 | 365 | |
366 | | - $res = $dbr->select( 'watchlist', array( 'wl_user' ), |
| 366 | + $res = $dbr->select( array( 'watchlist', 'user' ), array( 'user.*' ), |
367 | 367 | array( |
| 368 | + 'wl_user=user_id', |
368 | 369 | 'wl_title' => $title->getDBkey(), |
369 | 370 | 'wl_namespace' => $title->getNamespace(), |
370 | 371 | $userCondition, |
371 | 372 | 'wl_notificationtimestamp IS NULL', |
372 | 373 | ), __METHOD__ ); |
| 374 | + $userArray = UserArray::newFromResult( $res ); |
373 | 375 | |
374 | | - foreach ( $res as $row ) { |
375 | | - $watchingUser = User::newFromId( $row->wl_user ); |
| 376 | + foreach ( $userArray as $watchingUser ) { |
376 | 377 | if ( $watchingUser->getOption( 'enotifwatchlistpages' ) && |
377 | 378 | ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) && |
378 | 379 | $watchingUser->isEmailConfirmed() ) |
Index: trunk/phase3/includes/SpecialConfirmemail.php |
— | — | @@ -84,15 +84,13 @@ |
85 | 85 | global $wgUser, $wgOut; |
86 | 86 | $user = User::newFromConfirmationCode( $code ); |
87 | 87 | if( is_object( $user ) ) { |
88 | | - if( $user->confirmEmail() ) { |
89 | | - $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; |
90 | | - $wgOut->addWikiMsg( $message ); |
91 | | - if( !$wgUser->isLoggedIn() ) { |
92 | | - $title = SpecialPage::getTitleFor( 'Userlogin' ); |
93 | | - $wgOut->returnToMain( true, $title->getPrefixedText() ); |
94 | | - } |
95 | | - } else { |
96 | | - $wgOut->addWikiMsg( 'confirmemail_error' ); |
| 88 | + $user->confirmEmail(); |
| 89 | + $user->saveSettings(); |
| 90 | + $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; |
| 91 | + $wgOut->addWikiMsg( $message ); |
| 92 | + if( !$wgUser->isLoggedIn() ) { |
| 93 | + $title = SpecialPage::getTitleFor( 'Userlogin' ); |
| 94 | + $wgOut->returnToMain( true, $title->getPrefixedText() ); |
97 | 95 | } |
98 | 96 | } else { |
99 | 97 | $wgOut->addWikiMsg( 'confirmemail_invalid' ); |
— | — | @@ -129,13 +127,10 @@ |
130 | 128 | $user = User::newFromConfirmationCode( $code ); |
131 | 129 | if( is_object( $user ) ) { |
132 | 130 | $user->invalidateEmail(); |
133 | | - if( $user->invalidateEmail() ) { |
134 | | - $wgOut->addWikiMsg( 'confirmemail_invalidated' ); |
135 | | - if( !$wgUser->isLoggedIn() ) { |
136 | | - $wgOut->returnToMain(); |
137 | | - } |
138 | | - } else { |
139 | | - $wgOut->addWikiMsg( 'confirmemail_error' ); |
| 131 | + $user->saveSettings(); |
| 132 | + $wgOut->addWikiMsg( 'confirmemail_invalidated' ); |
| 133 | + if( !$wgUser->isLoggedIn() ) { |
| 134 | + $wgOut->returnToMain(); |
140 | 135 | } |
141 | 136 | } else { |
142 | 137 | $wgOut->addWikiMsg( 'confirmemail_invalid' ); |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -266,6 +266,7 @@ |
267 | 267 | 'UploadForm' => 'includes/SpecialUpload.php', |
268 | 268 | 'UploadFormMogile' => 'includes/SpecialUploadMogile.php', |
269 | 269 | 'User' => 'includes/User.php', |
| 270 | + 'UserArray' => 'includes/UserArray.php', |
270 | 271 | 'UserMailer' => 'includes/UserMailer.php', |
271 | 272 | 'UserrightsPage' => 'includes/SpecialUserrights.php', |
272 | 273 | 'UserRightsProxy' => 'includes/UserRightsProxy.php', |
Index: trunk/phase3/includes/SpecialPreferences.php |
— | — | @@ -310,8 +310,10 @@ |
311 | 311 | if( ($newadr != '') && ($newadr != $oldadr) ) { |
312 | 312 | # the user has supplied a new email address on the login page |
313 | 313 | if( $wgUser->isValidEmailAddr( $newadr ) ) { |
314 | | - $wgUser->mEmail = $newadr; # new behaviour: set this new emailaddr from login-page into user database record |
315 | | - $wgUser->mEmailAuthenticated = null; # but flag as "dirty" = unauthenticated |
| 314 | + # new behaviour: set this new emailaddr from login-page into user database record |
| 315 | + $wgUser->setEmail( $newadr ); |
| 316 | + # but flag as "dirty" = unauthenticated |
| 317 | + $wgUser->invalidateEmail(); |
316 | 318 | if ($wgEmailAuthentication) { |
317 | 319 | # Mail a temporary password to the dirty address. |
318 | 320 | # User can come back through the confirmation URL to re-enable email. |
Index: trunk/phase3/includes/UserArray.php |
— | — | @@ -0,0 +1,62 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +abstract class UserArray implements Iterator { |
| 5 | + static function newFromResult( $res ) { |
| 6 | + $userArray = null; |
| 7 | + if ( !wfRunHooks( 'UserArrayFromResult', array( &$userArray, $res ) ) ) { |
| 8 | + return null; |
| 9 | + } |
| 10 | + if ( $userArray === null ) { |
| 11 | + $userArray = self::newFromResult_internal( $res ); |
| 12 | + } |
| 13 | + return $userArray; |
| 14 | + } |
| 15 | + |
| 16 | + protected static function newFromResult_internal( $res ) { |
| 17 | + $userArray = new UserArrayFromResult( $res ); |
| 18 | + return $userArray; |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +class UserArrayFromResult extends UserArray { |
| 23 | + var $res; |
| 24 | + var $key, $current; |
| 25 | + |
| 26 | + function __construct( $res ) { |
| 27 | + $this->res = $res; |
| 28 | + $this->key = 0; |
| 29 | + $this->setCurrent( $this->res->current() ); |
| 30 | + } |
| 31 | + |
| 32 | + protected function setCurrent( $row ) { |
| 33 | + if ( $row === false ) { |
| 34 | + $this->current = false; |
| 35 | + } else { |
| 36 | + $this->current = User::newFromRow( $row ); |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + function current() { |
| 41 | + return $this->current; |
| 42 | + } |
| 43 | + |
| 44 | + function key() { |
| 45 | + return $this->key; |
| 46 | + } |
| 47 | + |
| 48 | + function next() { |
| 49 | + $row = $this->res->next(); |
| 50 | + $this->setCurrent( $row ); |
| 51 | + $this->key++; |
| 52 | + } |
| 53 | + |
| 54 | + function rewind() { |
| 55 | + $this->res->rewind(); |
| 56 | + $this->key = 0; |
| 57 | + $this->setCurrent( $this->res->current() ); |
| 58 | + } |
| 59 | + |
| 60 | + function valid() { |
| 61 | + return $this->current !== false; |
| 62 | + } |
| 63 | +} |
Property changes on: trunk/phase3/includes/UserArray.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 64 | + native |