profile.module 25.9 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 = %d ORDER BY weight', PROFILE_PUBLIC);
63
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
            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
89
/**
Dries's avatar
   
Dries committed
90
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
91
 */
Dries's avatar
   
Dries committed
92
function profile_menu($may_cache) {
93
  global $user;
Dries's avatar
   
Dries committed
94
  $items = array();
Dries's avatar
   
Dries committed
95
96
97
98

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

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

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

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

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

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

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

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

Dries's avatar
   
Dries committed
161
    // Extract the affected users:
Dries's avatar
Dries committed
162
    $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
163

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

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

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

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

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

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

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

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

Dries's avatar
Dries committed
239
240
241
  if ($field->fid == 18 || $field->fid == 19 || $field->fid == 20) {
    return;
  }
Dries's avatar
Dries committed
242

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

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

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

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

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

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

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

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

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

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

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

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

Steven Wittens's avatar
Steven Wittens committed
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
403
404
405
/**
 * 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>';

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

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

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

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

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

  return $edit;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return form($output);
}

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

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

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

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

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

634
635
636
637
638
639
640
641
642
643
644
645
646
647
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
648
649
650

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

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

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

  return $output;
}

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

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

Dries's avatar
   
Dries committed
679
?>