You are here

advuser.module in Advanced User 5.2

Advanced user module allows you to select users based on an advanced set of filtering and apply actions to block, unblock, delete or email the selected users.

File

advuser.module
View source
<?php

/**
 * @file
 * Advanced user module allows you to select users based on an advanced set of
 * filtering and apply actions to block, unblock, delete or email the selected
 * users.
 *
 **/

/**
 * @constants
 */
define('ADVUSER_SUBSTITUTION_TEXT', '<strong>Substitution variables</strong> available in subject and email body<br/><em> %user_name, %user_email, %user_status, %user_created, %user_theme, %user_timezone, %user_language, %user_signature, %site, %uri, %google_user (search google for user email), %yahoo_user (search yahoo for user email)</em>');

/**
 * Implementation of hook_perm().
 */
function advuser_perm() {
  return array(
    'administer advuser',
    'access advuser',
    'send email advuser',
    'receive email advuser',
  );
}

/**
 * Implementation of hook_menu().
 */
function advuser_menu($may_cache) {

  // Include filters
  include_once drupal_get_path('module', 'advuser') . '/advuser_filters.inc';
  $admin_access = user_access('administer advuser');
  $access_access = user_access('access advuser');
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/settings/advuser',
      'title' => t('Advanced User'),
      'description' => t('Advanced User Settings'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'advuser_settings',
      ),
      'access' => $admin_access,
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/user/user/advuser',
      'title' => t('Advanced'),
      'description' => t('List, add, edit and email users.'),
      'callback' => 'advuser_admin',
      'callback arguments' => array(
        'list',
      ),
      'access' => $access_access,
      'type' => MENU_LOCAL_TASK,
    );
  }
  return $items;
}
function advuser_admin($callback_arg = '') {
  $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
  switch ($op) {
    default:
      if ($_POST['accounts'] && $_POST['operation'] == 'delete') {
        $output = drupal_get_form('advuser_multiple_delete_confirm');
      }
      elseif ($_POST['accounts'] && $_POST['operation'] == 'email') {
        $output = drupal_get_form('advuser_multiple_email_confirm');
      }
      else {
        $output = drupal_get_form('advuser_filter_form');
        $output .= drupal_get_form('advuser_admin_account');
      }
      break;
  }
  return $output;
}
function advuser_admin_account() {
  $filter = advuser_build_filter_query();
  $header = array(
    array(),
    array(
      'data' => t('Username'),
      'field' => 'u.name',
    ),
    array(
      'data' => t('Status'),
      'field' => 'u.status',
    ),
  );
  $roles = advuser_user_roles();
  if (count($roles)) {
    $header[] = t('Roles');
  }
  $header = array_merge($header, array(
    array(
      'data' => t('Member for'),
      'field' => 'u.created',
      'sort' => 'desc',
    ),
    array(
      'data' => t('Last access'),
      'field' => 'u.access',
    ),
  ));
  $query = '';
  $ff = array();
  $pf = array();
  foreach (advuser_profile_fields() as $field) {
    $ff[] = array(
      'data' => t($field->title),
      'field' => "{$field->name}.value",
    );
    $pf[] = "LEFT JOIN {profile_values} {$field->name} ON {$field->name}.fid = {$field->fid} AND {$field->name}.uid = u.uid";
  }
  $header = array_merge($header, $ff);
  $header[] = t('Operations');
  $filter['join'] .= count($pf) ? ' ' . implode(' ', array_unique($pf)) : NULL;
  $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, u.access ' . $pquery . ' FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid ' . $filter['join'] . ' WHERE u.uid != 0 ' . $filter['where'];
  $sql .= tablesort_sql($header);
  $query_count = 'SELECT COUNT(DISTINCT u.uid) FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid ' . $filter['join'] . ' WHERE u.uid != 0 ' . $filter['where'];
  $result = pager_query($sql, variable_get('advuser_listno', 50), 0, $query_count, $filter['args']);
  $form['options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Update options'),
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $options = array();
  $operations = module_invoke_all('user_operations');
  $operations = array_merge($operations, module_invoke_all('advuser_operations'));
  foreach ($operations as $operation => $array) {
    $options[$operation] = $array['label'];
  }
  $form['options']['operation'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#default_value' => 'unblock',
  );
  $form['options']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
  );
  $destination = drupal_get_destination();
  $status = array(
    t('blocked'),
    t('active'),
  );
  $roles = advuser_user_roles();
  while ($account = db_fetch_object($result)) {
    $accounts[$account->uid] = '';
    $form['name'][$account->uid] = array(
      '#value' => theme('username', $account),
    );
    $form['status'][$account->uid] = array(
      '#value' => $status[$account->status],
    );
    $users_roles = array();
    $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $account->uid);
    while ($user_role = db_fetch_object($roles_result)) {
      $users_roles[] = $roles[$user_role->rid];
    }
    asort($users_roles);
    $form['roles'][$account->uid][0] = array(
      '#value' => theme('item_list', $users_roles),
    );
    $form['member_for'][$account->uid] = array(
      '#value' => format_interval(time() - $account->created),
    );
    $form['last_access'][$account->uid] = array(
      '#value' => $account->access ? t('@time ago', array(
        '@time' => format_interval(time() - $account->access),
      )) : t('never'),
    );
    module_invoke('profile', 'load_profile', $account);
    foreach (advuser_profile_fields() as $field) {
      $form[$field->name][$account->uid] = array(
        '#value' => profile_view_field($account, $field),
      );
    }
    $fv = l(t('edit'), "user/{$account->uid}/edit", array(), $destination);
    if ($account->uid != 1) {
      $fv .= ' | ' . l(t('delete'), "user/{$account->uid}/delete", array(), $destination);
    }
    $form['operations'][$account->uid] = array(
      '#value' => $fv,
    );
  }
  $form['accounts'] = array(
    '#type' => 'checkboxes',
    '#options' => $accounts,
  );
  $form['pager'] = array(
    '#value' => theme('pager', NULL, 50, 0),
  );
  return $form;
}

