profile.module 26.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
/**
 * Flags to define the visibility of a profile field.
 */
define('PROFILE_PRIVATE', 1);
define('PROFILE_PUBLIC', 2);
define('PROFILE_PUBLIC_LISTINGS', 3);
15
define('PROFILE_HIDDEN', 4);
16

Dries's avatar
   
Dries committed
17
18
19
/**
 * Implementation of hook_help().
 */
Dries's avatar
   
Dries committed
20
function profile_help($section) {
Dries's avatar
   
Dries committed
21
  switch ($section) {
Dries's avatar
   
Dries committed
22
    case 'admin/modules#description':
23
      return t('Supports configurable user profiles.');
24
    case 'admin/settings/profile':
25
      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
26
27
28
  }
}

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
 * Implementation of hook_block().
 */
function profile_block($op = 'list', $delta = 0, $edit = array()) {

  if ($op == 'list') {
     $blocks[0]['info'] = t('Author information');

     return $blocks;
  }
  else if ($op == 'configure' && $delta == 0) {
    // Compile a list of fields to show
    $fields = array();
    $result = db_query('SELECT name, title FROM {profile_fields} ORDER BY weight');
    while ($record = db_fetch_object($result)) {
      $fields[$record->name] = $record->title;
    }
    $fields['user_profile'] = t('Link to full user profile');
    $output .= form_checkboxes(t('Profile fields to display'), 'profile_block_author_fields', variable_get('profile_block_author_fields', NULL), $fields, t('Select which profile fields you wish to display in the block.  Only fields designated as public in the <a href="%profile-admin">profile field configuration</a> are available.', array('%profile-admin' => url('admin/settings/profile'))));
    return $output;
  }
  else if ($op == 'save' && $delta == 0) {
    variable_set('profile_block_author_fields', $edit['profile_block_author_fields']);
  }
  else if ($op == 'view') {
    if (user_access('access user profiles')) {
      if ((arg(0) == 'node') && is_numeric(arg(1)) && (arg(2) == NULL)) {
56
        $node = node_load(arg(1));
57
58
59
60
61
        $account = user_load(array('uid' => $node->uid));

        if ($use_fields = variable_get('profile_block_author_fields', array())) {
          // Compile a list of fields to show
          $fields = array();
62
          $result = db_query('SELECT name, title, type, visibility FROM {profile_fields} WHERE visibility IN (%d, %d) ORDER BY weight', PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS);
63
64
65
66
67
68
69
70
71
            while ($record = db_fetch_object($result)) {
              // Endure that field is displayed only if it is among the defined block fields and, if it is private, the user has appropriate permissions.
              if (in_array($record->name, $use_fields)) {
              $fields[] = $record;
            }
          }
        }

        if ($fields) {
72
          _profile_update_user_fields($fields, $account);
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
          $output .= theme('profile_block', $account, $fields, true);
        }

        if (in_array('user_profile', $use_fields)) {
          $output .= '<div>' . l(t('View full user profile'), 'user/' . $account->uid) . '</div>';
        }
      }

      if ($output) {
         $block['subject'] = t('About %name', array('%name' => $account->name));
         $block['content'] = $output;
         return $block;
      }
    }
  }
}

Dries's avatar
   
Dries committed
90
/**
Dries's avatar
   
Dries committed
91
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
92
 */
Dries's avatar
   
