} # has tag attach access ?> <!-- spacer --> <tr class="spacer"> <td colspan="6"></td> </tr> <!-- Custom Fields --> <?php $t_custom_fields_found = false; $t_related_custom_field_ids = custom_field_get_linked_ids($t_bug->project_id); foreach ($t_related_custom_field_ids as $t_id) { if (!custom_field_has_read_access($t_id, $f_bug_id)) { continue; } # has read access $t_custom_fields_found = true; $t_def = custom_field_get_definition($t_id); ?> <tr <?php echo helper_alternate_class(); ?> > <td class="category"> <?php echo string_display(lang_get_defaulted($t_def['name'])); ?> </td>
/** * Get the custom field values associated with the specified issue id. * * @param integer $p_issue_id Issue id to get the custom field values for. * * @return null if no custom field defined for the project that contains the issue, or if no custom * fields are accessible to the current user. */ function mci_issue_get_custom_fields($p_issue_id) { $t_project_id = bug_get_field($p_issue_id, 'project_id'); $t_custom_fields = array(); $t_related_custom_field_ids = custom_field_get_linked_ids($t_project_id); foreach ($t_related_custom_field_ids as $t_id) { $t_def = custom_field_get_definition($t_id); if (custom_field_has_read_access($t_id, $p_issue_id)) { # user has not access to read this custom field. $t_value = custom_field_get_value($t_id, $p_issue_id); if ($t_value === false) { continue; } # return a blank string if the custom field value is undefined if ($t_value === null) { $t_value = ''; } $t_custom_field_value = array(); $t_custom_field_value['field'] = array(); $t_custom_field_value['field']['id'] = $t_id; $t_custom_field_value['field']['name'] = $t_def['name']; $t_custom_field_value['value'] = $t_value; $t_custom_fields[] = $t_custom_field_value; } } return count($t_custom_fields) == 0 ? null : $t_custom_fields; }
/** * Gets the next accessible history event for current user and specified db result. * @param string $p_result The database result. * @param integer $p_user_id The user id or null for logged in user. * @param boolean $p_check_access_to_issue true: check that user has access to bugs, * false otherwise. * @return array containing the history event or false if no more matches. */ function history_get_event_from_row($p_result, $p_user_id = null, $p_check_access_to_issue = true) { static $s_bug_visible = array(); $t_user_id = null === $p_user_id ? auth_get_current_user_id() : $p_user_id; $t_project_id = helper_get_current_project(); while ($t_row = db_fetch_array($p_result)) { extract($t_row, EXTR_PREFIX_ALL, 'v'); # Make sure the entry belongs to current project. if ($t_project_id != ALL_PROJECTS && $t_project_id != bug_get_field($v_bug_id, 'project_id')) { continue; } if ($p_check_access_to_issue) { if (!isset($s_bug_visible[$v_bug_id])) { $s_bug_visible[$v_bug_id] = access_has_bug_level(VIEWER, $v_bug_id); } if (!$s_bug_visible[$v_bug_id]) { continue; } } if ($v_type == NORMAL_TYPE) { if (!in_array($v_field_name, columns_get_standard())) { # check that the item should be visible to the user $t_field_id = custom_field_get_id_from_name($v_field_name); if (false !== $t_field_id && !custom_field_has_read_access($t_field_id, $v_bug_id, $t_user_id)) { continue; } } if ($v_field_name == 'target_version' && !access_has_bug_level(config_get('roadmap_view_threshold'), $v_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'due_date' && !access_has_bug_level(config_get('due_date_view_threshold'), $v_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'handler_id' && !access_has_bug_level(config_get('view_handler_threshold'), $v_bug_id, $t_user_id)) { continue; } } # bugnotes if ($t_user_id != $v_user_id) { # bypass if user originated note if ($v_type == BUGNOTE_ADDED || $v_type == BUGNOTE_UPDATED || $v_type == BUGNOTE_DELETED) { if (!access_has_bug_level(config_get('private_bugnote_threshold'), $v_bug_id, $t_user_id) && bugnote_get_field($v_old_value, 'view_state') == VS_PRIVATE) { continue; } } if ($v_type == BUGNOTE_STATE_CHANGED) { if (!access_has_bug_level(config_get('private_bugnote_threshold'), $v_bug_id, $t_user_id) && bugnote_get_field($v_new_value, 'view_state') == VS_PRIVATE) { continue; } } } # tags if ($v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED) { if (!access_has_bug_level(config_get('tag_view_threshold'), $v_bug_id, $t_user_id)) { continue; } } # attachments if ($v_type == FILE_ADDED || $v_type == FILE_DELETED) { if (!access_has_bug_level(config_get('view_attachments_threshold'), $v_bug_id, $t_user_id)) { continue; } } # monitoring if ($v_type == BUG_MONITOR || $v_type == BUG_UNMONITOR) { if (!access_has_bug_level(config_get('show_monitor_list_threshold'), $v_bug_id, $t_user_id)) { continue; } } # relationships if ($v_type == BUG_ADD_RELATIONSHIP || $v_type == BUG_DEL_RELATIONSHIP || $v_type == BUG_REPLACE_RELATIONSHIP) { $t_related_bug_id = $v_new_value; # If bug doesn't exist, then we don't know whether to expose it or not based on the fact whether it was # accessible to user or not. This also simplifies client code that is accessing the history log. if (!bug_exists($t_related_bug_id) || !access_has_bug_level(config_get('view_bug_threshold'), $t_related_bug_id, $t_user_id)) { continue; } } $t_event = array(); $t_event['bug_id'] = $v_bug_id; $t_event['date'] = $v_date_modified; $t_event['userid'] = $v_user_id; # user_get_name handles deleted users, and username vs realname $t_event['username'] = user_get_name($v_user_id); $t_event['field'] = $v_field_name; $t_event['type'] = $v_type; $t_event['old_value'] = $v_old_value; $t_event['new_value'] = $v_new_value; return $t_event; } return false; }
/** * Retrieves the raw history events for the specified bug id and returns it in an array * The array is indexed from 0 to N-1. The second dimension is: 'date', 'userid', 'username', * 'field','type','old_value','new_value' * @param int $p_bug_id * @param int $p_user_id * @return array */ function history_get_raw_events_array($p_bug_id, $p_user_id = null) { $t_mantis_bug_history_table = db_get_table('mantis_bug_history_table'); $t_mantis_user_table = db_get_table('mantis_user_table'); $t_history_order = config_get('history_order'); $c_bug_id = db_prepare_int($p_bug_id); $t_user_id = null === $p_user_id ? auth_get_current_user_id() : $p_user_id; $t_roadmap_view_access_level = config_get('roadmap_view_threshold'); $t_due_date_view_threshold = config_get('due_date_view_threshold'); # grab history and display by date_modified then field_name # @@@ by MASC I guess it's better by id then by field_name. When we have more history lines with the same # date, it's better to respect the storing order otherwise we should risk to mix different information # I give you an example. We create a child of a bug with different custom fields. In the history of the child # bug we will find the line related to the relationship mixed with the custom fields (the history is creted # for the new bug with the same timestamp...) $query = "SELECT *\n\t\t\t\tFROM {$t_mantis_bug_history_table}\n\t\t\t\tWHERE bug_id=" . db_param() . "\n\t\t\t\tORDER BY date_modified {$t_history_order},id"; $result = db_query_bound($query, array($c_bug_id)); $raw_history_count = db_num_rows($result); $raw_history = array(); $t_private_bugnote_threshold = config_get('private_bugnote_threshold'); $t_private_bugnote_visible = access_has_bug_level(config_get('private_bugnote_threshold'), $p_bug_id, $t_user_id); $t_tag_view_threshold = config_get('tag_view_threshold'); $t_view_attachments_threshold = config_get('view_attachments_threshold'); $t_show_monitor_list_threshold = config_get('show_monitor_list_threshold'); $t_show_handler_threshold = config_get('view_handler_threshold'); $t_standard_fields = columns_get_standard(); for ($i = 0, $j = 0; $i < $raw_history_count; ++$i) { $t_row = db_fetch_array($result); $v_type = $t_row['type']; $v_field_name = $t_row['field_name']; $v_user_id = $t_row['user_id']; $v_new_value = $t_row['new_value']; $v_old_value = $t_row['old_value']; $v_date_modified = $t_row['date_modified']; if ($v_type == NORMAL_TYPE) { if (!in_array($v_field_name, $t_standard_fields)) { # check that the item should be visible to the user # We are passing 32 here to notify the custom field API # that legacy history entries for field names longer than # 32 chars created when the db column was of that size were # truncated (no longer the case since 1.1.0a4, see #8002) $t_field_id = custom_field_get_id_from_name($v_field_name, 32); if (false !== $t_field_id && !custom_field_has_read_access($t_field_id, $p_bug_id, $t_user_id)) { continue; } } if ($v_field_name == 'target_version' && !access_has_bug_level($t_roadmap_view_access_level, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'due_date' && !access_has_bug_level($t_due_date_view_threshold, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'handler_id' && !access_has_bug_level($t_show_handler_threshold, $p_bug_id, $t_user_id)) { continue; } } // bugnotes if ($t_user_id != $v_user_id) { // bypass if user originated note if ($v_type == BUGNOTE_ADDED || $v_type == BUGNOTE_UPDATED || $v_type == BUGNOTE_DELETED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_old_value, 'view_state') == VS_PRIVATE) { continue; } } if ($v_type == BUGNOTE_STATE_CHANGED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_new_value, 'view_state') == VS_PRIVATE) { continue; } } } // tags if ($v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED) { if (!access_has_bug_level($t_tag_view_threshold, $p_bug_id, $t_user_id)) { continue; } } # attachments if ($v_type == FILE_ADDED || $v_type == FILE_DELETED) { if (!access_has_bug_level($t_view_attachments_threshold, $p_bug_id, $t_user_id)) { continue; } } // monitoring if ($v_type == BUG_MONITOR || $v_type == BUG_UNMONITOR) { if (!access_has_bug_level($t_show_monitor_list_threshold, $p_bug_id, $t_user_id)) { continue; } } # relationships if ($v_type == BUG_ADD_RELATIONSHIP || $v_type == BUG_DEL_RELATIONSHIP || $v_type == BUG_REPLACE_RELATIONSHIP) { $t_related_bug_id = $v_new_value; # If bug doesn't exist, then we don't know whether to expose it or not based on the fact whether it was # accessible to user or not. This also simplifies client code that is accessing the history log. if (!bug_exists($t_related_bug_id) || !access_has_bug_level(VIEWER, $t_related_bug_id, $t_user_id)) { continue; } } $raw_history[$j]['date'] = $v_date_modified; $raw_history[$j]['userid'] = $v_user_id; # user_get_name handles deleted users, and username vs realname $raw_history[$j]['username'] = user_get_name($v_user_id); $raw_history[$j]['field'] = $v_field_name; $raw_history[$j]['type'] = $v_type; $raw_history[$j]['old_value'] = $v_old_value; $raw_history[$j]['new_value'] = $v_new_value; $j++; } # end for loop return $raw_history; }
/** * Get the value of a custom field for the given bug * @todo return values are unclear... should we error when access is denied * and provide an api to check whether it will be? * @param integer $p_field_id Custom field id. * @param integer $p_bug_id A bug identifier. * @return mixed: value is defined, null: no value is defined, false: read access is denied * @access public */ function custom_field_get_value($p_field_id, $p_bug_id) { $t_row = custom_field_cache_row($p_field_id); $t_access_level_r = $t_row['access_level_r']; $t_default_value = $t_row['default_value']; if (!custom_field_has_read_access($p_field_id, $p_bug_id, auth_get_current_user_id())) { return false; } $t_value_field = $t_row['type'] == CUSTOM_FIELD_TYPE_TEXTAREA ? 'text' : 'value'; $t_query = 'SELECT ' . $t_value_field . ' FROM {custom_field_string} WHERE bug_id=' . db_param() . ' AND field_id=' . db_param(); $t_result = db_query($t_query, array($p_bug_id, $p_field_id)); if (db_num_rows($t_result) > 0) { return custom_field_database_to_value(db_result($t_result), $t_row['type']); } else { return null; } }
/** * Retrieves the raw history events for the specified bug id and returns it in an array * The array is indexed from 0 to N-1. The second dimension is: 'date', 'userid', 'username', * 'field','type','old_value','new_value' * @param integer $p_bug_id A valid bug identifier. * @param integer $p_user_id A valid user identifier. * @param integer $p_start_time The start time to filter by, or null for all. * @param integer $p_end_time The end time to filter by, or null for all. * @return array */ function history_get_raw_events_array($p_bug_id, $p_user_id = null, $p_start_time = null, $p_end_time = null) { $t_history_order = config_get('history_order'); $t_user_id = null === $p_user_id ? auth_get_current_user_id() : $p_user_id; $t_roadmap_view_access_level = config_get('roadmap_view_threshold'); $t_due_date_view_threshold = config_get('due_date_view_threshold'); # grab history and display by date_modified then field_name # @@@ by MASC I guess it's better by id then by field_name. When we have more history lines with the same # date, it's better to respect the storing order otherwise we should risk to mix different information # I give you an example. We create a child of a bug with different custom fields. In the history of the child # bug we will find the line related to the relationship mixed with the custom fields (the history is creted # for the new bug with the same timestamp...) $t_params = array($p_bug_id); $t_query = 'SELECT * FROM {bug_history} WHERE bug_id=' . db_param(); $t_where = array(); if ($p_start_time !== null) { $t_where[] = 'date_modified >= ' . db_param(); $t_params[] = $p_start_time; } if ($p_end_time !== null) { $t_where[] = 'date_modified < ' . db_param(); $t_params[] = $p_end_time; } if (count($t_where) > 0) { $t_query .= ' AND ' . implode(' AND ', $t_where); } $t_query .= ' ORDER BY date_modified ' . $t_history_order . ',id'; $t_result = db_query($t_query, $t_params); $t_raw_history = array(); $t_private_bugnote_visible = access_has_bug_level(config_get('private_bugnote_threshold'), $p_bug_id, $t_user_id); $t_tag_view_threshold = config_get('tag_view_threshold'); $t_view_attachments_threshold = config_get('view_attachments_threshold'); $t_show_monitor_list_threshold = config_get('show_monitor_list_threshold'); $t_show_handler_threshold = config_get('view_handler_threshold'); $t_standard_fields = columns_get_standard(); $j = 0; while ($t_row = db_fetch_array($t_result)) { extract($t_row, EXTR_PREFIX_ALL, 'v'); if ($v_type == NORMAL_TYPE) { if (!in_array($v_field_name, $t_standard_fields)) { # check that the item should be visible to the user $t_field_id = custom_field_get_id_from_name($v_field_name); if (false !== $t_field_id && !custom_field_has_read_access($t_field_id, $p_bug_id, $t_user_id)) { continue; } } if ($v_field_name == 'target_version' && !access_has_bug_level($t_roadmap_view_access_level, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'due_date' && !access_has_bug_level($t_due_date_view_threshold, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'handler_id' && !access_has_bug_level($t_show_handler_threshold, $p_bug_id, $t_user_id)) { continue; } } # bugnotes if ($t_user_id != $v_user_id) { # bypass if user originated note if ($v_type == BUGNOTE_ADDED || $v_type == BUGNOTE_UPDATED || $v_type == BUGNOTE_DELETED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_old_value, 'view_state') == VS_PRIVATE) { continue; } } if ($v_type == BUGNOTE_STATE_CHANGED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_new_value, 'view_state') == VS_PRIVATE) { continue; } } } # tags if ($v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED) { if (!access_has_bug_level($t_tag_view_threshold, $p_bug_id, $t_user_id)) { continue; } } # attachments if ($v_type == FILE_ADDED || $v_type == FILE_DELETED) { if (!access_has_bug_level($t_view_attachments_threshold, $p_bug_id, $t_user_id)) { continue; } } # monitoring if ($v_type == BUG_MONITOR || $v_type == BUG_UNMONITOR) { if (!access_has_bug_level($t_show_monitor_list_threshold, $p_bug_id, $t_user_id)) { continue; } } # relationships if ($v_type == BUG_ADD_RELATIONSHIP || $v_type == BUG_DEL_RELATIONSHIP || $v_type == BUG_REPLACE_RELATIONSHIP) { $t_related_bug_id = $v_new_value; # If bug doesn't exist, then we don't know whether to expose it or not based on the fact whether it was # accessible to user or not. This also simplifies client code that is accessing the history log. if (!bug_exists($t_related_bug_id) || !access_has_bug_level(config_get('view_bug_threshold'), $t_related_bug_id, $t_user_id)) { continue; } } $t_raw_history[$j]['date'] = $v_date_modified; $t_raw_history[$j]['userid'] = $v_user_id; # user_get_name handles deleted users, and username vs realname $t_raw_history[$j]['username'] = user_get_name($v_user_id); $t_raw_history[$j]['field'] = $v_field_name; $t_raw_history[$j]['type'] = $v_type; $t_raw_history[$j]['old_value'] = $v_old_value; $t_raw_history[$j]['new_value'] = $v_new_value; $j++; } # end for loop return $t_raw_history; }
?> <!-- spacer --> <tr class="spacer"> <td colspan="6"></td> </tr> <!-- Custom Fields --> <?php $t_custom_fields_found = false; $t_related_custom_field_ids = custom_field_get_linked_ids($t_bug->project_id); foreach ($t_related_custom_field_ids as $t_id) { $t_def = custom_field_get_definition($t_id); if (!$t_def['advanced'] && custom_field_has_read_access($t_id, $f_bug_id)) { $t_custom_fields_found = true; ?> <tr <?php echo helper_alternate_class(); ?> > <td class="category"> <?php echo string_display(lang_get_defaulted($t_def['name'])); ?> </td> <td colspan="5"> <?php print_custom_field_value($t_def, $t_id, $f_bug_id); ?>
function history_get_raw_events_array($p_bug_id, $p_user_id = null) { $t_mantis_bug_history_table = config_get('mantis_bug_history_table'); $t_mantis_user_table = config_get('mantis_user_table'); $t_history_order = config_get('history_order'); $c_bug_id = db_prepare_int($p_bug_id); $t_user_id = null === $p_user_id ? auth_get_current_user_id() : $p_user_id; $t_roadmap_view_access_level = config_get('roadmap_view_threshold'); # grab history and display by date_modified then field_name # @@@ by MASC I guess it's better by id then by field_name. When we have more history lines with the same # date, it's better to respect the storing order otherwise we should risk to mix different information # I give you an example. We create a child of a bug with different custom fields. In the history of the child # bug we will find the line related to the relationship mixed with the custom fields (the history is creted # for the new bug with the same timestamp...) $query = "SELECT *\n\t\t\t\tFROM {$t_mantis_bug_history_table}\n\t\t\t\tWHERE bug_id='{$c_bug_id}'\n\t\t\t\tORDER BY date_modified {$t_history_order},id"; $result = db_query($query); $raw_history_count = db_num_rows($result); $raw_history = array(); $t_private_bugnote_threshold = config_get('private_bugnote_threshold'); $t_private_bugnote_visible = access_has_bug_level(config_get('private_bugnote_threshold'), $p_bug_id, $t_user_id); for ($i = 0, $j = 0; $i < $raw_history_count; ++$i) { $row = db_fetch_array($result); extract($row, EXTR_PREFIX_ALL, 'v'); // check that the item should be visible to the user // custom fields - we are passing 32 here to notify the API that the custom field name is truncated by the history column from 64 to 32 characters. $t_field_id = custom_field_get_id_from_name($v_field_name, 32); if (false !== $t_field_id && !custom_field_has_read_access($t_field_id, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'target_version' && !access_has_bug_level($t_roadmap_view_access_level, $p_bug_id, $t_user_id)) { continue; } // bugnotes if ($t_user_id != $v_user_id) { // bypass if user originated note if ($v_type == BUGNOTE_ADDED || $v_type == BUGNOTE_UPDATED || $v_type == BUGNOTE_DELETED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_old_value, 'view_state') == VS_PRIVATE) { continue; } } if ($v_type == BUGNOTE_STATE_CHANGED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_new_value, 'view_state') == VS_PRIVATE) { continue; } } } // tags if ($v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED) { if (!access_has_global_level(config_get('tag_view_threshold'))) { continue; } } $raw_history[$j]['date'] = db_unixtimestamp($v_date_modified); $raw_history[$j]['userid'] = $v_user_id; # user_get_name handles deleted users, and username vs realname $raw_history[$j]['username'] = user_get_name($v_user_id); $raw_history[$j]['field'] = $v_field_name; $raw_history[$j]['type'] = $v_type; $raw_history[$j]['old_value'] = $v_old_value; $raw_history[$j]['new_value'] = $v_new_value; $j++; } # end for loop return $raw_history; }
function custom_field_get_value($p_field_id, $p_bug_id) { $c_field_id = db_prepare_int($p_field_id); $c_bug_id = db_prepare_int($p_bug_id); custom_field_ensure_exists($p_field_id); $t_custom_field_table = config_get('mantis_custom_field_table'); $query = "SELECT access_level_r, default_value, type\r\n\t\t\t\t FROM {$t_custom_field_table}\r\n\t\t\t\t WHERE id='{$c_field_id}'"; $result = db_query($query); $row = db_fetch_array($result); $t_access_level_r = $row['access_level_r']; $t_default_value = $row['default_value']; if (!custom_field_has_read_access($p_field_id, $p_bug_id, auth_get_current_user_id())) { return false; } $t_custom_field_string_table = config_get('mantis_custom_field_string_table'); $query = "SELECT value\r\n\t\t\t\t FROM {$t_custom_field_string_table}\r\n\t\t\t\t WHERE bug_id='{$c_bug_id}' AND\r\n\t\t\t\t \t\tfield_id='{$c_field_id}'"; $result = db_query($query); if (db_num_rows($result) > 0) { return custom_field_database_to_value(db_result($result), $row['type']); } else { return $t_default_value; } }
/** * Get the value of a custom field for the given bug * @todo return values are unclear... should we error when access is denied * and provide an api to check whether it will be? * @param int $p_field_id custom field id * @param int $p_bug_id bug id * @return mixed: value is defined, null: no value is defined, false: read access is denied * @access public */ function custom_field_get_value($p_field_id, $p_bug_id) { $c_field_id = db_prepare_int($p_field_id); $c_bug_id = db_prepare_int($p_bug_id); $row = custom_field_cache_row($p_field_id); $t_access_level_r = $row['access_level_r']; $t_default_value = $row['default_value']; if (!custom_field_has_read_access($p_field_id, $p_bug_id, auth_get_current_user_id())) { return false; } $t_value_field = $row['type'] == CUSTOM_FIELD_TYPE_TEXTAREA ? 'text' : 'value'; $t_custom_field_string_table = db_get_table('custom_field_string'); $query = "SELECT {$t_value_field}\n\t\t\t\t FROM {$t_custom_field_string_table}\n\t\t\t\t WHERE bug_id=" . db_param() . " AND\n\t\t\t\t \t\tfield_id=" . db_param(); $result = db_query_bound($query, array($c_bug_id, $c_field_id)); if (db_num_rows($result) > 0) { return custom_field_database_to_value(db_result($result), $row['type']); } else { return null; } }
/** * Retrieves the raw history events for the specified bug id and returns it in an array * The array is indexed from 0 to N-1. The second dimension is: 'date', 'userid', 'username', * 'field','type','old_value','new_value' * @param int $p_bug_id * @param int $p_user_id * @return array */ function history_get_raw_events_array($p_bug_id, $p_user_id = null) { $t_history_order = config_get('history_order'); $t_user_id = null === $p_user_id ? auth_get_current_user_id() : $p_user_id; $t_roadmap_view_access_level = config_get('roadmap_view_threshold'); $t_due_date_view_threshold = config_get('due_date_view_threshold'); # grab history and display by date_modified then field_name # @@@ by MASC I guess it's better by id then by field_name. When we have more history lines with the same # date, it's better to respect the storing order otherwise we should risk to mix different information # I give you an example. We create a child of a bug with different custom fields. In the history of the child # bug we will find the line related to the relationship mixed with the custom fields (the history is creted # for the new bug with the same timestamp...) $t_mantis_bug_history_table = db_get_table('bug_history'); $query = "SELECT *\n\t\t\t\tFROM {$t_mantis_bug_history_table}\n\t\t\t\tWHERE bug_id=" . db_param() . "\n\t\t\t\tORDER BY date_modified {$t_history_order},id"; $result = db_query_bound($query, array($p_bug_id)); $raw_history = array(); $t_private_bugnote_threshold = config_get('private_bugnote_threshold'); $t_private_bugnote_visible = access_has_bug_level(config_get('private_bugnote_threshold'), $p_bug_id, $t_user_id); $t_tag_view_threshold = config_get('tag_view_threshold'); $t_show_monitor_list_threshold = config_get('show_monitor_list_threshold'); $t_show_handler_threshold = config_get('view_handler_threshold'); $t_standard_fields = columns_get_standard(); $j = 0; while ($t_row = db_fetch_array($result)) { extract($t_row, EXTR_PREFIX_ALL, 'v'); if ($v_type == NORMAL_TYPE) { if (!in_array($v_field_name, $t_standard_fields)) { # check that the item should be visible to the user $t_field_id = custom_field_get_id_from_name($v_field_name); if (false !== $t_field_id && !custom_field_has_read_access($t_field_id, $p_bug_id, $t_user_id)) { continue; } } if ($v_field_name == 'target_version' && !access_has_bug_level($t_roadmap_view_access_level, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'due_date' && !access_has_bug_level($t_due_date_view_threshold, $p_bug_id, $t_user_id)) { continue; } if ($v_field_name == 'handler_id' && !access_has_bug_level($t_show_handler_threshold, $p_bug_id, $t_user_id)) { continue; } } // bugnotes if ($t_user_id != $v_user_id) { // bypass if user originated note if ($v_type == BUGNOTE_ADDED || $v_type == BUGNOTE_UPDATED || $v_type == BUGNOTE_DELETED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_old_value, 'view_state') == VS_PRIVATE) { continue; } } if ($v_type == BUGNOTE_STATE_CHANGED) { if (!$t_private_bugnote_visible && bugnote_get_field($v_new_value, 'view_state') == VS_PRIVATE) { continue; } } } // tags if ($v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED) { if (!access_has_bug_level($t_tag_view_threshold, $p_bug_id, $t_user_id)) { continue; } } // monitoring if ($v_type == BUG_MONITOR || $v_type == BUG_UNMONITOR) { if (!access_has_bug_level($t_show_monitor_list_threshold, $p_bug_id, $t_user_id)) { continue; } } $raw_history[$j]['date'] = $v_date_modified; $raw_history[$j]['userid'] = $v_user_id; # user_get_name handles deleted users, and username vs realname $raw_history[$j]['username'] = user_get_name($v_user_id); $raw_history[$j]['field'] = $v_field_name; $raw_history[$j]['type'] = $v_type; $raw_history[$j]['old_value'] = $v_old_value; $raw_history[$j]['new_value'] = $v_new_value; $j++; } # end for loop return $raw_history; }
foreach ($t_related_custom_field_ids as $key => $t_id) { if (!custom_field_has_read_access($t_id, $t_bug->id)) { continue; } $t_custom_fields_found = true; $t_def = custom_field_get_definition($t_id); $t_def_custom = 'custom_' . strtolower($t_def['name']); if ($t_def_custom === $t_column_name) { echo '<td class="custom_field pad1 center" title="', string_display(lang_get_defaulted($t_def['name'])), '">', print_custom_field_value($t_def, $t_id, $t_bug->id), '</td>'; } } } } else { foreach ($g_show_only_custom_fields as $t_display_id) { foreach ($t_related_custom_field_ids as $key => $t_id) { if (!custom_field_has_read_access($t_id, $t_bug->id)) { continue; } # has read access #d8d8d8 $t_custom_fields_found = true; $t_def = custom_field_get_definition($t_id); $t_def_custom = 'custom_' . strtolower($t_def['name']); if ($key + 1 === $t_display_id) { echo '<td class="custom_field pad1 center" title="', string_display(lang_get_defaulted($t_def['name'])), '">', print_custom_field_value($t_def, $t_id, $t_bug->id), '</td>'; } } } } echo '</tr>'; if ($t_custom_fields_found) { # spacer