profile.module 25.5 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();
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.changed 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
180
    drupal_set_title($title);
    print theme('page', $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
194
195
196
197
  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)) {
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
204
    drupal_set_title(t('user list'));
    print theme('page', $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;

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

Dries's avatar
   
Dries committed
276
function profile_view_profile($user) {
Dries's avatar
   
Dries committed
277

278
  profile_load_profile($user);
Dries's avatar
   
Dries committed
279

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

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

Dries's avatar
Dries committed
296
  return $fields;
Dries's avatar
   
Dries committed
297
}
Dries's avatar
   
Dries committed
298

299
300
function _profile_form_explanation($field) {
  $output = $field->explanation;
Dries's avatar
   
Dries committed
301

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

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

Dries's avatar
   
Dries committed
323
  $fields = array();
Dries's avatar
   
Dries committed
324
  while ($field = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
325
    $category = $field->category;
Dries's avatar
   
Dries committed
326
327
    switch ($field->type) {
      case 'textfield':
328
      case 'url':
329
        $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
330
331
        break;
      case 'textarea':
332
        $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
333
334
        break;
      case 'list':
335
        $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
336
337
        break;
      case 'checkbox':
338
        $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
339
340
341
        break;
      case 'selection':
        $options = array('--');
Dries's avatar
   
Dries committed
342
        $lines = split("[,\n\r]", $field->options);
Dries's avatar
   
Dries committed
343
344
345
346
347
348
        foreach ($lines as $line) {
          if ($line = trim($line)) {
            $options[$line] = $line;
          }
        }

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

Dries's avatar
   
Dries committed
357
358
359
360
361
  if ($fields) {
    foreach ($fields as $category => $data) {
      $output[] = array('title' => $category, 'data' => $data);
    }
    return $output;
362
  }
Dries's avatar
   
Dries committed
363
364
}

Steven Wittens's avatar
Steven Wittens committed
365
366
367
368
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
/**
 * 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>';

403
  return form_item(check_plain($field->title), $output, _profile_form_explanation($field), NULL, $field->required);
Steven Wittens's avatar
Steven Wittens committed
404
405
406
407
408
409
410
411
412
}

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

413
function profile_validate_profile($edit, $category) {
Dries's avatar
   
Dries committed
414
415
416
417
418

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

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

  return $edit;
}

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

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

Dries's avatar
   
Dries committed
470
function profile_validate_form($edit) {
Dries's avatar
   
Dries committed
471

Dries's avatar
   
Dries committed
472
  // Validate the title:
Dries's avatar
   
Dries committed
473

Dries's avatar
   
Dries committed
474
  if (!$edit['title']) {
Dries's avatar
   
Dries committed
475
    form_set_error('title', t('You must enter a title.'));
Dries's avatar
   
Dries committed
476
477
  }

Dries's avatar
   
Dries committed
478
  // Validate the 'form name':
Dries's avatar
   
Dries committed
479

Dries's avatar
   
Dries committed
480
  if (eregi('[^a-z0-9_-]', $edit['name'])) {
Dries's avatar
   
Dries committed
481
    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
482
483
  }

Dries's avatar
   
Dries committed
484
  if (in_array($edit['name'], user_fields())) {
Dries's avatar
   
Dries committed
485
    form_set_error('name', t('The specified form name is reserved for use by Drupal.'));
Dries's avatar
   
Dries committed
486
487
  }

Dries's avatar
   
Dries committed
488
489
  // Validate the category:
  if (!$edit['category']) {
Dries's avatar
   
Dries committed
490
    form_set_error('category', t('You must enter a category.'));
Dries's avatar
   
Dries committed
491
  }
Dries's avatar
   
Dries committed
492
493
}

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

Dries's avatar
   
Dries committed
501
502
503
    // Validate the form:
    profile_validate_form($data);

504
    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
505
      form_set_error('title', t('The specified title is already in use.'));
506
    }
Dries's avatar
   
Dries committed
507
508

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

Dries's avatar
   
Dries committed
512
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
513
      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
514

Dries's avatar
   
Dries committed
515
516
      cache_clear_all();

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

525
526
  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
527
528
}

Dries's avatar
   
Dries committed
529
530
531
/**
 * Menu callback; displays the profile field editing form.
 */
Dries's avatar
   
Dries committed
532
function profile_admin_edit($fid) {
Dries's avatar
   
Dries committed
533

Dries's avatar
   
Dries committed
534
535
  if ($_POST['op']) {
    $data = $_POST['edit'];
Dries's avatar
   
Dries committed
536

Dries's avatar
   
Dries committed
537
538
    // Validate form:
    profile_validate_form($data);
Dries's avatar
   
Dries committed
539

Dries's avatar
   
Dries committed
540
    if (!form_get_errors()) {
Dries's avatar
   
Dries committed
541
      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
542

Dries's avatar
   
Dries committed
543
544
      cache_clear_all();

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

553
554
  drupal_set_title(t('Edit %type', array('%type' => $data['type'])));
  print theme('page', _profile_field_form($data['type'], $data));
Dries's avatar
   
Dries committed
555
556
}

Dries's avatar
   
Dries committed
557
558
559
/**
 * Menu callback; deletes a field from all user profiles.
 */
Dries's avatar
   
Dries committed
560
561
function profile_admin_delete($fid) {
  db_query('DELETE FROM {profile_fields} WHERE fid = %d', $fid);
Dries's avatar
   
Dries committed
562
563
564

  cache_clear_all();

Steven Wittens's avatar
Steven Wittens committed
565
  drupal_set_message(t('The field has been deleted.'));
566
  drupal_goto('admin/settings/profile');
Dries's avatar
   
Dries committed
567
568
}

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

Dries's avatar
   
Dries committed
571
572
573
574
575
  $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
576
  if ($type == 'selection') {
Dries's avatar
   
Dries committed
577
    $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
578
  }
Dries's avatar
   
Dries committed
579
  $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.'));
580
  $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
581
  if ($type == 'selection' || $type == 'list') {
582
    $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
583
584
  }
  else {
585
    $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
586
  }
Dries's avatar
   
Dries committed
587
588
  $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
589

590
  $output  = form_group(t('Field settings'), $group);
Dries's avatar
   
Dries committed
591
592
593
594
595
  $output .= form_submit(t('Save field'));

  return form($output);
}

Dries's avatar
   
Dries committed
596
597
598
/**
 * Menu callback; display a listing of all editable profile fields.
 */
Dries's avatar
   
Dries committed
599
600
601
function profile_admin_overview() {

  $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
Steven Wittens's avatar
Steven Wittens committed
602
  $rows = array();
Dries's avatar
   
Dries committed
603
  while ($field = db_fetch_object($result)) {
604
    $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
605
606
607
  }
  if (count($rows) == 0) {
    $rows[] = array(array('data' => t('No fields defined.'), 'colspan' => '6'));
Dries's avatar
   
Dries committed
608
  }
Dries's avatar
   
Dries committed
609

Dries's avatar
   
Dries committed
610
  $header = array(t('Title'), t('Name'), t('Type'), t('Category'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
   
Dries committed
611
612

  $output  = theme('table', $header, $rows);
Steven Wittens's avatar
Steven Wittens committed
613
  $output .= '<h2>'. t('Add new field') .'</h2>';
Dries's avatar
   
Dries committed
614
615
  $output .= '<ul>';
  foreach (_profile_field_types() as $key => $value) {
616
    $output .= '<li>'. l($value, "admin/settings/profile/add/$key") .'</li>';
Dries's avatar
   
Dries committed
617
  }
Dries's avatar
   
Dries committed
618
619
620
  $output .= '</ul>';

  print theme('page', $output);
Dries's avatar
   
Dries committed
621
622
}

623
624
625
626
627
628
629
630
631
632
633
634
635
636
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
637
638
639

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

  foreach ($fields as $field) {
643
644
    if ($value = profile_view_field($user, $field)) {
      $output .= " <div class=\"field\">$value</div>\n";
Dries's avatar
   
Dries committed
645
646
    }
  }
Dries's avatar
   
Dries committed
647
648
649
650
651
652
653

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

  return $output;
}

function _profile_field_types($type = NULL) {
Steven Wittens's avatar
Steven Wittens committed
654
655
656
657
658
659
660
  $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
661
  return isset($type) ? $types[$type] : $types;
Dries's avatar
   
Dries committed
662
663
}

Steven Wittens's avatar
Steven Wittens committed
664
665
666
667
function _profile_field_serialize($type = NULL) {
  return $type == 'date';
}

Dries's avatar
   
Dries committed
668
?>