You are here

legal.module in Legal 6.8

Displays Terms & Conditions, and makes sure they are accepted before registration is accepted.

File

legal.module
View source
<?php

// $Id$

/**
 * @file
 * Displays Terms & Conditions, and makes sure they are
 * accepted before registration is accepted.
 */

/**
 * Implementation of hook_help().
 */
function legal_help($path, $arg) {
  $output = '';
  switch ($path) {
    case 'admin/help#legal':
      $output .= t('Display a Terms & Conditions statement on the registration page, require visitor to accept T&C to register.
                    When a user creates an account they are required to accept your Terms & Conditions to complete their registration.');
      break;
    case 'admin/settings/legal':
      $output .= t('Display a Terms & Conditions statement on the registration page, require visitor to accept the T&C to register.
                    A <a href="@page">page</a> displaying your T&C will be automatically created, access to this page can be set via the <a href="@access">permissions</a> administration page.', array(
        '@page' => url('legal'),
        '@access' => url('admin/user/permissions'),
      ));
  }
  return $output;
}

/**
 * Implementation of hook_perm().
 */
function legal_perm() {
  return array(
    'administer Terms and Conditions',
    'view Terms and Conditions',
  );
}

/**
 * Implementation of hook_access().
 */
function legal_access($op, $node, $account) {
  return $op == 'view' && (user_access('view Terms and Conditions') || user_access('administer Terms and Conditions'));
}

/**
 * Implementation of hook_menu().
 */