Dries committed
93
function profile_menu($may_cache) {
94
  global $user;
Dries's avatar
   
Dries committed
95
  $items = array();
Dries's avatar
   
Dries committed
96
97
98
99

  if ($may_cache) {
    $items[] = array('path' => 'profile', 'title' => t('user list'),
      'callback' => 'profile_browse',
100
      'access' => user_access('access user profiles'),
Dries's avatar
   
Dries committed
101
      'type' => MENU_SUGGESTED_ITEM);
102
    $items[] = array('path' => 'admin/settings/profile', 'title' => t('profiles'),
Dries's avatar
   
Dries committed
103
      'callback' => 'profile_admin_overview',
104
105
      'access' => user_access('administer users'));
    $items[] = array('path' => 'admin/settings/profile/add', 'title' => t('add field'),
Dries's avatar
   
Dries committed
106
107
108
      'callback' => 'profile_admin_add',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
109
    $items[] = array('path' => 'admin/settings/profile/edit', 'title' => t('edit field'),
Dries's avatar
   
Dries committed
110
111
112
      'callback' => 'profile_admin_edit',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
113
    $items[] = array('path' => 'admin/settings/profile/delete', 'title' => t('delete field'),
Dries's avatar
   
Dries committed
114
115
116
117
      'callback' => 'profile_admin_delete',
      'access' => user_access('administer users'),
      'type' => MENU_CALLBACK);
  }
118

Dries's avatar
   
Dries committed
119
  return $items;
Dries's avatar
   
Dries committed
120
}
Dries's avatar
   
Dries committed
121

Dries's avatar
   
Dries committed
122
123
124
/**
 * Menu callback; display a list of user information.
 */
Dries's avatar
   
Dries committed
125
function profile_browse() {
Dries's avatar
   
Dries committed
126

Steven Wittens's avatar
Steven Wittens committed
127
128
  $name = arg(1);
  $value = arg(2);
Dries's avatar
   
Dries committed
129

Steven Wittens's avatar
Steven Wittens committed
130
  $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
131

Dries's avatar
   
Dries committed
132
  if ($name && $field->fid) {
Steven Wittens's avatar
Steven Wittens committed
133
134
135
136
137
138
    // Do not allow browsing of private fields by non-admins
    if (!user_access('administer users') && $field->visibility == PROFILE_PRIVATE) {
       drupal_access_denied();
       return;
    }

139
    // Compile a list of fields to show
Dries's avatar
   
Dries committed
140
    $fields = array();
Dries's avatar
   
Dries committed
141
    $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
142
143
144
    while ($record = db_fetch_object($result)) {
      $fields[] = $record;
    }
Dries's avatar
   
Dries committed
145

Dries's avatar
Dries committed
146
147
148
149
150
151
    // Determine what query to use:
    switch ($field->type) {
      case 'checkbox':
        $query = 'v.value = 1';
        break;
      case 'selection':
Dries's avatar
   
Dries committed
152
        $query = "v.value = '". db_escape_string($value) ."'";
Dries's avatar
Dries committed
153
154
        break;
      case 'list':
Dries's avatar
   
Dries committed
155
        $query = "v.value LIKE '%%". db_escape_string($value) ."%%'";
Dries's avatar
Dries committed
156
        break;
Steven Wittens's avatar
Steven Wittens committed
157
158
159
      default:
        drupal_not_found();
        return;
Dries's avatar
Dries committed
160
161
    }

Dries's avatar
   
Dries committed
162
    // Extract the affected users:
Dries's avatar
Dries committed
163
    $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.access DESC", 20, 0, NULL, $field->fid);
Dries's avatar
   
Dries committed
164

Dries's avatar
   
Dries committed
165
    $output = '<div id="profile">';
Dries's avatar
   
Dries committed
166
    while ($account = db_fetch_object($result)) {
167
168
169
      $account = user_load(array('uid' => $account->uid));
      _profile_update_user_fields($fields, $account);
      $output .= theme('profile_listing', $account, $fields);
Dries's avatar
   
Dries committed
170
171
172
    }
    $output .= theme('pager', NULL, 20);

Dries's avatar
Dries committed
173
    if ($field->type == 'selection' || $field->type == 'list') {
174
      $title = strtr($field->page, array('%value' => theme('placeholder', $value)));
Dries's avatar
   
Dries committed
175
176
    }
    else {
Dries's avatar
   
Dries committed
177
      $title = $field->page;
Dries's avatar
   
Dries committed
178
    }
Dries's avatar
   
Dries committed
179
    $output .= '</div>';
Dries's avatar
   
Dries committed
180

181
    drupal_set_title($title);
Dries's avatar
   
Dries committed
182
    return $output;
Dries's avatar
   
Dries committed
183
  }
Dries's avatar
   
Dries committed
184
  else if ($name && !$field->id) {
Dries's avatar
   
Dries committed
185
    drupal_not_found();
Dries's avatar
   
Dries committed
186
  }
Dries's avatar
   
Dries committed
187
188
189
190
191
192
193
194
195
  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:
Dries's avatar
Dries committed
196
    $result = pager_query("SELECT uid FROM {users} WHERE uid > 0 ORDER BY access DESC", 20, 0, NULL);
Dries's avatar
   
Dries committed
197
198
199

    $output = '<div id="profile">';
    while ($account = db_fetch_object($result)) {
200
201
202
      $account = user_load(array('uid' => $account->uid));
      _profile_update_user_fields($fields, $account);
      $output .= theme('profile_listing', $account, $fields);
Dries's avatar
   
Dries committed
203
204
205
206
    }
    $output .= '</div>';
    $output .= theme('pager', NULL, 20);

207
    drupal_set_title(t('user list'));
Dries's avatar
   
Dries committed
208
    return $output;
Dries's avatar
   
Dries committed
209
  }
Dries's avatar
   
Dries committed
210
}
Dries's avatar
   
Dries committed
211

Dries's avatar
   
Dries committed
212
function profile_load_profile(&$user) {
Steven Wittens's avatar
Steven Wittens committed
213
  $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
214
215
  while ($field = db_fetch_object($result)) {
    if (empty($user->{$field->name})) {
Steven Wittens's avatar
Steven Wittens committed
216
      $user->{$field->name} = _profile_field_serialize($field->type) ? unserialize($field->value) : $field->value;
Dries's avatar
   
Dries committed
217
    }
Dries's avatar
   
Dries committed
218
  }
Dries's avatar
   
Dries committed
219
220
}

221
function profile_save_profile(&$edit, &$user, $category) {
Dries's avatar
   
Dries committed
222
  if (($_GET['q'] == 'user/register') ? 1 : 0) {
223
    $result = db_query('SELECT fid, name, type FROM {profile_fields} WHERE register = 1 AND visibility != %d ORDER BY category, weight', PROFILE_HIDDEN);
Dries's avatar
   
Dries committed
224
225
  }
  else {
226
    $result = db_query("SELECT fid, name, type FROM {profile_fields} WHERE LOWER(category) = LOWER('%s') AND visibility != %d", $category, PROFILE_HIDDEN);
227
    // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues.
Dries's avatar
   
Dries committed
228
  }
Dries's avatar
   
Dries committed
229
  while ($field = db_fetch_object($result)) {
Steven Wittens's avatar
Steven Wittens committed
230
231
232
    if (_profile_field_serialize($field->type)) {
       $edit[$field->name] = serialize($edit[$field->name]);
    }
233
234
    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]);
235
    // Mark field as handled (prevents saving to user->data).
236
    $edit[$field->name] = NULL;
Dries's avatar
   
Dries committed
237
  }
