NULL, 'submitted' => FALSE, 'rebuild' => TRUE); $form_build_id = $_POST['form_build_id']; $form = form_get_cache($form_build_id, $form_state); $args = $form['#parameters']; $form_id = array_shift($args); $form_state['post'] = $form['#post'] = $_POST; $form['#programmed'] = $form['#redirect'] = FALSE; drupal_process_form($form_id, $form, $form_state); // Rebuild the form and cache it again. $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id); // These used to be path arguments. Now they arrive via form element. $issue_nid = $form['nid']['#value']; $pid = $form_state['values']['project_info']['pid']; $rid = isset($form_state['values']['project_info']['rid']) ? $form_state['values']['project_info']['rid'] : 0; $cid = $form_state['values']['cid']; $assigned_uid = $form_state['values']['project_info']['assigned']; $project_info = $form['original_issue']['project_info']; // Only generate release stuff if the project_release module is enabled. if (module_exists('project_release')) { $project->nid = $pid; if ($releases = project_release_get_releases($project, 0)) { $old_version = db_result(db_query("SELECT version FROM {project_release_nodes} WHERE nid = %d", $rid)); $releases = array(t('')) + $releases; // Since the value of releases is by nid, try to match release // based on the label instead. $default = 0; foreach ($releases as $key => $label) { if ($old_version == $label) { $default = $key; } } // Element is tree'd here to match the original form layout. $project_info['#tree'] = TRUE; $project_info['rid']['#options'] = $releases; $project_info['rid']['#disabled'] = FALSE; if (!empty($default)) { $project_info['rid']['#value'] = $default; $project_info['rid']['#default_value'] = $default; } } else { $project_info['rid']['#disabled'] = TRUE; $project_info['rid']['#options'] = array(); } } // Assigned. if (is_numeric($issue_nid)) { $issue = node_load(array('nid' => $issue_nid, 'type' => 'project_issue')); } else { // @TODO: This case should not ever be hit until // http://drupal.org/node/197281 lands. $issue = new stdClass; } $issue->project_issue['pid'] = $pid; $assigned_choices = project_issue_assigned_choices($issue); $project_info['assigned']['#default_value'] = $assigned_uid; $project_info['assigned']['#options'] = $assigned_choices; // Components. $project = db_fetch_object(db_query('SELECT * FROM {project_issue_projects} WHERE nid = %d', $pid)); $components = array(); if ($project->components) { $components = array(t('')); foreach (unserialize($project->components) as $component) { $component = check_plain($component); $components[$component] = $component; } } $project_info['component']['#default_value'] = $cid; $project_info['component']['#options'] = $components; // Build the HTML output for the component select. $output = theme('status_messages') . drupal_render($project_info); drupal_json(array('status' => TRUE, 'data' => $output)); exit; } /** * Build an array of users to whom an issue may be assigned. * * @param $issue * The fully loaded issue node object. * @return * A keyed array in the form uid => name containing users * to whom an issue may be assigned. */ function project_issue_assigned_choices($issue) { // Setup the array of choices for who the issue is assigned to. $assigned = array(); foreach (module_implements('project_issue_assignees') as $module) { $function = "{$module}_project_issue_assignees"; $function($assigned, $issue); } natcasesort($assigned); $assigned = array(0 => empty($issue->project_issue['assigned']) ? t('Unassigned') : t('Unassign')) + $assigned; return $assigned; } /** * Implementation of hook_project_issue_assignees(). * * This hook is used to modify the list of 'Assigned' users when creating or * commenting on an issue. * * @param $assigned * An array of key => value pairs in the format of uid => name that represents * the list of users that the issue may be assigned to. This parameter * is passed by reference so the hook may make changes, such as adding or * removing elements. * @param $node * The node object for the issue. */ function project_issue_project_issue_assignees(&$assigned, $node) { global $user; if ($user->uid) { if (isset($node->project_issue['assigned']) && $user->uid != $node->project_issue['assigned']) { // Assigned to someone else, add the currently assigned user. $account = user_load(array('uid' => $node->project_issue['assigned'])); $assigned[$node->project_issue['assigned']] = $account->name; } // Always let the person replying assign it to themselves. $assigned[$user->uid] = $user->name; } if (user_access('assign and be assigned project issues')) { // All users are included if either anon or auth user has the perm. if (db_result(db_query("SELECT rid FROM {permission} WHERE perm LIKE '%%%s%%' AND rid IN(%d, %d)", 'assign and be assigned project issues', DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { $result = db_query("SELECT uid, name FROM {users}"); } else { $result = db_query("SELECT u.uid, u.name FROM {users} u INNER JOIN {users_roles} ur ON u.uid = ur.uid INNER JOIN {role} r ON ur.rid = r.rid INNER JOIN {permission} p ON p.rid = r.rid WHERE p.perm LIKE '%%%s%%'", 'assign and be assigned project issues'); } while ($assignee = db_fetch_object($result)) { $assigned[$assignee->uid] = $assignee->name; } } } // Support stuff /** * Return information about project issue state values. * * @param $sid * Integer state id to return information about, or 0 for all states. * @param $restrict * Boolean to determine if states should be restricted based on the * permissions of the current user or $account if that parameter * is provided. * @param $is_author * Boolean that indicates if the current user is the author of the * issue, which can potentially grant a wider selection of states. * @param $current_sid * The current integer state id for the issue. * @param $defaults * Boolean to request the states used for default issue queries. * @param $account * Account of a user to pass to user_access() for access checking. * This parameter will have no effect unless $restrict is also * set to TRUE. * * @return * An array of states (sid as key, name as value) that match the * given filters, or the name of the requested state. * NOTE: The state name returned is raw text, and should be filtered via * check_plain() or filter_xss() before being printed as HTML output. */ function project_issue_state($sid = 0, $restrict = false, $is_author = false, $current_sid = 0, $defaults = false, $account = NULL) { static $options; if (!$options) { $result = db_query('SELECT * FROM {project_issue_state} ORDER BY weight'); while ($state = db_fetch_object($result)) { $options[] = $state; } } foreach($options as $state) { if ($restrict) { // Check if user has access, // or if status is default status and therefore available to all, // or if user is original issue author and author has access, // or if the issue is already in a state, even if the user doesn't have // access to that state themselves. if (user_access('set issue status '. str_replace("'", "", $state->name), $account) || user_access('administer projects', $account) || ($state->sid == variable_get('project_issue_default_state', 1)) || ($state->author_has && $is_author) || ($state->sid == $current_sid) ) { $states[$state->sid] = $state->name; } } else if ($defaults) { if ($state->default_query) { $states[$state->sid] = $state->name; } } else { $states[$state->sid] = $state->name; } } return $sid ? $states[$sid] : $states; } /** * Return an array of state ids that should be used for default queries. */ function project_issue_default_states() { static $defaults; if (empty($defaults)) { $states = project_issue_state(0, false, false, 0, true); $defaults = !empty($states) ? array_keys($states) : array(1, 2, 4); } return $defaults; } function project_issue_priority($priority = 0) { $priorities = array(1 => t('critical'), t('normal'), t('minor')); return $priority ? $priorities[$priority] : $priorities; } function project_issue_category($category = 0, $plural = 1) { if ($plural) { $categories = array('bug' => t('bug reports'), 'task' => t('tasks'), 'feature' => t('feature requests'), 'support' => t('support requests')); } else { $categories = array('bug' => t('bug report'), 'task' => t('task'), 'feature' => t('feature request'), 'support' => t('support request')); } return $category ? $categories[$category] : $categories; } function project_issue_count($pid) { $state = array(); $result = db_query('SELECT p.sid, count(p.sid) AS count FROM {node} n INNER JOIN {project_issues} p ON n.nid = p.nid WHERE n.status = 1 AND p.pid = %d GROUP BY p.sid', $pid); while ($data = db_fetch_object($result)) { $state[$data->sid] = $data->count; } return $state; } /** * Return the HTML to use for the links at the top of issue query pages. * * @param $links * Array of links, indexed by the action ('create', 'search', etc). * * @see project_issue_query_result() * @see theme_links() */ function theme_project_issue_query_result_links($links) { return theme('links', $links); } /** * Provide an array of project issue summary fields. * @param $context * The context in which the fields will be displayed. * 'web' for project_issue node and comment summary tables. * 'email' for project_issue notification e-mail messages. */ function project_issue_field_labels($context) { if ($context == 'web') { $labels = array('title' => t('Title')); } else { $labels = array(); } $labels += array( 'pid' => t('Project'), 'rid' => t('Version'), 'component' => t('Component'), 'category' => t('Category'), 'priority' => t('Priority'), 'assigned' => t('Assigned to'), 'sid' => t('Status'), ); if ($context == 'email') { $labels += array( 'name' => t('Reported by'), 'updator' => t('Updated by'), ); } return $labels; } /** * Provide the text displayed to a user for a specific metadata field. * * @param $field * Name of the field. * @param $value * Value of the field. * * @return * Text to display to user. NOTE: This is unfiltered text! If this output is * being sent over the web, you must use check_plain(). */ function project_issue_change_summary($field, $value) { switch ($field) { case 'pid': $project = node_load(array('nid' => $value, 'type' => 'project_project')); return $project->title; case 'category': return $value ? project_issue_category($value, 0) : t(''); case 'priority': return $value ? project_issue_priority($value) : t(''); case 'rid': if ($value) { $release->nid = $value; if (module_exists('project_release')) { $release = project_release_load($release); } else { $release->project_release['version'] = t('Unknown'); } return $release->project_release['version']; } return t(''); case 'assigned': $user = user_load(array('uid' => $value)); return (int) $value === 0 ? variable_get('anonymous', t('Anonymous')) : $user->name; case 'sid': return $value ? project_issue_state($value) : t(''); default: return $value; } } function theme_project_issue_create_forbidden($uri = '') { global $user; if ($user->uid) { return ''; } // We cannot use drupal_get_destination() because these links sometimes appear on /node and taxo listing pages. $destination = "destination=". drupal_urlencode("node/add/project-issue/$uri"); if (variable_get('user_register', 1)) { return t('Login or register to create an issue', array('@login' => url('user/login', array('query' => $destination)), '@register' => url('user/register', array('query' => $destination)))); } else { return t('Login to create an issue', array('@login' => url('user/login', array('query' => $destination)))); } }