/** * Renders a screen for setting permissions on approval points. * * @return tempcode The UI */ function second_screen() { require_code('form_templates'); // See if we're redefining everything $redefining = array_key_exists('redefine_points', $_POST); // Grab all of the requested points $points = array_map('trim', explode("\n", trim(post_param('points')))); // Throw out whitespace $temp_points = array(); foreach ($points as $p) { if (strlen(trim($p)) > 0) { $temp_points[] = trim($p); } } $points = $temp_points; unset($temp_points); // Clean them up a bit. We'll allow spaces, but no other punctuation. $clean_points = array(); foreach ($points as $p) { $clean_points[] = implode(' ', array_map('strip_tags', explode(' ', $p))); } $points = $clean_points; unset($clean_points); // Find any points which are already defined $all_points = get_all_approval_points(); // This will hold new points $clarify_points = array(); // This will hold existing points we're redefining $redefine_points = array(); // See if we need to define any foreach ($points as $p) { if (!in_array($p, $all_points)) { // Found an undefined point. We need more information. $clarify_points[] = $p; } elseif ($redefining) { $redefine_points[] = $p; } } // These will hold our form fields $fields = new ocp_tempcode(); $hidden = new ocp_tempcode(); // Pass through the previous screen's data foreach (array('points', 'is_default', 'name') as $n) { $hidden->attach(form_input_hidden($n, post_param($n, ''))); } // We need a list of groups so that the user can choose those to give // permission to $usergroups = $GLOBALS['FORUM_DRIVER']->get_usergroup_list(true, true, false, NULL, NULL); // Add the form elements for each section if (count($clarify_points) > 0) { $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('TITLE' => do_lang('DEFINE_WORKFLOW_POINTS'), 'HELP' => do_lang_tempcode('DEFINE_WORKFLOW_POINTS_HELP', implode(', ', $clarify_points))))); $counter = 0; foreach ($clarify_points as $p) { // Add a code to reference these elements by later $hidden->attach(form_input_hidden('code_' . strval($counter), $p)); // Now add a list of the groups to allow $content = array(); foreach ($usergroups as $group_id => $group_name) { $content[] = array($group_name, 'groups_' . strval($counter) . '[' . strval($group_id) . ']', false, ''); } $fields->attach(form_input_various_ticks($content, do_lang('WORKFLOW_POINT_GROUPS_DESC', $p), NULL, do_lang('WORKFLOW_POINT_GROUPS', $p), true)); $counter++; } } if (count($redefine_points) > 0) { $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('TITLE' => do_lang('REDEFINE_WORKFLOW_POINTS'), 'HELP' => do_lang('REDEFINE_WORKFLOW_POINTS_HELP')))); // These points already exist, so look them up $all_points = array_flip(get_all_approval_points()); foreach ($redefine_points as $p) { // Add a code to reference these elements by later $hidden->attach(form_input_hidden('redef_' . strval($all_points[$p]), $p)); // Now add a list of the groups to allow, defaulting to those which // already have permission $groups = get_groups_for_point($all_points[$p], false); $content = array(); foreach ($usergroups as $group_id => $group_name) { $content[] = array($group_name, 'redef_groups_' . strval($all_points[$p]) . '[' . strval($group_id) . ']', in_array($group_id, $groups), ''); } $fields->attach(form_input_various_ticks($content, do_lang('WORKFLOW_POINT_GROUPS_DESC', $p), NULL, do_lang('WORKFLOW_POINT_GROUPS', $p), true)); } } $self_url = get_self_url(); return do_template('FORM_SCREEN', array('TITLE' => do_template('SCREEN_TITLE', array('TITLE' => do_lang('DEFINE_WORKFLOW_POINTS'), 'HELP_URL' => '')), 'FIELDS' => $fields, 'TEXT' => '', 'HIDDEN' => $hidden, 'URL' => is_object($self_url) ? $self_url->evaluate() : $self_url, 'SUBMIT_NAME' => do_lang_tempcode('PROCEED'))); }
/** * Handler for workflow form submission. * * @return tempcode Either an error page or a success message */ function workflow_update_handler() { require_lang('workflows'); require_code('database'); $success_message = do_lang('APPROVAL_UNCHANGED'); ///////////////////////////////////////// // Grab everything we need from $_POST // ///////////////////////////////////////// $workflow_id = post_param('workflow_id'); $content_id = post_param('content_id'); $workflow_notes = post_param('workflow_notes'); // Find out which approvals have been given $approvals = array(); foreach (get_requirements_for_workflow(post_param('workflow_id')) as $approval_id) { // We might not have a value for this point, since we may not have given a tick box for it if (array_key_exists('approval_' . strval($approval_id), $_POST)) { $approvals[$approval_id] = post_param_integer('approval_' . strval($approval_id)); } elseif (array_key_exists('tick_on_form__approval_' . strval($approval_id), $_POST)) { $approvals[$approval_id] = post_param_integer('tick_on_form__approval_' . strval($approval_id)); } } //////////////////////// // Get member details // //////////////////////// // Find out which groups/members to inform, starting with the // original submitter $send_to_members = array(); if (array_key_exists('send_author', $_POST)) { if (post_param_integer('send_author') == 1) { $submitter = get_submitter_of_workflow_content($content_id); if (!is_null($submitter)) { $send_to_members[$submitter] = 1; } } } // Now get the groups $group_ids = array(); // Only remember 1 copy of each group foreach (get_requirements_for_workflow($workflow_id) as $requirement) { foreach (get_groups_for_point($requirement) as $group) { if (!in_array($group, $group_ids)) { if (post_param_integer('send_' . strval($group), 0) == 1) { $group_ids[] = $group; } } } } // From the groups we can get the members, and from there the emails foreach ($GLOBALS['FORUM_DRIVER']->member_group_query($group_ids) as $member) { $send_to_members[$member['id']] = 1; } //////////////////////////////////////////// // Now play with the database as required // //////////////////////////////////////////// // See which values need updating (ie. approvals have been given/withdrawn) $updated_approvals = array(); $all_approval_statuses = array(); // Grab each point's status from the database $old_values = $GLOBALS['SITE_DB']->query_select('workflow_content_status', array('workflow_approval_name', 'status_code'), array('workflow_content_id' => $content_id)); $accounted_for_statuses = array(); // Look for any differences we need to make foreach ($old_values as $old_value) { $noted = false; // Keep a note of each value for including in emails // Only compare against values which we've been given if (array_key_exists($old_value['workflow_approval_name'], $approvals)) { $accounted_for_statuses[] = $old_value['workflow_approval_name']; // See if the database entry is the same as the given status if ($old_value['status_code'] != $approvals[$old_value['workflow_approval_name']]) { // If not then see if we have permission to change it $members_with_permission = array(); foreach ($GLOBALS['FORUM_DRIVER']->member_group_query(get_groups_for_point($old_value['workflow_approval_name'])) as $permitted) { $members_with_permission[] = $permitted['id']; } if (in_array(get_member(), $members_with_permission)) { // Remember that this needs to be changed $updated_approvals[$old_value['workflow_approval_name']] = $approvals[$old_value['workflow_approval_name']]; // Make a note of this value in the array of all statuses $all_approval_statuses[$old_value['workflow_approval_name']] = $approvals[$old_value['workflow_approval_name']]; $noted = true; } } } if (!$noted) { // If we're here then this status has either not been passed or // it does not need modifying. Either way we can grab a valid // status from the database. $all_approval_statuses[$old_value['workflow_approval_name']] = $old_value['status_code']; } } // Now add any unaccounted-for points to those which need updating $new_approvals = array(); foreach (array_keys($approvals) as $a) { if (!in_array($a, $accounted_for_statuses)) { $updated_approvals[$a] = $approvals[$a]; $new_approvals[] = $a; } } // Now we know which fields to update, let's do so foreach ($updated_approvals as $approval_id => $status_code) { $success_message = do_lang('APPROVAL_CHANGED_DESCRIPTION'); if (in_array($approval_id, $new_approvals)) { $GLOBALS['SITE_DB']->query_insert('workflow_content_status', array('status_code' => $status_code, 'approved_by' => get_member(), 'workflow_content_id' => $content_id, 'workflow_approval_name' => $approval_id)); } else { $GLOBALS['SITE_DB']->query_update('workflow_content_status', array('status_code' => $status_code, 'approved_by' => get_member()), array('workflow_content_id' => $content_id, 'workflow_approval_name' => $approval_id), '', 1, NULL, false, false); } } // Update the notes (this is done destructively, but is simplest) // We append a timestamped log of the action taken $notes_approved = array(); $notes_disapproved = array(); foreach ($updated_approvals as $approval_id => $status_code) { if ($status_code) { $notes_approved[] = $approval_id; } else { // Just because it's not approved, doesn't mean that it was unticked. // It may have just been added to the workflow. if (!in_array($approval_id, $new_approvals)) { $notes_disapproved[] = $approval_id; } } } if (count($notes_approved) + count($notes_disapproved) > 0) { $note_title = date('Y-m-d H:i') . ' ' . $GLOBALS['FORUM_DRIVER']->get_username(get_member()); $workflow_notes = $workflow_notes . "\n\n" . $note_title . "\n" . str_repeat('-', strlen($note_title)); $notes_approved = array_map('get_translated_text', $notes_approved); $notes_disapproved = array_map('get_translated_text', $notes_disapproved); if (count($notes_approved) > 0) { $workflow_notes .= "\n" . do_lang('WORKFLOW_APPROVED') . ': ' . implode(', ', $notes_approved); } if (count($notes_disapproved) > 0) { $workflow_notes .= "\n" . do_lang('WORKFLOW_DISAPPROVED') . ': ' . implode(', ', $notes_disapproved); } } $GLOBALS['SITE_DB']->query_update('workflow_content', array('notes' => $workflow_notes), array('id' => $content_id), '', 1); ///////////////////////////// // See if we're going live // ///////////////////////////// // Validation is stored, for the most part, in a 'validated' field // of the content's table. Those which store it elsewhere must // specify this via their content-meta-aware info. // Grab lookup data from the workflows database $content_details = $GLOBALS['SITE_DB']->query_select('workflow_content', array('source_type', 'source_id'), array('id' => $content_id), '', 1); if ($content_details == array()) { warn_exit(do_lang_tempcode('_MISSING_RESOURCE', 'workflow_content->' . strval($content_id))); } // Now use it to find this content's validation field $hooks = find_all_hooks('systems', 'content_meta_aware'); $found = false; // Guilty until proven innocent again foreach (array_keys($hooks) as $hook) { // Skip if this is not the hook we're after if ($hook != $content_details[0]['source_type']) { continue; } // Otherwise load and instantiate the hook require_code('hooks/systems/content_meta_aware/' . filter_naughty_harsh($hook)); $ob = object_factory('Hook_content_meta_aware_' . filter_naughty_harsh($hook), true); if (is_null($ob)) { continue; } // Bail out if the hook fails // Grab information about the hook $info = $ob->info(); $content_table = $info['table']; $content_field = $info['id_field']; if (array_key_exists('validated_field', $info)) { $content_validated_field = $info['validated_field']; } else { // Fall back to 'validated' if nothing is specified $content_validated_field = 'validated'; } if ($info['id_field_numeric']) { // If so then flag it with a shorter name, and use a different // name for the converted ID (ocPortal avoids dynamic typing) $numeric = true; $numeric_id = intval($content_details[0]['source_id']); // Errors arise from passing an object, but should be noticed by type checker } else { // Otherwise set the flag as false. We've already got a string. $numeric = false; } } // Now we have the details required to lookup this entry, wherever it // is. Let's get its current validation status and compare to what // the workflow would have it be if ($numeric) { $content_is_validated = $GLOBALS['SITE_DB']->query_select($content_table, array($content_validated_field), array($content_field => $numeric_id), '', 1); } else { $content_is_validated = $GLOBALS['SITE_DB']->query_select($content_table, array($content_validated_field), array($content_field => $content_details[0]['source_id']), '', 1); } // Make sure we've actually found something if ($content_is_validated == array()) { $source_id = $content_details[0]['source_id']; $validated_field = $source_id->content_validated_field; warn_exit(do_lang_tempcode('_MISSING_RESOURCE', $content_table . '->' . $content_field . '->' . $validated_field)); } // In order for content to go live all points must be approved // See if all points have been approved. If so, none will have // status 0 $all_points_approved = false; if ($GLOBALS['SITE_DB']->query_select('workflow_content_status', array('workflow_approval_name'), array('workflow_content_id' => $content_id, 'status_code' => 0)) == array()) { $all_points_approved = true; } // We need to act if the validation status is different to the total // completion of the workflow if (($content_is_validated[0][$content_validated_field] == 1) != $all_points_approved) { $success_message = $all_points_approved ? do_lang('APPROVAL_COMPLETE') : do_lang('APPROVAL_REVOKED'); $GLOBALS['SITE_DB']->query_update($content_table, array($content_validated_field => $all_points_approved ? 1 : 0), array($content_field => $content_details[0]['source_id']), '', 1); } /////////////////////////////////////////// // Now inform members about this content // /////////////////////////////////////////// // Make a nicely formatted list of the statuses $status_list = ''; foreach ($all_approval_statuses as $point => $status) { $status_list .= get_translated_text($point) . ': '; $status_list .= $status == 1 ? 'approved' : 'not approved'; $status_list .= ', '; } // At last we can send the email require_code('notifications'); if (count($send_to_members) > 0) { $success_message .= do_lang('APPROVAL_CHANGED_NOTIFICATIONS'); } //require_code('developer_tools'); //inspect($emails); $subject = do_lang('APPROVAL_EMAIL_SUBJECT', NULL, NULL, NULL, get_site_default_lang()); $body = do_lang('APPROVAL_EMAIL_BODY', post_param('http_referer', ocp_srv('HTTP_REFERER')), $status_list, $workflow_notes, get_site_default_lang()); dispatch_notification('workflow_step', NULL, $subject, $body, $send_to_members); // Finally return a success message $return_url = strip_tags(post_param('return_url')); return redirect_screen(new ocp_tempcode(), $return_url, $success_message); }