Dries's avatar
   
Dries committed
238
239
}

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

Dries's avatar
Dries committed
244
245
246
  if ($field->fid == 18 || $field->fid == 19 || $field->fid == 20) {
    return;
  }
Dries's avatar
Dries committed
247

248
249
250
  if ($value = $user->{$field->name}) {
    switch ($field->type) {
      case 'textfield':
251
        return check_plain($value);
252
      case 'textarea':
253
        return check_markup($value);
254
      case 'selection':
255
        return $browse ? l($value, "profile/$field->name/$value") : check_plain($value);
256
      case 'checkbox':
257
        return $browse ? l($field->title, "profile/$field->name") : check_plain($field->title);
258
      case 'url':
259
        return '<a href="'. check_url($value) .'">'. check_plain($value) .'</a>';
Steven Wittens's avatar
Steven Wittens committed
260
261
262
263
264
265
266
267
268
269
270
      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);
271
      case 'list':
Dries's avatar
   
Dries committed
272
        $values = split("[,\n\r]", $value);
Dries's avatar
Dries committed
273
274
        $fields = array();
        foreach ($values as $value) {
Steven Wittens's avatar
Steven Wittens committed
275
          if ($value = trim($value)) {
276
            $fields[] = $browse ? l($value, "profile/". urlencode($field->name) ."/". urlencode($value)) : check_plain($value);
Dries's avatar
Dries committed
277
278
279
          }
        }
        return implode(', ', $fields);
280
281
282
283
    }
  }
}

