profile.module 22.4 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
Dries's avatar
Dries committed
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Support for configurable user profiles.
 */

9
10
11
12
13
14
15
/**
 * Flags to define the visibility of a profile field.
 */
define('PROFILE_PRIVATE', 1);
define('PROFILE_PUBLIC', 2);
define('PROFILE_PUBLIC_LISTINGS', 3);

Dries's avatar
   
Dries committed
16
17
18
/**
 * Implementation of hook_help().
 */
Dries's avatar
   
Dries committed
19
function profile_help($section) {
Dries's avatar
   
Dries committed
20
  switch ($section) {
Dries's avatar
   
Dries committed
21
22
    case 'admin/modules#description':
      return t('Support for configurable user profiles.');
23
    case 'admin/settings/profile':
24
      return t('<p>Here you can define custom fields that users can fill in in their user profile (such as <em>country</em>, <em>real name</em>, <em>age</em>, ...).</p>');
Dries's avatar
   
Dries committed
25
26
27
  }
}

Dries's avatar
   
Dries committed
28
/**
Dries's avatar
   
Dries committed
29
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
30
 */
Dries's avatar
   
Dries committed
31
function profile_menu($may_cache) {
32
  global $user;
Dries's avatar
   
Dries committed
33
  $items = array();
Dries's avatar
   
Dries committed
34
35
36
37
38
39

  if ($may_cache) {
    $items[] = array('path' => 'profile', 'title' => t('user list'),
      'callback' => 'profile_browse',
      'access' => TRUE,
      'type' => MENU_SUGGESTED_ITEM);
40
    $items[] = array('path' => 'admin/settings/profile', 'title' => t('profiles'),
Dries's avatar
   
Dries committed
41
      'callback' => 'profile_admin_overview',
42
43
      'access' => user_access('administer users'));
    $items[] = array('path' => 'admin/settings/profile/add', 'title' => t('add field'),
Dries's avatar
   
Dries committed
44
45
46
      'callback' => 'profile_admin_add',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
47
    $items[] = array('path' => 'admin/settings/profile/edit', 'title' => t('edit field'),
Dries's avatar
   
Dries committed
48
49
50
      'callback' => 'profile_admin_edit',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
51
    $items[] = array('path' => 'admin/settings/profile/delete', 'title' => t('delete field'),
Dries's avatar
   
Dries committed
52
53
54
55
      'callback' => 'profile_admin_delete',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
  }
56

Dries's avatar
   
Dries committed
57
  return $items;
Dries's avatar
   
Dries committed
58
}
Dries's avatar
 
Dries committed
59

Dries's avatar
   
Dries committed
60
61
62
/**
 * Menu callback; display a list of user information.
 */
Dries's avatar
   
Dries committed
63
function profile_browse() {
Dries's avatar
   
Dries committed
64

Steven Wittens's avatar
Steven Wittens committed
65
66
  $name = arg(1);
  $value = arg(2);
Dries's avatar
   
Dries committed
67

Steven Wittens's avatar
Steven Wittens committed
68
  $field = db_fetch_object(db_query("SELECT DISTINCT(fid), type, title, page, visibility FROM {profile_fields} WHERE name = '%s'", $name));
Dries's avatar
 
Dries committed
69

Dries's avatar
   
Dries committed
70
  if ($name && $field->fid) {
Steven Wittens's avatar
Steven Wittens committed
71
72
73
74
75
76
    // Do not allow browsing of private fields by non-admins
    if (!user_access('administer users') && $field->visibility == PROFILE_PRIVATE) {
       drupal_access_denied();
       return;
    }

77
    // Compile a list of fields to show
Dries's avatar
   
Dries committed
78
    $fields = array();
Dries's avatar
   
Dries committed
79
    $result = db_query('SELECT name, title, type FROM {profile_fields} WHERE fid != %d AND visibility = %d ORDER BY weight', $field->fid, PROFILE_PUBLIC_LISTINGS);
Dries's avatar
   
Dries committed
80
81
82
    while ($record = db_fetch_object($result)) {
      $fields[] = $record;
    }
Dries's avatar
 
Dries committed
83

Dries's avatar
Dries committed
84
85
86
87
88
89
    // Determine what query to use:
    switch ($field->type) {
      case 'checkbox':
        $query = 'v.value = 1';
        break;
      case 'selection':
Dries's avatar
   
Dries committed
90
        $query = "v.value = '". db_escape_string($value) ."'";
Dries's avatar
Dries committed
91
92
        break;
      case 'list':
Dries's avatar
   
Dries committed
93
        $query = "v.value LIKE '%%". db_escape_string($value) ."%%'";
Dries's avatar
Dries committed
94
        break;
Steven Wittens's avatar
Steven Wittens committed
95
96
97
      default:
        drupal_not_found();
        return;
Dries's avatar
Dries committed
98
99
    }

Dries's avatar
   
Dries committed
100
    // Extract the affected users:
Dries's avatar
   
Dries committed
101
    $result = pager_query("SELECT u.uid FROM {users} u INNER JOIN {profile_values} v ON u.uid = v.uid WHERE v.fid = %d AND $query ORDER BY u.changed DESC", 20, 0, NULL, $field->fid);
Dries's avatar
 
Dries committed
102

Dries's avatar
   
Dries committed
103
    $output = '<div id="profile">';
Dries's avatar
   
Dries committed
104
105
106
107
108
    while ($account = db_fetch_object($result)) {
      $output .= theme('profile_profile', user_load(array('uid' => $account->uid)), $fields);
    }
    $output .= theme('pager', NULL, 20);

Dries's avatar
Dries committed
109
    if ($field->type == 'selection' || $field->type == 'list') {
110
      $title = strtr($field->page, array('%value' => $value));
Dries's avatar
   
Dries committed
111
112
    }
    else {
Dries's avatar
   
Dries committed
113
      $title = $field->page;
Dries's avatar
   
Dries committed
114
    }
Dries's avatar
   
Dries committed
115
    $output .= '</div>';
Dries's avatar
   
Dries committed
116

117
118
    drupal_set_title($title);
    print theme('page', $output);
Dries's avatar
   
Dries committed
119
  }
Dries's avatar
   
Dries committed
120
  else if ($name && !$field->id) {
Dries's avatar
   
Dries committed
121
    drupal_not_found();
Dries's avatar
 
Dries committed
122
  }
Dries's avatar
   
Dries committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  else {
    // Compile a list of fields to show
    $fields = array();
    $result = db_query('SELECT name, title, type FROM {profile_fields} WHERE visibility = %d', PROFILE_PUBLIC_LISTINGS);
    while ($record = db_fetch_object($result)) {
      $fields[] = $record;
    }

    // Extract the affected users:
    $result = pager_query("SELECT uid FROM {users} WHERE uid > 0 ORDER BY changed DESC", 20, 0, NULL);

    $output = '<div id="profile">';
    while ($account = db_fetch_object($result)) {
      $output .= theme('profile_profile', user_load(array('uid' => $account->uid)), $fields);
    }
    $output .= '</div>';
    $output .= theme('pager', NULL, 20);

141
142
    drupal_set_title(t('user list'));
    print theme('page', $output);
Dries's avatar
   
Dries committed
143
  }
Dries's avatar
   
Dries committed
144
}
Dries's avatar
 
Dries committed
145

Dries's avatar
   
Dries committed
146
function profile_load_profile(&$user) {
Steven Wittens's avatar
Steven Wittens committed
147
  $result = db_query('SELECT f.name, f.type, v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE uid = %d', $user->uid);
Dries's avatar
   
Dries committed
148
149
  while ($field = db_fetch_object($result)) {
    if (empty($user->{$field->name})) {
Steven Wittens's avatar
Steven Wittens committed
150
      $user->{$field->name} = _profile_field_serialize($field->type) ? unserialize($field->value) : $field->value;
Dries's avatar
   
Dries committed
151
    }
Dries's avatar
   
Dries committed
152
  }
Dries's avatar
 
Dries committed
153
154
}

155
function profile_save_profile(&$edit, &$user, $category) {
Dries's avatar
   
Dries committed
156
157
158
159
  if (($_GET['q'] == 'user/register') ? 1 : 0) {
    $result = db_query('SELECT fid, name, type FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
  }
  else {
160
161
    $result = db_query("SELECT fid, name, type FROM {profile_fields} WHERE LOWER(category) = LOWER('%s')", $category);
    // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues.
Dries's avatar
   
Dries committed
162
  }
Dries's avatar
   
Dries committed
163
  while ($field = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
164
165
166
    if (_profile_field_serialize($field->type)) {
       $edit[$field->name] = serialize($edit[$field->name]);
    }
167
168
    db_query("DELETE FROM {profile_values} WHERE fid = %d AND uid = %d", $field->fid, $user->uid);
    db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]);
169
170
    // Mark field as handled (prevents saving to user->data).
    $edit[$field->name] = null;
Dries's avatar
   
Dries committed
171
  }
Dries's avatar
 
Dries committed
172
173
}

174
function profile_view_field($user, $field) {
Steven Wittens's avatar
Steven Wittens committed
175
176
177
  // Only allow browsing of private fields for admins
  $browse = user_access('administer users') || $field->visibility != PROFILE_PRIVATE;

178
179
180
  if ($value = $user->{$field->name}) {
    switch ($field->type) {
      case 'textfield':
Steven Wittens's avatar
Steven Wittens committed
181
        return drupal_specialchars($value);
182
183
184
      case 'textarea':
        return check_output($value);
      case 'selection':
Steven Wittens's avatar
Steven Wittens committed
185
        return $browse ? l(drupal_specialchars($value), "profile/$field->name/". check_url($value)) : drupal_specialchars($value);
186
      case 'checkbox':
Dries's avatar
   
Dries committed
187
        return $browse ? l(strip_tags($field->title), "profile/$field->name") : drupal_specialchars($field->title);
188
      case 'url':
Steven Wittens's avatar
Steven Wittens committed
189
190
191
192
193
194
195
196
197
198
199
200
        return '<a href="'. check_url($value) .'">'. drupal_specialchars($value) .'</a>';
      case 'date':
        list($format) = explode(' - ', variable_get('date_format_short', 'm/d/Y - H:i'), 2);
        // Note: we avoid PHP's date() because it does not handle dates before
        // 1970 on Windows. This would make the date field useless for e.g.
        // birthdays.
        $replace = array('d' => sprintf('%02d', $value['day']),
                         'j' => $value['day'],
                         'm' => sprintf('%02d', $value['month']),
                         'M' => _profile_map_month($value['month']),
                         'Y' => $value['year']);
        return strtr($format, $replace);
201
      case 'list':
Dries's avatar
   
Dries committed
202
        $values = split("[,\n\r]", $value);
Dries's avatar
Dries committed
203
204
        $fields = array();
        foreach ($values as $value) {
Steven Wittens's avatar
Steven Wittens committed
205
206
          if ($value = trim($value)) {
            $fields[] = $browse ? l(drupal_specialchars($value), "profile/$field->name/". check_url($value)) : drupal_specialchars($value);
Dries's avatar
Dries committed
207
208
209
          }
        }
        return implode(', ', $fields);
210
211
212
213
    }
  }
}

Dries's avatar
   
Dries committed
214
function profile_view_profile($user) {
Dries's avatar
 
Dries committed
215

216
  profile_load_profile($user);
Dries's avatar
 
Dries committed
217

Steven Wittens's avatar
Steven Wittens committed
218
219
220
221
222
223
224
225
  // Show private fields to administrators and people viewing their own account.
  if (user_access('administer users') || $GLOBALS['user']->uid == $user->uid) {
    $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
  }
  else {
    $result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d ORDER BY category, weight', PROFILE_PRIVATE);
  }

Dries's avatar
   
Dries committed
226
  while ($field = db_fetch_object($result)) {
227
    if ($value = profile_view_field($user, $field)) {
Steven Wittens's avatar
Steven Wittens committed
228
229
230
      $description = ($field->visibility == PROFILE_PRIVATE) ? t('The content of this field is private and only visible to yourself.') : '';
      $title = ($field->type != 'checkbox') ? $field->title : '';
      $fields[$field->category] .= form_item($title, $value, $description);
Dries's avatar
 
Dries committed
231
232
233
    }
  }

Dries's avatar
Dries committed
234
  return $fields;
Dries's avatar
   
Dries committed
235
}
Dries's avatar
 
Dries committed
236

237
238
function _profile_form_explanation($field) {
  $output = $field->explanation;
Dries's avatar
   
Dries committed
239

240
  if ($field->type == 'list') {
Dries's avatar
   
Dries committed
241
    $output .= ' '. t('Put each item on a separate line or separate them by commas.  No HTML allowed.');
242
243
244
245
246
247
248
249
250
251
252
  }

  if ($field->visibility == PROFILE_PRIVATE) {
    $output .= ' '. t('The content of this field is kept private and will not be shown publicly.');
  }

  return $output;
}

function profile_form_profile($edit, $user, $category) {

Dries's avatar
   
Dries committed
253
254
255
256
  if (($_GET['q'] == 'user/register') ? 1 : 0) {
    $result = db_query('SELECT * FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
  }
  else {
257
258
    $result = db_query("SELECT * FROM {profile_fields} WHERE LOWER(category) = LOWER('%s') ORDER BY weight", $category);
    // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues.
Dries's avatar
   
Dries committed
259
  }
Dries's avatar
   
Dries committed
260

Dries's avatar
   
Dries committed
261
  $fields = array();
Dries's avatar
   
Dries committed
262
  while ($field = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
263
    $category = $field->category;
Dries's avatar
   
Dries committed
264
265
    switch ($field->type) {
      case 'textfield':
266
      case 'url':
Dries's avatar
   
Dries committed
267
        $fields[$category] .= form_textfield($field->title, $field->name, $edit[$field->name], 70, 255, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
268
269
        break;
      case 'textarea':
270
        $fields[$category] .= form_textarea($field->title, $field->name, $edit[$field->name], 70, 5, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
Dries committed
271
272
        break;
      case 'list':
273
        $fields[$category] .= form_textarea($field->title, $field->name, $edit[$field->name], 70, 5, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
274
275
        break;
      case 'checkbox':
Dries's avatar
   
Dries committed
276
        $fields[$category] .= form_checkbox($field->title, $field->name, 1, $edit[$field->name], _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
277
278
279
        break;
      case 'selection':
        $options = array('--');
Dries's avatar
   
Dries committed
280
        $lines = split("[,\n\r]", $field->options);
Dries's avatar
   
Dries committed
281
282
283
284
285
286
        foreach ($lines as $line) {
          if ($line = trim($line)) {
            $options[$line] = $line;
          }
        }

Dries's avatar
   
Dries committed
287
        $fields[$category] .= form_select($field->title, $field->name, $edit[$field->name], $options, _profile_form_explanation($field), 0, 0, $field->required);
Dries's avatar
   
Dries committed
288
        break;
Steven Wittens's avatar
Steven Wittens committed
289
      case 'date':
Dries's avatar
   
Dries committed
290
        $fields[$category] .= _profile_date_field($field, $edit);
Steven Wittens's avatar
Steven Wittens committed
291
        break;
Dries's avatar
 
Dries committed
292
293
294
    }
  }

Dries's avatar
   
Dries committed
295
296
297
298
299
  if ($fields) {
    foreach ($fields as $category => $data) {
      $output[] = array('title' => $category, 'data' => $data);
    }
    return $output;
300
  }
Dries's avatar
 
Dries committed
301
302
}

Steven Wittens's avatar
Steven Wittens committed
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/**
 * Helper function: output a date selector
 */
function _profile_date_field($field, $edit) {
  // Default to current date
  if (!isset($edit[$field->name])) {
    $edit[$field->name] = array('day' => format_date(time(), 'custom', 'j'),
                                'month' => format_date(time(), 'custom', 'n'),
                                'year' => format_date(time(), 'custom', 'Y'));
  }

  // Determine the order of day, month, year in the site's chosen date format.
  $format = variable_get('date_format_short', 'm/d/Y');
  $sort = array();
  $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j'));
  $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M'));
  $sort['year'] = strpos($format, 'Y');
  asort($sort);
  $order = array_keys($sort);

  // Output multi-selector for date
  $output = '<div class="container-inline">';
  foreach ($order as $type) {
    switch ($type) {
      case 'day':
        $options = drupal_map_assoc(range(1, 31));
        break;
      case 'month':
        $options = drupal_map_assoc(range(1, 12), '_profile_map_month');
        break;
      case 'year':
        $options = drupal_map_assoc(range(1900, 2050));
        break;
    }
    $output .= form_select('', $field->name .']['. $type, $edit[$field->name][$type], $options, '', 0, 0);
  }
  $output .= '</div>';

  return form_item($field->title, $output, _profile_form_explanation($field), NULL, $field->required);
}

/**
 * Helper function for usage with drupal_map_assoc
 */
function _profile_map_month($month) {
  return format_date(gmmktime(0, 0, 0, $month, 2, 1970), 'custom', 'M', 0);
}

351
function profile_validate_profile($edit, $category) {
Dries's avatar
   
Dries committed
352
353
354
355
356

  if (($_GET['q'] == 'user/register') ? 1 : 0) {
    $result = db_query('SELECT * FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
  }
  else {
357
358
    $result = db_query("SELECT * FROM {profile_fields} WHERE LOWER(category) = LOWER('%s') ORDER BY weight", $category);
    // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues.
Dries's avatar
   
Dries committed
359
  }
360
361

  while ($field = db_fetch_object($result)) {
362
    if ($edit[$field->name]) {
Dries's avatar
   
Dries committed
363
364
      if ($field->type == 'url') {
        if (!valid_url($edit[$field->name], true)) {
Dries's avatar
   
Dries committed
365
          form_set_error($field->name, t('The value provided for %field is not a valid URL.', array('%field' => "<em>$field->title</em>")));
Dries's avatar
   
Dries committed
366
         }
367
368
      }
    }
369
    else if ($field->required && !user_access('administer users')) {
Dries's avatar
   
Dries committed
370
      form_set_error($field->name, t('The field %field is required.', array('%field' => "<em>$field->title</em>")));
Dries's avatar
   
Dries committed
371
    }
372
373
374
375
376
  }

  return $edit;
}

377
378
379
function profile_categories() {
  $result = db_query("SELECT DISTINCT(category) FROM {profile_fields}");
  while ($category = db_fetch_object($result)) {
380
    $data[] = array('name' => drupal_specialchars($category->category), 'title' => $category->category, 'weight' => 3);
381
382
383
384
  }
  return $data;
}

Dries's avatar
   
Dries committed
385
386
387
/**
 * Implementation of hook_user().
 */
388
function profile_user($type, &$edit, &$user, $category = NULL) {
Dries's avatar
   
Dries committed
389
390
391
  switch ($type) {
    case 'load':
      return profile_load_profile($user);
Dries's avatar
   
Dries committed
392
393
    case 'register':
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
394
    case 'update':
395
    case 'insert':
396
      return profile_save_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
397
398
    case 'view':
      return profile_view_profile($user);
399
    case 'form':
400
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
401
    case 'validate':
402
403
404
      return profile_validate_profile($edit, $category);
    case 'categories':
      return profile_categories();
Dries's avatar
   
Dries committed
405
406
  }
}
Dries's avatar
   
Dries committed
407

Dries's avatar
   
Dries committed
408
function profile_validate_form($edit) {
Dries's avatar
 
Dries committed
409

Dries's avatar
   
Dries committed
410
  // Validate the title:
Dries's avatar
 
Dries committed
411

Dries's avatar
   
Dries committed
412
  if (!$edit['title']) {
Dries's avatar
   
Dries committed
413
    form_set_error('title', t('You must enter a title.'));
Dries's avatar
 
Dries committed
414
415
  }

Dries's avatar
   
Dries committed
416
  // Validate the 'form name':
Dries's avatar
 
Dries committed
417

Dries's avatar
   
Dries committed
418
  if (eregi('[^a-z0-9_-]', $edit['name'])) {
Dries's avatar
   
Dries committed
419
    form_set_error('name', t('The specified form name contains one or more illegal characters.  Spaces or any other special characters expect dash (-) and underscore (_) are not allowed.'));
Dries's avatar
 
Dries committed
420
421
  }

Dries's avatar
   
Dries committed
422
  if (in_array($edit['name'], user_fields())) {
Dries's avatar
   
Dries committed
423
    form_set_error('name', t('The specified form name is reserved for use by Drupal.'));
Dries's avatar
 
Dries committed
424
425
  }

Dries's avatar
   
Dries committed
426
427
  // Validate the category:
  if (!$edit['category']) {
Dries's avatar
   
Dries committed
428
    form_set_error('category', t('You must enter a category.'));
Dries's avatar
   
Dries committed
429
  }
Dries's avatar
 
Dries committed
430
431
}

Dries's avatar
   
Dries committed
432
433
434
/**
 * Menu callback; adds a new field to all user profiles.
 */
Dries's avatar
   
Dries committed
435
436
437
function profile_admin_add($type) {
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
 
Dries committed
438

Dries's avatar
   
Dries committed
439
440
441
    // Validate the form:
    profile_validate_form($data);

442
    if (db_result(db_query("SELECT fid FROM {profile_fields} WHERE title = '%s' AND category = '%s'", $data['title'], $data['category']))) {
Steven Wittens's avatar
Steven Wittens committed
443
      form_set_error('title', t('The specified title is already in use.'));
444
    }
Dries's avatar
   
Dries committed
445
446

    if (db_result(db_query("SELECT fid FROM {profile_fields} WHERE name = '%s'", $data['name']))) {
Steven Wittens's avatar
Steven Wittens committed
447
      form_set_error('name', t('The specified name is already in use.'));
448
    }
Dries's avatar
   
Dries committed
449

Dries's avatar
   
Dries committed
450
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
451
      db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, required, register, visibility, options, page) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page']);
Dries's avatar
 
Dries committed
452

Dries's avatar
   
Dries committed
453
454
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
455
      drupal_set_message(t('The field has been created.'));
456
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
457
    }
Dries's avatar
   
Dries committed
458
  }
Dries's avatar
   
Dries committed
459
460
461
462
  else {
    $data = array('name' => 'profile_');
  }

463
464
  drupal_set_title(t('Add new %type', array('%type' => _profile_field_types($type))));
  print theme('page', _profile_field_form($type, $data));
Dries's avatar
   
Dries committed
465
466
}

Dries's avatar
   
Dries committed
467
468
469
/**
 * Menu callback; displays the profile field editing form.
 */
Dries's avatar
   
Dries committed
470
function profile_admin_edit($fid) {
Dries's avatar
 
Dries committed
471

Dries's avatar
   
Dries committed
472
473
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
 
Dries committed
474

Dries's avatar
   
Dries committed
475
476
    // Validate form:
    profile_validate_form($data);
Dries's avatar
 
Dries committed
477

Dries's avatar
   
Dries committed
478
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
479
      db_query("UPDATE {profile_fields} SET title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d, required = %d, register = %d, visibility = %d, options = '%s', page = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page'], $fid);
Dries's avatar
   
Dries committed
480

Dries's avatar
   
Dries committed
481
482
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
483
      drupal_set_message(t('The field has been updated.'));
484
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
485
    }
Dries's avatar
   
Dries committed
486
487
  }
  else {
Dries's avatar
   
Dries committed
488
    $data = db_fetch_array(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid));
Dries's avatar
 
Dries committed
489
490
  }

491
492
  drupal_set_title(t('Edit %type', array('%type' => $data['type'])));
  print theme('page', _profile_field_form($data['type'], $data));
Dries's avatar
 
Dries committed
493
494
}

Dries's avatar
   
Dries committed
495
496
497
/**
 * Menu callback; deletes a field from all user profiles.
 */
Dries's avatar
   
Dries committed
498
499
function profile_admin_delete($fid) {
  db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid);
Dries's avatar
   
Dries committed
500
501
502

  cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
503
  drupal_set_message(t('The field has been deleted.'));
504
  drupal_goto('admin/settings/profile');
Dries's avatar
 
Dries committed
505
506
}

Dries's avatar
   
Dries committed
507
508
function _profile_field_form($type, $edit = array()) {

Dries's avatar
   
Dries committed
509
510
511
512
513
  $group  = form_textfield(t('Category'), 'category', $edit['category'], 70, 128, t('The category the new field should be part of.  Categories are used to group fields logically.  An example category is "Personal information".'));
  $group .= form_textfield(t('Title'), 'title', $edit['title'], 70, 128, t('The title of the new field.  The title will be shown to the user.  An example title is "Favorite color".'));
  $group .= form_textfield(t('Form name'), 'name', $edit['name'], 70, 128, t('The name of the field.  The form name is not shown to the user but used internally in the HTML code and URLs.
Unless you know what you are doing, it is highly recommended that you prefix the form name with <code>profile_</code> to avoid name clashes with other fields.  Spaces or any other special characters except dash (-) and underscore (_) are not allowed. An example name is "profile_favorite_color" or perhaps just "profile_color".'));
  $group .= form_textarea(t('Explanation'), 'explanation', $edit['explanation'], 70, 3, t('An optional explanation to go with the new field.  The explanation will be shown to the user.'));
Dries's avatar
   
Dries committed
514
  if ($type == 'selection') {
Dries's avatar
   
Dries committed
515
    $group .= form_textarea(t('Selection options'), 'options', $edit['options'], 70, 8, t('A list of all options.  Put each option on a separate line.  Example options are "red", "blue", "green", etc.'));
Dries's avatar
   
Dries committed
516
  }
Dries's avatar
   
Dries committed
517
  $group .= form_weight(t('Weight'), 'weight', $edit['weight'], 5, t('The weights define the order in which the form fields are shown.  Lighter fields "float up" towards the top of the category.'));
518
  $group .= form_radios(t('Visibility'), 'visibility', $edit['visibility'], array(PROFILE_PRIVATE => t('Private field, content only available to privileged users.'), PROFILE_PUBLIC => t('Public field, content shown on profile page but not used on member list pages.'), PROFILE_PUBLIC_LISTINGS => t('Public field, content shown on profile page and on member list pages.')));
Dries's avatar
Dries committed
519
  if ($type == 'selection' || $type == 'list') {
520
    $group .= form_textfield(t('Page title'), 'page', $edit['page'], 70, 128, t('The title of the page showing all users with the specified field.  The word <code>%value</code> will be substituted with the corresponding value.  An example page title is "People whose favorite color is %value".  Only applicable if the field is configured to be shown on member list pages.'));
Dries's avatar
   
Dries committed
521
522
  }
  else {
523
    $group .= form_textfield(t('Page title'), 'page', $edit['page'], 70, 128, t('The title of the page showing all users with the specified field.  Only applicable if the field is configured to be shown on member listings.'));
Dries's avatar
 
Dries committed
524
  }
Dries's avatar
   
Dries committed
525
526
  $group .= form_checkbox(t('The user must enter a value.'), 'required', 1, $edit['required']);
  $group .= form_checkbox(t('Visible in user registration form.'), 'register', 1, $edit['register']);
Dries's avatar
 
Dries committed
527

528
  $output  = form_group(t('Field settings'), $group);
Dries's avatar
   
Dries committed
529
530
531
532
533
  $output .= form_submit(t('Save field'));

  return form($output);
}

Dries's avatar
   
Dries committed
534
535
536
/**
 * Menu callback; display a listing of all editable profile fields.
 */
Dries's avatar
   
Dries committed
537
538
539
function profile_admin_overview() {

  $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
Steven Wittens's avatar
Steven Wittens committed
540
  $rows = array();
Dries's avatar
   
Dries committed
541
  while ($field = db_fetch_object($result)) {
542
    $rows[] = array($field->title, $field->name, _profile_field_types($field->type), $field->category, l(t('edit'), "admin/settings/profile/edit/$field->fid"), l(t('delete'), "admin/settings/profile/delete/$field->fid"));
Steven Wittens's avatar
Steven Wittens committed
543
544
545
  }
  if (count($rows) == 0) {
    $rows[] = array(array('data' => t('No fields defined.'), 'colspan' => '6'));
Dries's avatar
 
Dries committed
546
  }
Dries's avatar
   
Dries committed
547

Dries's avatar
   
Dries committed
548
  $header = array(t('Title'), t('Name'), t('Type'), t('Category'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
   
Dries committed
549
550

  $output  = theme('table', $header, $rows);
Steven Wittens's avatar
Steven Wittens committed
551
  $output .= '<h2>'. t('Add new field') .'</h2>';
Dries's avatar
   
Dries committed
552
553
  $output .= '<ul>';
  foreach (_profile_field_types() as $key => $value) {
554
    $output .= '<li>'. l($value, "admin/settings/profile/add/$key") .'</li>';
Dries's avatar
 
Dries committed
555
  }
Dries's avatar
   
Dries committed
556
557
558
  $output .= '</ul>';

  print theme('page', $output);
Dries's avatar
 
Dries committed
559
560
}

Dries's avatar
   
Dries committed
561
562
563
564
function theme_profile_profile($user, $fields = array()) {

  $output  = "<div class=\"profile\">\n";
  $output .= theme('user_picture', $user);
Dries's avatar
   
Dries committed
565
  $output .= ' <div class="name">'. format_name($user) ."</div>\n";
Dries's avatar
   
Dries committed
566
567

  foreach ($fields as $field) {
568
569
    if ($value = profile_view_field($user, $field)) {
      $output .= " <div class=\"field\">$value</div>\n";
Dries's avatar
 
Dries committed
570
571
    }
  }
Dries's avatar
   
Dries committed
572
573
574
575
576
577
578

  $output .= "</div>\n";

  return $output;
}

function _profile_field_types($type = NULL) {
Steven Wittens's avatar
Steven Wittens committed
579
580
581
582
583
584
585
  $types = array('textfield' => t('single-line textfield'),
                 'textarea' => t('multi-line textfield'),
                 'checkbox' => t('checkbox'),
                 'selection' => t('list selection'),
                 'list' => t('freeform list'),
                 'url' => t('URL'),
                 'date' => t('date'));
Dries's avatar
   
Dries committed
586
  return isset($type) ? $types[$type] : $types;
Dries's avatar
 
Dries committed
587
588
}

Steven Wittens's avatar
Steven Wittens committed
589
590
591
592
function _profile_field_serialize($type = NULL) {
  return $type == 'date';
}

Dries's avatar
   
Dries committed
593
?>