/** * Update a note * * @param string $p_username The name of the user trying to add a note to an issue. * param string $p_password The password of the user. * @param IssueNoteData $p_note The note to update. * @return true on success, false on failure */ function mc_issue_note_update( $p_username, $p_password, $p_note ) { $t_user_id = mci_check_login( $p_username, $p_password ); if( $t_user_id === false ) { return mci_soap_fault_login_failed(); } if ( !isset( $p_note['id'] ) || is_blank( $p_note['id'] ) ) { return new soap_fault( 'Client', '', "Issue id must not be blank." ); } if ( !isset( $p_note['text'] ) || is_blank( $p_note['text'] ) ) { return new soap_fault( 'Client', '', "Issue note text must not be blank." ); } $t_issue_note_id = $p_note['id']; if( !bugnote_exists( $t_issue_note_id ) ) { return new soap_fault( 'Server', '', "Issue note '$t_issue_note_id' does not exist." ); } $t_issue_id = bugnote_get_field( $t_issue_note_id, 'bug_id' ); $t_project_id = bug_get_field( $t_issue_id, 'project_id' ); if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) { return mci_soap_fault_access_denied( $t_user_id ); } if( !access_has_bug_level( config_get( 'add_bugnote_threshold' ), $t_issue_id, $t_user_id ) ) { return mci_soap_fault_access_denied( $t_user_id, "You do not have access rights to add notes to this issue" ); } if( bug_is_readonly( $t_issue_id ) ) { return mci_soap_fault_access_denied( $t_user_id, "Issue ' . $t_issue_id . ' is readonly" ); } if( isset( $p_note['view_state'] )) { $t_view_state = $p_note['view_state']; $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state ); bugnote_set_view_state( $t_issue_note_id, $t_view_state_id ); } bugnote_set_text( $t_issue_note_id, $p_note['text'] ); return bugnote_date_update( $t_issue_note_id ); }
/** * @todo yarick123: email_collect_recipients(...) will be completely rewritten to provide additional information such as language, user access,.. * @todo yarick123:sort recipients list by language to reduce switches between different languages * @param int $p_bug_id * @param string $p_notify_type * @param array $p_extra_user_ids_to_email * @return array */ function email_collect_recipients($p_bug_id, $p_notify_type, $p_extra_user_ids_to_email = array()) { $c_bug_id = db_prepare_int($p_bug_id); $t_recipients = array(); # add explicitly specified users if (ON == email_notify_flag($p_notify_type, 'explicit')) { foreach ($p_extra_user_ids_to_email as $t_user_id) { $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add explicitly specified user = @U%d', $p_bug_id, $t_user_id)); } } # add Reporter if (ON == email_notify_flag($p_notify_type, 'reporter')) { $t_reporter_id = bug_get_field($p_bug_id, 'reporter_id'); $t_recipients[$t_reporter_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add Reporter = @U%d', $p_bug_id, $t_reporter_id)); } # add Handler if (ON == email_notify_flag($p_notify_type, 'handler')) { $t_handler_id = bug_get_field($p_bug_id, 'handler_id'); if ($t_handler_id > 0) { $t_recipients[$t_handler_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add Handler = @U%d', $p_bug_id, $t_handler_id)); } } $t_project_id = bug_get_field($p_bug_id, 'project_id'); # add users monitoring the bug $t_bug_monitor_table = db_get_table('mantis_bug_monitor_table'); if (ON == email_notify_flag($p_notify_type, 'monitor')) { $query = "SELECT DISTINCT user_id\n\t\t\t\t\t FROM {$t_bug_monitor_table}\n\t\t\t\t\t WHERE bug_id=" . db_param(); $result = db_query_bound($query, array($c_bug_id)); $count = db_num_rows($result); for ($i = 0; $i < $count; $i++) { $t_user_id = db_result($result, $i); $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add Monitor = @U%d', $p_bug_id, $t_user_id)); } } # add users who contributed bugnotes $t_bugnote_id = bugnote_get_latest_id($p_bug_id); $t_bugnote_view = bugnote_get_field($t_bugnote_id, 'view_state'); $t_bugnote_date = bugnote_get_field($t_bugnote_id, 'last_modified'); $t_bug = bug_get($p_bug_id); $t_bug_date = $t_bug->last_updated; $t_bugnote_table = db_get_table('mantis_bugnote_table'); if (ON == email_notify_flag($p_notify_type, 'bugnotes')) { $query = "SELECT DISTINCT reporter_id\n\t\t\t\t\t FROM {$t_bugnote_table}\n\t\t\t\t\t WHERE bug_id = " . db_param(); $result = db_query_bound($query, array($c_bug_id)); $count = db_num_rows($result); for ($i = 0; $i < $count; $i++) { $t_user_id = db_result($result, $i); $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add Note Author = @U%d', $p_bug_id, $t_user_id)); } } # add project users who meet the thresholds $t_bug_is_private = bug_get_field($p_bug_id, 'view_state') == VS_PRIVATE; $t_threshold_min = email_notify_flag($p_notify_type, 'threshold_min'); $t_threshold_max = email_notify_flag($p_notify_type, 'threshold_max'); $t_threshold_users = project_get_all_user_rows($t_project_id, $t_threshold_min); foreach ($t_threshold_users as $t_user) { if ($t_user['access_level'] <= $t_threshold_max) { if (!$t_bug_is_private || access_compare_level($t_user['access_level'], config_get('private_bug_threshold'))) { $t_recipients[$t_user['id']] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, add Project User = @U%d', $p_bug_id, $t_user['id'])); } } } # add users as specified by plugins $t_recipients_include_data = event_signal('EVENT_NOTIFY_USER_INCLUDE', array($p_bug_id, $p_notify_type)); foreach ($t_recipients_include_data as $t_plugin => $t_recipients_include_data2) { foreach ($t_recipients_include_data2 as $t_callback => $t_recipients_included) { # only handle if we get an array from the callback if (is_array($t_recipients_included)) { foreach ($t_recipients_included as $t_user_id) { $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, %s plugin added user @U%d', $p_bug_id, $t_plugin, $t_user_id)); } } } } # FIXME: the value of $p_notify_type could at this stage be either a status # or a built-in actions such as 'owner and 'sponsor'. We have absolutely no # idea whether 'new' is indicating a new bug has been filed, or if the # status of an existing bug has been changed to 'new'. Therefore it is best # to just assume built-in actions have precedence over status changes. switch ($p_notify_type) { case 'new': case 'feedback': # This isn't really a built-in action (delete me!) # This isn't really a built-in action (delete me!) case 'reopened': case 'resolved': case 'closed': case 'bugnote': $t_pref_field = 'email_on_' . $p_notify_type; break; case 'owner': # The email_on_assigned notification type is now effectively # email_on_change_of_handler. $t_pref_field = 'email_on_assigned'; break; case 'deleted': case 'updated': case 'sponsor': case 'relation': case 'monitor': case 'priority': # This is never used, but exists in the database! # FIXME: these notification actions are not actually implemented # in the database and therefore aren't adjustable on a per-user # basis! The exception is 'monitor' that makes no sense being a # customisable per-user preference. $t_pref_field = false; break; default: # Anything not built-in is probably going to be a status $t_pref_field = 'email_on_status'; break; } # @@@ we could optimize by modifiying user_cache() to take an array # of user ids so we could pull them all in. We'll see if it's necessary $t_final_recipients = array(); $t_user_ids = array_keys($t_recipients); user_cache_array_rows($t_user_ids); user_pref_cache_array_rows($t_user_ids); user_pref_cache_array_rows($t_user_ids, $t_bug->project_id); # Check whether users should receive the emails # and put email address to $t_recipients[user_id] foreach ($t_recipients as $t_id => $t_ignore) { # Possibly eliminate the current user if (auth_get_current_user_id() == $t_id && OFF == config_get('email_receive_own')) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (own)', $p_bug_id, $t_id)); continue; } # Eliminate users who don't exist anymore or who are disabled if (!user_exists($t_id) || !user_is_enabled($t_id)) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (disabled)', $p_bug_id, $t_id)); continue; } # Exclude users who have this notification type turned off if ($t_pref_field) { $t_notify = user_pref_get_pref($t_id, $t_pref_field); if (OFF == $t_notify) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (pref %s off)', $p_bug_id, $t_id, $t_pref_field)); continue; } else { # Users can define the severity of an issue before they are emailed for # each type of notification $t_min_sev_pref_field = $t_pref_field . '_min_severity'; $t_min_sev_notify = user_pref_get_pref($t_id, $t_min_sev_pref_field); $t_bug_severity = bug_get_field($p_bug_id, 'severity'); if ($t_bug_severity < $t_min_sev_notify) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (pref threshold)', $p_bug_id, $t_id)); continue; } } } # exclude users who don't have at least viewer access to the bug, # or who can't see bugnotes if the last update included a bugnote if (!access_has_bug_level(VIEWER, $p_bug_id, $t_id) || $t_bug_date == $t_bugnote_date && !access_has_bugnote_level(VIEWER, $t_bugnote_id, $t_id)) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (access level)', $p_bug_id, $t_id)); continue; } # check to exclude users as specified by plugins $t_recipient_exclude_data = event_signal('EVENT_NOTIFY_USER_EXCLUDE', array($p_bug_id, $p_notify_type, $t_id)); $t_exclude = false; foreach ($t_recipient_exclude_data as $t_plugin => $t_recipient_exclude_data2) { foreach ($t_recipient_exclude_data2 as $t_callback => $t_recipient_excluded) { # exclude if any plugin returns true (excludes the user) if ($t_recipient_excluded) { $t_exclude = true; log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, %s plugin dropped user @U%d', $p_bug_id, $t_plugin, $t_id)); } } } # user was excluded by a plugin if ($t_exclude) { continue; } # Finally, let's get their emails, if they've set one $t_email = user_get_email($t_id); if (is_blank($t_email)) { log_event(LOG_EMAIL_RECIPIENT, sprintf('Issue = #%d, drop @U%d (no email)', $p_bug_id, $t_id)); } else { # @@@ we could check the emails for validity again but I think # it would be too slow $t_final_recipients[$t_id] = $t_email; } } return $t_final_recipients; }
function email_collect_recipients($p_bug_id, $p_notify_type) { $c_bug_id = db_prepare_int($p_bug_id); $t_recipients = array(); # add Reporter if (ON == email_notify_flag($p_notify_type, 'reporter')) { $t_reporter_id = bug_get_field($p_bug_id, 'reporter_id'); $t_recipients[$t_reporter_id] = true; log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, add reporter={$t_reporter_id}"); } # add Handler if (ON == email_notify_flag($p_notify_type, 'handler')) { $t_handler_id = bug_get_field($p_bug_id, 'handler_id'); $t_recipients[$t_handler_id] = true; log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, add handler={$t_handler_id}"); } $t_project_id = bug_get_field($p_bug_id, 'project_id'); # add users monitoring the bug $t_bug_monitor_table = config_get('mantis_bug_monitor_table'); if (ON == email_notify_flag($p_notify_type, 'monitor')) { $query = "SELECT DISTINCT user_id\n\t\t\t\t\t FROM {$t_bug_monitor_table}\n\t\t\t\t\t WHERE bug_id={$c_bug_id}"; $result = db_query($query); $count = db_num_rows($result); for ($i = 0; $i < $count; $i++) { $t_user_id = db_result($result, $i); $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, add monitor={$t_user_id}"); } } # add users who contributed bugnotes $t_bugnote_id = bugnote_get_latest_id($p_bug_id); $t_bugnote_view = bugnote_get_field($t_bugnote_id, 'view_state'); $t_bugnote_date = db_unixtimestamp(bugnote_get_field($t_bugnote_id, 'last_modified')); $t_bug_date = bug_get_field($p_bug_id, 'last_updated'); $t_bugnote_table = config_get('mantis_bugnote_table'); if (ON == email_notify_flag($p_notify_type, 'bugnotes')) { $query = "SELECT DISTINCT reporter_id\n\t\t\t\t\t FROM {$t_bugnote_table}\n\t\t\t\t\t WHERE bug_id = {$c_bug_id}"; $result = db_query($query); $count = db_num_rows($result); for ($i = 0; $i < $count; $i++) { $t_user_id = db_result($result, $i); $t_recipients[$t_user_id] = true; log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, add note={$t_user_id}"); } } # add project users who meet the thresholds $t_bug_is_private = bug_get_field($p_bug_id, 'view_state') == VS_PRIVATE; $t_threshold_min = email_notify_flag($p_notify_type, 'threshold_min'); $t_threshold_max = email_notify_flag($p_notify_type, 'threshold_max'); $t_threshold_users = project_get_all_user_rows($t_project_id, $t_threshold_min); foreach ($t_threshold_users as $t_user) { if ($t_user['access_level'] <= $t_threshold_max) { if (!$t_bug_is_private || access_compare_level($t_user['access_level'], config_get('private_bug_threshold'))) { $t_recipients[$t_user['id']] = true; log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, add project=" . $t_user['id']); } } } # set up to eliminate unwanted users # get list of status values that are not covered specifically in the prefs # These are handled by email_on_status generically # @@@ thraxisp note that email_on_assigned was co-opted to handle change in handler $t_status_change = get_enum_to_array(config_get('status_enum_string')); unset($t_status_change[NEW_]); unset($t_status_change[FEEDBACK]); unset($t_status_change[RESOLVED]); unset($t_status_change[CLOSED]); if ('owner' == $p_notify_type) { $t_pref_field = 'email_on_assigned'; } else { if (in_array($p_notify_type, $t_status_change)) { $t_pref_field = 'email_on_status'; } else { $t_pref_field = 'email_on_' . $p_notify_type; } } $t_user_pref_table = config_get('mantis_user_pref_table'); if (!db_field_exists($t_pref_field, $t_user_pref_table)) { $t_pref_field = false; } # @@@ we could optimize by modifiying user_cache() to take an array # of user ids so we could pull them all in. We'll see if it's necessary $t_final_recipients = array(); # Check whether users should receive the emails # and put email address to $t_recipients[user_id] foreach ($t_recipients as $t_id => $t_ignore) { # Possibly eliminate the current user if (auth_get_current_user_id() == $t_id && OFF == config_get('email_receive_own')) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (own)"); continue; } # Eliminate users who don't exist anymore or who are disabled if (!user_exists($t_id) || !user_is_enabled($t_id)) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (disabled)"); continue; } # Exclude users who have this notification type turned off if ($t_pref_field) { $t_notify = user_pref_get_pref($t_id, $t_pref_field); if (OFF == $t_notify) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (pref {$t_pref_field} off)"); continue; } else { # Users can define the severity of an issue before they are emailed for # each type of notification $t_min_sev_pref_field = $t_pref_field . '_min_severity'; $t_min_sev_notify = user_pref_get_pref($t_id, $t_min_sev_pref_field); $t_bug_severity = bug_get_field($p_bug_id, 'severity'); if ($t_bug_severity < $t_min_sev_notify) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (pref threshold)"); continue; } } } # check that user can see bugnotes if the last update included a bugnote if ($t_bug_date == $t_bugnote_date) { if (!access_has_bugnote_level(VIEWER, $t_bugnote_id, $t_id)) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (access level)"); continue; } } # Finally, let's get their emails, if they've set one $t_email = user_get_email($t_id); if (is_blank($t_email)) { log_event(LOG_EMAIL_RECIPIENT, "bug= {$p_bug_id}, drop {$t_id} (no email)"); } else { # @@@ we could check the emails for validity again but I think # it would be too slow $t_final_recipients[$t_id] = $t_email; } } return $t_final_recipients; }
/** * 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; }
/** * Set the view state of the bugnote * @param int $p_bugnote_id bugnote id * @param bool $p_private * @return bool * @access public */ function bugnote_set_view_state($p_bugnote_id, $p_private) { $c_bugnote_id = db_prepare_int($p_bugnote_id); $t_bug_id = bugnote_get_field($p_bugnote_id, 'bug_id'); if ($p_private) { $t_view_state = VS_PRIVATE; } else { $t_view_state = VS_PUBLIC; } $t_bugnote_table = db_get_table('mantis_bugnote_table'); $query = "UPDATE {$t_bugnote_table}\n\t\t \tSET view_state=" . db_param() . "\n\t\t \tWHERE id=" . db_param(); db_query_bound($query, array($t_view_state, $c_bugnote_id)); history_log_event_special($t_bug_id, BUGNOTE_STATE_CHANGED, $t_view_state, bugnote_format_id($p_bugnote_id)); return true; }
require_api('lang_api.php'); require_api('print_api.php'); require_api('string_api.php'); require_api('user_api.php'); $f_bug_id = gpc_get_int('bug_id', 0); $f_bugnote_id = gpc_get_int('bugnote_id', 0); $f_rev_id = gpc_get_int('rev_id', 0); $t_title = ''; if ($f_bug_id) { $t_bug_id = $f_bug_id; $t_bug_data = bug_get($t_bug_id, true); $t_bug_revisions = array_reverse(bug_revision_list($t_bug_id), true); $t_title = lang_get('issue_id') . $t_bug_id; } else { if ($f_bugnote_id) { $t_bug_id = bugnote_get_field($f_bugnote_id, 'bug_id'); $t_bug_data = bug_get($t_bug_id, true); $t_bug_revisions = bug_revision_list($t_bug_id, REV_ANY, $f_bugnote_id); $t_title = lang_get('bugnote') . ' ' . $f_bugnote_id; } else { if ($f_rev_id) { $t_bug_revisions = bug_revision_like($f_rev_id); if (count($t_bug_revisions) < 1) { trigger_error(ERROR_GENERIC, ERROR); } $t_bug_id = $t_bug_revisions[$f_rev_id]['bug_id']; $t_bug_data = bug_get($t_bug_id, true); $t_title = lang_get('issue_id') . $t_bug_id; } else { trigger_error(ERROR_GENERIC, ERROR); }
/** * 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; }
/** * 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; }
public function put($request) { /** * Updates the note. * * Only the text and view state of the note can be altered. * * @param $request - The request we're responding to */ $this->note_id = Bugnote::get_mantis_id_from_url($request->url); if (!bugnote_exists($this->note_id)) { throw new HTTPException(404, "No such bug note: {$this->note_id}"); } # Check if the current user is allowed to edit the bugnote # (This comes from Mantis's bugnote_update.php) $user_id = auth_get_current_user_id(); $reporter_id = bugnote_get_field($this->note_id, 'reporter_id'); $bug_id = bugnote_get_field($this->note_id, 'bug_id'); if ($user_id != $reporter_id || OFF == config_get('bugnote_allow_user_edit_delete')) { if (!access_has_bugnote_level(config_get('update_bugnote_threshold'), $this->note_id)) { throw new HTTPException(403, "Access denied"); } } if (bug_is_readonly($bug_id)) { throw new HTTPException(500, "Can't edit a note on a read-only bug"); } $this->populate_from_repr($request->body); bugnote_set_view_state($this->note_id, !!$this->_get_rsrc_attr('private')); bugnote_set_text($this->note_id, $this->_get_mantis_attr('note')); $resp = new Response(); $resp->status = 204; return $resp; }
function bugnote_set_view_state($p_bugnote_id, $p_private) { $c_bugnote_id = db_prepare_int($p_bugnote_id); $t_bug_id = bugnote_get_field($p_bugnote_id, 'bug_id'); if ($p_private) { $t_view_state = VS_PRIVATE; } else { $t_view_state = VS_PUBLIC; } $t_bugnote_table = config_get('mantis_bugnote_table'); # update view_state $query = "UPDATE {$t_bugnote_table}\r\n\t\t \tSET view_state='{$t_view_state}'\r\n\t\t \tWHERE id='{$c_bugnote_id}'"; db_query($query); history_log_event_special($t_bug_id, BUGNOTE_STATE_CHANGED, bugnote_format_id($t_view_state), $p_bugnote_id); return true; }
/** * Delete a note given its id. * * @param string $p_username The name of the user trying to add a note to an issue. * @param string $p_password The password of the user. * @param integer $p_issue_note_id The id of the note to be deleted. * @return true: success, false: failure */ function mc_issue_note_delete($p_username, $p_password, $p_issue_note_id) { $t_user_id = mci_check_login($p_username, $p_password); if ($t_user_id === false) { return new soap_fault('Client', '', 'Access Denied'); } if ((int) $p_issue_note_id < 1) { return new soap_fault('Client', '', "Invalid issue note id '{$p_issue_note_id}'."); } if (!bugnote_exists($p_issue_note_id)) { return new soap_fault('Server', '', "Issue note '{$p_issue_note_id}' does not exist."); } $t_issue_id = bugnote_get_field($p_issue_note_id, 'bug_id'); $t_project_id = bug_get_field($t_issue_id, 'project_id'); if (!mci_has_readwrite_access($t_user_id, $t_project_id)) { return new soap_fault('Client', '', 'Access Denied'); } return bugnote_delete($p_issue_note_id); }
/** * Update a note * * @param string $p_username The name of the user trying to add a note to an issue. * param string $p_password The password of the user. * @param IssueNoteData $p_note The note to update. * @return true on success, false on failure */ function mc_issue_note_update($p_username, $p_password, $p_note) { $t_user_id = mci_check_login($p_username, $p_password); if ($t_user_id === false) { return mci_soap_fault_login_failed(); } if (!isset($p_note['id']) || is_blank($p_note['id'])) { return new soap_fault('Client', '', "Issue note id must not be blank."); } if (!isset($p_note['text']) || is_blank($p_note['text'])) { return new soap_fault('Client', '', "Issue note text must not be blank."); } $t_issue_note_id = $p_note['id']; if (!bugnote_exists($t_issue_note_id)) { return new soap_fault('Server', '', "Issue note '{$t_issue_note_id}' does not exist."); } $t_issue_id = bugnote_get_field($t_issue_note_id, 'bug_id'); $t_project_id = bug_get_field($t_issue_id, 'project_id'); if (!mci_has_readwrite_access($t_user_id, $t_project_id)) { return mci_soap_fault_access_denied($t_user_id); } $t_issue_author_id = bugnote_get_field($t_issue_note_id, 'reporter_id'); # Check if the user owns the bugnote and is allowed to update their own bugnotes # regardless of the update_bugnote_threshold level. $t_user_owns_the_bugnote = bugnote_is_user_reporter($t_issue_note_id, $t_user_id); $t_user_can_update_own_bugnote = config_get('bugnote_allow_user_edit_delete', null, $t_user_id, $t_project_id); if ($t_user_owns_the_bugnote && !$t_user_can_update_own_bugnote) { return mci_soap_fault_access_denied($t_user_id); } # Check if the user has an access level beyond update_bugnote_threshold for the # project containing the bugnote to update. $t_update_bugnote_threshold = config_get('update_bugnote_threshold', null, $t_user_id, $t_project_id); if (!$t_user_owns_the_bugnote && !access_has_bugnote_level($t_update_bugnote_threshold, $t_issue_note_id, $t_user_id)) { return mci_soap_fault_access_denied($t_user_id); } # Check if the bug is readonly if (bug_is_readonly($t_issue_id)) { return mci_soap_fault_access_denied($t_user_id, "Issue ' . {$t_issue_id} . ' is readonly"); } if (isset($p_note['view_state'])) { $t_view_state = $p_note['view_state']; $t_view_state_id = mci_get_enum_id_from_objectref('view_state', $t_view_state); bugnote_set_view_state($t_issue_note_id, $t_view_state_id); } bugnote_set_text($t_issue_note_id, $p_note['text']); return bugnote_date_update($t_issue_note_id); }
function bugnote_is_private($bug_id, $bugnote_id) { return bugnote_get_field($bugnote_id, 'view_state') == VS_PRIVATE || bug_get($bug_id)->view_state == VS_PRIVATE; }
require_api('form_api.php'); require_api('gpc_api.php'); require_api('helper_api.php'); require_api('print_api.php'); require_api('string_api.php'); form_security_validate('bugnote_set_view_state'); $f_bugnote_id = gpc_get_int('bugnote_id'); $f_private = gpc_get_bool('private'); $t_bug_id = bugnote_get_field($f_bugnote_id, 'bug_id'); $t_bug = bug_get($t_bug_id, true); if ($t_bug->project_id != helper_get_current_project()) { # in case the current project is not the same project of the bug we are viewing... # ... override the current project. This to avoid problems with categories and handlers lists etc. $g_project_override = $t_bug->project_id; } # Check if the bug is readonly if (bug_is_readonly($t_bug_id)) { error_parameters($t_bug_id); trigger_error(ERROR_BUG_READ_ONLY_ACTION_DENIED, ERROR); } # Check if the current user is allowed to change the view state of this bugnote $t_user_id = bugnote_get_field($f_bugnote_id, 'reporter_id'); if ($t_user_id == auth_get_current_user_id()) { access_ensure_bugnote_level(config_get('bugnote_user_change_view_state_threshold'), $f_bugnote_id); } else { access_ensure_bugnote_level(config_get('update_bugnote_threshold'), $f_bugnote_id); access_ensure_bugnote_level(config_get('change_view_status_threshold'), $f_bugnote_id); } bugnote_set_view_state($f_bugnote_id, $f_private); form_security_purge('bugnote_set_view_state'); print_successful_redirect(string_get_bug_view_url($t_bug_id) . '#bugnotes');
} # Check if the current user is allowed to edit the bugnote $t_user_id = auth_get_current_user_id(); $t_reporter_id = bugnote_get_field($f_bugnote_id, 'reporter_id'); if ($t_user_id != $t_reporter_id || OFF == config_get('bugnote_allow_user_edit_delete')) { access_ensure_bugnote_level(config_get('update_bugnote_threshold'), $f_bugnote_id); } # Check if the bug is readonly if (bug_is_readonly($t_bug_id)) { error_parameters($t_bug_id); trigger_error(ERROR_BUG_READ_ONLY_ACTION_DENIED, ERROR); } $t_bugnote_text = string_textarea(bugnote_get_text($f_bugnote_id)); # No need to gather the extra information if not used if (config_get('time_tracking_enabled') && access_has_bug_level(config_get('time_tracking_edit_threshold'), $t_bug_id)) { $t_time_tracking = bugnote_get_field($f_bugnote_id, "time_tracking"); $t_time_tracking = db_minutes_to_hhmm($t_time_tracking); } # Determine which view page to redirect back to. $t_redirect_url = string_get_bug_view_url($t_bug_id); html_page_top(bug_format_summary($t_bug_id, SUMMARY_CAPTION)); ?> <br /> <div align="center"> <form method="post" action="bugnote_update.php"> <?php echo form_security_field('bugnote_update'); ?> <table class="width75" cellspacing="1"> <tr> <td class="form-title">
/** * return an href anchor that links to a bug VIEW page for the given bug * account for the user preference and site override * @param integer $p_bug_id A bug identifier. * @param integer $p_bugnote_id A bugnote identifier. * @param integer $p_user_id A valid user identifier. * @param boolean $p_detail_info Whether to include more detailed information (e.g. title attribute / project) in the returned string. * @param boolean $p_fqdn Whether to return an absolute or relative link. * @return string */ function string_get_bugnote_view_link($p_bug_id, $p_bugnote_id, $p_user_id = null, $p_detail_info = true, $p_fqdn = false) { $t_bug_id = (int) $p_bug_id; if (bug_exists($t_bug_id) && bugnote_exists($p_bugnote_id)) { $t_link = '<a href="'; if ($p_fqdn) { $t_link .= config_get_global('path'); } else { $t_link .= config_get_global('short_path'); } $t_link .= string_get_bugnote_view_url($p_bug_id, $p_bugnote_id, $p_user_id) . '"'; if ($p_detail_info) { $t_reporter = string_attribute(user_get_name(bugnote_get_field($p_bugnote_id, 'reporter_id'))); $t_update_date = string_attribute(date(config_get('normal_date_format'), bugnote_get_field($p_bugnote_id, 'last_modified'))); $t_link .= ' title="' . bug_format_id($t_bug_id) . ': [' . $t_update_date . '] ' . $t_reporter . '"'; } $t_link .= '>' . bug_format_id($t_bug_id) . ':' . bugnote_format_id($p_bugnote_id) . '</a>'; } else { $t_link = bugnote_format_id($t_bug_id) . ':' . bugnote_format_id($p_bugnote_id); } return $t_link; }
function email_format_bug_message($p_visible_bug_data) { $t_normal_date_format = config_get('normal_date_format'); $t_complete_date_format = config_get('complete_date_format'); $t_email_separator1 = config_get('email_separator1'); $t_email_separator2 = config_get('email_separator2'); $t_email_padding_length = config_get('email_padding_length'); $t_status = $p_visible_bug_data['email_status']; $p_visible_bug_data['email_date_submitted'] = date($t_complete_date_format, $p_visible_bug_data['email_date_submitted']); $p_visible_bug_data['email_last_modified'] = date($t_complete_date_format, $p_visible_bug_data['email_last_modified']); $p_visible_bug_data['email_status'] = get_enum_element('status', $t_status); $p_visible_bug_data['email_severity'] = get_enum_element('severity', $p_visible_bug_data['email_severity']); $p_visible_bug_data['email_priority'] = get_enum_element('priority', $p_visible_bug_data['email_priority']); $p_visible_bug_data['email_reproducibility'] = get_enum_element('reproducibility', $p_visible_bug_data['email_reproducibility']); $t_message = $t_email_separator1 . " \n"; if (isset($p_visible_bug_data['email_bug_view_url'])) { $t_message .= $p_visible_bug_data['email_bug_view_url'] . " \n"; $t_message .= $t_email_separator1 . " \n"; } $t_message .= email_format_attribute($p_visible_bug_data, 'email_reporter'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_handler'); $t_message .= $t_email_separator1 . " \n"; $t_message .= email_format_attribute($p_visible_bug_data, 'email_project'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_bug'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_category'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_reproducibility'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_severity'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_priority'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_status'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_target_version'); # custom fields formatting foreach ($p_visible_bug_data['custom_fields'] as $t_custom_field_name => $t_custom_field_data) { $t_message .= str_pad(lang_get_defaulted($t_custom_field_name, null) . ': ', $t_email_padding_length, ' ', STR_PAD_RIGHT); $t_message .= string_custom_field_value_for_email($t_custom_field_data['value'], $t_custom_field_data['type']); $t_message .= " \n"; } # end foreach custom field if (config_get('bug_resolved_status_threshold') <= $t_status) { $p_visible_bug_data['email_resolution'] = get_enum_element('resolution', $p_visible_bug_data['email_resolution']); $t_message .= email_format_attribute($p_visible_bug_data, 'email_resolution'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_duplicate'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_fixed_in_version'); } $t_message .= $t_email_separator1 . " \n"; $t_message .= email_format_attribute($p_visible_bug_data, 'email_date_submitted'); $t_message .= email_format_attribute($p_visible_bug_data, 'email_last_modified'); $t_message .= $t_email_separator1 . " \n"; $t_message .= email_format_attribute($p_visible_bug_data, 'email_summary'); $t_message .= lang_get('email_description') . ": \n" . wordwrap($p_visible_bug_data['email_description']) . "\n"; # MASC RELATIONSHIP if (ON == config_get('enable_relationship')) { if (isset($p_visible_bug_data['relations'])) { $t_message .= $p_visible_bug_data['relations']; } } # MASC RELATIONSHIP # Sponsorship if (isset($p_visible_bug_data['sponsorship_total']) && $p_visible_bug_data['sponsorship_total'] > 0) { $t_message .= $t_email_separator1 . " \n"; $t_message .= sprintf(lang_get('total_sponsorship_amount'), sponsorship_format_amount($p_visible_bug_data['sponsorship_total'])) . "\n" . "\n"; if (isset($p_visible_bug_data['sponsorships'])) { foreach ($p_visible_bug_data['sponsorships'] as $t_sponsorship) { $t_date_added = date(config_get('normal_date_format'), $t_sponsorship->date_submitted); $t_message .= $t_date_added . ': '; $t_message .= user_get_name($t_sponsorship->user_id); $t_message .= ' (' . sponsorship_format_amount($t_sponsorship->amount) . ')' . " \n"; } } } $t_message .= $t_email_separator1 . " \n\n"; # format bugnotes foreach ($p_visible_bug_data['bugnotes'] as $t_bugnote) { $t_last_modified = date($t_normal_date_format, $t_bugnote->last_modified); $t_formatted_bugnote_id = bugnote_format_id($t_bugnote->id); $t_bugnote_link = string_process_bugnote_link(config_get('bugnote_link_tag') . $t_bugnote->id, false, false, true); $t_time_tracking = ''; # the bugnote objects array is retrieved from bugnote_get_all_visible_bugnotes which already checks for # time_tracking_view_threshold. If user does not have view permission the value is set to 0. if ($t_bugnote->time_tracking > 0) { $t_time_tracking_minutes = bugnote_get_field($t_bugnote->id, 'time_tracking'); if ($t_time_tracking_minutes > 0) { $t_time_tracking = ' ' . lang_get('time_tracking') . ' ' . db_minutes_to_hhmm($t_time_tracking_minutes) . "\n"; } } if (user_exists($t_bugnote->reporter_id)) { $t_access_level = access_get_project_level(null, $t_bugnote->reporter_id); $t_access_level_string = ' (' . get_enum_element('access_levels', $t_access_level) . ') - '; } else { $t_access_level_string = ''; } $t_string = ' (' . $t_formatted_bugnote_id . ') ' . user_get_name($t_bugnote->reporter_id) . $t_access_level_string . $t_last_modified . "\n" . $t_time_tracking . ' ' . $t_bugnote_link; $t_message .= $t_email_separator2 . " \n"; $t_message .= $t_string . " \n"; $t_message .= $t_email_separator2 . " \n"; $t_message .= wordwrap($t_bugnote->note) . " \n\n"; } # format history if (array_key_exists('history', $p_visible_bug_data)) { $t_message .= lang_get('bug_history') . " \n"; $t_message .= str_pad(lang_get('date_modified'), 17) . str_pad(lang_get('username'), 15) . str_pad(lang_get('field'), 25) . str_pad(lang_get('change'), 20) . " \n"; $t_message .= $t_email_separator1 . " \n"; foreach ($p_visible_bug_data['history'] as $t_raw_history_item) { $t_localized_item = history_localize_item($t_raw_history_item['field'], $t_raw_history_item['type'], $t_raw_history_item['old_value'], $t_raw_history_item['new_value']); $t_message .= str_pad(date($t_normal_date_format, $t_raw_history_item['date']), 17) . str_pad($t_raw_history_item['username'], 15) . str_pad($t_localized_item['note'], 25) . str_pad($t_localized_item['change'], 20) . "\n"; } $t_message .= $t_email_separator1 . " \n\n"; } return $t_message; }
/** * Update a note * * @param string $p_username The name of the user trying to add a note to an issue. * @param string $p_password The password of the user. * @param stdClass $p_note The note to update. * @return true on success, false on failure */ function mc_issue_note_update($p_username, $p_password, stdClass $p_note) { global $g_project_override; $t_user_id = mci_check_login($p_username, $p_password); if ($t_user_id === false) { return mci_soap_fault_login_failed(); } $p_note = SoapObjectsFactory::unwrapObject($p_note); if (!isset($p_note['id']) || is_blank($p_note['id'])) { return SoapObjectsFactory::newSoapFault('Client', 'Issue note id must not be blank.'); } if (!isset($p_note['text']) || is_blank($p_note['text'])) { return SoapObjectsFactory::newSoapFault('Client', 'Issue note text must not be blank.'); } $t_issue_note_id = $p_note['id']; if (!bugnote_exists($t_issue_note_id)) { return SoapObjectsFactory::newSoapFault('Client', 'Issue note \'' . $t_issue_note_id . '\' does not exist.'); } $t_issue_id = bugnote_get_field($t_issue_note_id, 'bug_id'); $t_project_id = bug_get_field($t_issue_id, 'project_id'); $g_project_override = $t_project_id; if (!mci_has_readwrite_access($t_user_id, $t_project_id)) { return mci_soap_fault_access_denied($t_user_id); } $t_issue_author_id = bugnote_get_field($t_issue_note_id, 'reporter_id'); # Check if the user owns the bugnote and is allowed to update their own bugnotes # regardless of the update_bugnote_threshold level. $t_user_owns_the_bugnote = bugnote_is_user_reporter($t_issue_note_id, $t_user_id); $t_user_can_update_own_bugnote = config_get('bugnote_user_edit_threshold', null, $t_user_id, $t_project_id); if ($t_user_owns_the_bugnote && !$t_user_can_update_own_bugnote) { return mci_soap_fault_access_denied($t_user_id); } # Check if the user has an access level beyond update_bugnote_threshold for the # project containing the bugnote to update. $t_update_bugnote_threshold = config_get('update_bugnote_threshold', null, $t_user_id, $t_project_id); if (!$t_user_owns_the_bugnote && !access_has_bugnote_level($t_update_bugnote_threshold, $t_issue_note_id, $t_user_id)) { return mci_soap_fault_access_denied($t_user_id); } # Check if the bug is readonly if (bug_is_readonly($t_issue_id)) { return mci_soap_fault_access_denied($t_user_id, 'Issue \'' . $t_issue_id . '\' is readonly'); } if (isset($p_note['view_state'])) { $t_view_state = $p_note['view_state']; $t_view_state_id = mci_get_enum_id_from_objectref('view_state', $t_view_state); bugnote_set_view_state($t_issue_note_id, $t_view_state_id == VS_PRIVATE); } log_event(LOG_WEBSERVICE, 'updating bugnote id \'' . $t_issue_note_id . '\''); bugnote_set_text($t_issue_note_id, $p_note['text']); return bugnote_date_update($t_issue_note_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; }
/** * 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; }
/** * Set the view state of the bugnote * @param integer $p_bugnote_id A bugnote identifier. * @param boolean $p_private Whether bugnote should be set to private status. * @return boolean * @access public */ function bugnote_set_view_state($p_bugnote_id, $p_private) { $t_bug_id = bugnote_get_field($p_bugnote_id, 'bug_id'); if ($p_private) { $t_view_state = VS_PRIVATE; } else { $t_view_state = VS_PUBLIC; } $t_query = 'UPDATE {bugnote} SET view_state=' . db_param() . ' WHERE id=' . db_param(); db_query($t_query, array($t_view_state, $p_bugnote_id)); history_log_event_special($t_bug_id, BUGNOTE_STATE_CHANGED, $t_view_state, bugnote_format_id($p_bugnote_id)); return true; }
/** * Check the current user's access against the given value and return true * if the user's access is equal to or higher, false otherwise. * This function looks up the bugnote's bug and performs an access check * against that bug * @param int $p_access_level integer representing access level * @param int $p_bugnote_id integer representing bugnote id to check access against * @param int|null $p_user_id integer representing user id, defaults to null to use current user * @return bool whether user has access level specified * @access public */ function access_has_bugnote_level($p_access_level, $p_bugnote_id, $p_user_id = null) { if (null === $p_user_id) { $p_user_id = auth_get_current_user_id(); } $t_bug_id = bugnote_get_field($p_bugnote_id, 'bug_id'); $t_project_id = bug_get_field($t_bug_id, 'project_id'); # If the bug is private and the user is not the reporter, then the # the user must also have higher access than private_bug_threshold if (bugnote_get_field($p_bugnote_id, 'view_state') == VS_PRIVATE && !bugnote_is_user_reporter($p_bugnote_id, $p_user_id)) { $t_private_bugnote_threshold = config_get('private_bugnote_threshold', null, $p_user_id, $t_project_id); $p_access_level = max($p_access_level, $t_private_bugnote_threshold); } return access_has_bug_level($p_access_level, $t_bug_id, $p_user_id); }
$t_user_id = auth_get_current_user_id(); $t_reporter_id = bugnote_get_field($f_bugnote_id, 'reporter_id'); if ($t_user_id == $t_reporter_id) { access_ensure_bugnote_level(config_get('bugnote_user_edit_threshold'), $f_bugnote_id); } else { access_ensure_bugnote_level(config_get('update_bugnote_threshold'), $f_bugnote_id); } # Check if the bug is readonly if (bug_is_readonly($t_bug_id)) { error_parameters($t_bug_id); trigger_error(ERROR_BUG_READ_ONLY_ACTION_DENIED, ERROR); } $t_bugnote_text = string_textarea(bugnote_get_text($f_bugnote_id)); # No need to gather the extra information if not used if (config_get('time_tracking_enabled') && access_has_bug_level(config_get('time_tracking_edit_threshold'), $t_bug_id)) { $t_time_tracking = bugnote_get_field($f_bugnote_id, 'time_tracking'); $t_time_tracking = db_minutes_to_hhmm($t_time_tracking); } # Determine which view page to redirect back to. $t_redirect_url = string_get_bug_view_url($t_bug_id); html_page_top(bug_format_summary($t_bug_id, SUMMARY_CAPTION)); ?> <br /> <div> <form method="post" action="bugnote_update.php"> <?php echo form_security_field('bugnote_update'); ?> <table class="width75" cellspacing="1"> <tr> <td class="form-title">