Dries's avatar
   
Dries committed
284
function profile_view_profile($user) {
Dries's avatar
   
Dries committed
285

286
  profile_load_profile($user);
Dries's avatar
   
Dries committed
287

Steven Wittens's avatar
Steven Wittens committed
288
289
  // Show private fields to administrators and people viewing their own account.
  if (user_access('administer users') || $GLOBALS['user']->uid == $user->uid) {
290
    $result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d ORDER BY category, weight', PROFILE_HIDDEN);
Steven Wittens's avatar
Steven Wittens committed
291
292
  }
  else {
293
    $result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d AND visibility != %d ORDER BY category, weight', PROFILE_PRIVATE, PROFILE_HIDDEN);
Steven Wittens's avatar
Steven Wittens committed
294
295
  }

Dries's avatar
   
Dries committed
296
  while ($field = db_fetch_object($result)) {
297
    if ($value = profile_view_field($user, $field)) {
Steven Wittens's avatar
Steven Wittens committed
298
      $description = ($field->visibility == PROFILE_PRIVATE) ? t('The content of this field is private and only visible to yourself.') : '';
299
      $title = ($field->type != 'checkbox') ? check_plain($field->title) : '';
Steven Wittens's avatar
Steven Wittens committed
300
      $fields[$field->category] .= form_item($title, $value, $description);
Dries's avatar
   
Dries committed
301
302
303
    }
  }

Dries's avatar
Dries committed
304
  return $fields;
Dries's avatar
   
Dries committed
305
}
Dries's avatar
   
Dries committed
306

