profile.module 26 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
56
57
58
59
60
61
62
/**
 * 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)) {
        $result = db_query('SELECT uid FROM {node} WHERE nid = %d ORDER BY uid DESC', arg(1));
        $node = db_fetch_object($result);
        $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();
Dries's avatar
Dries committed
63
          $result = db_query('SELECT name, title, type, visibility FROM {profile_fields} WHERE visibility = %d ORDER BY weight', PROFILE_PUBLIC, PROFILE_PUBLIC_LISTING);
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            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) {
          $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
      $output .= theme('profile_listing', user_load(array('uid' => $account->uid)), $fields);
Dries's avatar
   
Dries committed
168
169
170
    }
    $output .= theme('pager', NULL, 20);

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

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

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

203
    drupal_set_title(t('user list'));
Dries's avatar
   
Dries committed
204
    return $output;
Dries's avatar
   
Dries committed
205
  }
Dries's avatar
   
Dries committed
206
}
Dries's avatar
   
Dries committed
207

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

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

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

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

Dries's avatar
   
Dries committed
280
function profile_view_profile($user) {
Dries's avatar
   
Dries committed
281

282
  profile_load_profile($user);
Dries's avatar
   
Dries committed
283

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

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

Dries's avatar
Dries committed
300
  return $fields;
Dries's avatar
   
Dries committed
301
}
Dries's avatar
   
Dries committed
302

303
304
function _profile_form_explanation($field) {
  $output = $field->explanation;
Dries's avatar
   
Dries committed
305

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

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

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

353
        $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
354
        break;
Steven Wittens's avatar
Steven Wittens committed
355
      case 'date':
Dries's avatar
   
Dries committed
356
        $fields[$category] .= _profile_date_field($field, $edit);
Steven Wittens's avatar
Steven Wittens committed
357
        break;
Dries's avatar
   
Dries committed
358
359
360
    }
  }

Dries's avatar
   
Dries committed
361
362
363
364
365
  if ($fields) {
    foreach ($fields as $category => $data) {
      $output[] = array('title' => $category, 'data' => $data);
    }
    return $output;
366
  }
Dries's avatar
   
Dries committed
367
368
}

Steven Wittens's avatar
Steven Wittens committed
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/**
 * 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>';

407
  return form_item(check_plain($field->title), $output, _profile_form_explanation($field), NULL, $field->required);
Steven Wittens's avatar
Steven Wittens committed
408
409
410
411
412
413
414
415
416
}

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

417
function profile_validate_profile($edit, $category) {
Dries's avatar
   
Dries committed
418
419
420
421
422

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

  while ($field = db_fetch_object($result)) {
428
    if ($edit[$field->name]) {
Dries's avatar
   
Dries committed
429
430
      if ($field->type == 'url') {
        if (!valid_url($edit[$field->name], true)) {
431
432
          form_set_error($field->name, t('The value provided for %field is not a valid URL.', array('%field' => theme('placeholder', $field->title))));
        }
433
434
      }
    }
435
    else if ($field->required && !user_access('administer users')) {
436
      form_set_error($field->name, t('The field %field is required.', array('%field' => theme('placeholder', $field->title))));
Dries's avatar
   
Dries committed
437
    }
438
439
440
441
442
  }

  return $edit;
}

443
444
445
function profile_categories() {
  $result = db_query("SELECT DISTINCT(category) FROM {profile_fields}");
  while ($category = db_fetch_object($result)) {
446
    $data[] = array('name' => check_plain($category->category), 'title' => $category->category, 'weight' => 3);
447
448
449
450
  }
  return $data;
}

Dries's avatar
   
Dries committed
451
452
453
/**
 * Implementation of hook_user().
 */