function legal_menu() {
  $items = array();
  $items['admin/settings/legal'] = array(
    'title' => 'Legal',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'legal_administration',
    ),
    'access arguments' => array(
      'administer Terms and Conditions',
    ),
    'description' => 'Display Terms and Conditions statement on the registration page.',
    'file' => 'legal.admin.inc',
  );
  $items['admin/settings/legal/terms'] = array(
    'title' => 'Add T&C',
    'access arguments' => array(
      'administer Terms and Conditions',
    ),
    'description' => 'Display Terms and Conditions statement on the registration page.',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/settings/legal/languages'] = array(
    'title' => 'Languages',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'legal_languages',
    ),
    'access callback' => 'legal_languages_access',
    'access arguments' => array(
      'administer Terms and Conditions',
    ),
    'description' => 'Display Terms and Conditions statement on the registration page.',
    'weight' => 10,
    'type' => MENU_LOCAL_TASK,
    'file' => 'legal.admin.inc',
  );
  $items['legal'] = array(
    'title' => 'Terms and Conditions',
    'page callback' => 'legal_page',
    'access arguments' => array(
      'view Terms and Conditions',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'legal.pages.inc',
  );
  $items['legal_accept/%/%'] = array(
    'title' => 'Terms and Conditions',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'legal_login',
      1,
      2,
    ),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_theme().
 */
function legal_theme() {
  return array(
    'legal_administration' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'legal_display' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'legal_page' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'legal_login' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
  );
}
function legal_display_fields($conditions) {
  $form = array();
  $accept_label = t('<strong>Accept</strong> Terms & Conditions of Use');
  $form['current_id'] = array(
    '#type' => 'value',
    '#value' => $conditions['version'],
  );
  $form['language_value'] = array(
    '#type' => 'value',
    '#value' => $conditions['language'],
  );
  $form['revision_id'] = array(
    '#type' => 'value',
    '#value' => $conditions['revision'],
  );
  $form['current_date'] = array(
    '#type' => 'value',
    '#value' => $conditions['date'],
  );
  $form['display'] = array(
    '#type' => 'value',
    '#value' => variable_get('legal_display', '0'),
  );
  $form['legal'] = array(
    '#type' => 'fieldset',
    '#title' => t('Terms and Conditions of Use'),
    '#weight' => 29,
  );
  switch (variable_get('legal_display', '0')) {
    case 1:

    // Scroll box (CSS).
    case 2:

      // HTML.
      $form['legal']['conditions'] = array(
        '#value' => filter_xss_admin($conditions['conditions']),
      );
      break;
    case 3:

      // Page Link.
      $form['legal']['conditions'] = array(
        '#value' => ' ',
      );
      $accept_label = t('<strong>Accept</strong> <a href="@terms">Terms & Conditions</a> of Use', array(
        '@terms' => url('legal'),
      ));
      break;
    default:

      // Scroll box (HTML).
      $form['legal']['conditions'] = array(
        '#type' => 'textarea',
        '#title' => t('Terms & Conditions'),
        '#default_value' => $conditions['conditions'],
        '#value' => $conditions['conditions'],
        '#rows' => 10,
        '#weight' => 0,
        '#attributes' => array(
          'readonly' => 'readonly',
        ),
      );
  }
  if (!empty($conditions['extras'])) {
    foreach ($conditions['extras'] as $key => $label) {
      if (!empty($label)) {
        $form['legal'][$key] = array(
          '#type' => 'checkbox',
          '#title' => filter_xss_admin($label),
          '#default_value' => 0,
          '#weight' => 2,
          '#required' => TRUE,
        );
      }
    }
  }
  $form['legal']['legal_accept'] = array(
    '#type' => 'checkbox',
    '#title' => $accept_label,
    '#default_value' => 0,
    '#weight' => 50,
    '#required' => TRUE,
  );
  return $form;
}
function theme_legal_display($form) {
  if (!empty($form['legal']['conditions']['#value'])) {

    // Scroll box (CSS).
    if ($form['display']['#value'] == 1) {
      $path = base_path() . drupal_get_path('module', 'legal');
      drupal_add_css(drupal_get_path('module', 'legal') . '/legal.css');
      $form['legal']['conditions']['#prefix'] = '<div class="legal-terms">';
      $form['legal']['conditions']['#suffix'] = '</div>';
    }
    return $form;
  }
}
function theme_legal_page($form) {
  if (!empty($form['current_id']['#value'])) {
    $form = theme('legal_display', $form);
    return drupal_render($form);
  }
}

/**
 * Implementation of hook_user().
 */
function legal_user($op, &$edit, &$account, $category = FALSE) {
  global $user;
  global $language;
  switch ($op) {
    case 'register':
      $conditions = legal_get_conditions($language->language);

      // Do nothing if no Terms and Conditions text set.
      if (empty($conditions['conditions'])) {
        return;
      }
      $form_fields = legal_display_fields($conditions);

      /**
       * Disable checkbox if:
       * - user is already registered (administer users)
       * - users with 'administer users' can access
       *   registration on admin/user/user/create.
       */
      if (!empty($user->uid)) {
        $form_fields['legal']['legal_accept']['#attributes'] = array(
          'disabled' => 'disabled',
        );
        $form_fields['legal']['legal_accept']['#required'] = FALSE;
        if (is_array($conditions['extras'])) {
          foreach ($conditions['extras'] as $key => $label) {
            if (!empty($label)) {
              $form_fields['legal'][$key]['#attributes'] = array(
                'disabled' => 'disabled',
              );
              $form_fields['legal'][$key]['#required'] = FALSE;
            }
          }
        }
      }
      else {
        $form_fields['legal']['legal_accept']['#default_value'] = $edit['legal_accept'];
      }
      $form = theme('legal_display', $form_fields);
      return $form;
    case 'login':
      if ($user->uid == 1) {
        break;
      }

      // Get last accepted version for this account.
      $legal_account = legal_get_accept($user->uid);

      // If no version has been accepted yet,
      // get version with current language revision.
      if (empty($legal_account['version'])) {
        $conditions = legal_get_conditions($language->language);

        // No conditions set yet.
        if (empty($conditions['conditions'])) {
          return;
        }
      }
      else {

        // Get version/revision of last accepted language.
        $conditions = legal_get_conditions($legal_account['language']);

        // No conditions set yet.
        if (empty($conditions['conditions'])) {
          return;
        }

        // Check latest version of T&C has been accepted.
        $accepted = legal_version_check($user->uid, $conditions['version'], $conditions['revision'], $legal_account);
        if ($accepted) {
          return;
        }
      }
      $uid = $user->uid;

      // Destroy the current session.
      session_destroy();
      session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc');
      $null = NULL;
      user_module_invoke('logout', $null, $user);

      // We have to use $GLOBALS to unset a global variable.
      $user = user_load(array(
        'uid' => 0,
      ));
      $query = NULL;

      // Deal with destination from password reset one time login link.
      if (arg(0) == 'user' && arg(1) == 'reset') {
        $query = array(
          'destination' => "user/{$uid}/edit",
        );
      }
      if (!empty($_REQUEST['destination'])) {
        $query = array(
          'destination' => $_REQUEST['destination'],
        );
      }
      unset($_REQUEST['destination']);
      $signatory = db_fetch_object(db_query_range('SELECT * FROM {users} WHERE uid = %d', $uid, 0, 1));
      drupal_goto('legal_accept/' . $signatory->uid . '/' . md5($signatory->name . $signatory->pass . $signatory->login), $query);
      break;
    case 'form':
      if ($category != 'account') {
        return;
      }

      // Get last accepted version for this account.
      $legal_account = legal_get_accept($account->uid);

      // If no version has been accepted yet,
      // get version with current language revision.
      if (empty($legal_account['version'])) {
        $conditions = legal_get_conditions($language->language);

        // No conditions set yet.
        if (empty($conditions['conditions'])) {
          return;
        }
      }
      else {

        // Get version/revision last accepted language.
        $conditions = legal_get_conditions($legal_account['language']);

        // No conditions set yet.
        if (empty($conditions['conditions'])) {
          return;
        }

        // Check latest version of T&C has been accepted.
        $accepted = legal_version_check($account->uid, $conditions['version'], $conditions['revision'], $legal_account);

        // Enable language switching if version
        // accepted and revision up to date.
        if ($accepted && $legal_account['language'] != $language->language) {
          $conditions = legal_get_conditions($language->language);
        }
      }
      $form_fields = legal_display_fields($conditions);
      if ($accepted === TRUE) {
        $form_fields['legal']['legal_accept']['#value'] = 1;
        if (!empty($conditions['extras'])) {
          foreach ($conditions['extras'] as $key => $label) {
            if (!empty($label)) {
              $form_fields['legal'][$key]['#value'] = 1;
            }
          }
        }
      }

      // Disable checkbox if:
      //  - user is not account owner;
      //  - latest T&C has already been accepted.
      if ($account->uid != $user->uid || $accepted == TRUE) {
        $form_fields['legal']['legal_accept']['#attributes'] = array(
          'disabled' => 'disabled',
        );
        if (!empty($conditions['extras'])) {
          reset($conditions['extras']);
          foreach ($conditions['extras'] as $key => $label) {
            if (!empty($label)) {
              $form_fields['legal'][$key]['#attributes'] = array(
                'disabled' => 'disabled',
              );
            }
          }
        }
      }

      // Not required if user is not account owner.
      if ($account->uid != $user->uid) {
        $form_fields['legal']['legal_accept']['#required'] = FALSE;
        if (!empty($conditions['extras'])) {
          reset($conditions['extras']);
          foreach ($conditions['extras'] as $key => $label) {
            if (!empty($label)) {
              $form_fields['legal'][$key]['#required'] = FALSE;
            }
          }
        }
      }

      // Enable account owner to accept.
      if ($account->uid == $user->uid && $accepted != TRUE) {
        $form_fields['legal']['legal_accept']['#default_value'] = isset($edit['legal_accept']) ? $edit['legal_accept'] : '';
        $form_fields['legal']['legal_accept']['#required'] = TRUE;
        if (!empty($conditions['extras'])) {
          reset($conditions['extras']);
          foreach ($conditions['extras'] as $key => $label) {
            if (!empty($label)) {
              $form_fields['legal'][$key]['#default_value'] = isset($edit[$key]) ? $edit[$key] : '';
              $form_fields['legal'][$key]['#required'] = TRUE;
            }
          }
        }
      }
      $form = theme('legal_display', $form_fields);
      return $form;
      break;
    case 'insert':
      $conditions = legal_get_conditions($language->language);
      if (empty($conditions['conditions'])) {
        return;
      }

      // Record the accepted state before removing legal_accept from $edit.
      $accepted = $edit['legal_accept'];
      $edit['legal_accept'] = NULL;
      $edit['conditions'] = NULL;
      foreach ($conditions['extras'] as $key => $label) {
        $edit[$key] = NULL;
      }

      // Don't insert if user is already registered (administrator).
      if (!empty($user->uid)) {
        break;
      }
      if ($accepted) {
        legal_save_accept($conditions['version'], $conditions['revision'], $conditions['language'], $account->uid);
      }
      break;
    case 'update':
      $conditions = legal_get_conditions($language->language);
      if (empty($conditions['conditions'])) {
        return;
      }

      // Record the accepted state before removing legal_accept from $edit.
      $accepted = $edit['legal_accept'];
      $edit['legal_accept'] = NULL;
      $edit['conditions'] = NULL;
      foreach ($conditions['extras'] as $key => $label) {
        $edit[$key] = NULL;
      }
      if ($account->uid != $user->uid) {
        break;
      }

      // If already accepted skip data entry.
      $previously_accepted = legal_version_check($account->uid, $conditions['version'], $conditions['revision']);
      if ($previously_accepted === TRUE) {
        break;
      }
      if ($accepted) {
        legal_save_accept($conditions['version'], $conditions['revision'], $conditions['language'], $account->uid);
      }
      break;
  }
}

/**
 * Require registered users to accept new T&C.
 */
function legal_login($constructor, $uid, $id_hash = NULL) {
  global $language;

  // Get last accepted version for this account.
  $legal_account = legal_get_accept($uid);

  // If no version has been accepted yet,
  // get version with current language revision.
  if (empty($legal_account['version'])) {
    $conditions = legal_get_conditions($language->language);

    // No conditions set yet.
    if (empty($conditions['conditions'])) {
      return;
    }
  }
  else {

    // Get version / revision of last accepted language.
    $conditions = legal_get_conditions($legal_account['language']);

    // No conditions set yet.
    if (empty($conditions['conditions'])) {
      return;
    }

    // Check latest version of T&C has been accepted.
    $accepted = legal_version_check($uid, $conditions['version'], $conditions['revision'], $legal_account);
    if ($accepted) {
      return;
    }
  }
  $form = legal_display_fields($conditions);
  $form['uid'] = array(
    '#type' => 'value',
    '#value' => $uid,
  );
  $form['id_hash'] = array(
    '#type' => 'value',
    '#value' => $id_hash,
  );
  $form['tc_id'] = array(
    '#type' => 'value',
    '#value' => $conditions['tc_id'],
  );
  $form['version'] = array(
    '#type' => 'value',
    '#value' => $conditions['version'],
  );
  $form['revision'] = array(
    '#type' => 'value',
    '#value' => $conditions['revision'],
  );
  $form['language'] = array(
    '#type' => 'value',
    '#value' => $conditions['language'],
  );
  $form = legal_display_changes($form, $uid);
  $redirect = 'user/' . $uid;
  if (!empty($_GET['destination'])) {
    $redirect = $_GET['destination'];
  }
  $form['#redirect'] = $redirect;
  $form['save'] = array(
    '#type' => 'submit',
    '#value' => t('Confirm'),
  );
  return $form;
}
function legal_login_validate($form, &$form_state) {
  $account = db_fetch_object(db_query_range('SELECT * FROM {users} WHERE uid = %d', $form_state['values']['uid'], 0, 1));
  $id_hash = md5($account->name . $account->pass . $account->login);
  if ($id_hash != $form_state['values']['id_hash']) {
    form_set_error('legal_accept', t('User ID cannot be identified.'));
    drupal_goto();
  }
}
function legal_login_submit($form, &$form_state) {
  global $user;
  $values = $form_state['values'];
  $user = user_load(array(
    'uid' => $values['uid'],
  ));
  legal_save_accept($values['version'], $values['revision'], $values['language'], $user->uid);
  watchdog('legal', '%name accepted T&C version %tc_id.', array(
    '%name' => $user->name,
    '%tc_id' => $values['tc_id'],
  ));

  // Update the user table timestamp noting user has logged in.
  db_query("UPDATE {users} SET login = '%d' WHERE uid = '%s'", time(), $user->uid);

  // User has new permissions, so we clear their menu cache.
  cache_clear_all($user->uid, 'cache_menu', TRUE);

  // Fixes login problems in Pressflow.
  sess_regenerate();
  user_module_invoke('login', $edit, $user);
}
function theme_legal_login($form) {
  $form = theme('legal_display', $form);
  $output = '<p>' . t('To continue to use this site please read the Terms & Conditions below, and complete the form to confirm your acceptance.') . '</p>';
  if (isset($form['changes']['#value'])) {
    foreach (element_children($form['changes']) as $key) {
      $form['changes'][$key]['#prefix'] .= '<li>';
      $form['changes'][$key]['#suffix'] .= '</li>';
    }
    $form['changes']['start_list'] = array(
      '#value' => '<ul>',
      '#weight' => 0,
    );
    $form['changes']['end_list'] = array(
      '#value' => '</ul>',
      '#weight' => 3,
    );
    $output .= drupal_render($form['changes']);
  }
  $save = drupal_render($form['save']);
  $output .= drupal_render($form);
  $output .= $save;
  return $output;
}
function legal_get_accept($uid) {
  $keys = array(
    'legal_id',
    'version',
    'revision',
    'language',
    'uid',
    'accepted',
  );
  $result = db_fetch_array(db_query_range("SELECT * FROM {legal_accepted} WHERE uid = %d ORDER BY version DESC, revision DESC", $uid, 0, 1));
  foreach ($keys as $key) {
    $accept[$key] = $result[$key];
  }
  return $accept;
}
function legal_save_accept($version, $revision, $language, $uid) {
  db_query("INSERT INTO {legal_accepted} (version, revision, language, uid, accepted) VALUES (%d, %d, '%s', %d, %d)", $version, $revision, $language, $uid, time());
}
function legal_get_conditions($language = NULL) {
  $keys = array(
    'tc_id',
    'version',
    'revision',
    'language',
    'conditions',
    'date',
    'extras',
    'changes',
  );
  if (!empty($language)) {
    $args[] = $language;
    $result = db_fetch_array(db_query_range("SELECT * FROM {legal_conditions} WHERE language = '%s' ORDER BY version DESC, revision DESC", $args, 0, 1));
  }
  else {
    $result = db_fetch_array(db_query_range("SELECT * FROM {legal_conditions} ORDER BY tc_id DESC", 0, 1));
  }
  foreach ($keys as $key) {
    $conditions[$key] = isset($result[$key]) ? $result[$key] : '';
  }
  $conditions['extras'] = empty($conditions['extras']) ? array() : unserialize($conditions['extras']);
  return $conditions;
}

/**
 * Get all changes since user last accepted.
 */
function legal_display_changes($form, $uid) {
  $is_list = FALSE;
  $bullet_points = array();
  $last_accepted = legal_get_accept($uid);
  if (empty($last_accepted)) {
    return $form;
  }
  $result = db_query("SELECT changes FROM {legal_conditions}\n                      WHERE ((version > %d) OR (version = %d AND revision > %d)) AND language = '%s'\n                      ORDER BY revision ASC, version ASC", $last_accepted['version'], $last_accepted['version'], $last_accepted['revision'], $last_accepted['language']);
  if (empty($result)) {
    return $form;
  }
  while ($term = db_fetch_object($result)) {
    $changes = filter_xss_admin($term->changes);
    if (!empty($changes)) {
      $bullet_points = array_merge($bullet_points, explode("\r\n", $changes));
    }
  }
  if (empty($bullet_points)) {
    return $form;
  }
  $form['changes'] = array(
    '#type' => 'fieldset',
    '#title' => t('Changes List'),
    '#description' => t('Changes to the Terms & Conditions since last accepted:'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#tree' => TRUE,
  );
  $form['changes']['bullet_points'] = array(
    '#value' => theme('item_list', $bullet_points),
  );
  return $form;
}

/**
 * Check if user has accepted latest version of T&C.
 */
function legal_version_check($uid, $version, $revision, $legal_account = array()) {
  if (empty($legal_account)) {
    $legal_account = legal_get_accept($uid);
  }
  if ($legal_account['version'] == $version && $legal_account['revision'] == $revision) {
    $accepted = TRUE;
  }
  else {
    $accepted = FALSE;
  }
  return $accepted;
}

/**
 * Access control callback.
 * Check that Locale module is enabled and user has access permission.
 */
function legal_languages_access($perm) {
  if (!module_exists('locale')) {
    return FALSE;
  }
  if (!user_access($perm)) {
    return FALSE;
  }
  return TRUE;
}

/**
 * Implementation of hook_views_api().
 */
function legal_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'legal') . '/views',
  );
}

Functions

Namesort descending Description
legal_access Implementation of hook_access().
legal_display_changes Get all changes since user last accepted.
legal_display_fields
legal_get_accept
legal_get_conditions
legal_help Implementation of hook_help().
legal_languages_access Access control callback. Check that Locale module is enabled and user has access permission.
legal_login Require registered users to accept new T&C.
legal_login_submit
legal_login_validate
legal_menu Implementation of hook_menu().
legal_perm Implementation of hook_perm().
legal_save_accept
legal_theme Implementation of hook_theme().
legal_user Implementation of hook_user().
legal_version_check Check if user has accepted latest version of T&C.
legal_views_api Implementation of hook_views_api().
theme_legal_display
theme_legal_login
theme_legal_page