307
308
function _profile_form_explanation($field) {
  $output = $field->explanation;
Dries's avatar
   
Dries committed
309

310
  if ($field->type == 'list') {
Dries's avatar
   
Dries committed
311
    $output .= ' '. t('Put each item on a separate line or separate them by commas.  No HTML allowed.');
312
313
314
315
316
317
318
319
320
321
322
  }

  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
323
324
325
326
  if (($_GET['q'] == 'user/register') ? 1 : 0) {
    $result = db_query('SELECT * FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
  }
  else {
327
328
    $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
329
  }
Dries's avatar
   
Dries committed
330

Dries's avatar
   
Dries committed
331
  $fields = array();
Dries's avatar
   
Dries committed
332
  while ($field = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
333
    $category = $field->category;
Dries's avatar
   
Dries committed
334
335
    switch ($field->type) {
      case 'textfield':
336
      case 'url':
337
        $fields[$category] .= form_textfield(check_plain($field->title), $field->name, $edit[$field->name], 60, 255, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
338
339
        break;
      case 'textarea':
340
        $fields[$category] .= form_textarea(check_plain($field->title), $field->name, $edit[$field->name], 60, 5, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
Dries committed
341
342
        break;
      case 'list':
343
        $fields[$category] .= form_textarea(check_plain($field->title), $field->name, $edit[$field->name], 60, 5, _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
344
345
        break;
      case 'checkbox':
346
        $fields[$category] .= form_checkbox(check_plain($field->title), $field->name, 1, $edit[$field->name], _profile_form_explanation($field), NULL, $field->required);
Dries's avatar
   
Dries committed
347
348
349
        break;
      case 'selection':
        $options = array('--');
Dries's avatar
   
Dries committed
350
        $lines = split("[,\n\r]", $field->options);
Dries's avatar
   
Dries committed
351
352
353
354
355
356
        foreach ($lines as $line) {
          if ($line = trim($line)) {
            $options[$line] = $line;
          }
        }

357
        $fields[$category] .= form_select(check_plain($field->title), $field->name, $edit[$field->name], $options, _profile_form_explanation($field), 0, 0, $field->required);
Dries's avatar
   
Dries committed
358
        break;
Steven Wittens's avatar
Steven Wittens committed
359
      case 'date':
Dries's avatar
   
Dries committed
360
        $fields[$category] .= _profile_date_field($field, $edit);
Steven Wittens's avatar
Steven Wittens committed
361
        break;
Dries's avatar
   
Dries committed
362
363
364
    }
  }

Dries's avatar
   
Dries committed
365
366
367
368
369
  if ($fields) {
    foreach ($fields as $category => $data) {
      $output[] = array('title' => $category, 'data' => $data);
    }
    return $output;
370
  }
Dries's avatar
   
Dries committed
371
372
}

373
374
375
376
377
378
379
380
381
382
383
/**
 * Helper function: update an array of user fields by calling profile_view_field
 */
function _profile_update_user_fields(&$fields, $account) {
  foreach ($fields as $key => $field) {
    if ($value = profile_view_field($account, $field)) {
      $fields[$key]->value = $value;
    }
  }
}

Steven Wittens's avatar
Steven Wittens committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/**
 * 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>';

422
  return form_item(check_plain($field->title), $output, _profile_form_explanation($field), NULL, $field->required);
Steven Wittens's avatar
Steven Wittens committed
423
424
425
426
427
428
429
430
431
}

/**
 * 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);
}

432
function profile_validate_profile($edit, $category) {
Dries's avatar
   
Dries committed
433
434
435
436
437

  if (($_GET['q'] == 'user/register') ? 1 : 0) {
    $result = db_query('SELECT * FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
  }
  else {
438
439
    $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
440
  }
441
442

  while ($field = db_fetch_object($result)) {
443
    if ($edit[$field->name]) {
Dries's avatar
   
Dries committed
444
445
      if ($field->type == 'url') {
        if (!valid_url($edit[$field->name], true)) {
446
447
          form_set_error($field->name, t('The value provided for %field is not a valid URL.', array('%field' => theme('placeholder', $field->title))));
        }
448
449
      }
    }
450
    else if ($field->required && !user_access('administer users')) {
451
      form_set_error($field->name, t('The field %field is required.', array('%field' => theme('placeholder', $field->title))));
Dries's avatar
   
Dries committed
452
    }
453
454
455
456
457
  }

  return $edit;
}

458
459
460
function profile_categories() {
  $result = db_query("SELECT DISTINCT(category) FROM {profile_fields}");
  while ($category = db_fetch_object($result)) {
461
    $data[] = array('name' => check_plain($category->category), 'title' => $category->category, 'weight' => 3);
462
463
464
465
  }
  return $data;
}

Dries's avatar
   
Dries committed
466
467
468
/**
 * Implementation of hook_user().
 */
469
function profile_user($type, &$edit, &$user, $category = NULL) {
Dries's avatar
   
Dries committed
470
471
472
  switch ($type) {
    case 'load':
      return profile_load_profile($user);
Dries's avatar
   
Dries committed
473
474
    case 'register':
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
475
    case 'update':
476
    case 'insert':
477
      return profile_save_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
478
479
    case 'view':
      return profile_view_profile($user);
480
    case 'form':
481
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
482
    case 'validate':
483
484
485
      return profile_validate_profile($edit, $category);
    case 'categories':
      return profile_categories();
Dries's avatar
   
Dries committed
486
487
  }
}
Dries's avatar
   
Dries committed
488

Dries's avatar
   
Dries committed
489
function profile_validate_form($edit) {
Dries's avatar
   
Dries committed
490

Dries's avatar
   
Dries committed
491
  // Validate the title:
Dries's avatar
   
Dries committed
492

Dries's avatar
   
Dries committed
493
  if (!$edit['title']) {
Dries's avatar
   
Dries committed
494
    form_set_error('title', t('You must enter a title.'));
Dries's avatar
   
Dries committed
495
496
  }

Dries's avatar
   
Dries committed
497
  // Validate the 'form name':
Dries's avatar
   
Dries committed
498

Dries's avatar
   
Dries committed
499
  if (eregi('[^a-z0-9_-]', $edit['name'])) {
Dries's avatar
   
Dries committed
500
    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
501
502
  }

Dries's avatar
   
Dries committed
503
  if (in_array($edit['name'], user_fields())) {
Dries's avatar
   
Dries committed
504
    form_set_error('name', t('The specified form name is reserved for use by Drupal.'));
Dries's avatar
   
Dries committed
505
506
  }

Dries's avatar
   
Dries committed
507
508
  // Validate the category:
  if (!$edit['category']) {
Dries's avatar
   
Dries committed
509
    form_set_error('category', t('You must enter a category.'));
Dries's avatar
   
Dries committed
510
  }
Dries's avatar
   
Dries committed
511
512
}

Dries's avatar
   
Dries committed
513
514
515
/**
 * Menu callback; adds a new field to all user profiles.
 */
Dries's avatar
   
Dries committed
516
517
518
function profile_admin_add($type) {
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
   
Dries committed
519

Dries's avatar
   
Dries committed
520
521
522
    // Validate the form:
    profile_validate_form($data);

523
    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
524
      form_set_error('title', t('The specified title is already in use.'));
525
    }
Dries's avatar
   
Dries committed
526
527

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

Dries's avatar
   
Dries committed
531
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
532
      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
533

Dries's avatar
   
Dries committed
534
535
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
536
      drupal_set_message(t('The field has been created.'));
537
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
538
    }
Dries's avatar
   
Dries committed
539
  }
Dries's avatar
   
Dries committed
540
541
542
543
  else {
    $data = array('name' => 'profile_');
  }

544
  drupal_set_title(t('Add new %type', array('%type' => _profile_field_types($type))));
Dries's avatar
   
Dries committed
545
  return _profile_field_form($type, $data);
Dries's avatar
   
Dries committed
546
547
}

Dries's avatar
   
Dries committed
548
549
550
/**
 * Menu callback; displays the profile field editing form.
 */
Dries's avatar
   
Dries committed
551
function profile_admin_edit($fid) {
Dries's avatar
   
Dries committed
552

Dries's avatar
   
Dries committed
553
554
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
   
Dries committed
555

Dries's avatar
   
Dries committed
556
557
    // Validate form:
    profile_validate_form($data);
Dries's avatar
   
Dries committed
558

Dries's avatar
   
Dries committed
559
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
560
      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
561

Dries's avatar
   
Dries committed
562
563
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
564
      drupal_set_message(t('The field has been updated.'));
565
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
566
    }
Dries's avatar
   
Dries committed
567
568
  }
  else {
Dries's avatar
   
Dries committed
569
    $data = db_fetch_array(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid));
