/[drupal]/drupal/modules/user/user.install
ViewVC logotype

Contents of /drupal/modules/user/user.install

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.31 - (show annotations) (download) (as text)
Sun Oct 18 06:56:24 2009 UTC (5 weeks, 5 days ago) by webchick
Branch: MAIN
CVS Tags: DRUPAL-7-0-UNSTABLE-10, HEAD
Changes since 1.30: +3 -2 lines
File MIME type: text/x-php
#356074 by chx and Damien Tournoud: Provide a sequences API. Gets rid of stupid tables that only contain an incrementing ID, and fixes database import problems due to user ID 0.
1 <?php
2 // $Id: user.install,v 1.30 2009/09/29 15:13:57 dries Exp $
3
4 /**
5 * @file
6 * Install, update and uninstall functions for the user module.
7 */
8
9 /**
10 * Implement hook_schema().
11 */
12 function user_schema() {
13 $schema['authmap'] = array(
14 'description' => 'Stores distributed authentication mapping.',
15 'fields' => array(
16 'aid' => array(
17 'description' => 'Primary Key: Unique authmap ID.',
18 'type' => 'serial',
19 'unsigned' => TRUE,
20 'not null' => TRUE,
21 ),
22 'uid' => array(
23 'type' => 'int',
24 'not null' => TRUE,
25 'default' => 0,
26 'description' => "User's {users}.uid.",
27 ),
28 'authname' => array(
29 'type' => 'varchar',
30 'length' => 128,
31 'not null' => TRUE,
32 'default' => '',
33 'description' => 'Unique authentication name.',
34 ),
35 'module' => array(
36 'type' => 'varchar',
37 'length' => 128,
38 'not null' => TRUE,
39 'default' => '',
40 'description' => 'Module which is controlling the authentication.',
41 ),
42 ),
43 'unique keys' => array(
44 'authname' => array('authname'),
45 ),
46 'primary key' => array('aid'),
47 'foreign keys' => array(
48 'uid' => array('users' => 'uid'),
49 ),
50 );
51
52 $schema['role_permission'] = array(
53 'description' => 'Stores the permissions assigned to user roles.',
54 'fields' => array(
55 'rid' => array(
56 'type' => 'int',
57 'unsigned' => TRUE,
58 'not null' => TRUE,
59 'description' => 'Foreign Key: {role}.rid.',
60 ),
61 'permission' => array(
62 'type' => 'varchar',
63 'length' => 64,
64 'not null' => TRUE,
65 'default' => '',
66 'description' => 'A single permission granted to the role identified by rid.',
67 ),
68 ),
69 'primary key' => array('rid', 'permission'),
70 'indexes' => array(
71 'permission' => array('permission'),
72 ),
73 'foreign keys' => array(
74 'rid' => array('role' => 'rid'),
75 ),
76 );
77
78 $schema['role'] = array(
79 'description' => 'Stores user roles.',
80 'fields' => array(
81 'rid' => array(
82 'type' => 'serial',
83 'unsigned' => TRUE,
84 'not null' => TRUE,
85 'description' => 'Primary Key: Unique role ID.',
86 ),
87 'name' => array(
88 'type' => 'varchar',
89 'length' => 64,
90 'not null' => TRUE,
91 'default' => '',
92 'description' => 'Unique role name.',
93 ),
94 ),
95 'unique keys' => array(
96 'name' => array('name'),
97 ),
98 'primary key' => array('rid'),
99 );
100
101 $schema['users'] = array(
102 'description' => 'Stores user data.',
103 'fields' => array(
104 'uid' => array(
105 'type' => 'int',
106 'unsigned' => TRUE,
107 'not null' => TRUE,
108 'description' => 'Primary Key: Unique user ID.',
109 'default' => 0,
110 ),
111 'name' => array(
112 'type' => 'varchar',
113 'length' => 60,
114 'not null' => TRUE,
115 'default' => '',
116 'description' => 'Unique user name.',
117 ),
118 'pass' => array(
119 'type' => 'varchar',
120 'length' => 128,
121 'not null' => TRUE,
122 'default' => '',
123 'description' => "User's password (hashed).",
124 ),
125 'mail' => array(
126 'type' => 'varchar',
127 'length' => 64,
128 'not null' => FALSE,
129 'default' => '',
130 'description' => "User's email address.",
131 ),
132 'theme' => array(
133 'type' => 'varchar',
134 'length' => 255,
135 'not null' => TRUE,
136 'default' => '',
137 'description' => "User's default theme.",
138 ),
139 'signature' => array(
140 'type' => 'varchar',
141 'length' => 255,
142 'not null' => TRUE,
143 'default' => '',
144 'description' => "User's signature.",
145 ),
146 'created' => array(
147 'type' => 'int',
148 'not null' => TRUE,
149 'default' => 0,
150 'description' => 'Timestamp for when user was created.',
151 ),
152 'access' => array(
153 'type' => 'int',
154 'not null' => TRUE,
155 'default' => 0,
156 'description' => 'Timestamp for previous time user accessed the site.',
157 ),
158 'login' => array(
159 'type' => 'int',
160 'not null' => TRUE,
161 'default' => 0,
162 'description' => "Timestamp for user's last login.",
163 ),
164 'status' => array(
165 'type' => 'int',
166 'not null' => TRUE,
167 'default' => 0,
168 'size' => 'tiny',
169 'description' => 'Whether the user is active(1) or blocked(0).',
170 ),
171 'timezone' => array(
172 'type' => 'varchar',
173 'length' => 32,
174 'not null' => FALSE,
175 'description' => "User's time zone.",
176 ),
177 'language' => array(
178 'type' => 'varchar',
179 'length' => 12,
180 'not null' => TRUE,
181 'default' => '',
182 'description' => "User's default language.",
183 ),
184 'picture' => array(
185 'type' => 'int',
186 'not null' => TRUE,
187 'default' => 0,
188 'description' => "Foreign key: {file}.fid of user's picture.",
189 ),
190 'init' => array(
191 'type' => 'varchar',
192 'length' => 64,
193 'not null' => FALSE,
194 'default' => '',
195 'description' => 'Email address used for initial account creation.',
196 ),
197 'data' => array(
198 'type' => 'text',
199 'not null' => FALSE,
200 'size' => 'big',
201 'serialize' => TRUE,
202 'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.',
203 ),
204 ),
205 'indexes' => array(
206 'access' => array('access'),
207 'created' => array('created'),
208 'mail' => array('mail'),
209 ),
210 'unique keys' => array(
211 'name' => array('name'),
212 ),
213 'primary key' => array('uid'),
214 );
215
216 $schema['users_roles'] = array(
217 'description' => 'Maps users to roles.',
218 'fields' => array(
219 'uid' => array(
220 'type' => 'int',
221 'unsigned' => TRUE,
222 'not null' => TRUE,
223 'default' => 0,
224 'description' => 'Primary Key: {users}.uid for user.',
225 ),
226 'rid' => array(
227 'type' => 'int',
228 'unsigned' => TRUE,
229 'not null' => TRUE,
230 'default' => 0,
231 'description' => 'Primary Key: {role}.rid for role.',
232 ),
233 ),
234 'primary key' => array('uid', 'rid'),
235 'indexes' => array(
236 'rid' => array('rid'),
237 ),
238 'foreign keys' => array(
239 'uid' => array('users' => 'uid'),
240 'rid' => array('role' => 'rid'),
241 ),
242 );
243
244 return $schema;
245 }
246
247 /**
248 * @defgroup user-updates-6.x-to-7.x User updates from 6.x to 7.x
249 * @{
250 */
251
252 /**
253 * Increase the length of the password field to accommodate better hashes.
254 *
255 * Also re-hashes all current passwords to improve security. This may be a
256 * lengthy process, and is performed batch-wise.
257 */
258 function user_update_7000(&$sandbox) {
259 $sandbox['#finished'] = 0;
260 // Lower than DRUPAL_HASH_COUNT to make the update run at a reasonable speed.
261 $hash_count_log2 = 11;
262 // Multi-part update.
263 if (!isset($sandbox['user_from'])) {
264 db_change_field('users', 'pass', 'pass', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
265 $sandbox['user_from'] = 0;
266 $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
267 }
268 else {
269 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
270 // Hash again all current hashed passwords.
271 $has_rows = FALSE;
272 // Update this many per page load.
273 $count = 1000;
274 $result = db_query_range("SELECT uid, pass FROM {users} WHERE uid > 0 ORDER BY uid", $sandbox['user_from'], $count);
275 foreach ($result as $account) {
276 $has_rows = TRUE;
277 $new_hash = user_hash_password($account->pass, $hash_count_log2);
278 if ($new_hash) {
279 // Indicate an updated password.
280 $new_hash = 'U' . $new_hash;
281 db_update('users')
282 ->fields(array('pass' => $new_hash))
283 ->condition('uid', $account->uid)
284 ->execute();
285 }
286 }
287 $sandbox['#finished'] = $sandbox['user_from']/$sandbox['user_count'];
288 $sandbox['user_from'] += $count;
289 if (!$has_rows) {
290 $sandbox['#finished'] = 1;
291 return t('User passwords rehashed to improve security');
292 }
293 }
294 }
295
296 /**
297 * Remove the 'threshold', 'mode' and 'sort' columns from the {users} table.
298 *
299 * These fields were previously used to store per-user comment settings.
300 */
301
302 function user_update_7001() {
303 db_drop_field('users', 'threshold');
304 db_drop_field('users', 'mode');
305 db_drop_field('users', 'sort');
306 }
307
308 /**
309 * Convert user time zones from time zone offsets to time zone names.
310 */
311 function user_update_7002(&$sandbox) {
312 $sandbox['#finished'] = 0;
313
314 // Multi-part update.
315 if (!isset($sandbox['user_from'])) {
316 db_change_field('users', 'timezone', 'timezone', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE));
317 $sandbox['user_from'] = 0;
318 $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
319 $sandbox['user_not_migrated'] = 0;
320 }
321 else {
322 $timezones = system_time_zones();
323 // Update this many per page load.
324 $count = 10000;
325 $contributed_date_module = db_column_exists('users', 'timezone_name');
326 $contributed_event_module = db_column_exists('users', 'timezone_id');
327
328 $results = db_query_range("SELECT uid FROM {users} ORDER BY uid", $sandbox['user_from'], $count);
329 foreach ($results as $account) {
330 $timezone = NULL;
331 // If the contributed Date module has created a users.timezone_name
332 // column, use this data to set each user's time zone.
333 if ($contributed_date_module) {
334 $date_timezone = db_query("SELECT timezone_name FROM {users} WHERE uid = :uid", array(':uid' => $account->uid))->fetchField();
335 if (isset($timezones[$date_timezone])) {
336 $timezone = $date_timezone;
337 }
338 }
339 // If the contributed Event module has stored user time zone information
340 // use that information to update the user accounts.
341 if (!$timezone && $contributed_event_module) {
342 try {
343 $event_timezone = db_query("SELECT t.name FROM {users} u LEFT JOIN {event_timezones} t ON u.timezone_id = t.timezone WHERE u.uid = :uid", array(':uid' => $account->uid))->fetchField();
344 $event_timezone = str_replace(' ', '_', $event_timezone);
345 if (isset($timezones[$event_timezone])) {
346 $timezone = $event_timezone;
347 }
348 }
349 catch (PDOException $e) {
350 // Ignore error if event_timezones table does not exist or unexpected
351 // schema found.
352 }
353 }
354 if ($timezone) {
355 db_update('users')
356 ->fields(array('timezone' => $timezone))
357 ->condition('uid', $account->uid)
358 ->execute();
359 }
360 else {
361 $sandbox['user_not_migrated']++;
362 db_update('users')
363 ->fields(array('timezone', NULL))
364 ->condition('uid', $account->uid)
365 ->execute();
366 }
367 $sandbox['user_from']++;
368 }
369
370 $sandbox['#finished'] = $sandbox['user_from'] / $sandbox['user_count'];
371 if ($sandbox['user_from'] == $sandbox['user_count']) {
372 if ($sandbox['user_not_migrated'] > 0) {
373 variable_set('empty_timezone_message', 1);
374 drupal_set_message('Some user time zones have been emptied and need to be set to the correct values. Use the new ' . l('time zone options', 'admin/config/regional/settings') . ' to choose whether to remind users at login to set the correct time zone.', 'warning');
375 }
376 return t('Migrated user time zones');
377 }
378 }
379 }
380
381 /**
382 * Update user settings for cancelling user accounts.
383 *
384 * Prior to 7.x, users were not able to cancel their accounts. When
385 * administrators deleted an account, all contents were assigned to uid 0,
386 * which is the same as the 'user_cancel_reassign' method now.
387 */
388 function user_update_7003() {
389 // Set the default account cancellation method.
390 variable_set('user_cancel_method', 'user_cancel_reassign');
391 // Re-assign notification setting.
392 if ($setting = variable_get('user_mail_status_deleted_notify', FALSE)) {
393 variable_set('user_mail_status_canceled_notify', $setting);
394 variable_del('user_mail_status_deleted_notify');
395 }
396 // Re-assign "Account deleted" mail strings to "Account canceled" mail.
397 if ($setting = variable_get('user_mail_status_deleted_subject', FALSE)) {
398 variable_set('user_mail_status_canceled_subject', $setting);
399 variable_del('user_mail_status_deleted_subject');
400 }
401 if ($setting = variable_get('user_mail_status_deleted_body', FALSE)) {
402 variable_set('user_mail_status_canceled_body', $setting);
403 variable_del('user_mail_status_deleted_body');
404 }
405 }
406
407 /**
408 * Add the user's pictures to the {file} table and make them managed files.
409 */
410 function user_update_7004(&$sandbox) {
411
412 $picture_field = array(
413 'type' => 'int',
414 'not null' => TRUE,
415 'default' => 0,
416 'description' => t("Foriegn key: {file}.fid of user's picture."),
417 );
418
419 if (!isset($sandbox['progress'])) {
420 // Check that the field hasn't been updated in an aborted run of this
421 // update.
422 if (!db_column_exists('users', 'picture_fid')) {
423 // Add a new field for the fid.
424 db_add_field('users', 'picture_fid', $picture_field);
425 }
426
427 // Initialize batch update information.
428 $sandbox['progress'] = 0;
429 $sandbox['last_user_processed'] = -1;
430 $sandbox['max'] = db_query("SELECT COUNT(*) FROM {user} WHERE picture <> ''")->fetchField();
431 }
432
433 // As a batch operation move the photos into the {file} table and update the
434 // {users} records.
435 $limit = 500;
436 $result = db_query_range("SELECT uid, picture FROM {user} WHERE picture <> '' AND uid > :uid ORDER BY uid", 0, $limit, array(':uid' => $sandbox['last_user_processed']));
437 foreach ($result as $user) {
438 // Don't bother adding files that don't exist.
439 if (!file_exists($user->picture)) {
440 continue;
441 }
442
443 // Check if the file already exists.
444 $files = file_load_multiple(array(), array('uri' => $user->picture));
445 if (count($files)) {
446 $file = reset($files);
447 }
448 else {
449 // Create a file object.
450 $file = new stdClass();
451 $file->uri = $user->picture;
452 $file->filename = basename($file->uri);
453 $file->filemime = file_get_mimetype($file->uri);
454 $file->uid = $user->uid;
455 $file->status = FILE_STATUS_PERMANENT;
456 $file = file_save($file);
457 }
458
459 db_update('users')
460 ->fields(array('picture_fid' => $file->fid))
461 ->condition('uid', $user->uid)
462 ->execute();
463
464 // Update our progress information for the batch update.
465 $sandbox['progress']++;
466 $sandbox['last_user_processed'] = $user->uid;
467 }
468
469 // Indicate our current progress to the batch update system. If there's no
470 // max value then there's nothing to update and we're finished.
471 $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
472
473 // When we're finished, drop the old picture field and rename the new one to
474 // replace it.
475 if (isset($sandbox['#finished']) && $sandbox['#finished'] == 1) {
476 db_drop_field('user', 'picture');
477 db_change_field('user', 'picture_fid', 'picture', $picture_field);
478 }
479 }
480
481 /**
482 * @} End of "defgroup user-updates-6.x-to-7.x"
483 * The next series of updates should start at 8000.
484 */
485

  ViewVC Help
Powered by ViewVC 1.1.2