454
function profile_user($type, &$edit, &$user, $category = NULL) {
Dries's avatar
   
Dries committed
455
456
457
  switch ($type) {
    case 'load':
      return profile_load_profile($user);
Dries's avatar
   
Dries committed
458
459
    case 'register':
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
460
    case 'update':
461
    case 'insert':
462
      return profile_save_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
463
464
    case 'view':
      return profile_view_profile($user);
465
    case 'form':
466
      return profile_form_profile($edit, $user, $category);
Dries's avatar
   
Dries committed
467
    case 'validate':
468
469
470
      return profile_validate_profile($edit, $category);
    case 'categories':
      return profile_categories();
Dries's avatar
   
Dries committed
471
472
  }
}
Dries's avatar
   
Dries committed
473

Dries's avatar
   
Dries committed
474
function profile_validate_form($edit) {
Dries's avatar
   
Dries committed
475

Dries's avatar
   
Dries committed
476
  // Validate the title:
Dries's avatar
   
Dries committed
477

Dries's avatar
   
Dries committed
478
  if (!$edit['title']) {
Dries's avatar
   
Dries committed
479
    form_set_error('title', t('You must enter a title.'));
Dries's avatar
   
Dries committed
480
481
  }

Dries's avatar
   
Dries committed
482
  // Validate the 'form name':
Dries's avatar
   
Dries committed
483

Dries's avatar
   
Dries committed
484
  if (eregi('[^a-z0-9_-]', $edit['name'])) {
Dries's avatar
   
Dries committed
485
    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
486
487
  }

Dries's avatar
   
Dries committed
488
  if (in_array($edit['name'], user_fields())) {
Dries's avatar
   
Dries committed
489
    form_set_error('name', t('The specified form name is reserved for use by Drupal.'));
Dries's avatar
   
Dries committed
490
491
  }

Dries's avatar
   
Dries committed
492
493
  // Validate the category:
  if (!$edit['category']) {
Dries's avatar
   
Dries committed
494
    form_set_error('category', t('You must enter a category.'));
Dries's avatar
   
Dries committed
495
  }
Dries's avatar
   
Dries committed
496
497
}

Dries's avatar
   
Dries committed
498
499
500
/**
 * Menu callback; adds a new field to all user profiles.
 */
Dries's avatar
   
Dries committed
501
502
503
function profile_admin_add($type) {
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
   
Dries committed
504

Dries's avatar
   
Dries committed
505
506
507
    // Validate the form:
    profile_validate_form($data);

508
    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
509
      form_set_error('title', t('The specified title is already in use.'));
510
    }
Dries's avatar
   
Dries committed
511
512

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

Dries's avatar
   
Dries committed
516
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
517
      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
518

Dries's avatar
   
Dries committed
519
520
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
521
      drupal_set_message(t('The field has been created.'));
522
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
523
    }
Dries's avatar
   
Dries committed
524
  }
Dries's avatar
   
Dries committed
525
526
527
528
  else {
    $data = array('name' => 'profile_');
  }

529
  drupal_set_title(t('Add new %type', array('%type' => _profile_field_types($type))));
Dries's avatar
   
Dries committed
530
  return _profile_field_form($type, $data);
Dries's avatar
   
Dries committed
531
532
}

Dries's avatar
   
Dries committed
533
534
535
/**
 * Menu callback; displays the profile field editing form.
 */
Dries's avatar
   
Dries committed
536
function profile_admin_edit($fid) {
Dries's avatar
   
Dries committed
537

Dries's avatar
   
Dries committed
538
539
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
   
Dries committed
540

Dries's avatar
   
Dries committed
541
542
    // Validate form:
    profile_validate_form($data);
Dries's avatar
   
Dries committed
543

Dries's avatar
   
Dries committed
544
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
545
      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
546

Dries's avatar
   
Dries committed
547
548
      cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
549
      drupal_set_message(t('The field has been updated.'));
550
      drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
551
    }
Dries's avatar
   
Dries committed
552
553
  }
  else {
Dries's avatar
   
Dries committed
554
    $data = db_fetch_array(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid));
Dries's avatar
   