Dries's avatar
   
Dries committed
570
571
  }

572
  drupal_set_title(t('Edit %type', array('%type' => $data['type'])));
Dries's avatar
   
Dries committed
573
  return _profile_field_form($data['type'], $data);
Dries's avatar
   
Dries committed
574
575
}

Dries's avatar
   
Dries committed
576
577
578
/**
 * Menu callback; deletes a field from all user profiles.
 */
Dries's avatar
   
Dries committed
579
function profile_admin_delete($fid) {
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  $field = db_fetch_object(db_query("SELECT title FROM {profile_fields} WHERE fid = %d", $fid));
  if ($_POST['edit']['confirm']) {
    db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid);
    cache_clear_all();
    drupal_set_message(t('The field %field has been deleted.', array('%field' => theme('placeholder', $field->title))));
    drupal_goto('admin/settings/profile');
  }
  else {
    $output = theme('confirm',
                    t('Do you want to remove the field %field?',
                    array('%field' => $field->title)),
                    'admin/settings/profile');
    return $output;
  }
Dries's avatar
   
Dries committed
594
595
}

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

598
599
600
  $group  = form_textfield(t('Category'), 'category', $edit['category'], 60, 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'], 60, 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'], 60, 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.
Dries's avatar
   
Dries committed
601
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".'));
602
  $group .= form_textarea(t('Explanation'), 'explanation', $edit['explanation'], 60, 5, t('An optional explanation to go with the new field.  The explanation will be shown to the user.'));