/**
 * Theme user administration overview.
 */
function theme_advuser_admin_account($form) {
  static $profile_fields = array();

  // Overview table:
  $header = array(
    theme('table_select_header_cell'),
    array(
      'data' => t('Username'),
      'field' => 'u.name',
    ),
    array(
      'data' => t('Status'),
      'field' => 'u.status',
    ),
  );
  $roles = advuser_user_roles();
  if (count($roles)) {
    $header[] = t('Roles');
  }
  $header = array_merge($header, array(
    array(
      'data' => t('Member for'),
      'field' => 'u.created',
      'sort' => 'desc',
    ),
    array(
      'data' => t('Last access'),
      'field' => 'u.access',
    ),
  ));
  $ff = array();
  foreach (advuser_profile_fields() as $field) {
    $ff[] = array(
      'data' => t($field->title),
      'field' => $field->name,
    );
  }
  $header = array_merge($header, $ff);
  $header[] = t('Operations');
  $output = drupal_render($form['options']);
  if (isset($form['name']) && is_array($form['name'])) {
    foreach (element_children($form['name']) as $key) {
      $row = array(
        drupal_render($form['accounts'][$key]),
        drupal_render($form['name'][$key]),
        drupal_render($form['status'][$key]),
      );
      $roles = advuser_user_roles();
      if (count($roles)) {
        $row[] = drupal_render($form['roles'][$key]);
      }
      $row = array_merge($row, array(
        drupal_render($form['member_for'][$key]),
        drupal_render($form['last_access'][$key]),
      ));
      if (module_exists('profile')) {
        $fields = variable_get('advuser_profile_fields', NULL);
        if (is_array($fields)) {
          foreach ($fields as $fid => $value) {
            if ($value) {
              if (empty($profile_fields[$fid])) {
                $field = db_fetch_object(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid));
                $profile_fields[$fid] = $field;
              }
              else {
                $field = $profile_fields[$fid];
              }
              $row[] = drupal_render($form[$field->name][$key]);
            }
          }
        }
      }
      $row[] = drupal_render($form['operations'][$key]);
      $rows[] = $row;
    }
  }
  else {
    $rows[] = array(
      array(
        'data' => t('No users available.'),
        'colspan' => '7',
      ),
    );
  }
  $output .= theme('table', $header, $rows);
  if ($form['pager']['#value']) {
    $output .= drupal_render($form['pager']);
  }
  $output .= drupal_render($form);
  return $output;
}