Dries committed
555
556
  }

557
  drupal_set_title(t('Edit %type', array('%type' => $data['type'])));
Dries's avatar
   
Dries committed
558
  return _profile_field_form($data['type'], $data);
Dries's avatar
   
Dries committed
559
560
}

Dries's avatar
   
Dries committed
561
562
563
/**
 * Menu callback; deletes a field from all user profiles.
 */
Dries's avatar
   
Dries committed
564
function profile_admin_delete($fid) {
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  $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
579
580
}

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

Dries's avatar
   
Dries committed
583
584
585
586
587
  $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
588
  if ($type == 'selection') {
Dries's avatar
   
Dries committed
589
    $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
590
  }
Dries's avatar
   
Dries committed
591
  $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.'));
592
  $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
593
  if ($type == 'selection' || $type == 'list') {
594
    $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
595
596
  }
  else {
597
    $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
598
  }
Dries's avatar
   
Dries committed
599
600
  $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
601

602
  $output  = form_group(t('Field settings'), $group);
Dries's avatar
   
Dries committed
603
604
605
606
607
  $output .= form_submit(t('Save field'));

  return form($output);
}

Dries's avatar
   
Dries committed
608
609
610
/**
 * Menu callback; display a listing of all editable profile fields.
 */
Dries's avatar
   
Dries committed
611
612
613
function profile_admin_overview() {

  $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
Steven Wittens's avatar
Steven Wittens committed
614
  $rows = array();
Dries's avatar
   
Dries committed
615
  while ($field = db_fetch_object($result)) {
616
    $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
617
618
619
  }
  if (count($rows) == 0) {
    $rows[] = array(array('data' => t('No fields defined.'), 'colspan' => '6'));
Dries's avatar
   
Dries committed
620
  }
Dries's avatar
   
Dries committed
621

Dries's avatar
   
Dries committed
622
  $header = array(t('Title'), t('Name'), t('Type'), t('Category'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
   
Dries committed
623
624

  $output  = theme('table', $header, $rows);
Steven Wittens's avatar
Steven Wittens committed
625
  $output .= '<h2>'. t('Add new field') .'</h2>';
Dries's avatar
   
Dries committed
626
627
  $output .= '<ul>';
  foreach (_profile_field_types() as $key => $value) {
628
    $output .= '<li>'. l($value, "admin/settings/profile/add/$key") .'</li>';
Dries's avatar
   
Dries committed
629
  }
Dries's avatar
   
Dries committed
630
631
  $output .= '</ul>';

Dries's avatar
   
Dries committed
632
  return $output;
Dries's avatar
   
Dries committed
633
634
}

635
636
637
638
639
640
641
642
643
644
645
646
647
648
function theme_profile_block($user, $fields = array()) {

  $output .= theme('user_picture', $user);

  foreach ($fields as $field) {
    if ($value = profile_view_field($user, $field)) {
      $output .= "<p><strong>$field->title:</strong><br />$value</p>\n";
    }
  }

  return $output;
}

function theme_profile_listing($user, $fields = array()) {
Dries's avatar
   
Dries committed
649
650
651

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

  foreach ($fields as $field) {
655
656
    if ($value = profile_view_field($user, $field)) {
      $output .= " <div class=\"field\">$value</div>\n";
Dries's avatar
   
Dries committed
657
658
    }
  }
Dries's avatar
   
Dries committed
659
660
661
662
663
664
665

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

  return $output;
}

function _profile_field_types($type = NULL) {
Steven Wittens's avatar
Steven Wittens committed
666
667
668
669
670
671
672
  $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
673
  return isset($type) ? $types[$type] : $types;
Dries's avatar
   
Dries committed
674
675
}

Steven Wittens's avatar
Steven Wittens committed
676
677
678
679
function _profile_field_serialize($type = NULL) {
  return $type == 'date';
}

Dries's avatar
   
Dries committed
680
?>