Rules interface to limit which orders they are applied to. Most important is the order status on which role granting will be triggered.', array('!url' => url(RULES_UI_PATH))); } switch ($path) { case 'admin/people/expiration': return t('Ubercart grants certain roles to customers when they purchase products with a role assignment feature. These can be permanent or temporary roles. Here you can view and edit when temporary roles are set to expire.'); } } /** * Implements hook_cron(). */ function uc_roles_cron() { $reminder_granularity = variable_get('uc_roles_reminder_granularity', 'never'); $reminder_qty = variable_get('uc_roles_reminder_length', NULL); $result = db_query("SELECT * FROM {uc_roles_expirations}"); foreach ($result as $expiration) { $account = user_load($expiration->uid); // User has to contain roles to manage. if (!is_array($account->roles) || !count($account->roles)) { continue; } // Cleanup if this role was deleted off the user already. if (!in_array($expiration->rid, array_keys($account->roles))) { uc_roles_delete($account, $expiration->rid); } // Role expired. elseif ($expiration->expiration <= REQUEST_TIME) { uc_roles_revoke($account, $expiration->rid); if (module_exists('rules')) { rules_invoke_event('uc_roles_notify_revoke', $account, $expiration); } } // Remind the user about an upcoming expiration. elseif ($reminder_granularity != 'never') { // Only if not already notified. if (intval($expiration->notified) >= 1) { continue; } // If we're past the expiration time minus the reminder time. $threshold = _uc_roles_get_expiration(-$reminder_qty, $reminder_granularity, $expiration->expiration); if ($threshold <= REQUEST_TIME) { if (module_exists('rules')) { rules_invoke_event('uc_roles_notify_reminder', $account, $expiration); } db_update('uc_roles_expirations') ->fields(array('notified' => 1)) ->condition('uid', $account->uid) ->condition('rid', $expiriation->rid) ->execute(); } } } } /** * Implements hook_menu(). */ function uc_roles_menu() { $items = array(); $items['admin/people/expiration'] = array( 'title' => 'Role expiration', 'description' => 'Edit and view role expirations set by Ubercart', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_roles_expiration'), 'access arguments' => array('administer users'), 'type' => MENU_LOCAL_TASK, 'file' => 'uc_roles.admin.inc', ); $items['admin/people/expiration/delete/%user/%'] = array( 'title' => 'Delete role expiration', 'description' => 'Delete a specified role expiration', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_roles_deletion_form', 5, 6), 'access arguments' => array('administer users'), 'type' => MENU_CALLBACK, 'file' => 'uc_roles.admin.inc', ); return $items; } /** * Implements hook_init(). */ function uc_roles_init() { drupal_add_js(drupal_get_path('module', 'uc_roles') . '/uc_roles.js', array('every_page' => TRUE)); drupal_add_css(drupal_get_path('module', 'uc_roles') . '/uc_roles.css', array('every_page' => TRUE)); global $conf; $conf['i18n_variables'][] = 'uc_roles_default_expiration_header'; $conf['i18n_variables'][] = 'uc_roles_default_expiration_message'; $conf['i18n_variables'][] = 'uc_roles_default_expiration_title'; $conf['i18n_variables'][] = 'uc_roles_grant_notification_message'; $conf['i18n_variables'][] = 'uc_roles_grant_notification_subject'; $conf['i18n_variables'][] = 'uc_roles_reminder_message'; $conf['i18n_variables'][] = 'uc_roles_reminder_subject'; $conf['i18n_variables'][] = 'uc_roles_renewal_notification_message'; $conf['i18n_variables'][] = 'uc_roles_renewal_notification_subject'; $conf['i18n_variables'][] = 'uc_roles_revocation_notification_message'; $conf['i18n_variables'][] = 'uc_roles_revocation_notification_subject'; } /** * Implements hook_permission(). */ function uc_roles_permission() { return array( 'view all role expirations' => array( 'title' => t('View all role expirations'), ) ); } /** * Implements hook_theme(). */ function uc_roles_theme() { return array( 'uc_roles_expiration' => array( 'render element' => 'form', 'file' => 'uc_roles.admin.inc', ), 'uc_roles_user_expiration' => array( 'render element' => 'form', ), 'uc_roles_user_new' => array( 'render element' => 'form', ), ); } /** * Implements hook_node_delete(). */ function uc_roles_node_delete($node) { // Deleted node was a product; remove all role associations. if (uc_product_is_product($node->type)) { db_delete('uc_roles_products') ->condition('nid', $node->nid) ->execute(); } } /** * Implements hook_form_user_profile_form_alter(). */ function uc_roles_form_user_profile_form_alter(&$form, &$form_state) { $account = $form_state['build_info']['args'][0]; if (isset($form_state['build_info']['args'][1])) { $category = $form_state['build_info']['args'][1]; } else { // user_profile_form() has a default value for $category. $category = 'account'; } if (!user_access('administer users') || $category != 'account') { return; } $role_choices = _uc_roles_get_choices(array_keys($account->roles)); $polarity_widget = array( '#type' => 'select', '#options' => array( 'add' => '+', 'remove' => '-', ), ); $quantity_widget = array( '#type' => 'textfield', '#size' => 4, '#maxlength' => 4 ); $granularity_widget = array( '#type' => 'select', '#options' => array( 'day' => t('day(s)'), 'week' => t('week(s)'), 'month' => t('month(s)'), 'year' => t('year(s)'), ), ); $form['uc_roles'] = array( '#type' => 'fieldset', '#title' => t('Ubercart roles'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => 10, '#theme' => 'uc_roles_user_new', ); $form['uc_roles']['expirations'] = array( '#type' => 'fieldset', '#title' => t('Pending Expirations'), '#collapsible' => FALSE, '#weight' => 0, '#theme' => 'uc_roles_user_expiration', ); $form['uc_roles']['expirations']['table']['#tree'] = TRUE; // Create the expirations table. $expirations = db_query("SELECT * FROM {uc_roles_expirations} WHERE uid = :uid", array(':uid' => $account->uid)); foreach ($expirations as $expiration) { $form['uc_roles']['expirations']['table'][$expiration->rid] = array( 'name' => array( '#type' => 'value', '#value' => _uc_roles_get_name($expiration->rid), ), 'remove' => array( '#type' => 'checkbox', ), 'expiration' => array( '#type' => 'value', '#value' => $expiration->expiration, ), 'polarity' => $polarity_widget, 'qty' => $quantity_widget, 'granularity' => $granularity_widget, ); } // Option to allow temporary roles. if (!empty($role_choices)) { $form['uc_roles']['new_role'] = array( '#type' => 'checkbox', '#title' => t('Add role'), ); $form['uc_roles']['new_role_add'] = array( '#type' => 'select', '#default_value' => variable_get('uc_roles_default_role', NULL), '#options' => $role_choices, ); $form['uc_roles']['new_role_add_for'] = array( '#markup' => t(' for '), ); $form['uc_roles']['new_role_add_qty'] = $quantity_widget; $form['uc_roles']['new_role_add_granularity'] = $granularity_widget; if (($default_granularity = variable_get('uc_roles_default_granularity', 'never')) != 'never') { $form['uc_roles']['new_role_add_qty'] = $form['uc_roles']['new_role_add_qty'] + array('#default_value' => variable_get('uc_roles_default_length', NULL)); $form['uc_roles']['new_role_add_granularity'] = $form['uc_roles']['new_role_add_granularity'] + array('#default_value' => $default_granularity); } } $form['#validate'][] = 'uc_roles_user_validate'; return $form; } /** * Theme the roles dialog on the account edit page. * * @ingroup themeable */ function theme_uc_roles_user_new($variables) { $form = $variables['form']; // Render the expiration tables first. $output = drupal_render($form['expirations']); $output .= '
'; $output .= drupal_render($form['new_role']); $output .= drupal_render($form['new_role_add']); $output .= drupal_render($form['new_role_add_for']); $output .= drupal_render($form['new_role_add_qty']); $output .= drupal_render($form['new_role_add_granularity']); $output .= '
'; return $output; } /** * Themes the role expiration table within the roles dialog on the * account edit page. * * @ingroup themeable */ function theme_uc_roles_user_expiration($variables) { $form = $variables['form']; $header = array( array('data' => t('Make permanent')), array('data' => t('Role' )), array('data' => t('Expiration' )), array('data' => t('Add/remove time')), ); $rows = array(); // The expiration table. foreach ((array)$form['table'] as $rid => $expiration) { // We only want numeric rid's if (!is_numeric($rid)) { continue; } // Make sure the renders actually touch the elements. $data = &$form['table'][$rid]; $rows[] = array( array('data' => drupal_render($data['remove'])), array('data' => check_plain($data['name']['#value'])), array('data' => format_date($data['expiration']['#value'], 'short')), // Options to adjust the expiration. array('data' => '' . '
' . drupal_render($data['polarity']) . drupal_render($data['qty']) . drupal_render($data['granularity']) . '
'), ); } if (!count($rows)) { $rows[] = array( array('data' => t('There are no pending expirations for roles this user.'), 'colspan' => 4), ); } $output = theme('table', array('header' => $header, 'rows' => $rows, 'caption' => t('Below you can add or remove time to the expiration dates of the following roles.'))); $output .= drupal_render_children($form); return $output; } /** * User profile form validate handler. * * @see uc_roles_form_user_profile_form_alter() */ function uc_roles_user_validate($form, &$form_state, &$account, $category) { $edit = $form_state['values']; $account = $form_state['build_info']['args'][0]; $category = $form_state['build_info']['args'][1]; // Validate the amount of time for the expiration. if ($edit['new_role'] && $category == 'account') { if (intval($edit['new_role_add_qty']) < 1) { form_set_error('new_role_add_qty', t('The expiration length must be a positive integer')); } } // Validate adjusted expirations. foreach ((array)$edit['table'] as $rid => $value) { // We don't validate if nothing was actually selected, the role, or the // expiration is removed. if ($value['qty'] == 0 || $value['remove'] == 1 || !$edit['roles'][$rid]) { continue; } $qty = $value['qty']; $qty *= $value['polarity'] == 'add' ? 1 : -1; $new_expiration = _uc_roles_get_expiration($qty, $value['granularity'], $value['expiration']); if (REQUEST_TIME > $new_expiration) { form_set_error('qty', t("The new expiration date, %date, has already occurred.", array('%date' => format_date($new_expiration, 'short')))); } } } /** * Implements hook_user_cancel(). */ function uc_roles_user_cancel($edit, $account, $method) { uc_roles_delete($account); } /** * Implements hook_user_presave(). */ function uc_roles_user_presave(&$edit, $account, $category) { if (!user_access('administer users') || $category != 'account') { return; } // If a new temporary role is added. // Grant a new role. if (isset($edit['new_role']) && $category == 'account') { // Save our role info, but don't save the user; user.module will do it. uc_roles_grant($account, $edit['new_role_add'], _uc_roles_get_expiration($edit['new_role_add_qty'], $edit['new_role_add_granularity']), FALSE); // Push in values so user.module will save in the roles. $edit['roles'][$edit['new_role_add']] = _uc_roles_get_name($edit['new_role_add']); // Reset the new role form. $edit['new_role'] = $edit['new_role_add'] = $edit['new_role_add_qty'] = $edit['new_role_add_granularity'] = NULL; } // Check if any temporary role actions were taken. if (isset($edit['table'])) { foreach ((array)$edit['table'] as $rid => $value) { // Remove this expiration. if ($value['remove']) { uc_roles_delete($account, $rid); } // Adjust it. else { if ($value['qty'] && $edit['roles'][$rid]) { $qty = $value['qty']; $qty *= $value['polarity'] == 'add' ? 1 : -1; uc_roles_renew($account, $rid, _uc_roles_get_expiration($qty, $value['granularity'], $value['expiration'])); } } } } // If a user's role is removed using Drupal, then so is any expiration data. if (is_array($edit['roles'])) { foreach ($account->roles as $rid => $role) { if (!in_array($rid, array_keys($edit['roles'])) && $rid != DRUPAL_AUTHENTICATED_RID) { uc_roles_delete($account, $rid); } } } } /** * Implements hook_user_view(). * * Displays role expirations on the user account screen. */ function uc_roles_user_view($account, $view_mode) { global $user; // Kick out anonymous. if (!$user->uid) { return; } // Only show if this user can access all role expirations, or if it's the same // user and the expirations are showing on the user pages. $show_expiration = variable_get('uc_roles_default_show_expiration', TRUE); if (!user_access('view all role expirations') && ($user->uid != $account->uid || !$show_expiration)) { return; } $items = array(); $form = array(); $expirations = db_query("SELECT * FROM {uc_roles_expirations} WHERE uid = :uid", array(':uid' => $account->uid)); foreach ($expirations as $expiration) { $substitution = array('!role_name' => check_plain(_uc_roles_get_name($expiration->rid)), '!date' => format_date($expiration->expiration, 'short')); $form[$expiration->rid] = array( '#type' => 'user_profile_item', '#title' => strtr(variable_get('uc_roles_default_expiration_title', uc_get_message('uc_roles_user_expiration_title')), $substitution), '#markup' => strtr(variable_get('uc_roles_default_expiration_message', uc_get_message('uc_roles_user_expiration_message')), $substitution), ); } // Don't display anything if there aren't any expirations. if (!count($form)) { return; } $item = array( '#type' => 'user_profile_category', '#weight' => '-1', '#title' => variable_get('uc_roles_default_expiration_header', uc_get_message('uc_roles_user_expiration_header')), ); $account->content['uc_roles'] = $item + $form; } /****************************************************************************** * Ubercart Hooks * ******************************************************************************/ /** * Implements hook_uc_cart_item(). */ function uc_roles_uc_cart_item($op, $item) { switch ($op) { case 'can_ship': $roles = db_query("SELECT * FROM {uc_roles_products} WHERE nid = :nid", array(':nid' => $item->nid)); foreach ($roles as $role) { // If the model is empty, keep looking. (Everyone needs a role model...) if (empty($role->model)) { continue; } // If there's an adjusted SKU, use it... otherwise use the node SKU. $sku = (empty($item->data['model'])) ? $item->model : $item->data['model']; // Keep looking if it doesn't match. if ($sku != $role->model) { continue; } return $role->shippable; } break; } } /** * Implements hook_uc_product_feature(). */ function uc_roles_uc_product_feature() { $features[] = array( 'id' => 'role', 'title' => t('Role assignment'), 'callback' => 'uc_roles_feature_form', 'delete' => 'uc_roles_feature_delete', 'settings' => 'uc_roles_feature_settings', ); return $features; } /** * Implements hook_uc_store_status(). */ function uc_roles_uc_store_status() { $message = array(); $role_choices = _uc_roles_get_choices(); if (empty($role_choices)) { $message[] = array( 'status' => 'warning', 'title' => t('Roles'), 'desc' => t('There are no product role(s) that can be assigned upon product purchase. Set product roles in the product feature settings under the role assignment settings fieldset.', array('!url' => url('admin/store/settings/products/edit/features'))), ); } else { $message[] = array( 'status' => 'ok', 'title' => t('Roles'), 'desc' => t('The role(s) %roles are set to be used with the Role Assignment product feature.', array('%roles' => implode(', ', $role_choices))), ); } return $message; } /** * Implements hook_uc_message(). */ function uc_roles_uc_message() { $messages['uc_roles_grant_subject'] = t('[store:name]: [uc_role:name] role granted'); $messages['uc_roles_grant_message'] = t("[uc_order:first-name] [uc_order:last-name], \n\nThanks to your order, [uc_order:link], at [store:name] you now have a new role, [uc_role:name].\n\nThanks again, \n\n[store:name]\n[site:slogan]"); $messages['uc_roles_revoke_subject'] = t('[store:name]: [uc_role:name] role expired'); $messages['uc_roles_revoke_message'] = t("The role, [uc_role:name], you acquired by purchasing a product at our store has expired. Any special access or privileges that came with it are now gone. You can purchase it again by going to [store:link]\n\nThanks again, \n\n[store:name]\n[site:slogan]"); $messages['uc_roles_renew_subject'] = t('[store:name]: [uc_role:name] role renewed'); $messages['uc_roles_renew_message'] = t("[uc_order:first-name] [uc_order:last-name], \n\nThanks to your order, [uc_order:link], at [store:name] you have renewed the role, [uc_role:name]. It is now set to expire on [uc_role:expiration:short].\n\nThanks again, \n\n[store:name]\n[site:slogan]"); $messages['uc_roles_reminder_subject'] = t('[store:name]: [uc_role:name] role expiration notice'); $messages['uc_roles_reminder_message'] = t("This message is to remind you that the role, [uc_role:name], you acquired by making a purchase at our store will expire at [uc_role:expiration:short]. You may visit [store:link] to renew this role before it expires.\n\nThanks again, \n\n[store:name]\n[site:slogan]"); $messages['uc_roles_user_expiration_header'] = t("Expiring roles"); $messages['uc_roles_user_expiration_title'] = t("!role_name"); $messages['uc_roles_user_expiration_message'] = t("This role will expire on !date"); return $messages; } /****************************************************************************** * Callback Functions, Forms, and Tables * ******************************************************************************/ /** * Form builder for hook_product_feature. * * @see uc_roles_feature_form_validate() * @see uc_roles_feature_form_submit() * @ingroup forms */ function uc_roles_feature_form($form, &$form_state, $node, $feature) { $models = uc_product_get_models($node); // Check if editing or adding to set default values. if (!empty($feature)) { $product_role = db_query("SELECT * FROM {uc_roles_products} WHERE pfid = :pfid", array(':pfid' => $feature['pfid']))->fetchObject(); $default_model = $product_role->model; $default_role = $product_role->rid; $default_qty = $product_role->duration; $default_granularity = $product_role->granularity; $default_shippable = $product_role->shippable; $default_by_quantity = $product_role->by_quantity; if ($product_role->end_time) { $end_time = array( 'day' => date('d', $product_role->end_time), 'month' => date('m', $product_role->end_time), 'year' => date('Y', $product_role->end_time), ); $default_end_type = 'abs'; } else { $temp = _uc_roles_get_expiration($default_qty, $default_granularity); $end_time = array( 'day' => date('d', $temp), 'month' => date('m', $temp), 'year' => date('Y', $temp), ); $default_end_type = 'rel'; } $form['pfid'] = array( '#type' => 'value', '#value' => $feature['pfid'], ); $form['rpid'] = array( '#type' => 'value', '#value' => $product_role->rpid, ); $default_end_override = $product_role->end_override; } else { $default_model = 0; $default_role = variable_get('uc_roles_default_role', NULL); $default_qty = (variable_get('uc_roles_default_granularity', 'never') == 'never') ? NULL : variable_get('uc_roles_default_length', NULL); $default_granularity = variable_get('uc_roles_default_granularity', 'never'); $default_shippable = $node->shippable; $default_by_quantity = variable_get('uc_roles_default_by_quantity', FALSE); $end_time = variable_get('uc_roles_default_end_time', array( 'day' => date('d'), 'month' => date('m'), 'year' => date('Y'), )); $default_end_type = variable_get('uc_roles_default_end_expiration', 'rel'); $default_end_override = FALSE; } $roles = _uc_roles_get_choices(); if (!count($roles)) { // No actions can be done. Remove submit buttons. unset($form['buttons']); $form['no_roles'] = array( '#markup' => t('You need to create new roles before any can be added as product features.', array('!url' => url('admin/people/permissions/roles', array('query' => array('destination' => 'admin/store/settings/products/edit/features'))))), '#prefix' => '

', '#suffix' => '

', ); return $form; } $form['nid'] = array( '#type' => 'value', '#value' => $node->nid, ); $form['uc_roles_model'] = array( '#type' => 'select', '#title' => t('SKU'), '#default_value' => $default_model, '#description' => t('This is the SKU of the product that will grant the role.'), '#options' => $models, ); $form['uc_roles_role'] = array( '#type' => 'select', '#title' => t('Role'), '#default_value' => $default_role, '#description' => t('This is the role the customer will receive after purchasing the product.'), '#options' => $roles, ); $form['uc_roles_shippable'] = array( '#type' => 'checkbox', '#title' => t('Shippable product'), '#default_value' => $default_shippable, '#description' => t('Check if this product SKU that uses role assignment is associated with a shippable product.'), ); $form['role_lifetime'] = array( '#type' => 'fieldset', '#title' => t('Expiration period'), ); $form['role_lifetime']['end_override'] = array( '#type' => 'checkbox', '#title' => t('Override the default ending expiration'), '#default_value' => $default_end_override, ); $form['role_lifetime']['expiration'] = array( '#type' => 'select', '#title' => t('End'), '#options' => array( 'rel' => t('Relative from activation time'), 'abs' => t('Absolute role ending'), ), '#default_value' => $default_end_type, ); $form['role_lifetime']['uc_roles_expire_relative_duration'] = array( '#type' => 'textfield', '#default_value' => $default_qty, '#size' => 4, '#maxlength' => 4, '#prefix' => '
', '#suffix' => '
', ); $form['role_lifetime']['uc_roles_expire_relative_granularity'] = array( '#type' => 'select', '#options' => array( 'never' => t('never'), 'day' => t('day(s)'), 'week' => t('week(s)'), 'month' => t('month(s)'), 'year' => t('year(s)') ), '#default_value' => $default_granularity, '#description' => t('From the time the expiration period started.'), '#prefix' => '
', '#suffix' => '
', ); $form['role_lifetime']['uc_roles_expire_absolute'] = array( '#type' => 'date', '#description' => t('When this expiration period will end.'), ); if ($end_time) { $form['role_lifetime']['uc_roles_expire_absolute']['#default_value'] = $end_time; } $form['role_lifetime']['uc_roles_by_quantity'] = array( '#type' => 'checkbox', '#title' => t('Multiply by quantity'), '#default_value' => $default_by_quantity, '#description' => t('Check if the role duration should be multiplied by the quantity purchased.'), ); return $form; } /** * Validation function for the roles feature form. * * @see uc_roles_feature_form() * @see uc_roles_feature_form_submit() */ function uc_roles_feature_form_validate($form, &$form_state) { // Invalid quantity? if ($form_state['values']['expiration'] === 'abs') { $form_state['values']['uc_roles_expire_absolute'] = mktime(0, 0, 0, $form_state['values']['uc_roles_expire_absolute']['month'], $form_state['values']['uc_roles_expire_absolute']['day'], $form_state['values']['uc_roles_expire_absolute']['year'] ); if ($form_state['values']['uc_roles_expire_absolute'] <= REQUEST_TIME) { form_set_error('uc_roles_expire_absolute', t('The specified date !date has already occurred. Please choose another.', array('!date' => format_date($form_state['values']['uc_roles_expire_absolute'])))); } } else { if ($form_state['values']['uc_roles_expire_relative_granularity'] != 'never' && intval($form_state['values']['uc_roles_expire_relative_duration']) < 1) { form_set_error('uc_roles_expire_relative_duration', t('The amount of time must be a positive integer.')); } } // No roles? if (empty($form_state['values']['uc_roles_role'])) { form_set_error('uc_roles_role', t('You must have a role to assign. You may need to create a new role or perhaps set role assignment defaults.', array('!role_url' => url('admin/people/permissions/roles'), '!feature_url' => url('admin/store/settings/products/edit/features')))); } // This role already set on this SKU? if (!isset($form_state['values']['pfid']) && ($product_roles = db_query("SELECT * FROM {uc_roles_products} WHERE nid = :nid AND model = :model AND rid = :rid", array(':nid' => $form_state['values']['nid'], ':model' => $form_state['values']['uc_roles_model'], ':rid' => $form_state['values']['uc_roles_role']))->fetchObject())) { form_set_error('uc_roles_role', t('The combination of SKU and role already exists for this product.')); form_set_error('uc_roles_model', ' '); } } /** * Little helper for cleaning up input to drupal_write_record(). */ function uc_roles_product_write_record($product_role) { foreach (array('duration', 'granularity', 'end_time') as $property) { $product_role[$property] = $product_role[$property] === NULL ? 0 : $product_role[$property]; } $key = array(); if ($product_role['rpid']) { $key = 'rpid'; } drupal_write_record('uc_roles_products', $product_role, $key); } /** * Submission handler for uc_roles_feature_form(). * * @see uc_roles_feature_form() * @see uc_roles_feature_form_validate() */ function uc_roles_feature_form_submit($form, &$form_state) { $product_role = array( 'pfid' => isset($form_state['values']['pfid']) ? $form_state['values']['pfid'] : NULL, 'rpid' => isset($form_state['values']['rpid']) ? $form_state['values']['rpid'] : NULL, 'nid' => $form_state['values']['nid'], 'model' => $form_state['values']['uc_roles_model'], 'rid' => $form_state['values']['uc_roles_role'], 'duration' => $form_state['values']['uc_roles_expire_relative_granularity'] != 'never' ? $form_state['values']['uc_roles_expire_relative_duration'] : NULL, 'granularity' => $form_state['values']['uc_roles_expire_relative_granularity'], 'by_quantity' => $form_state['values']['uc_roles_by_quantity'], 'shippable' => $form_state['values']['uc_roles_shippable'], // We should be setting NULL, but drupal_write_record() ... 'end_override' => $form_state['values']['end_override'], 'end_time' => $form_state['values']['expiration' ] === 'abs' ? $form_state['values']['uc_roles_expire_absolute'] : NULL, ); $description = empty($product_role['model']) ? t('SKU: Any
') : t('SKU: !sku
', array('!sku' => $product_role['model'])); $description .= t('Role: @role_name
', array('@role_name' => _uc_roles_get_name($product_role['rid']))); if ($product_role['end_override']) { if ($product_role['end_time']) { $description .= t('Expiration: !date
', array('!date' => format_date($product_role['end_time']))); } else { switch ($product_role['granularity']) { case 'never': $description .= t('Expiration: never
'); break; case 'day': $description .= t('Expiration: !qty day(s)
', array('!qty' => $product_role['duration'])); break; case 'week': $description .= t('Expiration: !qty week(s)
', array('!qty' => $product_role['duration'])); break; case 'month': $description .= t('Expiration: !qty month(s)
', array('!qty' => $product_role['duration'])); break; case 'year': $description .= t('Expiration: !qty year(s)
', array('!qty' => $product_role['duration'])); break; default: break; } } } else { $description .= t('Expiration: !link (not overridden)
', array('!link' => l(t('Global expiration'), 'admin/store/settings/products/edit/features'))); } $description .= $product_role['shippable'] ? t('Shippable: Yes
') : t('Shippable: No
'); $description .= $product_role['by_quantity'] ? t('Multiply by quantity: Yes') : t('Multiply by quantity: No'); $data = array( 'pfid' => $product_role['pfid'], 'nid' => $product_role['nid'], 'fid' => 'role', 'description' => $description, ); $form_state['redirect'] = uc_product_feature_save($data); $product_role['pfid'] = $data['pfid']; // Insert or update uc_file_product table uc_roles_product_write_record($product_role); } /** * Form builder for role settings. * * @ingroup forms */ function uc_roles_feature_settings($form, &$form_state) { $default_role_choices = user_roles(TRUE); unset($default_role_choices[DRUPAL_AUTHENTICATED_RID]); if (!count($default_role_choices)) { $form['no_roles'] = array( '#markup' => t('You need to create new roles before any can be added as product features.', array('!url' => url('admin/people/permissions/roles', array('query' => array('destination' => 'admin/store/settings/products/edit/features'))))), '#prefix' => '

', '#suffix' => '

', ); return $form; } foreach (uc_order_status_list('general') as $status) { $statuses[$status['id']] = $status['title']; } $form['uc_roles_default_role'] = array( '#type' => 'select', '#title' => t('Default role'), '#default_value' => variable_get('uc_roles_default_role', NULL), '#description' => t('The default role Ubercart grants on specified products.'), '#options' => _uc_roles_get_choices(), ); $form['uc_roles_default_role_choices'] = array( '#type' => 'checkboxes', '#title' => t('Product roles'), '#default_value' => variable_get('uc_roles_default_role_choices', array()), '#multiple' => TRUE, '#description' => t('These are roles that Ubercart can grant to customers who purchase specified products. If you leave all roles unchecked, they will all be eligible for adding to a product.'), '#options' => $default_role_choices, ); $form['role_lifetime'] = array( '#type' => 'fieldset', '#title' => t('Expiration period'), ); $form['role_lifetime']['uc_roles_default_end_expiration'] = array( '#type' => 'select', '#title' => t('End'), '#options' => array( 'rel' => t('Relative from activation time'), 'abs' => t('Absolute role ending'), ), '#default_value' => variable_get('uc_roles_default_end_expiration', 'rel'), ); $form['role_lifetime']['uc_roles_default_length'] = array( '#type' => 'textfield', '#title' => t('Default expiration'), '#default_value' => (variable_get('uc_roles_default_granularity', 'never') == 'never') ? NULL : variable_get('uc_roles_default_length', NULL), '#size' => 4, '#maxlength' => 4, '#prefix' => '
', ); $form['role_lifetime']['uc_roles_default_granularity'] = array( '#type' => 'select', '#default_value' => variable_get('uc_roles_default_granularity', 'never'), '#options' => array( 'never' => t('never'), 'day' => t('day(s)'), 'week' => t('week(s)'), 'month' => t('month(s)'), 'year' => t('year(s)') ), '#description' => t('The default amount of time a granted Ubercart role will last until it expires.'), '#suffix' => '
', ); $form['role_lifetime']['uc_roles_default_end_time'] = array( '#type' => 'date', '#description' => t('When this expiration period will end.'), '#default_value' => variable_get('uc_roles_default_end_time', array( 'day' => date('d'), 'month' => date('m'), 'year' => date('Y'), )), ); $form['role_lifetime']['uc_roles_default_by_quantity'] = array( '#type' => 'checkbox', '#title' => t('Multiply by quantity'), '#description' => t('Check if the role duration should be multiplied by the quantity purchased.'), '#default_value' => variable_get('uc_roles_default_by_quantity', FALSE), ); $form['reminder']['uc_roles_reminder_length'] = array( '#type' => 'textfield', '#title' => t('Time before reminder'), '#default_value' => (variable_get('uc_roles_reminder_granularity', 'never') == 'never') ? NULL : variable_get('uc_roles_reminder_length', NULL), '#size' => 4, '#maxlength' => 4, '#prefix' => '
', '#suffix' => '
', ); $form['reminder']['uc_roles_reminder_granularity'] = array( '#type' => 'select', '#default_value' => variable_get('uc_roles_reminder_granularity', 'never'), '#options' => array( 'never' => t('never'), 'day' => t('day(s)'), 'week' => t('week(s)'), 'month' => t('month(s)'), 'year' => t('year(s)') ), '#description' => t('The amount of time before a role expiration takes place that a customer is notified of its expiration.'), '#prefix' => '
', '#suffix' => '
', ); $form['uc_roles_expiration_display'] = array( '#type' => 'fieldset', '#title' => t('Expiration display'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['uc_roles_expiration_display']['uc_roles_default_show_expiration'] = array( '#type' => 'checkbox', '#title' => t('Show expirations on user page'), '#default_value' => variable_get('uc_roles_default_show_expiration', TRUE), '#description' => t('If users have any role expirations they will be displayed on their account page.'), ); $form['uc_roles_expiration_display']['uc_roles_default_expiration_header'] = array( '#type' => 'textfield', '#title' => t('Header'), '#default_value' => variable_get('uc_roles_default_expiration_header', uc_get_message('uc_roles_user_expiration_header')), ); $form['uc_roles_expiration_display']['uc_roles_default_expiration_title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#default_value' => variable_get('uc_roles_default_expiration_title', uc_get_message('uc_roles_user_expiration_title')), ); $form['uc_roles_expiration_display']['uc_roles_default_expiration_message'] = array( '#type' => 'textfield', '#title' => t('Message'), '#default_value' => variable_get('uc_roles_default_expiration_message', uc_get_message('uc_roles_user_expiration_message')), '#description' => t('The message, with its accompanying title, and the header displayed above all role expirations. In the Title & Message fields "!role_name" and "!date" will translate to the corresponding Drupal role name and role expiration date.'), ); return $form; } /****************************************************************************** * Module and Helper Functions * ******************************************************************************/ /** * Gets role name. * * @param $rid * The Drupal role id number. * * @return * A string containing the name of the role, returns FALSE if rid is invalid. */ function _uc_roles_get_name($rid) { $roles = user_roles(TRUE); return (!is_null($roles[$rid])) ? $roles[$rid] : FALSE; } /** * Gets available roles for granting on product purchase. * * @param $exclude * A list of role ids to exclude from the list. * * @return * An assoc array with key = rid and value = role name. */ function _uc_roles_get_choices($exclude = array()) { $output = array(); // Get roles from Drupal, excluding Anonymous and Authenticated. $roles = user_roles(TRUE); unset($roles[DRUPAL_AUTHENTICATED_RID]); // User set specific roles that we must use? $selected = variable_get('uc_roles_default_role_choices', array()); // If there's none, or if none are checked, use all of em. $default = empty($selected) || array_sum($selected) == 0; foreach ($roles as $rid => $name) { if ($default || (!empty($selected[$rid]) && !in_array($rid, $exclude))) { $output[$rid] = $roles[$rid]; } } return $output; } /****************************************************************************** * Actions * ******************************************************************************/ /** * Deletes all data associated with a given product feature. * * @param $pfid * An Ubercart product feature ID. */ function uc_roles_feature_delete($pfid) { db_delete('uc_roles_products') ->condition('pfid', $pfid) ->execute(); } /** * Deletes an expiration using user id or user id and rid. * * This function deletes expirations associated with users and roles. If * no role ID is passed, the function deletes all role expirations associated * with the given user. Otherwise, the function only deletes expirations whose * user and role IDs match. If any roles were actually deleted, the function * notifies the user. The menu cache is then flushed, as privileges to view * menu items may have been lost in the process. * * @param $account * A Drupal user object. * @param $rid * A Drupal role ID. * @param $silent * When set to TRUE will suppress any Drupal messages from this function. */ function uc_roles_delete($account, $rid = NULL, $silent = FALSE) { global $user; $query = db_delete('uc_roles_expirations') ->condition('uid', $account->uid); if ($rid) { $query->condition('rid', $rid); } // Echo the deletion only if something was actually deleted. if ($query->execute() && !$silent) { if ($user->uid == $account->uid) { drupal_set_message(t('The expiration of your %role_name role has been deleted.', array('%role_name' => _uc_roles_get_name($rid)))); } else { drupal_set_message(t('The expiration of %role_name role for the user !user has been deleted.', array( '!user' => theme('username', array( 'account' => $account, 'name' => check_plain($account->name), 'link_path' => 'user/' . $account->uid, )), '%role_name' => _uc_roles_get_name($rid), ))); } } // Flush visible menu items, since our permissions could've changed. _uc_roles_flush_menu_cache($account); } /** * Revokes a role on a given user * * This function deletes a given role from a user's list of roles, as * well as removing any expiration data associated with the user/role. * The function notifies the user of revocation. * * @param $account * A Drupal user object. * @param $rid * A Drupal role ID. * @param $silent * When set to TRUE will suppress any Drupal messages from this function. */ function uc_roles_revoke($account, $rid, $silent = FALSE) { global $user; // Remove this role from the user's list. $roles_list = &$account->roles; unset($roles_list[$rid]); user_save($account, array('roles' => $roles_list)); // Remove our record of the expiration. uc_roles_delete($account, $rid); $role_name = db_query("SELECT name FROM {role} WHERE rid = :rid", array(':rid' => $rid))->fetchField(); if (!$silent) { if ($user->uid == $account->uid) { drupal_set_message(t('Your %role role has been revoked.', array('%role' => $role_name))); } else { drupal_set_message(t('!user has had the %role role revoked.', array( '!user' => theme('username', array( 'account' => $account, 'name' => check_plain($account->name), 'link_path' => 'user/' . $account->uid, )), '%role' => $role_name, ))); } } } /** * Grants a role to a given user * * This function grants a given role to a user's list of roles. If there * is a previous record of this user/role combination, it is first removed. * The function then saves the user (if $user_save is TRUE). Next, a check * to verify the role actually exists, if not, no expiration data is stored. * The menu cache is flushed, as new menu items may be visible after the * new role is granted. The function notifies the user of the role grant. * * @param $account * A Drupal user object. * @param $rid * A Drupal role ID. * @param $timestamp * When this role will expire. * @param $save_user * Optimization to prevent unnecessary user saving when calling from * uc_roles_user_presave(). * @param $silent * When set to TRUE will suppress any Drupal messages from this function. */ function uc_roles_grant(&$account, $rid, $timestamp, $save_user = TRUE, $silent = FALSE) { global $user; // First, delete any previous record of this user/role association. uc_roles_delete($account, $rid, $silent); if ($save_user) { // Punch the role into the user object. $account->roles += array($rid => _uc_roles_get_name($rid)); user_save($account, array('roles' => $account->roles)); } // If the role expires, keep a record. if (!is_null($timestamp)) { db_insert('uc_roles_expirations') ->fields(array( 'uid' => $account->uid, 'rid' => $rid, 'expiration' => $timestamp, )) ->execute(); } // Flush visible menu items, since our permissions could've changed. _uc_roles_flush_menu_cache($account); // Display the message if appropriate. if (!$silent) { $role_name = db_query("SELECT name FROM {role} WHERE rid = :rid", array(':rid' => $rid))->fetchField(); if ($user->uid == $account->uid) { $message = t('You have been granted the %role role.', array('%role' => $role_name)); } else { $message = t('!user has been granted the %role role.', array( '!user' => theme('username', array( 'account' => $account, 'name' => check_plain($account->name), 'link_path' => 'user/' . $account->uid, )), '%role' => $role_name, )); } if ($timestamp) { $message .= t(' It will expire on %date', array('%date' => format_date($timestamp, 'short'))); } drupal_set_message($message); } } /** * Renews a given role on a user. * * This function updates expiration time on a role already granted to a * user. First the function checks the new expiration. If it never expires, * the function deletes the past expiration record and returns, leaving * management up to Drupal. Otherwise, the record is updated with the new * expiration time, and the user is notified of the change. * * @param $account * A Drupal user object. * @param $rid * A Drupal role ID. * @param $timestamp * When this role will expire. * @param $silent * When set to TRUE will suppress any Drupal messages from this function. */ function uc_roles_renew($account, $rid, $timestamp, $silent = FALSE) { global $user; // If it doesn't expire, we'll remove our data associated with it. // After that, Drupal will take care of it. if (is_null($timestamp)) { uc_roles_delete($account, $rid); return; } // Update the expiration date. db_update('uc_roles_expirations') ->fields(array('expiration' => $timestamp)) ->condition('uid', $account->uid) ->condition('rid', $rid) ->execute(); if (!$silent) { $role_name = db_query("SELECT name FROM {role} WHERE rid = :rid", array(':rid' => $rid))->fetchField(); if ($user->uid == $account->uid) { $message = t('Your %role role has been renewed. It will expire on %date.', array('%role' => $role_name, '%date' => format_date($timestamp, 'short'))); } else { $message = t("!user's %role role has been renewed. It will expire on %date.", array( '!user' => theme('username', array( 'account' => $account, 'name' => check_plain($account->name), 'link_path' => 'user/' . $account->uid, )), '%role' => $role_name, '%date' => format_date($timestamp, 'short'), )); } drupal_set_message($message); } } /** * Flushes the menu cache. * * When roles are gained/lost, menu items might appear/disappear respectively, * so we have to ensure the cache is rebuilt with any new values. * * @param $account * A Drupal user object. * * @see uc_roles_delete() * @see uc_roles_grant() */ function _uc_roles_flush_menu_cache($account) { cache_clear_all($account->uid . ':', 'cache_menu', TRUE); } /** * Calculates the expiration time using a role_product object. * * @param $role_product * The role product object whose expiration times to calculate. * @param $quantity * Used to multiply any relative expiration time, if the $role_product says to. * @param $time * The current time to use as a starting point for relative expiration calculation. */ function _uc_roles_product_get_expiration($role_product, $quantity, $time) { // Override the end expiration? if ($role_product->end_override) { // Absolute times are easy... if ($role_product->end_time) { return $role_product->end_time; } // We're gonna have to calculate the relative time from $time. $length = $role_product->duration * ($role_product->by_quantity ? $quantity : 1); return _uc_roles_get_expiration($length, $role_product->granularity, $time); } // No override, use the default expiration values. else { // Relative... if (variable_get('uc_roles_default_end_expiration', 'rel') === 'rel') { $length = variable_get('uc_roles_default_length', NULL) * ($role_product->by_quantity ? $quantity : 1); return _uc_roles_get_expiration($length, variable_get('uc_roles_default_granularity', 'never'), $time); } // Absolute... $end_time = variable_get('uc_roles_default_end_time', NULL); if ($end_time) { $end_time = mktime(0, 0, 0, $end_time['month'], $end_time['day'], $end_time['year']); } return $end_time; } } /** * Returns an expiration time stamp given a certain amount of time * from a starting point (defaults to current time). * * @param $duration * The amount of time until expiration. * @param $granularity * A string representing the granularity's name (e.g. "day", "month", etc.). * @param $start_time * The starting date for when the role will last. * * @return * A UNIX timestamp representing the second that expiration takes place. */ function _uc_roles_get_expiration($duration, $granularity, $start_time = NULL) { // Never expires? if ($granularity == 'never') { return NULL; } $start_time = (!is_null($start_time)) ? $start_time : REQUEST_TIME; $operator = ($duration < 0) ? '' : '+'; return strtotime($operator . $duration . ' ' . $granularity, $start_time); }