regcode.module in Registration codes 7
Same filename and directory in other branches
Main functionality and hooks of regcode module.
File
regcode.moduleView source
<?php
/**
* @file
* Main functionality and hooks of regcode module.
*/
// Define validation error codes.
define('REGCODE_VALIDITY_NOTEXISTING', 0);
define('REGCODE_VALIDITY_NOTAVAILABLE', 1);
define('REGCODE_VALIDITY_TAKEN', 2);
define('REGCODE_VALIDITY_EXPIRED', 3);
define('REGCODE_MODE_REPLACE', 0);
define('REGCODE_MODE_SKIP', 1);
define('REGCODE_CLEAN_TRUNCATE', 1);
define('REGCODE_CLEAN_INACTIVE', 3);
define('REGCODE_CLEAN_EXPIRED', 4);
/**
* Implements hook_help().
*/
function regcode_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/config/people/regcode':
$output = '<p>' . t('View and manage created registration codes.') . '</p>';
break;
case 'admin/config/people/regcode/create':
$output = '<p>' . t('Create manually or generate new registration codes.') . '</p>';
break;
case 'admin/config/people/regcode/manage':
$output = '<p>' . t('Provides bulk management features for created registration codes.') . '</p>';
break;
case 'admin/config/people/regcode/settings':
$output = '<p>' . t('Configure the registration code module.') . '</p>';
break;
}
return $output;
}
/**
* Implements hook_permission().
*/
function regcode_permission() {
return array(
'administer registration codes' => array(
'title' => t('administer registration codes'),
'description' => t('Configure the module and generate and delete registration codes'),
),
);
}
/**
* Implements hook_menu().
*/
function regcode_menu() {
$items = array();
$items['admin/config/people/regcode'] = array(
'title' => 'Registration codes',
'description' => 'Manage registration codes.',
'file' => 'regcode.admin.php',
'page callback' => 'regcode_admin_list',
'access arguments' => array(
'administer registration codes',
),
);
$items['admin/config/people/regcode/list'] = array(
'title' => 'List',
'description' => 'List of registration codes',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 10,
);
$items['admin/config/people/regcode/create'] = array(
'title' => 'Create',
'description' => 'Create a registration code',
'type' => MENU_LOCAL_TASK | MENU_LOCAL_ACTION,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'regcode_admin_create',
),
'access arguments' => array(
'administer registration codes',
),
'file' => 'regcode.admin.php',
'weight' => 20,
);
$items['admin/config/people/regcode/manage'] = array(
'title' => 'Manage',
'description' => 'Manage the registration code database',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'regcode_admin_manage',
),
'access arguments' => array(
'administer registration codes',
),
'file' => 'regcode.admin.php',
'weight' => 30,
);
$items['admin/config/people/regcode/settings'] = array(
'title' => 'Settings',
'description' => 'Settings for registration code functionality.',
'type' => MENU_LOCAL_TASK,
'access arguments' => array(
'administer registration codes',
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'regcode_admin_settings',
),
'file' => 'regcode.admin.php',
'weight' => 40,
);
return $items;
}
/**
* Implements hook_entity_info().
*/
function regcode_entity_info() {
return array(
'regcode' => array(
'label' => t('Registration Code'),
'base table' => 'regcode',
'entity keys' => array(
'id' => 'rid',
'label' => 'code',
),
),
);
}
/**
* Implements hook_field_extra_fields().
*/
function regcode_field_extra_fields() {
$extra = array();
$extra['user']['user'] = array(
'form' => array(
'regcode' => array(
'label' => t('Registration code'),
'description' => t('Registration code form elements.'),
'weight' => -10,
),
),
'display' => array(
'regcode' => array(
'label' => t('Registration code history'),
'description' => t('Registration code history view element.'),
'weight' => 5,
),
),
);
return $extra;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function regcode_form_user_register_form_alter(&$form, &$form_state) {
$code_optional = variable_get('regcode_optional', FALSE);
$form['regcode'] = array(
'#type' => 'textfield',
'#title' => check_plain(variable_get('regcode_field_title', t('Registration Code'))),
'#description' => check_plain(variable_get('regcode_field_description', t('Please enter your registration code.'))),
'#required' => !($code_optional || user_access('administer users')),
'#element_validate' => array(
'regcode_code_element_validate',
),
);
// Capture the code from the url and inject it into the registration form.
if (isset($_GET['regcode'])) {
/*
* Form API can handle potentially unsafe characters as long as they are
* not printed directly. This code gets trimmed in regcode_code_validate().
*/
$form['regcode']['#value'] = $_GET['regcode'];
$form['regcode']['#description'] = NULL;
$form['regcode']['#disabled'] = TRUE;
}
}
/**
* Validate the content of the code-field on user registration.
*/
function regcode_code_element_validate(&$element, &$form_state) {
if (drupal_strlen(trim($element['#value']))) {
$code = regcode_code_validate($element['#value']);
if (!is_object($code)) {
form_error($element, regcode_errormsg($code));
watchdog('regcode', 'User entered invalid registration code (@code)', array(
'@code' => $element['#value'],
), WATCHDOG_WARNING);
}
}
}
/**
* Implements hook_user_insert().
*/
function regcode_user_insert(&$edit, $account) {
$account->regcode = FALSE;
if (empty($edit['regcode'])) {
return;
}
$code = regcode_code_consume($edit['regcode'], $account->uid);
if ($code) {
$account->regcode = $code;
}
watchdog('regcode', 'The registration code %code was used by !user', array(
'%code' => $edit['regcode'],
'!user' => l($account->name, 'user/' . $account->uid),
));
/*
* Modules are expected to "consume" any data in the $edit array once it
* has been used.
*/
$edit['code'] = NULL;
}
/**
* Implements hook_views_api().
*/
function regcode_views_api() {
return array(
'api' => 3,
);
}
/**
* Implements hook_action_info().
*/
function regcode_action_info() {
return array(
'regcode_activate_action' => array(
'type' => 'regcode',
'label' => t('Activate codes'),
'configurable' => FALSE,
'triggers' => array(
'any' => TRUE,
),
),
'regcode_deactivate_action' => array(
'type' => 'regcode',
'label' => t('Deactive codes'),
'configurable' => FALSE,
'triggers' => array(
'any' => TRUE,
),
),
'regcode_delete_action' => array(
'type' => 'regcode',
'label' => t('Delete codes'),
'configurable' => FALSE,
'triggers' => array(
'any' => TRUE,
),
),
'regcode_tag_action' => array(
'type' => 'regcode',
'label' => t('Tag codes'),
'configurable' => TRUE,
'triggers' => array(
'any' => TRUE,
),
),
);
}
/**
* Get the exposed regcode fields.
*
* @todo
* Make use of the entity API.
*
* @return array
* List of fields and their descriptions.
*/
function regcode_get_fields() {
// Core exposed fields.
$fields = array(
'begins' => array(
'description' => t('When code should be active from'),
'title' => t('Begins'),
),
'expires' => array(
'description' => t('When code should expire'),
'title' => t('Expires'),
),
'code' => array(
'description' => t('The registration code'),
'title' => t('Code'),
),
'is_active' => array(
'description' => t('Whether the code is active'),
'title' => t('Enabled'),
),
'maxuses' => array(
'description' => t('Maximum times the code can be used'),
'title' => t('Max'),
),
'uses' => array(
'description' => t('Number of times the code has been used'),
'title' => t('Uses'),
),
);
// Load contributed fields.
$contrib = module_invoke_all('regcode_fields');
if (is_array($contrib)) {
$fields += $contrib;
}
return $fields;
}
/**
* Return text message requested by given identifier/constant.
*
* @param int $err
* The error message code.
*
* @return string
* The text of the message.
*/
function regcode_errormsg($err) {
$messages = array(
REGCODE_VALIDITY_NOTEXISTING => t('Registration code does not exist'),
REGCODE_VALIDITY_NOTAVAILABLE => t('Registration code is not available'),
REGCODE_VALIDITY_TAKEN => t('Registration code has already been used'),
REGCODE_VALIDITY_EXPIRED => t('Registration code has expired'),
);
$msg = FALSE;
if (isset($messages[$err])) {
$msg = $messages[$err];
}
return $msg;
}
/**
* Load a registration code.
*
* @param int|null $id
* The database primary key (rid).
* @param array $conditions
* An associative array containing the search conditions.
*
* @return object|bool
* The regcode object or FALSE if the code does not exist.
*
* @example
* regcode_load(1231); // Loads the regcode with rid=1231
* regcode_load(NULL, array('code'=>'foobar')); // Loads the "foobar" regcode
*/
function regcode_load_single($id, $conditions = array()) {
// Build the query.
$query = db_select('regcode')
->fields('regcode', array(
'rid',
'uid',
'created',
'lastused',
'begins',
'expires',
'code',
'is_active',
'maxuses',
'uses',
))
->range(0, 1);
// Allow mixed search parameters.
if (!empty($id)) {
$query
->condition('rid', $id);
}
else {
foreach ($conditions as $field => $value) {
$query
->condition($field, $value);
}
}
// Run the query and grab a single regcode.
$regcode = $query
->execute()
->fetchObject();
if (!$regcode) {
return FALSE;
}
// Load the terms.
$query = db_select('regcode_term')
->fields('term_data', array(
'tid',
'name',
))
->condition('regcode_term.rid', $regcode->rid);
$query
->join('taxonomy_term_data', 'term_data', 'regcode_term.tid = term_data.tid');
$tags = $query
->execute();
$regcode->tags = array();
foreach ($tags as $tag) {
$regcode->tags[$tag->tid] = $tag->name;
}
/*
* Entity loaders expect arrays of objects. entity_load and
* this function both invoke the hook below.
*/
$reg_codes = array(
$regcode->rid => $regcode,
);
module_invoke_all('regcode_load', $reg_codes);
return $reg_codes[$regcode->rid];
}
/**
* Validate a regcode.
*
* @param string $regcode
* The regcode alphanumeric code.
*
* @return bool|int|object
* An error code, or the loaded regcode.
*/
function regcode_code_validate($regcode) {
// Load the code.
$code = regcode_load_single(NULL, array(
'code' => trim($regcode),
));
// Check validity.
if ($code === FALSE) {
return REGCODE_VALIDITY_NOTEXISTING;
}
if ($code->uses >= $code->maxuses && $code->maxuses !== '0') {
return REGCODE_VALIDITY_TAKEN;
}
if (!$code->is_active) {
return REGCODE_VALIDITY_NOTAVAILABLE;
}
if (!empty($code->begins) && $code->begins > REQUEST_TIME) {
return REGCODE_VALIDITY_NOTAVAILABLE;
}
if (!empty($code->expires) && $code->expires < REQUEST_TIME) {
return REGCODE_VALIDITY_EXPIRED;
}
return $code;
}
/**
* Consume a regcode and attribute it to a user.
*
* @param string $regcode
* The registration code.
* @param int $account_id
* Optional user id to assign the given code to.
*
* @return mixed
* An error code, or TRUE if the code was assigned successfully.
*/
function regcode_code_consume($regcode, $account_id) {
$code = regcode_code_validate($regcode);
// Check the code validated, otherwise return the error code.
if (!is_object($code)) {
return $code;
}
$code->uses++;
// Mark the code inactive if it's used up.
$active = 1;
if ($code->maxuses != 0 && $code->uses >= $code->maxuses) {
$active = 0;
}
// Use the code.
db_update('regcode')
->fields(array(
'uses' => $code->uses,
'lastused' => REQUEST_TIME,
'uid' => $account_id,
'is_active' => $active,
))
->condition('rid', $code->rid)
->execute();
// Trigger the regcode_used hook.
$account = user_load($account_id);
$account->regcode = $code;
foreach (module_implements('regcode_used') as $module) {
$hook = $module . '_regcode_used';
$hook($code, $account);
}
// Notify rules module.
if (is_object($code) && module_exists('rules')) {
rules_invoke_event('regcode_used', $account, $code);
}
return $code;
}
/**
* Gets the term ids associated with a registration code.
*
* @param object $code
* The registration code entity.
*
* @return array
* An array of term IDs.
*/
function regcode_get_term_ids(stdClass $code) {
return array_keys($code->tags);
}
/**
* Save given code to a record in the db and calls the regcode_presave hook.
*
* @todo
* Remove the $terms parameter and put it in the object
*
* @param object $code
* A code object (required fields are code, begins, expires, is_active, and
* maxuses.
* @param array $terms
* An array of terms to associate this tag with.
* @param int $action
* Action to perform when saving the code.
*
* @return bool
* TRUE if the code was saved.
*/
function regcode_save($code, $terms = array(), $action = REGCODE_MODE_REPLACE) {
// Sanity check.
if (empty($code) || empty($code->code)) {
return FALSE;
}
// Trigger the regcode_save hook.
foreach (module_implements('regcode_presave') as $module) {
$hook = $module . '_regcode_presave';
$hook($code, $terms);
}
// Insert mode.
if ($action == REGCODE_MODE_REPLACE) {
db_delete('regcode')
->condition('code', $code->code)
->execute();
}
// Insert.
$rid = db_insert('regcode')
->fields(array(
'created' => REQUEST_TIME,
'begins' => empty($code->begins) ? NULL : (int) $code->begins,
'expires' => empty($code->expires) ? NULL : (int) $code->expires,
'code' => check_plain($code->code),
'is_active' => isset($code->is_active) ? $code->is_active : 1,
'maxuses' => isset($code->maxuses) ? (int) $code->maxuses : 1,
))
->execute();
// Add tags.
if (count($terms)) {
foreach (array_filter($terms) as $tid => $enabled) {
db_insert('regcode_term')
->fields(array(
'rid' => $rid,
'tid' => $tid,
))
->execute();
}
}
return $rid;
}
/**
* Delete regcode codes.
*
* @param int $op
* The operation ID.
*
* @return bool|object|int
* Boolean false if nothing happened. True if tables were empties. The number
* of deleted rows otherwise.
*/
function regcode_clean($op) {
$res = FALSE;
switch ($op) {
case REGCODE_CLEAN_TRUNCATE:
db_query('TRUNCATE {regcode}');
db_query('TRUNCATE {regcode_term}');
$res = TRUE;
break;
case REGCODE_CLEAN_EXPIRED:
$res = db_delete('regcode')
->condition('expires', REQUEST_TIME, '<')
->execute();
break;
case REGCODE_CLEAN_INACTIVE:
$res = db_delete('regcode')
->condition('is_active', 0)
->execute();
break;
}
return $res;
}
/**
* Generate a code.
*/
function regcode_generate($length, $output, $case) {
static $seeded = FALSE;
// Possible seeds.
$outputs['alpha'] = 'abcdefghijklmnopqrstuvwqyz';
$outputs['numeric'] = '0123456789';
$outputs['alphanum'] = 'abcdefghijklmnopqrstuvwqyz0123456789';
$outputs['hexadec'] = '0123456789abcdef';
// Choose seed.
if (isset($outputs[$output])) {
$output = $outputs[$output];
}
// Seed generator (only do this once per invocation).
if (!$seeded) {
list($usec, $sec) = explode(' ', microtime());
$seed = (double) $sec + (double) $usec * 100000;
mt_srand($seed);
$seeded = TRUE;
}
// Generate.
$str = '';
$output_count = strlen($output);
for ($i = 0; $length > $i; $i++) {
$str .= $output[mt_rand(0, $output_count - 1)];
}
if ($case) {
$str = strtoupper($str);
}
return $str;
}
/**
* Regcode delete action.
*/
function regcode_delete_action(&$object, $context = array()) {
db_delete('regcode')
->condition('rid', $object->rid)
->execute();
}
/**
* Regcode activate action.
*/
function regcode_activate_action(&$object, $context = array()) {
db_update('regcode')
->fields(array(
'is_active' => 1,
))
->condition('rid', $object->rid)
->execute();
}
/**
* Regcode deactivate action.
*/
function regcode_deactivate_action(&$object, $context = array()) {
db_update('regcode')
->fields(array(
'is_active' => 0,
))
->condition('rid', $object->rid)
->execute();
}
/**
* Regcode tag action.
*/
function regcode_tag_action(&$object, $context = array()) {
// Apply terms.
foreach ($context['apply_terms'] as $term) {
$record = array(
'rid' => $object->rid,
'tid' => $term,
);
db_merge('regcode_term')
->key($record)
->fields($record)
->execute();
}
// Remove terms.
foreach ($context['remove_terms'] as $term) {
db_delete('regcode_term')
->condition('rid', $object->rid)
->condition('tid', $term)
->execute();
}
}
/**
* Form for tag_action.
*/
function regcode_tag_action_form() {
$form = array();
$form['regcode_apply_terms'] = array(
'#type' => 'checkboxes',
'#title' => t('Apply tags'),
'#description' => t('Select tags to be applied to the selected codes.'),
'#options' => regcode_get_vocab_terms(),
);
$form['regcode_remove_terms'] = array(
'#type' => 'checkboxes',
'#title' => t('Remove tags'),
'#description' => t('Select tags to be remove to the selected codes.'),
'#options' => regcode_get_vocab_terms(),
);
$vid = variable_get('regcode_vocabulary', 1);
$text = t('You can <a href="!url">create tags</a> through the taxonomy module.', array(
'!url' => url('admin/structure/taxonomy/' . $vid . '/add/term'),
));
$form['regcode_taxonomy'] = array(
'#value' => '<p>' . $text . '</p>',
);
return $form;
}
/**
* Submit handler for tag_action.
*/
function regcode_tag_action_submit($form, $form_state) {
return array(
'apply_terms' => array_filter($form_state['values']['regcode_apply_terms']),
'remove_terms' => array_filter($form_state['values']['regcode_remove_terms']),
);
}
/**
* Get a list of terms from the registration code vocabulary.
*/
function regcode_get_vocab_terms() {
$tree = taxonomy_get_tree(variable_get('regcode_vocabulary', 1));
$terms = array();
foreach ($tree as $term) {
$terms[$term->tid] = $term->name;
}
return $terms;
}
/**
* Implements hook_token_info().
*/
function regcode_token_info() {
$type = array(
'name' => t('Registration Codes'),
'description' => t('Replacement tokens for registration codes'),
'needs-data' => 'regcode',
);
$regcode['created'] = array(
'name' => t("Code creation time"),
'description' => t("The date the regcode was created."),
'type' => 'date',
);
$regcode['lastused'] = array(
'name' => t("Code last used time"),
'description' => t("The date the regcode was used last."),
'type' => 'date',
);
$regcode['begins'] = array(
'name' => t("Code activation date"),
'description' => t("The date the regcode gets activated."),
'type' => 'date',
);
$regcode['expires'] = array(
'name' => t("Code expiry date"),
'description' => t("The date the regcode expires."),
'type' => 'date',
);
$regcode['code'] = array(
'name' => t("Registration code"),
'description' => t("One single registration code"),
);
$regcode['regurl'] = array(
'name' => t("Registration URL"),
'description' => t("Link to the registration page with regcode included"),
);
$regcode['is_active'] = array(
'name' => t("State of the regcode"),
'description' => t("Whether the code is active"),
);
$regcode['maxuses'] = array(
'name' => t("Maximum usage count"),
'description' => t("Maximum times a code can be used"),
);
$regcode['uses'] = array(
'name' => t("Current usage count"),
'description' => t("Number of times the code already has been used"),
);
return array(
'types' => array(
'regcode' => $type,
),
'tokens' => array(
'regcode' => $regcode,
),
);
}
/**
* Implements hook_tokens().
*/
function regcode_tokens($type, $tokens, array $data = array(), array $options = array()) {
if (isset($options['language'])) {
$language_code = $options['language']->language;
}
else {
$language_code = NULL;
}
$replacements = array();
if ($type == 'regcode' && !empty($data['regcode'])) {
$regcode = $data['regcode'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'created':
$replacements[$original] = format_date($regcode->created, 'medium', '', NULL, $language_code);
break;
case 'lastused':
$replacements[$original] = format_date($regcode->created, 'medium', '', NULL, $language_code);
break;
case 'begins':
$replacements[$original] = format_date($regcode->created, 'medium', '', NULL, $language_code);
break;
case 'expires':
$replacements[$original] = format_date($regcode->created, 'medium', '', NULL, $language_code);
break;
case 'code':
$replacements[$original] = $regcode->code;
break;
case 'regurl':
$replacements[$original] = url('user/register', array(
'query' => array(
'regcode' => $regcode->code,
),
'absolute' => TRUE,
));
break;
case 'is_active':
$replacements[$original] = $regcode->is_active ? t('active') : t('inactive');
break;
case 'maxuses':
$replacements[$original] = $regcode->maxuses;
break;
case 'uses':
$replacements[$original] = $regcode->uses;
break;
}
}
if ($created_tokens = token_find_with_prefix($tokens, 'created')) {
$replacements += token_generate('date', $created_tokens, array(
'date' => $regcode->created,
), $options);
}
if ($lastused_tokens = token_find_with_prefix($tokens, 'lastused')) {
$replacements += token_generate('date', $lastused_tokens, array(
'date' => $regcode->lastused,
), $options);
}
if ($begins_tokens = token_find_with_prefix($tokens, 'begins')) {
$replacements += token_generate('date', $begins_tokens, array(
'date' => $regcode->begins,
), $options);
}
if ($expires_tokens = token_find_with_prefix($tokens, 'expires')) {
$replacements += token_generate('date', $expires_tokens, array(
'date' => $regcode->expires,
), $options);
}
}
return $replacements;
}
Functions
Name | Description |
---|---|
regcode_action_info | Implements hook_action_info(). |
regcode_activate_action | Regcode activate action. |
regcode_clean | Delete regcode codes. |
regcode_code_consume | Consume a regcode and attribute it to a user. |
regcode_code_element_validate | Validate the content of the code-field on user registration. |
regcode_code_validate | Validate a regcode. |
regcode_deactivate_action | Regcode deactivate action. |
regcode_delete_action | Regcode delete action. |
regcode_entity_info | Implements hook_entity_info(). |
regcode_errormsg | Return text message requested by given identifier/constant. |
regcode_field_extra_fields | Implements hook_field_extra_fields(). |
regcode_form_user_register_form_alter | Implements hook_form_FORM_ID_alter(). |
regcode_generate | Generate a code. |
regcode_get_fields | Get the exposed regcode fields. |
regcode_get_term_ids | Gets the term ids associated with a registration code. |
regcode_get_vocab_terms | Get a list of terms from the registration code vocabulary. |
regcode_help | Implements hook_help(). |
regcode_load_single | Load a registration code. |
regcode_menu | Implements hook_menu(). |
regcode_permission | Implements hook_permission(). |
regcode_save | Save given code to a record in the db and calls the regcode_presave hook. |
regcode_tag_action | Regcode tag action. |
regcode_tag_action_form | Form for tag_action. |
regcode_tag_action_submit | Submit handler for tag_action. |
regcode_tokens | Implements hook_tokens(). |
regcode_token_info | Implements hook_token_info(). |
regcode_user_insert | Implements hook_user_insert(). |
regcode_views_api | Implements hook_views_api(). |