nid); $comments_per_page = variable_get('comment_default_per_page', '50'); $result = pager_query($query, $comments_per_page, 0, $query_count, $query_args); $i = 1; while ($comment = db_fetch_object($result)) { $comment = drupal_unpack($comment); $comment->subject = 'Reply #'. $i; $comment->name = $comment->uid ? $comment->registered_name : $comment->name; $output .= theme('comment_view', $comment, array()); $i++; } $output .= theme('pager', NULL, $comments_per_page); return $output; } /** * Submit function for issue replies (form: 'comment_form') */ function issue_tracker_comment_submit($form, &$form_state) { $values = $form_state['values']; if ($values['form_id'] == 'comment_form') { $node = node_load($form_state['values']['nid']); if (user_access('edit issue')) { $vid = _issue_tracker_get_issue_vocabulary_id(); // Add special tags (status, assigned) if ($values['resolution'] != '-') { $values['issuestatus'] = 'status::closed'; } if ($values['taxonomy']['tags'][$vid] == '') { $values['taxonomy']['tags'][$vid] = $values['issuestatus']; } else { $values['taxonomy']['tags'][$vid] .= ', '. $values['issuestatus']; } if ($values['assignedto'] != '-') { $values['taxonomy']['tags'][$vid] .= ', '. $values['assignedto']; } if ($values['resolution'] != '-') { $values['taxonomy']['tags'][$vid] .= ', '. $values['resolution']; } if ($values['subscription'] != '') { $values['taxonomy']['tags'][$vid] .= ', '. $values['subscription']; } //check previous tags $terms = $node->taxonomy; $issuestatus = ''; $assignedto = '-'; $resolution = '-'; $old_terms = array(); $c = db_query(db_rewrite_sql("SELECT v.* FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $node->type); while ($vocabulary = db_fetch_object($c)) { if ($vocabulary->tags) { foreach ($terms as $term) { // Extract terms belonging to the vocabulary in question. if ($term->vid == $vocabulary->vid) { // Commas and quotes in terms are special cases, so encode 'em. if (strpos($term->name, ',') !== FALSE || strpos($term->name, '"') !== FALSE) { $term->name = '"'. str_replace('"', '""', $term->name) .'"'; } if ($vocabulary->name == 'Issue Tags') { if ($term->name == 'status::open') { $issuestatus = $term->name; } elseif ($term->name == 'status::closed') { $issuestatus = $term->name; } elseif (strpos($term->name, 'assigned::') !== FALSE) { $assignedto = $term->name; } elseif (strpos($term->name, 'resolution::') !== FALSE) { $resolution = $term->name; } else { $old_terms[] = $term->name; } } } } } } // add changed tags to comment $comment = ''; if ($values['issuestatus'] != $issuestatus) { if ($values['issuestatus'] == 'status::open') { $comment .= '--- Issue status set to: open ---'."\n\n"; } elseif ($values['issuestatus'] == 'status::closed') { $comment .= '--- Issue status set to: closed ---'."\n\n"; } } if ($values['assignedto'] != $assignedto) { if ($values['assignedto'] == '-') { $comment .= '--- Issue assignment removed ---'."\n\n"; } else { $comment .= '--- Issue assigned to: '. substr($form_state['values']['assignedto'], 10) .' ---'."\n\n"; } } if ($values['resolution'] != $resolution) { if ($values['resolution'] == '-') { $comment .= '--- Issue resolution removed ---'."\n\n"; } else { $comment .= '--- Issue resolution set to: '. substr($form_state['values']['resolution'], 12) .' ---'."\n\n"; } } $issue_query = db_query("SELECT issue_id FROM {issues} WHERE nid = %d", $node->nid); $issue = db_fetch_object($issue_query); $issue_data = origo_auth_xmlrpc_session(variable_get('origo_api_internal', ''), 'internal_issue.retrieve_planning_data', (int)variable_get('origo_project_id', 0), (int)$issue->issue_id); if ($values['deadline'] != '') { $deadline = $values['deadline']; $deadline_timestamp = gmmktime(0, 0, 0, $deadline['month'], $deadline['day'], $deadline['year']); if ($deadline_timestamp != $issue_data['deadline']) { $comment .= '--- Issue deadline set to: '. gmdate('Y-m-d', $deadline_timestamp) .' ---'."\n\n"; } } if (($values['work_amount'] != '') && ($values['work_amount'] != $issue_data['work_amount'])) { if ($values['work_amount'] == 0) { $comment .= '--- Issue work amount removed ---'."\n\n"; } else { $comment .= '--- Issue work amount set to: '. $form_state['values']['work_amount'] . format_plural($form_state['values']['work_amount'], ' day', ' days') .' ---'."\n\n"; } } if (!empty($comment)) { // Prepend comment annotations $form_state['values']['comment'] = $comment . $form_state['values']['comment']; // Also prepend to diff, if any if (isset($values['diff'])) { $form_state['values']['diff'] = $comment . $form_state['values']['diff']; } } taxonomy_node_save($node, $values['taxonomy']); } //update timestamp of corresponding issue $node_query = 'UPDATE {node} SET changed = %d WHERE nid = %d'; db_query($node_query, time(), $values['nid']); } } /** * Update the comment in the backend */ function comment_form_post_submit($form, &$form_state) { if (isset($form_state['values']['diff'])) { // A diff was provided, i.e. the comment was edited $comment = $form_state['values']['diff']; } else { // new comment $comment = $form_state['values']['comment']; } //add issue reply to origo if the call is coming from the web frontend if (!isset($form_state['storage'][ISSUE_TRACKER_STORAGE_COMMENT_SOURCE]) || $form_state['storage'][ISSUE_TRACKER_STORAGE_COMMENT_SOURCE] != 'api') { $node = node_load($form_state['values']['nid']); $issue_query = db_query("SELECT issue_id FROM {issues} WHERE nid = %d", $node->nid); $issue = db_fetch_object($issue_query); if (user_access('edit issue')) { // use taxonomy directly from the node, the values of the the form ($form_state['values']) // are sanatized and do *not* contain special tags, e.g. the status tag! // bherlig, 2009-12-29 // Thus we add them manually, directly from the form-fields. $tags = $form_state['values']['taxonomy']['tags'][_issue_tracker_get_issue_vocabulary_id()]; // add special tags if ($tags != '') { $tags .= ','; } $tags .= $form_state['values']['issuestatus']; if ($form_state['values']['assignedto'] != '-') { $tags .= ','. $form_state['values']['assignedto']; } if ($form_state['values']['resolution'] != '-') { $tags .= ','. $form_state['values']['resolution']; } $deadline = $form_state['values']['deadline']; $deadline_timestamp = gmmktime(0, 0, 0, $deadline['month'], $deadline['day'], $deadline['year']); $work_amount = $form_state['values']['work_amount']; origo_auth_xmlrpc_session(variable_get('origo_api_internal', ''), 'internal_issue.comment_extended_2', (int)variable_get('origo_project_id', 0), (int)$issue->issue_id, $comment, $tags, $deadline_timestamp, (int)$work_amount); } elseif ($GLOBALS['user']->uid > 0) { // only logged in users can create issue replies // use existing tags (the tags from the previous revision are taken) origo_auth_xmlrpc_session(variable_get('origo_api_internal', ''), 'internal_issue.comment', (int)variable_get('origo_project_id', 0), (int)$issue->issue_id, $comment); } } } /** * Implementation of hook_form_alter(). */ function issue_tracker_form_comment_form_alter(&$form, &$form_state) { // determine nid depending on if we already have a form state or not if (isset($form_state['values'])) { $nid = $form_state['values']['nid']; } else { $nid = $form['nid']['#value']; } $node = node_load($nid); if ($node->type == 'issue') { // add form submit handler $form['#submit'] = array(); $form['#submit'][] = 'issue_tracker_comment_submit'; // ugly hack $form['#submit'][] = 'comment_form_submit'; // provided by drupal - creates comment node $form['#submit'][] = 'comment_form_post_submit'; // simulate "post submit" hook // hide subject $form['subject']['#type'] = 'hidden'; $form['subject']['#default_value'] = 'Issue Reply'; //reorder form elements $form['_author']['#weight'] = -5; $form['comment_filter']['#weight'] = 7; if (user_access('edit issue')) { // include JavaScript for the "take" button global $user; drupal_add_js('var drupal_username = "'. $user->name .'";', 'inline'); drupal_add_js(drupal_get_path('module', 'issue_tracker') .'/js/edit_issue.js'); $form['comment_filter']['comment']['#required'] = FALSE; $issuestatus_default = 'status::open'; $assignedto_default = '-'; $resolution_default = '-'; // Taxonomy // Note: Currently there's only one vocabulary associated with Issues: "Issue Tags". // Thus the foreach-loop below will - for the moment - only be executed once. This // could change, though, in the unlikely event that we well use more than one vocab-term for issues. $terms = $node->taxonomy; $all_vocab = taxonomy_get_vocabularies($node->type); foreach ($all_vocab as $vocabulary) { if ($vocabulary->tags) { $typed_terms = array(); $subscription_tags = array(); foreach ($terms as $term) { // Extract terms belonging to the vocabulary in question. if ($term->vid == $vocabulary->vid) { // Commas and quotes in terms are special cases, so encode 'em. if (strpos($term->name, ',') !== FALSE || strpos($term->name, '"') !== FALSE) { $term->name = '"'. str_replace('"', '""', $term->name) .'"'; } if ($vocabulary->name == 'Issue Tags') { if ($term->name == 'status::open') { $issuestatus_default = $term->name; } elseif ($term->name == 'status::closed') { $issuestatus_default = $term->name; } elseif (strpos($term->name, 'assigned::') !== FALSE) { $assignedto_default = $term->name; } elseif (strpos($term->name, 'resolution::') !== FALSE) { $resolution_default = $term->name; } elseif (strpos($term->name, 'subscribed::') !== FALSE) { $subscription_tags[] = $term->name; } else { $typed_terms[] = $term->name; } } else { $typed_terms[] = $term->name; } } } $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL); if ($vocabulary->help) { $help = $vocabulary->help; } else { $help = t('A comma-separated list of terms describing this issue. Example: milestone1, frontend, "Company, Inc.".'); } $form['taxonomy']['tags'][$vocabulary->vid] = array('#type' => 'textfield', '#title' => $vocabulary->name, '#description' => $help, '#required' => $vocabulary->required, '#default_value' => $typed_string, '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid, '#weight' => $vocabulary->weight, '#maxlength' => 255, ); $form['subscription'] = array( '#type' => 'hidden', '#value' => implode(', ', $subscription_tags) ); } else { // Extract terms belonging to the vocabulary in question. $default_terms = array(); foreach ($terms as $term) { if ($term->vid == $vocabulary->vid) { $default_terms[$term->tid] = $term; } } $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help); $form['taxonomy'][$vocabulary->vid]['#weight'] = $vocabulary->weight; $form['taxonomy'][$vocabulary->vid]['#required'] = $vocabulary->required; } } if (is_array($form['taxonomy']) && !empty($form['taxonomy'])) { if (count($form['taxonomy']) > 1) { // Add fieldset only if form has more than 1 element. $form['taxonomy'] += array( '#type' => 'fieldset', '#title' => t('Categories'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); } $form['taxonomy']['#weight'] = 1; $form['taxonomy']['#tree'] = TRUE; } // Issue Status $form['issuestatus'] = array( '#prefix' => "
", '#type' => 'select', '#title' => t('Status'), '#options' => array('status::open' => t('Open'), 'status::closed' => t('Closed')), '#weight' => 2, '#default_value' => $issuestatus_default, ); $form['assignedto'] = array( '#type' => 'select', '#title' => t('Assigned to'), '#options' => array(), '#weight' => 3, '#default_value' => $assignedto_default, ); $form['resolution'] = array( '#type' => 'select', '#title' => t('Resolution'), '#options' => array( '-' => t('-'), 'resolution::fixed' => t('Fixed'), 'resolution::wontfix' => t('Won\'t fix'), 'resolution::duplicate' => t('Duplicate'), 'resolution::worksforme' => t('Works for me') ), '#weight' => 4, '#default_value' => $resolution_default, ); // set the default deadline to one week after today, 604800 = 7 * 24 * 60 * 60 $default_deadline = gmgetdate(time() + 604800); $default_work_amount = 0; if ($nid != '') { $issue_query = db_query("SELECT issue_id FROM {issues} WHERE nid = %d", $nid); $issue = db_fetch_object($issue_query); $default_work_amount = $issue_data['work_amount']; } $form['deadline'] = array( '#type' => 'date', '#title' => t('Deadline'), '#description' => t('The date until the issue should be fixed'), '#default_value' => array('year' => $default_deadline['year'], 'month' => $default_deadline['mon'], 'day' => $default_deadline['mday']), '#weight' => 5, ); $work_amount_options = array(0 => '-'); for ($i = 1; $i <= 14; $i++) $work_amount_options[$i] = $i; $form['work_amount'] = array( '#type' => 'select', '#title' => t('Work amount'), '#options' => $work_amount_options, '#default_value' => $default_work_amount, '#description' => t('Estimated number of days needed to fix the issue'), '#weight' => 6, '#suffix' => "
", // end 'issue-edit' ); } // if we submit this form programmatically, don't query the backend as we are already comming from the backend if (!isset($form_state['storage'][ISSUE_TRACKER_STORAGE_COMMENT_SOURCE]) || $form_state['storage'][ISSUE_TRACKER_STORAGE_COMMENT_SOURCE] != 'api') { // Assigned to: $members1 = origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'project.members', variable_get('origo_project_id', 0), 3); $members2 = origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'project.members', variable_get('origo_project_id', 0), 4); $members = array_merge($members1, $members2); $users = array('-' => t('-')); foreach ($members as $member) { $users['assigned::'. $member['name']] = t($member['name']); } asort($users); $form['assignedto']['#options'] = $users; // deadline $issue_data = origo_auth_xmlrpc_session(variable_get('origo_api_internal', ''), 'internal_issue.retrieve_planning_data', (int)variable_get('origo_project_id', 0), (int)$issue->issue_id); // get deadline from backend, if existing if ($issue_data['deadline'] != 0) { $default_deadline = gmgetdate($issue_data['deadline']); $default_work_amount = $issue_data['work_amount']; $form['deadline']['#default_value'] = array('year' => $default_deadline['year'], 'month' => $default_deadline['mon'], 'day' => $default_deadline['mday']); $form['work_amount']['#default_value'] = $default_work_amount; } } else { // we have to allow the the given value on the assigned box $form['assignedto']['#options'] = array($form_state['values']['assignedto'] => $form_state['values']['assignedto']); } } }