Index: trunk/extensions/NssMySQLAuth/NssMySQLAuth.i18n.php |
— | — | @@ -0,0 +1,17 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$messages = array(); |
| 5 | + |
| 6 | +$messages['en'] = array( |
| 7 | + 'accountmanager' => 'Account manager', |
| 8 | + |
| 9 | + 'am-username' => 'username', |
| 10 | + 'am-email' => 'email', |
| 11 | + 'am-active' => 'active', |
| 12 | + |
| 13 | + 'nss-save-changes' => 'Save changes', |
| 14 | + 'nss-create-account-header' => 'Create new account', |
| 15 | + 'nss-create-account' => 'Create account', |
| 16 | + |
| 17 | + 'nss-db-error' => 'Error reading from authentication database' |
| 18 | +); |
Property changes on: trunk/extensions/NssMySQLAuth/NssMySQLAuth.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 19 | + native |
Index: trunk/extensions/NssMySQLAuth/NssMySQLAuthPlugin.php |
— | — | @@ -18,6 +18,8 @@ |
19 | 19 | $wgHooks['UserEffectiveGroups'][] = array( $wgAuth, 'onUserEffectiveGroups' ); |
20 | 20 | $wgHooks['UserGetEmail'][] = array( $wgAuth, 'onUserGetEmail' ); |
21 | 21 | $wgHooks['UserSetEmail'][] = array( $wgAuth, 'onUserSetEmail' ); |
| 22 | + |
| 23 | + wfLoadExtensionMessages( 'nssmysqlauth' ); |
22 | 24 | } |
23 | 25 | |
24 | 26 | function __construct( $wikiName = false ) { |
— | — | @@ -145,5 +147,40 @@ |
146 | 148 | __METHOD__ |
147 | 149 | ); |
148 | 150 | } |
| 151 | + |
| 152 | + /** |
| 153 | + * Create an account, returning a random password |
| 154 | + */ |
| 155 | + function createAccount( $username, $options ) { |
| 156 | + global $wgDefaultGid, $wgHomeDirectory; |
| 157 | + $password = User::randomPassword(); |
| 158 | + |
| 159 | + $insert = array( |
| 160 | + 'pwd_name' => strtolower( $username ), |
| 161 | + 'pwd_password' => Md5crypt::encryptPassword( $password ), |
| 162 | + 'pwd_password_lastchange' => wfTimestamp( TS_UNIX ), |
| 163 | + 'pwd_gid' => $wgDefaultGid, |
| 164 | + 'pwd_home' => str_replace( '$1', strtolower( $username ), $wgHomeDirectory ) |
| 165 | + ); |
| 166 | + |
| 167 | + // $options is something that is passed to user_props |
| 168 | + $insert['pwd_email'] = $options['email']; |
| 169 | + $insert['pwd_active'] = $options['active']; |
| 170 | + |
| 171 | + // Guess a nice uid. We actually need a lock here |
| 172 | + $dbw = $this->getDB( DB_MASTER ); |
| 173 | + $row = $dbw->selectRow( 'passwd', 'MAX(pwd_uid) + 1 AS uid', array(), __METHOD__ ); |
| 174 | + $uid = $row->uid; |
| 175 | + if ( function_exists( 'posix_getpwuid' ) ) { |
| 176 | + while( posix_getpwuid( $uid ) ) |
| 177 | + $uid++; |
| 178 | + } |
| 179 | + |
| 180 | + $insert['pwd_uid'] = $uid; |
| 181 | + |
| 182 | + $dbw->insert( 'passwd', $insert, __METHOD__ ); |
| 183 | + |
| 184 | + return $password; |
| 185 | + } |
149 | 186 | |
150 | 187 | } |
Index: trunk/extensions/NssMySQLAuth/NssMySQLAuth.php |
— | — | @@ -26,5 +26,10 @@ |
27 | 27 | |
28 | 28 | $wgExtensionFunctions[] = array( 'NssMySQLAuthPlugin', 'initialize' ); |
29 | 29 | |
| 30 | +$wgExtensionMessagesFiles['nssmysqlauth'] = dirname( __FILE__ ).'/NssMySQLAuth.i18n.php'; |
| 31 | + |
30 | 32 | $wgUserProperties = array( 'address', 'city' ); |
31 | 33 | $wgActivityModes = array( 'active', 'inactive' ); |
| 34 | + |
| 35 | +$wgDefaultGid = 1001; |
| 36 | +$wgHomeDirectory = '/home/$1'; |
\ No newline at end of file |
Index: trunk/extensions/NssMySQLAuth/Md5crypt.php |
— | — | @@ -75,7 +75,7 @@ |
76 | 76 | mt_srand((double)(microtime() * 10000000)); |
77 | 77 | |
78 | 78 | while(strlen($salt) < 8) { |
79 | | - $salt .= self::$itoa64{mt_rand(0, strlen($itoa64))}; |
| 79 | + $salt .= self::$itoa64{mt_rand(0, strlen(self::$itoa64))}; |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
Index: trunk/extensions/NssMySQLAuth/SpecialAccountManager.php |
— | — | @@ -3,6 +3,7 @@ |
4 | 4 | class SpecialAccountManager extends SpecialPage { |
5 | 5 | function __construct() { |
6 | 6 | parent::__construct( 'AccountManager', 'accountmanager', false ); |
| 7 | + $this->mErrors = array(); |
7 | 8 | } |
8 | 9 | |
9 | 10 | function execute() { |
— | — | @@ -10,16 +11,27 @@ |
11 | 12 | if( !$this->userCanExecute( $wgUser ) ) |
12 | 13 | return $this->displayRestrictionError(); |
13 | 14 | |
| 15 | + $this->setHeaders(); |
| 16 | + |
14 | 17 | $this->users = UserProps::fetchAllUsers(); |
15 | | - if( $this->processData() === true) |
| 18 | + if( $this->processData() === true ) |
16 | 19 | $this->showSuccess(); |
| 20 | + if( $this->processCreateAccount() === true ) |
| 21 | + $this->showSuccessCreate(); |
| 22 | + |
| 23 | + $this->showErrors(); |
| 24 | + |
17 | 25 | $this->constructForm(); |
| 26 | + $this->constructCreateForm(); |
18 | 27 | } |
19 | 28 | |
20 | 29 | function showSuccess() { |
21 | 30 | global $wgOut; |
22 | 31 | $wgOut->addHTML( Xml::element('p', array(), 'Your changes have been successfully updated' ) ); |
23 | 32 | } |
| 33 | + function showSuccessCreate() { |
| 34 | + return $this->showSuccess(); |
| 35 | + } |
24 | 36 | |
25 | 37 | function constructForm() { |
26 | 38 | global $wgOut, $wgScript; |
— | — | @@ -27,14 +39,19 @@ |
28 | 40 | |
29 | 41 | // TODO: wfMsg etc. |
30 | 42 | $wgOut->addHTML( Xml::openElement( 'form', array( |
31 | | - 'action' => $wgScript, |
| 43 | + 'action' => $this->getTitle()->getLocalURL(), |
32 | 44 | 'method' => 'post' ) |
33 | 45 | ) ); |
34 | 46 | |
35 | 47 | $wgOut->addHTML("<table id=\"userprops\" border=\"1\">\n\t<tr>". |
36 | | - "<th>Username</th><th>Email</th><th>Active</th>"); |
37 | | - foreach( $wgUserProperties as $i ) |
38 | | - $wgOut->addHTML( Xml::element( 'th', null, $i ) ); |
| 48 | + "<th>".wfMsgHtml( 'am-username' ). |
| 49 | + "</th><th>".wfMsgHtml( 'am-email' ). |
| 50 | + "</th><th>".wfMsgHtml( 'am-active' )."</th>"); |
| 51 | + foreach( $wgUserProperties as $i ) { |
| 52 | + $msg = 'am-'.$i; |
| 53 | + $wgOut->addHTML( Xml::element( 'th', null, |
| 54 | + wfEmptyMsg( $msg, wfMsg( $msg ) ) ? $i : wfMsgHtml( $msg ) ) ); |
| 55 | + } |
39 | 56 | $wgOut->addHTML("</tr>\n\n"); |
40 | 57 | |
41 | 58 | foreach( $this->users as $user ) { |
— | — | @@ -61,16 +78,58 @@ |
62 | 79 | |
63 | 80 | $wgOut->addHTML( "</table>\n" ); |
64 | 81 | $wgOut->addHTML( "<div id=\"userprops-submit\">\n". |
65 | | - Xml::hidden( 'title', 'Special:AccountManager' ). |
66 | 82 | Xml::hidden( 'action', 'submit' ). |
67 | 83 | Xml::element( 'input', array( |
68 | 84 | 'type' => 'submit', |
69 | | - 'value' => 'Save changes' |
| 85 | + 'value' => wfMsg( 'nss-save-changes' ) |
70 | 86 | ) ). |
71 | 87 | "</div>\n</form>" |
72 | 88 | ); |
73 | 89 | } |
| 90 | + |
| 91 | + function constructCreateForm() { |
| 92 | + global $wgOut, $wgScript; |
| 93 | + global $wgUserProperties, $wgActivityModes; |
74 | 94 | |
| 95 | + $wgOut->addHTML( Xml::openElement( 'form', array( |
| 96 | + 'action' => $this->getTitle()->getLocalURL(), |
| 97 | + 'method' => 'post' ) |
| 98 | + ) ); |
| 99 | + |
| 100 | + $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'nss-create-account-header' ) )."\n" ); |
| 101 | + |
| 102 | + $wgOut->addHTML( "<table border=\"1\" id=\"newuser\">\n" ); |
| 103 | + |
| 104 | + $props = array_merge( array( 'username', 'email' ), $wgUserProperties ); |
| 105 | + foreach( $props as $i ) { |
| 106 | + $msg = 'am-'.$i; |
| 107 | + $wgOut->addHTML( "\t<tr><th>". |
| 108 | + (wfEmptyMsg( $msg, wfMsg( $msg ) ) ? $i : wfMsgHtml( $msg )). |
| 109 | + "</th><td>".Xml::input( "am-{$i}", 40 ). |
| 110 | + "</td></tr>\n" |
| 111 | + ); |
| 112 | + } |
| 113 | + |
| 114 | + global $wgActivityModes; |
| 115 | + $select = new XmlSelect( "am-active" ); |
| 116 | + $select->setDefault( 'active' ); |
| 117 | + $select->setAttribute( 'width', '100%' ); |
| 118 | + foreach( $wgActivityModes as $key ) |
| 119 | + $select->addOption( $key ); |
| 120 | + $wgOut->addHTML( "\t<tr><th>".wfMsgHtml( 'am-active' ). |
| 121 | + "</th><td>".$select->getHTML()."</td></tr>\n" ); |
| 122 | + |
| 123 | + $wgOut->addHTML( "</table>\n" ); |
| 124 | + $wgOut->addHTML( "<div id=\"newaccount-submit\">\n". |
| 125 | + Xml::hidden( 'action', 'create' ). |
| 126 | + Xml::element( 'input', array( |
| 127 | + 'type' => 'submit', |
| 128 | + 'value' => wfMsg( 'nss-create-account' ) |
| 129 | + ) ). |
| 130 | + "</div>\n</form>" |
| 131 | + ); |
| 132 | + } |
| 133 | + |
75 | 134 | function processData() { |
76 | 135 | global $wgRequest, $wgUserProperties; |
77 | 136 | if( !$wgRequest->wasPosted() || $wgRequest->getVal('action') != 'submit' ) |
— | — | @@ -100,6 +159,57 @@ |
101 | 160 | $user->update(); |
102 | 161 | return true; |
103 | 162 | } |
| 163 | + |
| 164 | + function processCreateAccount() { |
| 165 | + global $wgRequest, $wgUserProperties; |
| 166 | + if( !$wgRequest->wasPosted() || $wgRequest->getVal('action') != 'create' ) |
| 167 | + return; |
| 168 | + |
| 169 | + $options = array(); |
| 170 | + |
| 171 | + $post = $wgRequest->getValues(); |
| 172 | + foreach( $post as $key => $value ) { |
| 173 | + if( substr( $key, 0, 3 ) != 'am-' ) |
| 174 | + continue; |
| 175 | + $parts = explode( '-', $key, 2 ); |
| 176 | + if( count( $parts ) != 2 ) |
| 177 | + continue; |
| 178 | + |
| 179 | + $keyname = strtolower( $parts[1] ); |
| 180 | + $options[$keyname] = $value; |
| 181 | + } |
| 182 | + if( empty( $options['username'] ) ) { |
| 183 | + $this->mErrors[] = 'noname'; |
| 184 | + return false; |
| 185 | + } |
| 186 | + $username = $options['username']; |
| 187 | + unset( $options['username'] ); |
| 188 | + |
| 189 | + global $wgAuth; |
| 190 | + $password = $wgAuth->createAccount($username, $options); |
| 191 | + |
| 192 | + $user = UserProps::loadFromDb( $username ); |
| 193 | + if ( !$user ) { |
| 194 | + $this->mErrors[] = 'nss-db-error'; |
| 195 | + return false; |
| 196 | + } |
| 197 | + $this->users[$user->getName()] = $user; |
| 198 | + |
| 199 | + return true; |
| 200 | + } |
| 201 | + |
| 202 | + function showErrors() { |
| 203 | + if ( !$this->mErrors ) |
| 204 | + return; |
| 205 | + global $wgOut; |
| 206 | + foreach( $this->mErrors as $error ) |
| 207 | + $wgOut->addHTML( |
| 208 | + Xml::element( 'p', |
| 209 | + array( 'class' => 'error' ), |
| 210 | + wfMsg( $error ) |
| 211 | + )."\n" |
| 212 | + ); |
| 213 | + } |
104 | 214 | } |
105 | 215 | |
106 | 216 | class UserProps { |
— | — | @@ -114,6 +224,14 @@ |
115 | 225 | $res->free(); |
116 | 226 | return $users; |
117 | 227 | } |
| 228 | + static function loadFromDb( $username ) { |
| 229 | + $res = self::select( $username ); |
| 230 | + $row = $res->fetchObject(); |
| 231 | + if ( !$row ) |
| 232 | + return false; |
| 233 | + return new self( $row->pwd_name, $row->pwd_email, $row->pwd_active ); |
| 234 | + } |
| 235 | + |
118 | 236 | function __construct( $username, $email = null, $active = null ) { |
119 | 237 | $this->username = $username; |
120 | 238 | $this->props = array(); |
— | — | @@ -142,16 +260,15 @@ |
143 | 261 | static function select($username = null) { |
144 | 262 | global $wgAuth; |
145 | 263 | $dbr = $wgAuth->getDB( DB_READ ); |
146 | | - $join = is_null( $username ) ? 'RIGHT JOIN' : 'JOIN'; |
147 | | - $where = is_null( $username ) ? array() : array( 'up_user' => $username ); |
| 264 | + $where = is_null( $username ) ? array() : array( 'pwd_name' => $username ); |
148 | 265 | |
149 | 266 | return $dbr->select( |
150 | 267 | array( 'user_props', 'passwd' ), |
151 | 268 | array( 'up_name', 'up_value', 'pwd_name', 'pwd_email', 'pwd_active' ), |
152 | 269 | $where, |
153 | 270 | __METHOD__, |
154 | | - array( 'ORDER BY' => 'up_timestamp DESC', 'DISTINCT' ), |
155 | | - array( 'passwd' => array( $join, 'pwd_name = up_user' ) ) |
| 271 | + array( 'ORDER BY' => 'pwd_name ASC, up_timestamp ASC' ), |
| 272 | + array( 'passwd' => array( 'RIGHT JOIN', 'pwd_name = up_user' ) ) |
156 | 273 | ); |
157 | 274 | } |
158 | 275 | |