array('class' => 'jscalendar'), '#jscalendar_showsTime' => 'true', '#jscalendar_timeFormat' => '24' // '#jscalendar_ifFormat' => SCHED_ACT_FMT, ); function sched_act_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/actions/scheduled', 'title' => t('scheduled actions'), 'callback' => 'sched_act_page', 'access' => user_access('schedule actions') ); } return $items; } /** * Implementation of hook_perm(). */ function sched_act_perm() { return array('schedule actions'); } function sched_act_page() { $acts = db_query('SELECT * FROM {sched_act} ORDER BY actual, sched'); $form = _sched_act_form($acts, false); $form['sched_acts']['#theme'] = 'scheduled_actions_admin'; if ($form['sched_acts']['#collapsed'] == false /* kludge! */) { $form['submit'] = array('#type' => 'submit', '#value' => t('Submit')); } return drupal_get_form('sched_act', $form); } function sched_act_submit($form_id, $form) { $dels = $updates = 0; foreach ($form['sched_acts']['acts'] as $edit) { $said = $edit['said']; if ($edit['remove'] == 1) { db_query('DELETE FROM {sched_act} WHERE said = %d', $said); ++$dels; } else if (isset($edit['sched']) && $edit['sched']!=$edit['orig_sched']) { db_query('UPDATE {sched_act} SET sched = %d WHERE said = %d', strtotime($edit['sched']), $said); ++$updates; } } if ($updates > 0) { drupal_set_message(t('%n scheduled actions updated.', array('%n' => $updates))); } if ($dels > 0) { drupal_set_message(t('%n scheduled actions deleted.', array('%n' => $dels))); } } /** * Implementation of hook_form_alter(). */ function sched_act_form_alter($form_id, &$form) { if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) { if (user_access('schedule actions')) { $node = $form['#node']; $acts = db_query('SELECT * FROM {sched_act} WHERE (a1type = %d AND a1val = "%s") OR (a2type = %d AND a2val = "%s") OR (a3type = %d AND a3val = "%s") OR (a4type = %d AND a4val = "%s") ORDER BY actual, sched', SCHED_ACT_TYPE_NODE, $node->nid, SCHED_ACT_TYPE_NODE, $node->nid, SCHED_ACT_TYPE_NODE, $node->nid, SCHED_ACT_TYPE_NODE, $node->nid); $form = array_merge($form, _sched_act_form($acts, true)); } } } function _sched_act_form($q, $show_new) { $form['sched_acts'] = array( '#type' => 'fieldset', '#title' => 'Scheduled actions', '#collapsible' => TRUE, '#theme' => 'scheduled_actions', '#tree' => true ); if ($show_new) { $form['sched_acts']['#description'] .= t('Scheduled actions for this node are shown below. To schedule a new action, select the action from the drop-down and specify a time for it to run, then Submit the node.'); } else { $form['sched_acts']['#description'] .= t('All scheduled actions are shown below.'); } $actions = actions_get_all_actions(); if (! is_array($form['sched_acts']['acts'])) { while ($act = db_fetch_array($q)) { $form['sched_acts']['acts'][] = _sched_act_form_act($act, $actions); } } $form['sched_acts']['#collapsed'] = (count($form['sched_acts']['acts'])==0); if ($show_new) { $nform['aid'] = array ('#type' => 'select', '#options' => array_merge(array('' => ''), _sched_act_all_actions()), '#description' => t('To schedule an action, select it here.')); $nform['sched'] = array ('#type' => 'textfield', '#size' => 24, '#default_value' => format_date(time()+86400, 'custom', SCHED_ACT_FMT), '#description' => t('When to schedule it.')); global $_sched_act_jscal; $nform['sched'] += $_sched_act_jscal; $form['sched_acts']['new'] = $nform; } return $form; } function _sched_act_form_act($act, $actions) { $aform['said'] = array('#type' => 'value', '#value' => $act['said']); $aform['aid'] = array('#type' => 'value', '#value' => $act['aid']); $aform['remove'] = array('#type' => 'checkbox'); $aform['desc'] = array('#value' => $actions[$act['aid']]['description']); $aform['desc_val'] = array('#type' => 'hidden', '#value' => $actions[$act['aid']]['description']); $aform['sched'] = array('#value' => format_date($act['sched'], 'custom', SCHED_ACT_FMT)); if ($act['actual'] == 0) { $aform['orig_sched'] = $aform['sched']; $aform['orig_sched']['#type'] = 'value'; $aform['sched'] = array('#type' => 'textfield', '#size' => 24, '#default_value' => format_date($act['sched'], 'custom', SCHED_ACT_FMT)); global $_sched_act_jscal; $aform['sched'] += $_sched_act_jscal; } $aform['actual'] = array('#value' => ($act['actual'] > 0) ? format_date($act['actual'], 'custom', SCHED_ACT_FMT) : ''); $types = array(SCHED_ACT_TYPE_NODE => 'node'); $aform['a1type'] = array('#type' => 'value', '#value' => $types[$act['a1type']]); $aform['a1val'] = array('#type' => 'value', '#value' => $act['a1val']); $aform['a2type'] = array('#type' => 'value', '#value' => $types[$act['a2type']]); $aform['a2val'] = array('#type' => 'value', '#value' => $act['a2val']); $aform['a3type'] = array('#type' => 'value', '#value' => $types[$act['a3type']]); $aform['a3val'] = array('#type' => 'value', '#value' => $act['a3val']); $aform['a4type'] = array('#type' => 'value', '#value' => $types[$act['a4type']]); $aform['a4val'] = array('#type' => 'value', '#value' => $act['a4val']); return $aform; } /** * Theme the scheduled actions list. */ function theme_scheduled_actions_admin(&$form) { return theme('scheduled_actions', $form, true); } function theme_scheduled_actions(&$form, $links = false) { $header = array(t('Remove'), t('Action'), t('Scheduled'), t('Actual')); if ($links) { array_push($header, t('a1'), t('a2'), t('a3'), t('a4')); } $rows = array(); if (is_array($form['acts'])) { foreach ($form['acts'] as $key => $ignored) { if (! is_numeric($key)) { continue; } $row = array(); $row[] = drupal_render($form['acts'][$key]['remove']); $row[] = drupal_render($form['acts'][$key]['desc']); $row[] = drupal_render($form['acts'][$key]['sched']); $row[] = drupal_render($form['acts'][$key]['actual']); if ($links) { $l = ($form['acts'][$key]['a1type']['#value'] .'/'. $form['acts'][$key]['a1val']['#value']); $row[] = ($form['acts'][$key]['a1val']['#value'] > 0) ? l($l, $l) : ''; $l = ($form['acts'][$key]['a2type']['#value'] .'/'. $form['acts'][$key]['a2val']['#value']); $row[] = ($form['acts'][$key]['a2val']['#value'] > 0) ? l($l, $l) : ''; $l = ($form['acts'][$key]['a3type']['#value'] .'/'. $form['acts'][$key]['a3val']['#value']); $row[] = ($form['acts'][$key]['a3val']['#value'] > 0) ? l($l, $l) : ''; $l = ($form['acts'][$key]['a4type']['#value'] .'/'. $form['acts'][$key]['a4val']['#value']); $row[] = ($form['acts'][$key]['a4val']['#value'] > 0) ? l($l, $l) : ''; } $rows[] = $row; } if (count($rows) > 0) { $output .= theme('table', $header, $rows); } } if (isset($form['new'])) { $row = array(); $row[] = drupal_render($form['new']['aid']); $row[] = drupal_render($form['new']['sched']); $output .= theme('table', array(), array($row)); $output .= drupal_render($form['new']); } $output .= drupal_render($form); return $output; } function _sched_act_validate_action($name, $act) { $actions = actions_get_all_actions(); // If the action has occurred, $act['sched'] is just markup and does // not appear here. If it has not yet occurred, $act['sched'] is a // form field. So, the form value must either not exist OR contain // a valid value. if (isset($act['sched']) && ($act['sched'] == '' || $act['sched'] == 0)) { form_set_error('sched_acts]'. $name .'[sched', t('You must specify a scheduled time for the %desc action.', array('%desc' => theme('placeholder', $actions[$act['aid']]['description'])))); } } /** * Implementation of hook_nodeapi(). */ function sched_act_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { switch ($op) { case 'validate': if (user_access('schedule actions')) { if (is_array($node->sched_acts['acts'])) { foreach ($node->sched_acts['acts'] as $idx => $act) { _sched_act_validate_action("[acts][$idx]", $act); } } if ($node->sched_acts['new']['aid'] != '') { _sched_act_validate_action('[new]', $node->sched_acts['new']); } } break; case 'insert': case 'update': if (user_access('schedule actions')) { if (is_array($node->sched_acts['acts'])) { foreach ($node->sched_acts['acts'] as $act) { if ($act['remove'] === 1) { db_query('DELETE FROM {sched_act} WHERE said = %d', $act['said']); } else if ($act['sched'] != $act['orig_sched']) { db_query('UPDATE {sched_act} SET sched = %d WHERE said = %d', strtotime($act['sched']), $act['said']); } } } if ($node->sched_acts['new']['aid'] != '') { $act = $node->sched_acts['new']; $said = db_next_id('{sched_act}_said'); db_query("INSERT INTO {sched_act} (said, aid, sched, actual, a1type, a1val) VALUES (%d, '%s', %d, %d, %d, '%s') ", $said, $act['aid'], strtotime($act['sched']), 0, SCHED_ACT_TYPE_NODE, $node->nid); } } break; case 'delete': db_query('DELETE FROM {sched_act} WHERE (a1type = %d AND a1val = "%s") OR (a2type = %d AND a2val = "%s") OR (a3type = %d AND a3val = "%s") OR (a4type = %d AND a4val = "%s")', SCHED_ACT_TYPE_NODE, $node->nid, SCHED_ACT_TYPE_NODE, $node->nid,SCHED_ACT_TYPE_NODE, $node->nid, SCHED_ACT_TYPE_NODE, $node->nid); break; } } function _sched_act_all_actions() { $raw = actions_get_all_actions(); foreach ($raw as $aid => $data) { $cooked[$data['type']][$aid] = $data['description']; } return $cooked; } function _sched_act_arg_type($def, $num) { return array( '#type' => 'select', '#title' => t('Type of argument '. $num), '#options' => array(SCHED_ACT_TYPE_NONE => '', SCHED_ACT_TYPE_NODE => 'Node'), '#default_value' => (isset($def) ? $def : SCHED_ACT_TYPE_NONE), ); } function _sched_act_get_arg($type, $val, $name = '') { switch ($type) { case SCHED_ACT_TYPE_NODE: return node_load($val); } } function _sched_act_arg_id($type, $val) { switch ($type) { case SCHED_ACT_TYPE_NONE: return 0; case SCHED_ACT_TYPE_NODE: return $val->nid; } } function _sched_act_compute_when($num, $unit) { if (is_numeric($unit)) { return time() + $num*$unit; } else if ($unit == 'weekdays') { $when = time(); while ($num-- > 0) { $when += 86400; $tm = localtime($when, true); if ($tm['tm_wday'] == 0) { $when += 86400; } else if ($tm['tm_wday'] == 6) { $when += 2*86400; } } /* if $num was 0, still make sure it isn't a weekend */ $tm = localtime($when, true); if ($tm['tm_wday'] == 0) { $when += 86400; } else if ($tm['tm_wday'] == 6) { $when += 2*86400; } return $when; } return 0; } function _sched_act_count_array($a) { $sum = 0; foreach ($a as $e) { $sum += (is_array($e)) ? _sched_act_count_array($e) : 1; } return $sum; } function action_sched_act_asa($op, $edit, $a1=0, $a2=0, $a3=0, $a4=0) { switch ($op) { case 'metadata': return array ( 'type' => t('Schedule'), 'description' => 'Create an action-scheduling action', 'configurable' => true, 'batchable' => false /* XXX not sure yet */ ); case 'form': $form = array(); $form['help'] = array( '#type' => 'markup', '#value' => t('An action-scheduling action (ASA) schedules some other action to occur in the future. For example, if you create an ASA to execute the \'Publish a node\' action in 3 days, then when your newly created action is invoked on a node, that node will be published 3 days later.') ); $form['which'] = array( '#type' => 'select', '#title' => t('Action to schedule'), '#options' => array_merge(array('' => ''), _sched_act_all_actions()), '#default_value' => isset($edit['which']) ? $edit['which'] : 0, '#required' => true, '#description' => t('Select the action that this ASA should schedule to occur.'), ); $form['time'] = array( '#type' => 'fieldset', '#title' => 'When to schedule it' ); $form['time']['number'] = array( '#type' => 'textfield', '#title' => t('Number'), '#required' => true, '#size' => 3, '#default_value' => $edit['number'], ); $form['time']['unit'] = array( '#type' => 'select', '#title' => t('Unit'), '#options' => array( '1' => 'seconds', '60' => 'minutes', '3600' => 'hours', '86400' => 'days', 'weekdays' => 'weekdays' ), '#default_value' => isset($edit['unit']) ? $edit['unit'] : 86400, ); $form['args'] = array( '#type' => 'fieldset', '#title' => 'Arguments', '#description' => t('Specify the type of arguments this ASA will receive, which must be the same as what the action you are scheduling expects. If this ASA will be invoked by the Workflow module, select Node for the first and leave the rest blank.') ); $form['args']['a1type'] = _sched_act_arg_type($edit['a1type'], '1'); $form['args']['a1type']['#required'] = true; $form['args']['a2type'] = _sched_act_arg_type($edit['a2type'], '2'); $form['args']['a3type'] = _sched_act_arg_type($edit['a3type'], '3'); $form['args']['a4type'] = _sched_act_arg_type($edit['a4type'], '4'); $form['filter'] = array( '#type' => 'fieldset', '#title' => 'Filter' ); $options = taxonomy_form_all(); $form['filter']['terms'] = array( '#type' => 'select', '#title' => t('Filter'), '#options' => $options, '#multiple' => true, '#size' => min(9, _sched_act_count_array($options)), '#default_value' => isset($edit['terms']) ? $edit['terms'] : 0, '#description' => t('If the type of argument 1 is Node, the action will only be scheduled if the node has at least one of the terms selected. Leave blank to operate on any triggering node.'), ); return $form; case 'validate': if (isset($edit['number']) && !is_numeric($edit['number'])) form_set_error('number', 'The Number field must contain a number.'); else return true; return false; case 'submit': return $edit; case 'do': if (isset($edit['terms']) && is_array($edit['terms']) && count($edit['terms']) > 0 && count(array_intersect(array_keys($edit['terms']), array_keys(taxonomy_node_get_terms($a1->nid)))) == 0) { /* do nothing */ break; } $when = _sched_act_compute_when($edit['number'], $edit['unit']); $said = db_next_id('{sched_act}_said'); db_query("INSERT INTO {sched_act} (said, aid, sched, actual, a1type, a1val, a2type, a2val, a3type, a3val, a4type, a4val) VALUES (%d, '%s', %d, %d, %d, '%s', %d, '%s', %d, '%s', %d, '%s')", $said, $edit['which'], $when, 0, $edit['a1type'], _sched_act_arg_id($edit['a1type'], $a1), $edit['a2type'], _sched_act_arg_id($edit['a2type'], $a2), $edit['a3type'], _sched_act_arg_id($edit['a3type'], $a3), $edit['a4type'], _sched_act_arg_id($edit['a4type'], $a4)); break; } } /** * Implementation of hook_cron(). */ function sched_act_cron() { $clear_cache = FALSE; $acts = db_query('SELECT * from {sched_act} WHERE sched < %d AND actual = 0', time()); while ($act = db_fetch_object($acts)) { $a1 = _sched_act_get_arg($act->a1type, $act->a1val, 'arg 1'); $a2 = _sched_act_get_arg($act->a2type, $act->a2val, 'arg 2'); $a3 = _sched_act_get_arg($act->a3type, $act->a3val, 'arg 3'); $a4 = _sched_act_get_arg($act->a4type, $act->a4val, 'arg 4'); actions_do($act->aid, $a1, $a2, $a3, $a4); db_query('UPDATE {sched_act} SET actual = %d WHERE said = %d', time(), $act->said); $clear_cache = TRUE; } if ($clear_cache) { // clear the cache so an anonymous poster can see any changes cache_clear_all(); } }