Dries's avatar
   
Dries committed
603
  if ($type == 'selection') {
604
    $group .= form_textarea(t('Selection options'), 'options', $edit['options'], 60, 5, 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
605
  }
Dries's avatar
   
Dries committed
606
  $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.'));
607
  $group .= form_radios(t('Visibility'), 'visibility', $edit['visibility'], array(PROFILE_HIDDEN => t('Hidden profile field, only accessible by administrators, modules and themes.'), 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
608
  if ($type == 'selection' || $type == 'list') {
609
    $group .= form_textfield(t('Page title'), 'page', $edit['page'], 60, 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
610
611
  }
  else {
612
    $group .= form_textfield(t('Page title'), 'page', $edit['page'], 60, 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
613
  }
Dries's avatar
   
Dries committed
614
615
  $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
616

617
  $output  = form_group(t('Field settings'), $group);
Dries's avatar
   
Dries committed
618
619
620
621
622
  $output .= form_submit(t('Save field'));

  return form($output);
}

Dries's avatar
   
Dries committed
623
624
625
/**
 * Menu callback; display a listing of all editable profile fields.
 */
Dries's avatar
   
Dries committed
626
627
628
function profile_admin_overview() {

  $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
Steven Wittens's avatar
Steven Wittens committed
629
  $rows = array();
Dries's avatar
   
Dries committed
630
  while ($field = db_fetch_object($result)) {
631
    $rows[] = array(check_plain($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
632
633
634
  }
  if (count($rows) == 0) {
    $rows[] = array(array('data' => t('No fields defined.'), 'colspan' => '6'));
Dries's avatar
   
Dries committed
635
  }
Dries's avatar
   
Dries committed
636

Dries's avatar
   
Dries committed
637
  $header = array(t('Title'), t('Name'), t('Type'), t('Category'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
   
Dries committed
638
639

  $output  = theme('table', $header, $rows);
Steven Wittens's avatar
Steven Wittens committed
640
  $output .= '<h2>'. t('Add new field') .'</h2>';
Dries's avatar
   
Dries committed
641
642
  $output .= '<ul>';
  foreach (_profile_field_types() as $key => $value) {
643
    $output .= '<li>'. l($value, "admin/settings/profile/add/$key") .'</li>';
Dries's avatar
   
Dries committed
644
  }
Dries's avatar
   
Dries committed
645
646
  $output .= '</ul>';

Dries's avatar
   
Dries committed
647
  return $output;
Dries's avatar
   
Dries committed
648
649
}

650
function theme_profile_block($account, $fields = array()) {
651

652
  $output .= theme('user_picture', $account);
653
654

  foreach ($fields as $field) {
655
    if ($field->value) {
656
657
658
659
660
661
662
      $output .= "<p><strong>$field->title:</strong><br />$value</p>\n";
    }
  }

  return $output;
}

663
function theme_profile_listing($account, $fields = array()) {
Dries's avatar
   
Dries committed
664
665

  $output  = "<div class=\"profile\">\n";
666
667
  $output .= theme('user_picture', $account);
  $output .= ' <div class="name">'. theme('username', $account) ."</div>\n";
Dries's avatar
   
Dries committed
668
669

  foreach ($fields as $field) {
670
    if ($field->value) {
671
      $output .= " <div class=\"field\">$value</div>\n";
Dries's avatar
   
Dries committed
672
673
    }
  }
Dries's avatar
   
Dries committed
674
675
676
677
678
679
680

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

  return $output;
}

function _profile_field_types($type = NULL) {
Steven Wittens's avatar
Steven Wittens committed
681
682
683
684
685
686
687
  $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
688
  return isset($type) ? $types[$type] : $types;
Dries's avatar
   
Dries committed
689
690
}

Steven Wittens's avatar
Steven Wittens committed
691
692
693
694
function _profile_field_serialize($type = NULL) {
  return $type == 'date';
}

695