/**
 * Submit the user administration update form.
 */
function advuser_admin_account_submit($form_id, $form_values) {
  $operations = module_invoke_all('user_operations');
  $operations = array_merge($operations, module_invoke_all('advuser_operations'));
  $operation = $operations[$form_values['operation']];

  // Filter out unchecked accounts.
  $accounts = array_filter($form_values['accounts']);
  if ($function = $operation['callback']) {

    // Add in callback arguments if present.
    if (isset($operation['callback arguments'])) {
      $args = array_merge(array(
        $accounts,
      ), $operation['callback arguments']);
    }
    else {
      $args = array(
        $accounts,
      );
    }
    call_user_func_array($function, $args);
    cache_clear_all('*', 'cache_menu', TRUE);
    drupal_set_message(t('The update has been performed.'));
  }
}
function advuser_admin_account_validate($form_id, $form_values) {
  $form_values['accounts'] = array_filter($form_values['accounts']);
  if (count($form_values['accounts']) == 0) {
    form_set_error('', t('No users selected.'));
  }
}
function advuser_multiple_delete_confirm() {
  $edit = $_POST;
  $form['accounts'] = array(
    '#prefix' => '<ul>',
    '#suffix' => '</ul>',
    '#tree' => TRUE,
  );

  // array_filter returns only elements with TRUE values
  foreach (array_filter($edit['accounts']) as $uid => $value) {
    $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid));
    $form['accounts'][$uid] = array(
      '#type' => 'hidden',
      '#value' => $uid,
      '#prefix' => '<li>',
      '#suffix' => check_plain($user) . "</li>\n",
    );
  }
  $form['operation'] = array(
    '#type' => 'hidden',
    '#value' => 'delete',
  );
  return confirm_form($form, t('Are you sure you want to delete these users?'), 'admin/user/user/advuser', t('This action cannot be undone.'), t('Delete all'), t('Cancel'));
}
function advuser_multiple_delete_confirm_submit($form_id, $form_values) {
  if ($form_values['confirm']) {
    foreach ($form_values['accounts'] as $uid => $value) {
      user_delete($form_values, $uid);
    }
    drupal_set_message(t('The users have been deleted.'));
  }
  return 'admin/user/user/advuser';
}

/**
 * Email functionality
 */
function advuser_advuser_operations() {
  $operations = array(
    'email' => array(
      'label' => t('Email selected users'),
    ),
  );
  return $operations;
}
function advuser_multiple_email_confirm() {
  $edit = $_POST;
  $form['accounts'] = array(
    '#prefix' => '<ul>',
    '#suffix' => '</ul>',
    '#tree' => TRUE,
  );

  // array_filter returns only elements with TRUE values
  foreach (array_filter($edit['accounts']) as $uid => $value) {
    $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid));
    $form['accounts'][$uid] = array(
      '#type' => 'hidden',
      '#value' => $uid,
      '#prefix' => '<li>',
      '#suffix' => check_plain($user) . "</li>\n",
    );
  }
  $form['operation'] = array(
    '#type' => 'hidden',
    '#value' => 'email',
  );
  $form['variables'] = array(
    '#type' => 'markup',
    '#prefix' => '<div class="advuser-inset-panel">',
    '#value' => t(ADVUSER_SUBSTITUTION_TEXT),
    '#suffix' => '</div>',
  );
  $form['mailsubject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject'),
    '#required' => TRUE,
  );
  $form['mailbody'] = array(
    '#type' => 'textarea',
    '#title' => t('Mail body'),
    '#required' => TRUE,
  );
  return confirm_form($form, t('Are you sure you want to email these users?'), 'admin/user/user/advuser', t('This action cannot be undone.'), t('Email'), t('Cancel'));
}
function advuser_multiple_email_confirm_submit($form_id, $form_values) {
  if ($form_values['confirm']) {
    foreach ($form_values['accounts'] as $uid => $value) {
      $account = user_load(array(
        'uid' => $uid,
      ));
      $from = variable_get("site_mail", ini_get("sendmail_from"));

      // these are invariant for all sent emails
      $variables = _advuser_get_variables($account);
      $mail_subject = strtr($form_values['mailsubject'], $variables);
      $mail_body = strtr($form_values['mailbody'], $variables);
      drupal_mail('advance-user-mail', $account->mail, $mail_subject, $mail_body, $from);
    }
    drupal_set_message(t('The users have been mailed.'));
  }
  return 'admin/user/user/advuser';
}

