activity_ignore)) {
$account->activity_ignore = array();
}
$form['actions'] = array(
'#type' => 'fieldset',
'#title' => t('Actions within !site', array('!site' => variable_get('site_name', 'drupal'))),
'#description' => t('By default, all of the following actions you perform can be viewed on this site.
Select the activities you would like to exclude people from seeing.'),
);
$form['actions']['activity_ignore']['#tree'] = TRUE;
// In order to see what actions are being implemented on a given system we
// need to query the actions table joining the trigger_assignments.
$query = "SELECT a.aid, a.description, ta.hook, ta.op FROM {actions} a
INNER JOIN {trigger_assignments} ta ON ta.aid = a.aid
WHERE a.type = 'activity'";
$result = db_query($query);
while ($row = db_fetch_object($result)) {
$module = activity_module_name($row->hook);
// The module might be uninstalled and therefore, not exist anymore.
if (!empty($module)) {
$description = $row->description;
// This means we're basically keying off of the aid and not the triggers. We
// could possible key off of the triggers instead, and give the user more
// fine grained control over (i.e. I want to record my own node inserts but
// not my node updates).
$form['actions']['activity_ignore'][$row->aid] = array(
'#type' => 'radios',
'#title' => $description,
'#options' => array(1 => t('Record an activity message'), 0 => t('Do not record')),
'#default_value' => isset($account->activity_ignore[$row->aid]) ? $account->activity_ignore[$row->aid] : 1,
);
}
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
$form['#account'] = $account;
return $form;
}
/**
* User settings form submit handler.
*/
function activity_user_settings_submit($form, &$form_state) {
user_save($form['#account'], array('activity_ignore' => $form_state['values']['activity_ignore']));
}
/**
* Menu callback to administer activity messages.
*/
function activity_form(&$form_state, $arg1 = NULL, $arg2 = NULL) {
if (!empty($form_state['storage']['step'])) {
$function = $form_state['storage']['step'];
return $function($form_state);
}
else {
if ($arg1 == 'create') {
// if we have a specific callback to create a new action, do so
return _activity_settings_form_triggers($form_state);
}
elseif ($arg1 == 'configure') {
$form_state['storage']['action'] = $arg2;
return _activity_settings_form_messages($form_state);
}
else {
return _activity_settings_actions_list_form();
}
}
}
/**
* Form validation controller.
*/
function activity_form_validate($form, &$form_state) {
if (!empty($form_state['values']['step_validate'])) {
$function = $form_state['values']['step_validate'];
$function($form, $form_state);
}
}
/**
* Form submit controller.
*/
function activity_form_submit($form, &$form_state) {
if (empty($form_state['storage'])) {
$form_state['storage'] = array();
$form_state['storage']['values'] = array();
}
// Call user-defined submit function.
if (!empty($form_state['values']['step_submit'])) {
$function = $form_state['values']['step_submit'];
$function($form, $form_state);
}
// Store submitted form values, this must happen after function call above to
// allow for modifying $form_state['values'].
$this_step = $form_state['values']['this_step'];
$form_state['storage']['values'][$this_step] = $form_state['values'];
// Set up next step.
if (!empty($form_state['values']['step_next']) && $form_state['values']['op'] != 'Back') {
$form_state['storage']['step'] = $form_state['values']['step_next'];
}
else if ($form_state['values']['op'] == 'Back') {
// Set up previous step
$form_state['storage']['step'] = $form_state['values']['step_prev'];
}
else {
// Form complete!
$values = $form_state['storage']['values'];
$hook = $values['triggers']['hook'];
$op = $values['operations']['operation'];
$module = activity_module_name($hook) ;
$info = call_user_func($module .'_activity_info');
foreach (activity_enabled_languages() as $id => $language) {
foreach ($info->objects as $type) {
$params[$type .'-pattern-' . $id] = $values['messages'][$type .'-pattern-' . $id];
}
$params['everyone-pattern-' . $id] = $values['messages']['everyone-pattern-' . $id];
}
$desc = $values['messages']['description'];
$update = TRUE;
if (!$aid = $values['messages']['aid']) {
$aid = NULL;
$update = FALSE;
}
// handle the types, thanks Checkboxes :-D
foreach ($values['operations']['activity_types'] as $type => $nice_name) {
if (empty($nice_name)) {
unset($values['operations']['activity_types'][$type]);
}
}
$params['activity_types'] = $values['operations']['activity_types'];
// Save the action
include_once('includes/actions.inc');
// In order to save the aid into the actions.parameters column, when a new
// template is created, the aid must be generated. Can look into using
// {actions_aid} table for this as well. SELECT aid + 1 ORDER BY aid DESC ?
if (!$update) {
$aid = actions_save('activity_record', 'activity', $params, $desc);
}
$params['aid'] = $aid;
$aid = actions_save('activity_record', 'activity', $params, $desc, $aid);
// Save the trigger assignment
// @todo: calc weight (last param)
$record = new stdClass();
$record->hook = $hook;
$record->op = $op;
$record->aid = $aid;
$record->weight = 1;
// try update first
drupal_write_record('trigger_assignments', $record, array('aid'));
if (!db_affected_rows()) {
// ok then insert
drupal_write_record('trigger_assignments', $record);
}
unset($form_state['storage']);
$form_state['redirect'] = 'admin/build/activity';
drupal_set_message('Saved.');
}
}
/**
* List activity action that are already present in the system.
*/
function _activity_settings_actions_list_form() {
$form = array();
$sql = "SELECT ta.hook, ta.aid, a.description
FROM {trigger_assignments} ta
INNER JOIN {actions} a
ON a.aid = ta.aid
WHERE a.type = 'activity'";
$query = db_query($sql);
while ($result = db_fetch_array($query)) {
$results[] = $result;
}
if (!empty($results)) {
// since our originating callback is expecting a form
$form['activity_actions'] = array(
'#type' => 'markup',
'#value' => theme('activity_settings_actions_list', $results),
);
}
else {
$form['activity_create'] = array(
'#value' => t('There are no Activity Templates created yet. !link', array('!link' => l(t('Create one now.'), 'admin/build/activity/create'))),
);
}
return $form;
}
/**
* List of modules that implement activity_info().
*/
function _activity_settings_form_triggers(&$form_state) {
$form = array();
foreach (activity_get_module_info() as $module => $info) {
if (!empty($info->hooks)) {
foreach ($info->hooks as $hook => $ops) {
$options[$hook] = drupal_ucfirst(str_replace('_', ' ', $info->name));
}
}
}
$form['hook'] = array(
'#type' => 'radios',
'#title' => t('Available Activity Types'),
'#options' => $options,
'#default_value' => $form_state['storage']['values']['triggers']['hook'],
'#required' => TRUE,
'#description' => t('Please choose which type of activity you would like to record.'),
);
$form['continue'] = array(
'#type' => 'submit',
'#value' => 'Continue',
);
$form['this_step'] = array(
'#type' => 'value',
'#value' => 'triggers',
);
$form['step_next'] = array(
'#type' => 'value',
'#value' => '_activity_settings_form_operations',
);
return $form;
}
/**
* List the ops for the module selected in the _triggers step.
*/
function _activity_settings_form_operations(&$form_state) {
$form = array();
$hook = $form_state['storage']['values']['triggers']['hook'];
$module = activity_module_name($hook);
foreach (call_user_func($module .'_hook_info') as $module => $trigger_ops) {
// Compare ops with our activity_info so that we do not provide a trigger
// that activity doesn't support (ex: nodeapi - presave)
// @see: node_activity_info()
$module_info = activity_get_module_info($module);
foreach ($module_info->hooks[$hook] as $op) {
$ops[$hook][$op] = $trigger_ops[$hook][$op];
}
foreach ($ops as $trigger_name => $hooks) {
$options = array();
foreach ($hooks as $op => $runs_when) {
$options[$op] = $op .': '. $runs_when['runs when'];
}
$default_value = isset($form_state['storage']['values']['operations']['operation']) ? $form_state['storage']['values']['operations']['operation'] : '';
$form[$trigger_name]['operation'] = array(
'#type' => 'radios',
'#title' => t(drupal_ucfirst(str_replace('_', ' ', $trigger_name)) .' Triggers'),
'#description' => t('Please choose when you would like to record a message.'),
'#options' => $options,
'#default_value' => $default_value,
'#required' => TRUE,
);
}
}
if (!empty($module_info->type_options)) {
if (!empty($form_state['storage']['values']['operations']['activity_types'])) {
$default_types = $form_state['storage']['values']['operations']['activity_types'];
}
else {
$default_types = array();
}
$form['activity_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Record for the following types'),
'#options' => $module_info->type_options,
'#default_value' => $default_types,
'#description' => t('If none are selected then these messages will be recorded for all.'),
);
}
$form['back'] = array(
'#type' => 'submit',
'#value' => 'Back',
);
$form['continue'] = array(
'#type' => 'submit',
'#value' => 'Continue',
);
$form['step_prev'] = array(
'#type' => 'value',
'#value' => '_activity_settings_form_triggers',
);
$form['this_step'] = array(
'#type' => 'value',
'#value' => 'operations',
);
$form['step_next'] = array(
'#type' => 'value',
'#value' => '_activity_settings_form_messages',
);
return $form;
}
/**
* Show the text boxes according to the _triggers and _ops steps.
*/
function _activity_settings_form_messages(&$form_state) {
$form = array();
if (isset($form_state['storage']['step'])) {
$hook = $form_state['storage']['values']['triggers']['hook'];
$module = activity_module_name($hook);
$operation = $form_state['storage']['values']['operations']['operation'];
$aid = FALSE;
$activity_types = isset($form_state['storage']['values']['operations']['activity_types']) ? $form_state['storage']['values']['operations']['activity_types'] : array();
}
else {
$aid = $form_state['storage']['action']->aid;
// by doing this we assume that an action is not assigned to more than one trigger
$result = db_query('SELECT hook, op FROM {trigger_assignments} WHERE aid = %d', $aid);
while ($row = db_fetch_array($result)) {
$hook = $form_state['storage']['values']['triggers']['hook'] = $row['hook'];
$module = activity_module_name($hook);
$operation = $form_state['storage']['values']['operations']['operation'] = $row['op'];
}
}
$module_info = activity_get_module_info($module);
if (isset($form_state['storage']['action'])) {
$default_values = unserialize($form_state['storage']['action']->parameters);
}
else {
$default_values = array();
}
// If this came through the multistep process it is already set above.
// Otherwise we need to get it from the default values
if (!isset($activity_types)){
if (isset($default_values['activity_types'])) {
$activity_types = $default_values['activity_types'];
}
else {
$activity_types = array();
}
}
$form_state['storage']['values']['operations']['activity_types'] = $activity_types;
// Filter out false checkboxes.
$activity_types = array_filter($activity_types);
if (empty($activity_types)) {
$types = 'All';
}
else {
$types = implode(', ' , array_intersect_key($module_info->type_options, $activity_types));
}
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#default_value' => isset($form_state['storage']['action']) ? $form_state['storage']['action']->description : t('Record an activity message when: !module !op types !types', array('!module' => $module, '!op' => $operation, '!types' => $types)),
'#maxlength' => '254',
'#description' => t('A unique description for this advanced action. This description will be displayed in the interface of modules that integrate with actions, such as Trigger module.'),
);
// @todo: extend ->objects to have a description which will fill out the
// #description for this form element. Remember to adjust logic everywhere
// ->objects is used.
foreach (activity_enabled_languages() as $id => $language) {
$form["{$id}_fieldset"] = array(
'#type' => 'fieldset',
'#title' => t('@name messages', array('@name' => $language->name)),
'#collapsible' => TRUE,
'#collapsed' => $id != language_default('language'),
);
foreach ($module_info->objects as $label => $type) {
$clean_type = drupal_ucfirst(str_replace('_', ' ', $label));
$form["{$id}_fieldset"][$type .'-pattern-' . $id] = array(
'#type' => 'textarea',
'#title' => t('!type message', array('!type' => $clean_type)),
'#default_value' => isset($default_values[$type .'-pattern-' . $id]) ? $default_values[$type .'-pattern-' . $id] : '',
'#description' => t('Using the available tokens, enter a message as how it should appear to the !type of this particular activity.', array('!type' => $clean_type)),
);
}
$form["{$id}_fieldset"]['everyone-pattern-' . $id] = array(
'#type' => 'textarea',
'#title' => t('Public message'),
'#default_value' => isset($default_values['everyone-pattern-' . $id]) ? $default_values['everyone-pattern-' . $id] : '',
'#description' => t('Using the available tokens, enter a message as how it should appear to anyone who is not the author of this particular activity.'),
);
}
// don't show the back button when editing
if (!isset($form_state['storage']['action'])) {
$form['back'] = array(
'#type' => 'submit',
'#value' => 'Back',
);
}
$form['save'] = array(
'#type' => 'submit',
'#value' => 'Save',
);
$form['step_prev'] = array(
'#type' => 'value',
'#value' => '_activity_settings_form_operations',
);
$form['this_step'] = array(
'#type' => 'value',
'#value' => 'messages',
);
$form['token_help'] = array(
'#type' => 'fieldset',
'#title' => t('Available tokens'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['token_help']['tokens'] = array(
'#type' => 'markup',
'#value' => theme('activity_token_help', array_values($module_info->objects)),
);
$form['aid'] = array(
'#type' => 'value',
'#value' => $aid,
);
return $form;
}
/**
* Create the form for confirmation of deleting an activity action.
*
* @ingroup forms
* @see activity_actions_delete_form_submit()
*/
function activity_actions_delete_form(&$form_state, $action) {
$form['aid'] = array(
'#type' => 'hidden',
'#value' => $action->aid,
);
$form['delete_existing'] = array(
'#type' => 'checkbox',
'#default_value' => 0,
'#title' => t('Delete Existing Activities for this template'),
);
return confirm_form($form,
t('Are you sure you want to delete the action %action?', array('%action' => $action->description)),
'admin/build/activity',
t('This cannot be undone.'),
t('Delete'), t('Cancel')
);
}
/**
* Process activity_actions_delete form submissions.
*
* Post-deletion operations for activity action deletion.
*/
function activity_actions_delete_form_submit($form, &$form_state) {
$aid = $form_state['values']['aid'];
$action = actions_load($aid);
actions_delete($aid);
watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $action->description));
drupal_set_message(t('Action %action was deleted', array('%action' => $action->description)));
$form_state['redirect'] = 'admin/build/activity';
if (!empty($form_state['values']['delete_existing'])) {
$batch = array(
'title' => t('Deleting Existing @title', array('@title' => $action->description)),
'operations' => array(
array('activity_batch_delete', array($aid)),
),
'file' => drupal_get_path('module', 'activity') . '/activity.admin.inc',
);
batch_set($batch);
}
}
/**
* Form builder to dispaly settings for activity module
*/
function activity_settings_form(&$form_state = NULL) {
$form['activity_expiration'] = array(
'#type' => 'fieldset',
'#title' => t('Activity Expiration Settings'),
'#element_validate' => array('activity_expire_validate'),
);
$form['activity_expiration']['activity_expire'] = array(
'#type' => 'select',
'#title' => t('Activity log purge'),
'#description' => t("Allows you to set a time limit for storing activity records. Select 0 to keep all activity records."),
'#options' => drupal_map_assoc(array(0, 3600, 7200, 14400, 21600, 43200, 86400, 604800, 1209600, 2419200, 7257600, 15724800, 31536000), 'format_interval'),
'#default_value' => variable_get('activity_expire', 0),
);
$form['activity_expiration']['activity_min_count'] = array(
'#type' => 'select',
'#title' => t('Minimum Activities'),
'#description' => t('This is the minimum number activities that the user must have created before deleting any old activities.'),
'#options' => drupal_map_assoc(range(0, 200, 10)),
'#default_value' => variable_get('activity_min_count', 0),
);
// get all the modules and their realms
$api_info = activity_get_module_info();
$realms = array();
foreach ($api_info as $module => $info) {
foreach ($info->realms as $realm => $nice_name) {
$realms[$realm] = t('@module: @name', array('@module' => drupal_ucfirst($module), '@name' => $nice_name));
}
}
$form['activity_access'] = array(
'#type' => 'fieldset',
'#title' => t('Activity Access Control'),
'#attributes' => array('id' => 'activity-access-fieldset'),
);
$form['activity_access']['activity_access_realms'] = array(
'#type' => 'checkboxes',
'#title' => t('Realms'),
'#description' => t('Select the realms for which Activity access records should be recorded. These realms will allow a View to filter in more then just one users Activity.'),
'#options' => $realms,
'#default_value' => activity_access_realms(),
);
$form['activity_access']['activity_access_rebuild'] = array(
'#type' => 'submit',
'#value' => t('Rebuild Activity Access Table'),
'#submit' => array('activity_access_batch_set'),
);
// This tells system_settings_form to use array_filter for the checkboxes.
$form['array_filter'] = array('#type' => 'value', '#value' => TRUE);
return system_settings_form($form);
}
/**
* Element validate callback
*/
function activity_expire_validate($element, &$form_state) {
if (empty($form_state['values']['activity_expire']) && !empty($form_state['values']['activity_min_count'])) {
form_set_error($element['activity_expire'], t('You must set a time limit in order to use the minimum count'), $form_state);
}
}
/**
* Menu callback -- ask for confirmation of activity deletion
*/
function activity_delete_confirm(&$form_state, $aid) {
$form['aid'] = array(
'#type' => 'value',
'#value' => $aid,
);
return confirm_form($form,
t('Are you sure you want to delete this activity?'),
$_GET['destination'],
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
/**
* Execute activity deletion
*/
function activity_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
activity_delete($form_state['values']['aid']);
}
$form_state['redirect'] = '';
}
/**
* FAPI form submit function for the activity_rebuild button.
*
* @param array $form
* The FAPI form structure array.
*
* @param array &$form_state
* The FAPI form state array.
*
* @return none
*/
function activity_access_batch_set($form, &$form_state) {
// Address usability concern where the realms arn't set.
$submitted_realms = array_filter($form_state['values']['activity_access_realms']);
if ($submitted_realms != activity_access_realms()) {
variable_set('activity_access_realms', $submitted_realms);
}
$batch = array(
'title' => t('Rebuilding Activity Access Table'),
'operations' => array(
array('activity_access_rebuild_process', array()),
),
'file' => drupal_get_path('module', 'activity') . '/activity.admin.inc',
);
batch_set($batch);
$form_state['redirect'] = 'admin/settings/activity';
}
/**
* Batch API processing operation. Rebuilding Access table.
*
* @param array $context
* The batch api context array.
*
* @return none
*/
function activity_access_rebuild_process(&$context) {
if (!isset($context['sandbox']['last_aid'])) {
// Set up the sandbox for the first time.
$context['sandbox']['last_aid'] = 0;
$context['sandbox']['progress'] = 0;
// Activity can be happening on the site. Any Activity happening after this point
// will not be rebuilt. This is ok, as in that case, the new Activity will receive
// any and all new Activity Access Realms.
$context['sandbox']['max'] = db_result(db_query("SELECT COUNT(aid) FROM {activity}"));
}
// Process 100 Activities at a time.
$limit = 100;
$activities = db_query_range("SELECT * FROM {activity} WHERE aid > %d ORDER BY aid ASC", $context['sandbox']['last_aid'], 0, $limit);
while ($activity = db_fetch_object($activities)) {
$grants = activity_get_grants($activity);
// Delete existing records.
db_query("DELETE FROM {activity_access} WHERE aid = %d", $activity->aid);
// Insert new ones.
foreach ($grants as $realm => $values) {
foreach ($values as $value) {
// insert one by one. In D7 we can use the DBTNG to insert multiple
$perm = new stdClass();
$perm->aid = $activity->aid;
$perm->realm = $realm;
$perm->value = $value;
drupal_write_record('activity_access', $perm);
}
}
// Update sandbox variables.
$context['sandbox']['last_aid'] = $activity->aid;
$context['sandbox']['progress']++;
}
// Check if not finished.
if ($context['sandbox']['progress'] < $context['sandbox']['max']) {
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
}
else {
// If finished, delete the sandbox.
unset($context['sandbox']);
}
}
/**
* Set a batch process to regenerate activity for a specific hook and op pair.
*
* @param $aid
* The actions.aid for this template.
*
* @return none
*/
function activity_batch_regenerate($batches) {
$batch_set = FALSE;
foreach ($batches as $aid => $batch) {
$trigger_assignment = db_fetch_object(db_query("SELECT hook, op FROM {trigger_assignments} WHERE aid = '%s'", $aid));
if (!empty($trigger_assignment)) {
$batch_set = TRUE;
$batch = array(
'title' => t('Regenerating @description Activity', array('@description' => db_result(db_query("SELECT description from {actions} WHERE aid = '%s'", $aid)))),
'operations' => array(
array('activity_batch_delete', array($aid)),
array('activity_batch_regenerate_step', array($aid, $batch, $trigger_assignment->hook, $trigger_assignment->op)),
),
'file' => drupal_get_path('module', 'activity') . '/activity.admin.inc',
);
batch_set($batch);
}
}
if ($batch_set) {
batch_process('admin/build/activity');
}
else {
return '';
}
}
/**
* Batch deletion step.
*
* @param $aid
* The actions.aid for this template.
* @param $batch_context
* The context array for this batch operation.
*/
function activity_batch_delete($aid, &$batch_context) {
if (!isset($batch_context['sandbox']['last_activity_id'])) {
$batch_context['sandbox']['last_activity_id'] = 0;
$batch_context['sandbox']['progress'] = 0;
$batch_context['sandbox']['max'] = db_result(db_query("SELECT COUNT(aid) FROM {activity} WHERE actions_id = '%s'", $aid));
}
$limit = 200;
$activity_to_be_deleted = db_query_range("SELECT aid FROM {activity} WHERE aid > %d AND actions_id = '%s' ORDER BY aid ASC", $batch_context['sandbox']['last_activity_id'], $aid, 0, $limit);
$activity_ids = array();
while ($row = db_fetch_object($activity_to_be_deleted)) {
$activity_ids[] = $row->aid;
$batch_context['sandbox']['last_activity_id'] = $row->aid;
$batch_context['sandbox']['progress']++;
}
activity_delete($activity_ids);
// Check if not finished.
if ($batch_context['sandbox']['progress'] < $batch_context['sandbox']['max']) {
$batch_context['finished'] = $batch_context['sandbox']['progress'] / $batch_context['sandbox']['max'];
}
else {
// If finished, delete the sandbox.
unset($batch_context['sandbox']);
}
}
/**
* Batch regeneration step.
*
* @param $aid
* The actions.aid for this template.
* @param $hook
* The name of the hook being recorded.
* @param $op
* The op for the hook being recorded.
* @param $batch_context
* An array representing the context for the batch operation.
*/
function activity_batch_regenerate_step($aid, $batch, $hook, $op, &$batch_context) {
$module = activity_module_name($hook);
$info = activity_get_module_info($module);
$load_callback = $info->context_load_callback;
$limit = 50;
// Set up the sandbox for the regeneration.
if (!isset($batch_context['sandbox']['list'])) {
$batch_context['sandbox']['list'] = $batch;
$batch_context['sandbox']['max'] = count($batch_context['sandbox']['list']);
$batch_context['sandbox']['progress'] = 0;
$parameters = db_result(db_query("SELECT a.parameters FROM {actions} a WHERE aid = '%s'", $aid));
$batch_context['sandbox']['parameters'] = unserialize($parameters);
}
$count = 0;
foreach ($batch_context['sandbox']['list'] as $key => $event) {
$context = array();
if (++$count > $limit) {
break;
}
else {
$context = $load_callback($hook, $op, $event['id']);
if (!empty($context)) {
$context += array(
'created' => $event['created'],
'actor' => $event['actor'],
);
activity_record(NULL, $context + $batch_context['sandbox']['parameters']);
}
$batch_context['sandbox']['progress']++;
}
unset($batch_context['sandbox']['list'][$key]);
}
// Check if not finished.
if ($batch_context['sandbox']['progress'] < $batch_context['sandbox']['max']) {
$batch_context['finished'] = $batch_context['sandbox']['progress'] / $batch_context['sandbox']['max'];
}
else {
// If finished, delete the sandbox.
unset($batch_context['sandbox']);
}
}