Index: comment.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/comment.inc,v retrieving revision 1.140 diff -u -F^f -u -F^f -r1.140 comment.inc --- comment.inc 27 Jan 2009 17:03:58 -0000 1.140 +++ comment.inc 29 Jan 2009 21:22:27 -0000 @@ -78,7 +78,7 @@ function project_issue_comment(&$arg, $o $test->component = $arg->project_info['component']; $test->assigned = $arg->project_info['assigned']; // Add a dummy rid if necessary -- prevents incorrect change data. - $test->rid = $arg->project_info['rid'] ? $arg->project_info['rid'] : 0; + $test->rid = isset($arg->project_info['rid']) ? $arg->project_info['rid'] : 0; $comment_changes = project_issue_metadata_changes($node, $old_data, $test, project_issue_field_labels('web')); $project_issue_table = theme('project_issue_comment_table', $comment_changes); } @@ -92,13 +92,13 @@ function project_issue_comment(&$arg, $o /** * Add project issue metadata to the comment form. - * + * * @param $form * Reference to form structure. * @param $form_state * Current form state. */ -function project_issue_form_comment_form_alter(&$form, &$form_state) { +function _project_issue_form_comment_form_alter(&$form, &$form_state) { $nid = $form['nid']['#value']; $node = node_load($nid); @@ -106,7 +106,7 @@ function project_issue_form_comment_form if ($node->type != 'project_issue') { return; } - + // Add our own custom validation to the comment form for issue nodes. $form['#validate'][] = 'project_issue_form_comment_validate'; @@ -143,6 +143,10 @@ function project_issue_form_comment_form $form['#pre_render'][] = 'project_issue_comment_pre_render'; } + // Make sure project is current here -- it may have changed when posted. + if (!empty($form_state['values']['project_info']['pid'])) { + $node->project_issue['pid'] = $form_state['values']['project_info']['pid']; + } $project = node_load(array('nid' => $node->project_issue['pid'], 'type' => 'project_project')); // We have to set $form['#action'] to prevent AHAH nastiness. @@ -207,7 +211,7 @@ function project_issue_form_comment_form '#weight' => -30, '#required' => TRUE, ); - + $form['project_info']['assigned'] = $form['issue_info']['assigned']; unset($form['issue_info']['assigned']); @@ -231,8 +235,6 @@ function project_issue_form_comment_form $form['attachments']['#collapsed'] = FALSE; $form['attachments']['#weight'] = 2; } - - return $form; } /** @@ -243,13 +245,15 @@ function project_issue_form_comment_form * @param $form_state * The current state of the form. */ -function project_issue_form_comment_validate($form, &$form_state) { - if(isset($form_state['project_issue_ahah'])) { +function project_issue_form_comment_validate($form, &$form_state) { + if(!empty($form_state['rebuild'])) { return; } - $nid = $form_state['values']['nid']; + $values = $form_state['values']; + $project_info = $form_state['values']['project_info']; + $nid = $values['nid']; $node = node_load($nid); - + // Make a copy here so we have all the original metadata, since some // of it can change below. $original_node = drupal_clone($node); @@ -259,27 +263,28 @@ function project_issue_form_comment_vali // Adjust new file attachments to go to the issues directory. // We have to do this during validate, otherwise we might miss // adjusting the filename before comment upload saves it (module weighting) - project_issue_change_comment_upload_path($form_state['values']); - + // TODO: is this still true? + project_issue_change_comment_upload_path($values); + // Only validate metadata changes on new followups. - if (isset($form_state['values']['cid'])) { + if (isset($values['cid'])) { return; } // Make sure project is current here -- it may have changed when posted. - if (isset($form_state['values']['project_info']['pid'])) { - $node->project_issue['pid'] = $form_state['values']['project_info']['pid']; + if (isset($project_info['pid'])) { + $node->project_issue['pid'] = $project_info['pid']; } $project = node_load($node->project_issue['pid']); if (!empty($project) && $project->type == 'project_project') { // Force all comments to be a child of the main issue, to match the // flat display, and also to prevent accidentally deleting a thread. - form_set_value(array('#parents' => array('pid')), 0, $form_state); + $form_state['values']['pid'] = 0; // Validate version. - if (module_exists('project_release') && ($releases = project_release_get_releases($project, 0, 'version', 'all', array($form_state['values']['project_info']['rid'])))) { - $rid = $form_state['values']['project_info']['rid']; + if (module_exists('project_release') && isset($project_info['rid']) && ($releases = project_release_get_releases($project, 0, 'version', 'all', array($project_info['rid'])))) { + $rid = $project_info['rid']; if ($rid && !in_array($rid, array_keys($releases))) { $rid = 0; } @@ -295,8 +300,12 @@ function project_issue_form_comment_vali form_set_error('project_info][rid', t('You have to specify a valid version.')); } } + // Add a dummy rid if necessary -- prevents incorrect change data. + else { + $rid = 0; + } // Validate component. - $component = $form_state['values']['project_info']['component']; + $component = $project_info['component']; if ($component && !in_array($component, $project->project_issue['components'])) { $component = 0; } @@ -305,26 +314,31 @@ function project_issue_form_comment_vali else { form_set_error('project_info][pid', t('You have to specify a valid project.')); } - empty($form_state['values']['category']) && form_set_error('category', t('You have to specify a valid category.')); + empty($values['category']) && form_set_error('category', t('You have to specify a valid category.')); // Now, make sure the comment changes *something* about the issue. - // If the user uploaded a file, so long as it's not marked for removal, + // If the user uploaded a file, so long as it's not marked for removal, // we consider that a valid change to the issue, too. $has_file = FALSE; - $files = isset($form_state['values']['files']) ? $form_state['values']['files'] : array(); + $files = isset($values['files']) ? $values['files'] : array(); foreach ($files as $number => $data) { if (empty($data['remove'])) { $has_file = TRUE; break; } } - if (!$has_file && empty($form_state['values']['comment'])) { - $comment = drupal_clone((object)$form_state['values']); - $comment->pid = $form_state['values']['project_info']['pid']; - $comment->component = $form_state['values']['project_info']['component']; - // Add a dummy rid if necessary -- prevents incorrect change data. - $comment->rid = $form_state['values']['project_info']['rid'] ? $form_state['values']['project_info']['rid'] : 0; + if (!$has_file && empty($values['comment'])) { + + $comment = drupal_clone((object) $values); + $comment->pid = $project_info['pid']; + $comment->component = $component; + $comment->rid = $rid; + $comment->assigned = $project_info['assigned']; $comment_changes = project_issue_metadata_changes($node, $old_data, $comment, project_issue_field_labels('web')); + // If the PID changed, rebuild the form + if (isset($comment_changes['pid']['new']) && $comment_changes['pid']['new'] === TRUE) { + $form_state['rebuild'] = TRUE; + } $has_change = FALSE; foreach ($comment_changes as $field => $changes) { if (isset($changes['new'])) { @@ -333,7 +347,7 @@ function project_issue_form_comment_vali } } if (!$has_change) { - form_set_error('comment', t('You must either add a comment or change something about this issue.')); + form_set_error('comment', t('You must either add a comment, upload a file, or change something about this issue.')); } } } @@ -444,7 +458,7 @@ function project_issue_comment_view(&$no if (isset($comment)) { return isset($project_issue_tables[$comment->cid]) ? $project_issue_tables[$comment->cid] : ''; } - if ($node->comment_count) { + if (!empty($node->comment_count)) { $old = unserialize(db_result(db_query('SELECT original_issue_data FROM {project_issues} WHERE nid = %d', $node->nid))); $labels = project_issue_field_labels('web'); $result = db_query('SELECT p.cid, p.title, p.pid, p.rid, p.component, p.category, p.priority, p.assigned, p.sid FROM {project_issue_comments} p INNER JOIN {comments} c ON p.cid = c.cid WHERE p.nid = %d AND c.status = %d ORDER BY p.timestamp ASC', $node->nid, COMMENT_PUBLISHED); @@ -573,7 +587,7 @@ function project_issue_comment_pre_rende // after the comment form on preview, in the case where the comment // parent is 0. If we want our issue previews to be consistent, this // ugly hack is necessary. - if ($_POST['op'] == t('Preview comment')) { + if (isset($_POST['op']) && $_POST['op'] == t('Preview comment')) { $preview = comment_render($node, 0); } else { Index: issue.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/issue.inc,v retrieving revision 1.334 diff -u -F^f -u -F^f -r1.334 issue.inc --- issue.inc 28 Jan 2009 23:43:10 -0000 1.334 +++ issue.inc 29 Jan 2009 21:22:27 -0000 @@ -14,18 +14,16 @@ function project_issue_update_project() $form_id = array_shift($args); $form_state['post'] = $form['#post'] = $_POST; $form['#programmed'] = $form['#redirect'] = FALSE; - - // Skip validation in project issue. - $form_state['project_issue_ahah'] = TRUE; + 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 = $form_state['values']['project_info']['rid']; + $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']; @@ -33,7 +31,7 @@ function project_issue_update_project() // 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)); @@ -443,17 +441,25 @@ function project_issue_pick_project_form function project_issue_form($node, $form_state, $include_metadata_fields = FALSE) { global $user; + $defaults = array( + 'rid', + 'component', + 'category', + 'priority', + 'assigned', + 'sid', + ); + + // Set some defaults for new forms. + if (!isset($node->nid)) { + foreach ($defaults as $default) { + $node->project_issue[$default] = 0; + } + } + // In the case of an issue preview, get our defaults from the submitted form. // TODO: do we want to #tree our form so we don't need this hack? if (isset($form_state['node'])) { - $defaults = array( - 'rid', - 'component', - 'category', - 'priority', - 'assigned', - 'sid', - ); foreach ($defaults as $default) { if (isset($form_state['node'][$default])) { $node->project_issue[$default] = $form_state['node'][$default]; @@ -512,7 +518,7 @@ function project_issue_form($node, $form if (empty($pid)) { drupal_set_message(t('Invalid project selected.'), 'error'); - return drupal_goto('node/add/project-issue'); + drupal_goto('node/add/project-issue'); } // If this issue has already been created and is just being @@ -530,10 +536,10 @@ function project_issue_form($node, $form if ($project->type != 'project_project') { drupal_set_message(t('Invalid project selected.'), 'error'); // Not sure the best place to go here... - return drupal_goto('node/add/project-issue'); + drupal_goto('node/add/project-issue'); } if ($allow_metadata_changes) { - if (module_exists('project_release') && + if (module_exists('project_release') && isset($node->project_issue['rid']) && $releases = project_release_get_releases($project, 0, 'version', 'all', array($node->project_issue['rid']))) { $releases = array(t('')) + $releases; } @@ -551,7 +557,7 @@ function project_issue_form($node, $form } $categories = array_merge(array(t('')), project_issue_category(0, 0)); $priorities = project_issue_priority(); - $states = project_issue_state(0, true, $node->nid && ($node->uid == $user->uid), $node->project_issue['sid']); + $states = project_issue_state(0, TRUE, !empty($node->nid) && ($node->uid == $user->uid), $node->project_issue['sid']); $assigned = project_issue_assigned_choices($node); } Index: mail.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/mail.inc,v retrieving revision 1.117 diff -u -F^f -u -F^f -r1.117 mail.inc --- mail.inc 26 Jan 2009 15:53:40 -0000 1.117 +++ mail.inc 29 Jan 2009 21:22:27 -0000 @@ -182,6 +182,20 @@ function project_mail_notify($nid) { $node = node_load($nid, NULL, TRUE); $project = node_load(array('nid' => $node->project_issue['pid'], 'type' => 'project_project')); + // Store a copy of the issue, so we can load the original issue values + // below. + $issue = drupal_clone($node); + + // Load in the original issue data here, since we want a running + // reverse history. + $original_issue_data = unserialize($node->project_issue['original_issue_data']); + $fields = project_issue_field_labels('email'); + foreach ($fields as $field => $label) { + if ($field != 'name' && $field != 'updator') { + $issue->original_issue_metadata->$field = $original_issue_data->$field; + } + } + // Record users that are connected to this issue. $uids = array(); if (!empty($node->uid)) { @@ -236,7 +250,7 @@ function project_mail_notify($nid) { $params['node'] = $node; $params['project'] = $project; $params['history'] = $history; - + $sender->name = t('!name (!site)', array('!name' => $user->name, '!site' => variable_get('site_name', 'Drupal'))); $sender->mail = strtr(variable_get('project_issue_reply_to', variable_get('site_mail', ini_get('sendmail_from'))), array('%project' => $project->project['uri'])); // The sender name is enclosed by double quotes below @@ -244,20 +258,24 @@ function project_mail_notify($nid) { // which requires double quotes when special characters (including // some punctuation) are used. See example in Appendix A.1.2. $from = "\"$sender->name\" <$sender->mail>"; - + while ($recipient = db_fetch_object($result)) { // To save work, only go through a user_load if we need it. if ($check_file_perms || $check_node_access) { $account = user_load(array('uid' => $recipient->uid)); + $language = user_preferred_language($account); + } + else { + $language = language_default(); } - + $can_access = $check_node_access ? node_access('view', $node, $account) : TRUE; - + if ($can_access) { $display_files = $check_file_perms ? user_access('view uploaded files', $account) : TRUE; $params['display_files'] = $display_files; - drupal_mail('project_issue', 'project_issue_update_notification', $recipient->mail, user_preferred_language($account), $params, $from); + drupal_mail('project_issue', 'project_issue_update_notification', $recipient->mail, $language, $params, $from); } } @@ -288,26 +306,13 @@ function project_issue_mail($key, &$mess // There could be stale data in the cached node, so reset the cache. $node = $params['node']; $project = $params['project']; - $history = $params['history']; + $history = $params['history']; $fields = project_issue_field_labels('email'); - // Store a copy of the issue, so we can load the original issue values - // below. - $issue = drupal_clone($node); - - // Load in the original issue data here, since we want a running - // reverse history. - $original_issue_data = unserialize($node->project_issue['original_issue_data']); - foreach ($fields as $field => $label) { - if ($field != 'name' && $field != 'updator') { - $issue->project_issue[$field] = $original_issue_data->$field; - } - } - $domain = preg_replace('|.+://([a-zA-Z0-9\._-]+).*|', '\1', $base_url); - - $message['headers'] += array( - 'Date' => date('r'), + + $message['headers'] += array( + 'Date' => date('r'), 'X-Mailer' => 'Drupal Project module (http://drupal.org/project/project)', 'List-Id' => "$project->title <". $project->project['uri'] ."-issues-$domain>", 'List-Archive' => '<'. url('project/issues/'. $project->project['uri'], array('absolute' => TRUE)) .'>', @@ -322,7 +327,7 @@ function project_issue_mail($key, &$mess // message headers. Instead of issuing another query, just keep track // of them here. $previous_cid = isset($cid) ? $cid : ''; - $cid = $comment->cid; + $cid = isset($comment->cid) ? $comment->cid : 0; } $message['headers']['Message-Id'] = "nid&cid=$cid&host=@$domain>"; $message['headers']['In-Reply-To'] = "nid&host=@$domain>"; @@ -373,22 +378,31 @@ function project_mail_generate_followup_ } } - $fields = project_issue_field_labels('email'); - // Get most recent update. $entry = array_pop($history); + $node->project_issue['updator'] = $entry->name ? $entry->name : $user->name; // Check if the latest entry is actually the initial issue. if (empty($history)) { + $metadata_previous = new stdClass(); + // Have to get the metadata into the entry object. + $metadata_entry = $entry->original_issue_metadata; $content = $entry->body; } else { - $previous = end($history); + $metadata_previous = end($history); + // If the previous was the original issue, then we need to pull + // out the metadata from project_issue. + if (isset($metadata_previous->original_issue_metadata)) { + $metadata_previous = $metadata_previous->original_issue_metadata; + } + $metadata_entry = $entry; $content = $entry->comment; } - $comment_changes = project_issue_metadata_changes($node, $previous, $entry, $fields); + $fields = project_issue_field_labels('email'); + $comment_changes = project_issue_metadata_changes($node, $metadata_previous, $metadata_entry, $fields); // Since $node->name will always be the original issue author, and since // $node->project_issue['updator'] isn't a property of either $previous or @@ -558,6 +572,9 @@ function project_mail_format_attachments $output = ''; if ($display_files && is_array($entry->files)) { foreach ($entry->files as $file) { + // Comment upload has it's files in an array, so cast to an object + // for consistency. + $file = (object) $file; $output .= ' '. str_pad(t('Attachment') .':', 14) . file_create_url($file->filepath) .' ('. format_size($file->filesize) .")\n"; } } @@ -597,8 +614,9 @@ function project_mail_format_entry($entr $output .= project_mail_format_attachments($entry, $display_files); - // Must distinguish between nodes and comments. - if (!$entry->vid) { + // Must distinguish between nodes and comments -- here we do it + // by looking for a revision ID. + if (empty($entry->vid)) { $content = $entry->comment; } else { Index: project_issue.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.module,v retrieving revision 1.116 diff -u -F^f -u -F^f -r1.116 project_issue.module --- project_issue.module 28 Jan 2009 23:43:10 -0000 1.116 +++ project_issue.module 29 Jan 2009 21:22:27 -0000 @@ -334,9 +334,16 @@ function project_issue_form_alter(&$form } break; + case 'comment_form': + // Using a form-specific hook here causes some of the altering + // code to be run before we have all the form elements we need. + // So here we break out this code into a separate function for + // clarity but leave it in the general hook_form_alter(). + _project_issue_form_comment_form_alter($form, $form_state); + break; + case 'comment_confirm_delete': - $comment = $form['comment']['#value']; - $type = db_result(db_query("SELECT type FROM {node} WHERE nid = %d", $comment->nid)); + $type = db_result(db_query("SELECT type FROM {node} WHERE nid = %d", $form['#comment']->nid)); if (!empty($type) && $type == 'project_issue') { $form['description']['#value'] = t('This action cannot be undone.'); } @@ -1368,7 +1375,7 @@ function project_issue_metadata_changes( elseif (isset($old_data->$property)) { $changes[$property]['old'] = $old_data->$property; } - else { + elseif (isset($new_data->$property)) { $changes[$property]['new'] = $new_data->$property; } }