/**
 * advuser settings page
 */
function advuser_settings() {
  $form['advuser_mail'] = array(
    '#type' => 'fieldset',
    '#title' => t('Mail notifications on user account activity.'),
    '#collapsible' => FALSE,
    '#collapsed' => FALSE,
  );
  $form['advuser_mail']['variables'] = array(
    '#type' => 'markup',
    '#prefix' => '<div class="advuser-inset-panel">',
    '#value' => t(ADVUSER_SUBSTITUTION_TEXT),
    '#suffix' => '</div>',
  );

  //New User Notification
  $form['advuser_mail']['advuser_new_notify'] = array(
    '#type' => 'checkbox',
    '#title' => t('Send notifications on new user registration'),
    '#description' => t('Notify selected roles when new users register.'),
    '#default_value' => variable_get('advuser_new_notify', FALSE),
  );
  $form['advuser_mail']['advuser_new_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Mail subject'),
    '#description' => t('The subject of the mail that is going to be sent to the user.  You may insert substitution variables within this item.'),
    '#default_value' => variable_get('advuser_new_subject', NULL),
  );
  $form['advuser_mail']['advuser_new_mail'] = array(
    '#type' => 'textarea',
    '#title' => t('Mail body'),
    '#description' => t('The mail that is going to be sent to the selected roles.  You may insert substitution variables within this item.'),
    '#default_value' => variable_get('advuser_new_mail', NULL),
  );

  //User change notification
  $form['advuser_mail']['advuser_modify_notify'] = array(
    '#type' => 'checkbox',
    '#title' => t('Send notifications on user profile updates'),
    '#description' => t('Notify selected roles when users update their profiles.'),
    '#default_value' => variable_get('advuser_modify_notify', FALSE),
  );
  $form['advuser_mail']['advuser_modify_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Mail subject'),
    '#description' => t('The subject of the mail that is going to be sent when a user modifies their profiles.  You may insert substitution variables within this item.'),
    '#default_value' => variable_get('advuser_modify_subject', NULL),
  );
  $form['advuser_mail']['advuser_modify_mail'] = array(
    '#type' => 'textarea',
    '#title' => t('Mail body'),
    '#description' => t('The mail that is going to be sent to the selected roles when a user modifies their account.  You may insert substitution variables within this item.'),
    '#default_value' => variable_get('advuser_modify_mail', NULL),
  );

  //Maximum rows in dataset to display
  $form['advuser_mail']['advuser_listno'] = array(
    '#type' => 'select',
    '#options' => drupal_map_assoc(array(
      1,
      10,
      25,
      50,
      75,
      100,
      125,
      150,
      175,
      200,
    )),
    '#title' => t('Number of users in listing'),
    '#description' => t('Sets how many users to display in table view'),
    '#default_value' => variable_get('advuser_listno', 50),
  );
  $sel_roles_count = count(users_by_access('receive email advuser'));
  if ($sel_roles_count == 0) {
    $form['advuser_mailonnew']['no_roles_sel_warning'] = array(
      '#type' => 'markup',
      '#prefix' => '<div class="advuser-settings-warning">',
      '#value' => '<strong>WARNING: No users have "receive email advuser" ' . l('access permissions', 'admin/user/access') . '!</strong> - No email notifications will be sent.',
      '#suffix' => '</div>',
    );
  }
  if (module_exists('profile')) {
    $form['advuser_profile'] = array(
      '#type' => 'fieldset',
      '#title' => t('Profile module special settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $fields = array();
    $result = db_query('SELECT * FROM {profile_fields} ORDER BY category, weight');
    while ($row = db_fetch_object($result)) {
      $fields[$row->fid] = $row->title;
    }
    $values = array();
    $options = variable_get('advuser_profile_fields', NULL);
    foreach ((array) $options as $opt => $v) {
      if ($v > 0) {
        $values[] = $v;
      }
    }
    $form['advuser_profile']['advuser_profile_fields'] = array(
      '#type' => 'checkboxes',
      '#description' => t('Profile fields to be used as filters for the users.'),
      '#title' => t('Profile fields'),
      '#options' => $fields,
      '#default_value' => $values,
    );
  }
  return system_settings_form($form);
}

/**
 * Get a list of substitution variables for the user account
 * @param $user the user account
 * @return An associative array of substitution variables 
 */
function _advuser_get_variables($user) {
  return array(
    '%user_name' => $user->name,
    '%site' => variable_get("site_name", "drupal"),
    '%uri' => url('user/' . $user->uid, NULL, NULL, TRUE),
    '%user_email' => $user->mail,
    '%user_status' => t($user->status ? 'Active' : 'Blocked'),
    '%user_theme' => empty($user->theme) ? t('DEFAULT') : $user->theme,
    '%user_created' => strftime('%x %X', $user->created),
    '%user_language' => empty($user->language) ? t('DEFAULT') : $user->language,
    '%user_timezone' => empty($user->timezone) ? '0' : "{$user->timezone}",
    '%user_signature' => $user->signature,
    '%google_user' => "http://www.google.com/search?q=%22{$user->mail}%22",
    '%yahoo_user' => "http://search.yahoo.com/search/?p=%22{$user->mail}%22",
  );
}

/**
 * @private
 * Return a list of users to send notification of user changes.
 *
 * @return resource         // The result of the db_query.
 */
function _advuser_dbquery_users_to_notify() {
  $user_where = users_by_access('receive email advuser');
  $user_where = implode(',', $user_where);
  return empty($user_where) ? FALSE : db_query('SELECT u.mail, u.name FROM {users} u WHERE uid IN (' . $user_where . ')');
}

/**
 * Handle user insertion (new users)
 */
function advuser_user_insert($edit, $user, $category) {

  // Check to see if we notify the administrator of new users.
  // Only send if the user isn't created by an administrator.
  $new_notify = variable_get('advuser_new_notify', FALSE) && !user_access('administer_users');
  if ($new_notify) {
    $from = variable_get("site_mail", ini_get("sendmail_from"));
    $body = variable_get('advuser_new_mail', NULL);
    $subject = variable_get('advuser_new_subject', NULL);

    // these are invariant for all sent emails
    $variables = _advuser_get_variables($user);
    $user_subject = strtr($subject, $variables);
    $user_body = strtr($body, $variables);
    watchdog('advuser', "Sending user account mail: subj='{$user_subject}' body='{$user_body}'");
    _advuser_mail_roles($user_subject, $user_body, $from);
  }
}

/**
 * @public
 * List of users for given roles
 *
 * @param string $perm                  // The string permission.
 * @return array                        // An array of uid.
 */
function users_by_access($perm) {
  $select_permissions = "SELECT ur.uid FROM {permission} p LEFT JOIN {users_roles} ur ON ur.rid = p.rid WHERE p.perm like '%%%s%%'";
  $ret = array();
  $result = db_query($select_permissions, $perm);
  while ($data = db_fetch_object($result)) {
    if (isset($data->uid)) {
      $ret[] = $data->uid;
    }
  }
  return $ret;
}

/**
 * @private
 * Mail users in requested notification role.
 *
 * @param string $user_subject
 * @param string $user_body
 * @param string $from
 */
function _advuser_mail_roles($user_subject, $user_body, $from) {
  static $mail_list = array();
  if (empty($mail_list)) {
    $result = _advuser_dbquery_users_to_notify();
    while ($row = db_fetch_object($result)) {
      $mail_list[] = $row->mail;
    }
  }
  foreach ($mail_list as $to) {
    drupal_mail('advanced-user-mail', $to, $user_subject, $user_body, $from);
  }
}

/**
 * TODO: Need 'send test email' -> sends test email for current user account, to current user account
 */

/**
 * Notify administrator of user profile edit.
 */
function advuser_user_update($edit, $user, $category) {

  // Check to see if we notify the administrator of the modified user profile.
  // Only send if the user isn't modified by an administrator.
  $modify_notify = variable_get('advuser_modify_notify', FALSE) && !user_access('administer users');
  if ($modify_notify) {
    $from = variable_get("site_mail", ini_get("sendmail_from"));
    $body = variable_get('advuser_modify_mail', NULL);
    $subject = variable_get('advuser_modify_subject', NULL);

    // these are invariant for all sent emails
    $variables = _advuser_get_variables($user);
    $user_subject = strtr($subject, $variables);
    $user_body = strtr($body, $variables);
    watchdog('advuser', "Sending user account mail: subj='{$user_subject}' body='{$user_body}'");
    _advuser_mail_roles($user_subject, $user_body, $from);
  }
}

/** 
 * hook_user implementation  
 */
function advuser_user($type, &$edit, &$user, $category = NULL) {
  $return = NULL;
  switch ($type) {
    case 'insert':
      $return = advuser_user_insert($edit, $user, $category);
      break;
    case 'after_update':
      $return = advuser_user_update($edit, $user, $category);
      break;
  }
  return $return;
}

/**
 * Selected Profile Fields
 * @return array
 */
function advuser_profile_fields() {
  static $ret = array();
  if (!count($ret) && module_exists('profile')) {
    $fields = variable_get('advuser_profile_fields', NULL);
    if (is_array($fields)) {
      foreach ($fields as $fid => $value) {
        if ($value) {
          $ret[] = db_fetch_object(db_query('SELECT * FROM {profile_fields} WHERE fid = %d', $fid));
        }
      }
    }
  }
  return $ret;
}

/**
 * Profile Field Values
 *
 * @param int $fid
 * @param int $uid
 * @return mixed
 */
function advuser_profile_value($fid, $uid) {
  $ret = db_result(db_query("SELECT value FROM {profile_values} WHERE fid = %d and uid = %d", $fid, $uid));
  if ($ret === FALSE) {
    $ret = NULL;
  }
  return $ret;
}

/**
 * User Roles for use in ADVUSER.
 *
 * @return array
 */
function advuser_user_roles() {
  static $roles;
  if (empty($roles)) {
    $roles = user_roles(1);
    unset($roles[DRUPAL_AUTHENTICATED_RID]);
  }
  return $roles;
}

// vim:ft=php:sts=2:sw=2:ts=2:et:ai:sta:ff=unix

Functions

Namesort descending Description
advuser_admin
advuser_admin_account
advuser_admin_account_submit Submit the user administration update form.
advuser_admin_account_validate
advuser_advuser_operations Email functionality
advuser_menu Implementation of hook_menu().
advuser_multiple_delete_confirm
advuser_multiple_delete_confirm_submit
advuser_multiple_email_confirm
advuser_multiple_email_confirm_submit
advuser_perm Implementation of hook_perm().
advuser_profile_fields Selected Profile Fields
advuser_profile_value Profile Field Values
advuser_settings advuser settings page
advuser_user hook_user implementation
advuser_user_insert Handle user insertion (new users)
advuser_user_roles User Roles for use in ADVUSER.
advuser_user_update Notify administrator of user profile edit.
theme_advuser_admin_account Theme user administration overview.
users_by_access @public List of users for given roles
_advuser_dbquery_users_to_notify @private Return a list of users to send notification of user changes.
_advuser_get_variables Get a list of substitution variables for the user account
_advuser_mail_roles @private Mail users in requested notification role.

Constants

Namesort descending Description
ADVUSER_SUBSTITUTION_TEXT @constants