[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/api/soap/ -> mc_issue_api.php (source)

   1  <?php
   2  # MantisConnect - A webservice interface to Mantis Bug Tracker
   3  # Copyright (C) 2004-2011  Victor Boctor - vboctor@users.sourceforge.net
   4  # This program is distributed under dual licensing.  These include
   5  # GPL and a commercial licenses.  Victor Boctor reserves the right to
   6  # change the license of future releases.
   7  # See docs/ folder for more details
   8  
   9  require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'mc_core.php' );
  10  
  11  /**
  12   * Check if an issue with the given id exists.
  13   *
  14   * @param string $p_username  The name of the user trying to access the issue.
  15   * @param string $p_password  The password of the user.
  16   * @param integer $p_issue_id  The id of the issue to check.
  17   * @return boolean  true if there is an issue with the given id, false otherwise.
  18   */
  19  function mc_issue_exists( $p_username, $p_password, $p_issue_id ) {
  20      $t_user_id = mci_check_login( $p_username, $p_password );
  21      if( $t_user_id === false ) {
  22          return mci_soap_fault_login_failed();
  23      }
  24  
  25      if( !bug_exists( $p_issue_id ) ) {
  26          return false;
  27      }
  28  
  29      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
  30      if( !mci_has_readonly_access( $t_user_id, $t_project_id ) ) {
  31  
  32          // if we return an error here, then we answered the question!
  33          return false;
  34      }
  35  
  36      return true;
  37  }
  38  
  39  /**
  40   * Get all details about an issue.
  41   *
  42   * @param string $p_username  The name of the user trying to access the issue.
  43   * @param string $p_password  The password of the user.
  44   * @param integer $p_issue_id  The id of the issue to retrieve.
  45   * @return Array that represents an IssueData structure
  46   */
  47  function mc_issue_get( $p_username, $p_password, $p_issue_id ) {
  48      $t_user_id = mci_check_login( $p_username, $p_password );
  49      if( $t_user_id === false ) {
  50          return mci_soap_fault_login_failed();
  51      }
  52  
  53      $t_lang = mci_get_user_lang( $t_user_id );
  54  
  55      if( !bug_exists( $p_issue_id ) ) {
  56          return new soap_fault( 'Client', '', 'Issue does not exist.' );
  57      }
  58  
  59      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
  60      if( !mci_has_readonly_access( $t_user_id, $t_project_id ) ) {
  61          return mci_soap_fault_access_denied( $t_user_id );
  62      }
  63  
  64      if( !access_has_bug_level( VIEWER, $p_issue_id, $t_user_id ) ){
  65          return mci_soap_fault_access_denied( $t_user_id );
  66      }
  67  
  68      $t_bug = bug_get( $p_issue_id, true );
  69      $t_issue_data = array();
  70  
  71      $t_issue_data['id'] = $p_issue_id;
  72      $t_issue_data['view_state'] = mci_enum_get_array_by_id( $t_bug->view_state, 'view_state', $t_lang );
  73      $t_issue_data['last_updated'] = timestamp_to_iso8601( $t_bug->last_updated );
  74  
  75      $t_issue_data['project'] = mci_project_as_array_by_id( $t_bug->project_id );
  76      $t_issue_data['category'] = mci_get_category( $t_bug->category_id );
  77      $t_issue_data['priority'] = mci_enum_get_array_by_id( $t_bug->priority, 'priority', $t_lang );
  78      $t_issue_data['severity'] = mci_enum_get_array_by_id( $t_bug->severity, 'severity', $t_lang );
  79      $t_issue_data['status'] = mci_enum_get_array_by_id( $t_bug->status, 'status', $t_lang );
  80  
  81      $t_issue_data['reporter'] = mci_account_get_array_by_id( $t_bug->reporter_id );
  82      $t_issue_data['summary'] = $t_bug->summary;
  83      $t_issue_data['version'] = mci_null_if_empty( $t_bug->version );
  84      $t_issue_data['build'] = mci_null_if_empty( $t_bug->build );
  85      $t_issue_data['platform'] = mci_null_if_empty( $t_bug->platform );
  86      $t_issue_data['os'] = mci_null_if_empty( $t_bug->os );
  87      $t_issue_data['os_build'] = mci_null_if_empty( $t_bug->os_build );
  88      $t_issue_data['reproducibility'] = mci_enum_get_array_by_id( $t_bug->reproducibility, 'reproducibility', $t_lang );
  89      $t_issue_data['date_submitted'] = timestamp_to_iso8601( $t_bug->date_submitted );
  90  
  91      $t_issue_data['sponsorship_total'] = $t_bug->sponsorship_total;
  92  
  93      if( !empty( $t_bug->handler_id ) ) {
  94          $t_issue_data['handler'] = mci_account_get_array_by_id( $t_bug->handler_id );
  95      }
  96  
  97      $t_issue_data['projection'] = mci_enum_get_array_by_id( $t_bug->projection, 'projection', $t_lang );
  98      $t_issue_data['eta'] = mci_enum_get_array_by_id( $t_bug->eta, 'eta', $t_lang );
  99  
 100      $t_issue_data['resolution'] = mci_enum_get_array_by_id( $t_bug->resolution, 'resolution', $t_lang );
 101      $t_issue_data['fixed_in_version'] = mci_null_if_empty( $t_bug->fixed_in_version );
 102      $t_issue_data['target_version'] = mci_null_if_empty( $t_bug->target_version );
 103      $t_issue_data['due_date'] = mci_issue_get_due_date( $t_bug );
 104  
 105      $t_issue_data['description'] = $t_bug->description;
 106      $t_issue_data['steps_to_reproduce'] = mci_null_if_empty( $t_bug->steps_to_reproduce );
 107      $t_issue_data['additional_information'] = mci_null_if_empty( $t_bug->additional_information );
 108  
 109      $t_issue_data['attachments'] = mci_issue_get_attachments( $p_issue_id );
 110      $t_issue_data['relationships'] = mci_issue_get_relationships( $p_issue_id, $t_user_id );
 111      $t_issue_data['notes'] = mci_issue_get_notes( $p_issue_id );
 112      $t_issue_data['custom_fields'] = mci_issue_get_custom_fields( $p_issue_id );
 113      $t_issue_data['monitors'] = mci_account_get_array_by_ids( bug_get_monitors ( $p_issue_id ) );
 114      
 115      return $t_issue_data;
 116  }
 117  
 118  /**
 119   * Returns the category name, possibly null if no category is assigned
 120   *
 121   * @param int $p_category_id
 122   * @return string
 123   */
 124  function mci_get_category( $p_category_id ) {
 125      if ( $p_category_id == 0 )
 126          return '';
 127  
 128      return mci_null_if_empty( category_get_name( $p_category_id ) );
 129  }
 130  
 131  /**
 132   *
 133   * @param BugData $bug
 134   * @return soapval the value to be encoded as the due date
 135   */
 136  function mci_issue_get_due_date( $p_bug ) {
 137      if ( access_has_bug_level( config_get( 'due_date_view_threshold' ), $p_bug->id )  && !date_is_null( $p_bug->due_date ) ) {
 138          return new soapval( 'due_date', 'xsd:dateTime', timestamp_to_iso8601( $p_bug->due_date ) );
 139      } else {
 140          return new soapval( 'due_date','xsd:dateTime', null );
 141      }
 142  
 143  }
 144  
 145  /**
 146   * Sets the supplied array of custom field values to the specified issue id.
 147   *
 148   * @param $p_issue_id   Issue id to apply custom field values to.
 149   * @param $p_custom_fields  The array of custom field values as described in the webservice complex types.
 150   * @param boolean $p_log_insert create history logs for new values
 151   */
 152  function mci_issue_set_custom_fields( $p_issue_id, &$p_custom_fields, $p_log_insert ) {
 153      # set custom field values on the submitted issue
 154      if( isset( $p_custom_fields ) && is_array( $p_custom_fields ) ) {
 155          foreach( $p_custom_fields as $t_custom_field ) {
 156              # get custom field id from object ref
 157              $t_custom_field_id = mci_get_custom_field_id_from_objectref( $t_custom_field['field'] );
 158  
 159              if( $t_custom_field_id == 0 ) {
 160                  return new soap_fault( 'Client', '', 'Custom field ' . $t_custom_field['field']['name'] . ' not found.' );
 161              }
 162  
 163              # skip if current user doesn't have login access.
 164              if( !custom_field_has_write_access( $t_custom_field_id, $p_issue_id ) ) {
 165                  continue;
 166              }
 167  
 168              $t_value = $t_custom_field['value'];
 169  
 170              if( !custom_field_validate( $t_custom_field_id, $t_value ) ) {
 171                  return new soap_fault( 'Client', '', 'Invalid custom field value for field id ' . $t_custom_field_id . ' .');
 172              }
 173  
 174              if( !custom_field_set_value( $t_custom_field_id, $p_issue_id, $t_value, $p_log_insert  ) ) {
 175                  return new soap_fault( 'Server', '', 'Unable to set custom field value for field id ' . $t_custom_field_id . ' to issue ' . $p_issue_id. ' .' );
 176              }
 177          }
 178      }
 179  }
 180  
 181  /**
 182   * Get the custom field values associated with the specified issue id.
 183   *
 184   * @param $p_issue_id   Issue id to get the custom field values for.
 185   *
 186   * @return null if no custom field defined for the project that contains the issue, or if no custom
 187   *              fields are accessible to the current user.
 188   */
 189  function mci_issue_get_custom_fields( $p_issue_id ) {
 190      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
 191  
 192      $t_custom_fields = array();
 193      $t_related_custom_field_ids = custom_field_get_linked_ids( $t_project_id );
 194  
 195      foreach( $t_related_custom_field_ids as $t_id ) {
 196          $t_def = custom_field_get_definition( $t_id );
 197  
 198          if( custom_field_has_read_access( $t_id, $p_issue_id ) ) {
 199  
 200              # user has not access to read this custom field.
 201              $t_value = custom_field_get_value( $t_id, $p_issue_id );
 202              if( $t_value === false ) {
 203                  continue;
 204              }
 205  
 206              # return a blank string if the custom field value is undefined
 207              if( $t_value === null ) {
 208                  $t_value = '';
 209              }
 210  
 211              $t_custom_field_value = array();
 212              $t_custom_field_value['field'] = array();
 213              $t_custom_field_value['field']['id'] = $t_id;
 214              $t_custom_field_value['field']['name'] = $t_def['name'];
 215              $t_custom_field_value['value'] = $t_value;
 216  
 217              $t_custom_fields[] = $t_custom_field_value;
 218          }
 219      }
 220  
 221      # foreach
 222  
 223      return( count( $t_custom_fields ) == 0 ? null : $t_custom_fields );
 224  }
 225  
 226  /**
 227   * Get the attachments of an issue.
 228   *
 229   * @param integer $p_issue_id  The id of the issue to retrieve the attachments for
 230   * @return Array that represents an AttachmentData structure
 231   */
 232  function mci_issue_get_attachments( $p_issue_id ) {
 233      $t_attachment_rows = bug_get_attachments( $p_issue_id );
 234  
 235      if ( $t_attachment_rows == null) {
 236          return array();
 237      }
 238  
 239      $t_result = array();
 240      foreach( $t_attachment_rows as $t_attachment_row ) {
 241          if ( !file_can_view_bug_attachments( $p_issue_id, (int)$t_attachment_row['user_id'] ) ) {
 242              continue;
 243          }
 244          $t_attachment = array();
 245          $t_attachment['id'] = $t_attachment_row['id'];
 246          $t_attachment['filename'] = $t_attachment_row['filename'];
 247          $t_attachment['size'] = $t_attachment_row['filesize'];
 248          $t_attachment['content_type'] = $t_attachment_row['file_type'];
 249          $t_attachment['date_submitted'] = timestamp_to_iso8601( $t_attachment_row['date_added'] );
 250          $t_attachment['download_url'] = mci_get_mantis_path() . 'file_download.php?file_id=' . $t_attachment_row['id'] . '&amp;type=bug';
 251          $t_attachment['user_id'] = $t_attachment_row['user_id'];
 252          $t_result[] = $t_attachment;
 253      }
 254  
 255      return $t_result;
 256  }
 257  
 258  /**
 259   * Get the relationships of an issue.
 260   *
 261   * @param integer $p_issue_id  The id of the issue to retrieve the relationships for
 262   * @return Array that represents an RelationShipData structure
 263   */
 264  function mci_issue_get_relationships( $p_issue_id, $p_user_id ) {
 265      $t_relationships = array();
 266  
 267      $t_src_relationships = relationship_get_all_src( $p_issue_id );
 268      foreach( $t_src_relationships as $t_relship_row ) {
 269          if( access_has_bug_level( config_get( 'mc_readonly_access_level_threshold' ), $t_relship_row->dest_bug_id, $p_user_id ) ) {
 270              $t_relationship = array();
 271              $t_reltype = array();
 272              $t_relationship['id'] = $t_relship_row->id;
 273              $t_reltype['id'] = $t_relship_row->type;
 274              $t_reltype['name'] = relationship_get_description_src_side( $t_relship_row->type );
 275              $t_relationship['type'] = $t_reltype;
 276              $t_relationship['target_id'] = $t_relship_row->dest_bug_id;
 277              $t_relationships[] = $t_relationship;
 278          }
 279      }
 280  
 281      $t_dest_relationships = relationship_get_all_dest( $p_issue_id );
 282      foreach( $t_dest_relationships as $t_relship_row ) {
 283          if( access_has_bug_level( config_get( 'mc_readonly_access_level_threshold' ), $t_relship_row->src_bug_id, $p_user_id ) ) {
 284              $t_relationship = array();
 285              $t_relationship['id'] = $t_relship_row->id;
 286              $t_reltype = array();
 287              $t_reltype['id'] = relationship_get_complementary_type( $t_relship_row->type );
 288              $t_reltype['name'] = relationship_get_description_dest_side( $t_relship_row->type );
 289              $t_relationship['type'] = $t_reltype;
 290              $t_relationship['target_id'] = $t_relship_row->src_bug_id;
 291              $t_relationships[] = $t_relationship;
 292          }
 293      }
 294  
 295      return (count( $t_relationships ) == 0 ? null : $t_relationships );
 296  }
 297  
 298  /**
 299   * Get all visible notes for a specific issue
 300   *
 301   * @param integer $p_issue_id  The id of the issue to retrieve the notes for
 302   * @return Array that represents an IssueNoteData structure
 303   */
 304  function mci_issue_get_notes( $p_issue_id ) {
 305      $t_user_id = auth_get_current_user_id();
 306      $t_lang = mci_get_user_lang( $t_user_id );
 307      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
 308      $t_user_bugnote_order = 'ASC'; // always get the notes in ascending order for consistency to the calling application.
 309      $t_has_time_tracking_access = access_has_bug_level( config_get( 'time_tracking_view_threshold' ), $p_issue_id );
 310  
 311      $t_result = array();
 312      foreach( bugnote_get_all_visible_bugnotes( $p_issue_id, $t_user_bugnote_order, 0 ) as $t_value ) {
 313          $t_bugnote = array();
 314          $t_bugnote['id'] = $t_value->id;
 315          $t_bugnote['reporter'] = mci_account_get_array_by_id( $t_value->reporter_id );
 316          $t_bugnote['date_submitted'] = timestamp_to_iso8601( $t_value->date_submitted );
 317          $t_bugnote['last_modified'] = timestamp_to_iso8601( $t_value->last_modified );
 318          $t_bugnote['text'] = $t_value->note;
 319          $t_bugnote['view_state'] = mci_enum_get_array_by_id( $t_value->view_state, 'view_state', $t_lang );
 320          $t_bugnote['time_tracking'] = $t_has_time_tracking_access ? $t_value->time_tracking : 0;
 321          $t_bugnote['note_type'] = $t_value->note_type;
 322          $t_bugnote['note_attr'] = $t_value->note_attr;
 323          
 324          $t_result[] = $t_bugnote;
 325      }
 326  
 327      return (count( $t_result ) == 0 ? null : $t_result );
 328  }
 329  
 330  /**
 331   * Sets the monitors of the specified issue
 332   * 
 333   * <p>This functions performs access level checks and only performs operations which would
 334   * modify the existing monitors list.</p>
 335   * 
 336   * @param int $p_issue_id the issue id to set the monitors for
 337   * @param int $p_user_id the user which requests the monitor change
 338   * @param array $p_monitors An array of arrays with the <em>id</em> field set to the id 
 339   *  of the users which should monitor this issue.
 340   */
 341  function mci_issue_set_monitors( $p_issue_id , $p_user_id, $p_monitors ) {
 342      
 343      $t_existing_monitors = bug_get_monitors( $p_issue_id );
 344  
 345      $t_monitors = array();
 346      foreach ( $p_monitors as $t_monitor ) 
 347          $t_monitors[] = $t_monitor['id'];
 348      
 349      foreach ( $t_monitors as $t_user_id ) {
 350          
 351          if ( $p_user_id == $t_user_id ) {
 352              if ( ! access_has_bug_level( config_get( 'monitor_bug_threshold' ), $p_issue_id ) )
 353                  continue;
 354          } else {
 355              if ( !access_has_bug_level( config_get( 'monitor_add_others_bug_threshold' ), $p_issue_id ) )
 356                  continue;
 357          }
 358              
 359         if ( in_array( $p_user_id, $t_existing_monitors) )
 360             continue;
 361              
 362          bug_monitor( $p_issue_id, $t_user_id);
 363      }
 364      
 365      foreach ( $t_existing_monitors as $t_user_id ) {
 366  
 367          if ( $p_user_id == $t_user_id ) {
 368              if ( ! access_has_bug_level( config_get( 'monitor_bug_threshold' ), $p_issue_id ) )
 369                  continue;
 370          } else {
 371              if ( !access_has_bug_level( config_get( 'monitor_delete_others_bug_threshold' ), $p_issue_id ) )
 372                  continue;
 373          }
 374          
 375          if ( in_array( $p_user_id, $t_monitors) )
 376              continue;
 377              
 378          bug_unmonitor( $p_issue_id, $t_user_id);
 379      }
 380  }
 381  
 382  /**
 383   * Get the biggest issue id currently used.
 384   *
 385   * @param string $p_username  The name of the user trying to retrieve the information
 386   * @param string $p_password  The password of the user.
 387   * @param int    $p_project_id    -1 default project, 0 for all projects, otherwise project id.
 388   * @return integer  The biggest used issue id.
 389   */
 390  function mc_issue_get_biggest_id( $p_username, $p_password, $p_project_id ) {
 391      $t_user_id = mci_check_login( $p_username, $p_password );
 392      if( $t_user_id === false ) {
 393          return mci_soap_fault_login_failed();
 394      }
 395  
 396      $t_any = defined( 'META_FILTER_ANY' ) ? META_FILTER_ANY : 'any';
 397      $t_none = defined( 'META_FILTER_NONE' ) ? META_FILTER_NONE : 'none';
 398  
 399      $t_filter = array(
 400          'category_id' => Array(
 401              '0' => $t_any,
 402          ),
 403          'severity' => Array(
 404              '0' => $t_any,
 405          ),
 406          'status' => Array(
 407              '0' => $t_any,
 408          ),
 409          'highlight_changed' => 0,
 410          'reporter_id' => Array(
 411              '0' => $t_any,
 412          ),
 413          'handler_id' => Array(
 414              '0' => $t_any,
 415          ),
 416          'resolution' => Array(
 417              '0' => $t_any,
 418          ),
 419          'build' => Array(
 420              '0' => $t_any,
 421          ),
 422          'version' => Array(
 423              '0' => $t_any,
 424          ),
 425          'hide_status' => Array(
 426              '0' => $t_none,
 427          ),
 428          'monitor_user_id' => Array(
 429              '0' => $t_any,
 430          ),
 431          'dir' => 'DESC',
 432          'sort' => 'id',
 433      );
 434  
 435      $t_page_number = 1;
 436      $t_per_page = 1;
 437      $t_bug_count = 0;
 438      $t_page_count = 0;
 439  
 440      # Get project id, if -1, then retrieve the current which will be the default since there is no cookie.
 441      $t_project_id = $p_project_id;
 442      if( $t_project_id == -1 ) {
 443          $t_project_id = helper_get_current_project();
 444      }
 445  
 446      if(( $t_project_id > 0 ) && !project_exists( $t_project_id ) ) {
 447          return new soap_fault( 'Client', '', "Project '$t_project_id' does not exist." );
 448      }
 449  
 450      if( !mci_has_readonly_access( $t_user_id, $t_project_id ) ) {
 451          return mci_soap_fault_access_denied( $t_user_id );
 452      }
 453  
 454      $t_rows = filter_get_bug_rows( $t_page_number, $t_per_page, $t_page_count, $t_bug_count, $t_filter, $t_project_id, $t_user_id );
 455      if( count( $t_rows ) == 0 ) {
 456          return 0;
 457      } else {
 458          return $t_rows[0]->id;
 459      }
 460  }
 461  
 462  /**
 463   * Get the id of an issue via the issue's summary.
 464   *
 465   * @param string $p_username  The name of the user trying to delete the issue.
 466   * @param string $p_password  The password of the user.
 467   * @param string $p_summary  The summary of the issue to retrieve.
 468   * @return integer  The id of the issue with the given summary, 0 if there is no such issue.
 469   */
 470  function mc_issue_get_id_from_summary( $p_username, $p_password, $p_summary ) {
 471      $t_user_id = mci_check_login( $p_username, $p_password );
 472      if( $t_user_id === false ) {
 473          return mci_soap_fault_login_failed();
 474      }
 475  
 476      $t_bug_table = db_get_table( 'bug' );
 477  
 478      $query = "SELECT id
 479          FROM $t_bug_table
 480          WHERE summary = " . db_param();
 481  
 482      $result = db_query_bound( $query, Array( $p_summary ), 1 );
 483  
 484      if( db_num_rows( $result ) == 0 ) {
 485          return 0;
 486      } else {
 487          while(( $row = db_fetch_array( $result ) ) !== false ) {
 488              $t_issue_id = (int) $row['id'];
 489              $t_project_id = bug_get_field( $t_issue_id, 'project_id' );
 490  
 491              if( mci_has_readonly_access( $t_user_id, $t_project_id ) ) {
 492                  return $t_issue_id;
 493              }
 494          }
 495  
 496          // no issue found that belongs to a project that the user has read access to.
 497          return 0;
 498      }
 499  }
 500  
 501  /**
 502   * Add an issue to the database.
 503   *
 504   * @param string $p_username  The name of the user trying to add the issue.
 505   * @param string $p_password  The password of the user.
 506   * @param Array $p_issue  A IssueData structure containing information about the new issue.
 507   * @return integer  The id of the created issue.
 508   */
 509  function mc_issue_add( $p_username, $p_password, $p_issue ) {
 510      $t_user_id = mci_check_login( $p_username, $p_password );
 511      if( $t_user_id === false ) {
 512          return mci_soap_fault_login_failed();
 513      }
 514  
 515      $t_project = $p_issue['project'];
 516  
 517      $t_project_id = mci_get_project_id( $t_project );
 518  
 519      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 520          return mci_soap_fault_access_denied( $t_user_id );
 521      }
 522  
 523      $t_handler_id = isset( $p_issue['handler'] ) ? mci_get_user_id( $p_issue['handler'] ) : 0;
 524      $t_priority_id = isset( $p_issue['priority'] ) ? mci_get_priority_id( $p_issue['priority'] ) : config_get( 'default_bug_priority' );
 525      $t_severity_id = isset( $p_issue['severity'] ) ?  mci_get_severity_id( $p_issue['severity'] ) : config_get( 'default_bug_severity' );
 526      $t_status_id = isset( $p_issue['status'] ) ? mci_get_status_id( $p_issue['status'] ) : config_get( 'bug_submit_status' );
 527      $t_reproducibility_id = isset( $p_issue['reproducibility'] ) ?  mci_get_reproducibility_id( $p_issue['reproducibility'] ) : config_get( 'default_bug_reproducibility' );
 528      $t_resolution_id =  isset( $p_issue['resolution'] ) ? mci_get_resolution_id( $p_issue['resolution'] ) : config_get('default_bug_resolution');
 529      $t_projection_id = isset( $p_issue['projection'] ) ? mci_get_projection_id( $p_issue['projection'] ) : config_get('default_bug_resolution');
 530      $t_eta_id = isset( $p_issue['eta'] ) ? mci_get_eta_id( $p_issue['eta'] ) : config_get('default_bug_eta');
 531      $t_view_state_id = isset( $p_issue['view_state'] ) ?  mci_get_view_state_id( $p_issue['view_state'] ) : config_get( 'default_bug_view_status' );
 532      $t_reporter_id = isset( $p_issue['reporter'] ) ? mci_get_user_id( $p_issue['reporter'] )  : 0;
 533      $t_summary = $p_issue['summary'];
 534      $t_description = $p_issue['description'];
 535      $t_notes = isset( $p_issue['notes'] ) ? $p_issue['notes'] : array();
 536  
 537      if( $t_reporter_id == 0 ) {
 538          $t_reporter_id = $t_user_id;
 539      } else {
 540          if( $t_reporter_id != $t_user_id ) {
 541  
 542              # Make sure that active user has access level required to specify a different reporter.
 543              $t_specify_reporter_access_level = config_get( 'mc_specify_reporter_on_add_access_level_threshold' );
 544              if( !access_has_project_level( $t_specify_reporter_access_level, $t_project_id, $t_user_id ) ) {
 545                  return mci_soap_fault_access_denied( $t_user_id, "Active user does not have access level required to specify a different issue reporter" );
 546              }
 547          }
 548      }
 549  
 550      if(( $t_project_id == 0 ) || !project_exists( $t_project_id ) ) {
 551          if( $t_project_id == 0 ) {
 552              return new soap_fault( 'Client', '', "Project '" . $t_project['name'] . "' does not exist." );
 553          } else {
 554              return new soap_fault( 'Client', '', "Project with id '" . $t_project_id . "' does not exist." );
 555          }
 556      }
 557  
 558      if( !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $t_user_id ) ) {
 559          return mci_soap_fault_access_denied( "User '$t_user_id' does not have access right to report issues" );
 560      }
 561  
 562      #if ( !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id ) ||
 563      #    !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $v_reporter ) ) {
 564      #    return new soap_fault( 'Client', '', "User does not have access right to report issues." );
 565      #}
 566  
 567      if(( $t_handler_id != 0 ) && !user_exists( $t_handler_id ) ) {
 568          return new soap_fault( 'Client', '', "User '$t_handler_id' does not exist." );
 569      }
 570  
 571      $t_category = isset ( $p_issue['category'] ) ? $p_issue['category'] : null;
 572  
 573      $t_category_id = translate_category_name_to_id( $t_category, $t_project_id );
 574      if ( $t_category_id == 0 && !config_get( 'allow_no_category' ) ) {
 575          if ( !isset( $p_issue['category'] ) || is_blank( $p_issue['category'] ) ) {
 576              return new soap_fault( 'Client', '', "Category field must be supplied." );
 577          } else {
 578              return new soap_fault( 'Client', '', "Category '" . $p_issue['category'] . "' not found for project '$t_project_id'." );
 579          }
 580      }
 581  
 582      if ( isset( $p_issue['version'] ) && !is_blank( $p_issue['version'] ) && !version_get_id( $p_issue['version'], $t_project_id ) ) {
 583          $t_version = $p_issue['version'];
 584  
 585          $t_error_when_version_not_found = config_get( 'mc_error_when_version_not_found' );
 586          if( $t_error_when_version_not_found == ON ) {
 587              $t_project_name = project_get_name( $t_project_id );
 588              return new soap_fault( 'Client', '', "Version '$t_version' does not exist in project '$t_project_name'." );
 589          } else {
 590              $t_version_when_not_found = config_get( 'mc_version_when_not_found' );
 591              $t_version = $t_version_when_not_found;
 592          }
 593      }
 594  
 595      if ( is_blank( $t_summary ) ) {
 596          return new soap_fault( 'Client', '', "Mandatory field 'summary' is missing." );
 597      }
 598  
 599      if ( is_blank( $t_description ) ) {
 600          return new soap_fault( 'Client', '', "Mandatory field 'description' is missing." );
 601      }
 602  
 603      $t_bug_data = new BugData;
 604      $t_bug_data->profile_id = 0;
 605      $t_bug_data->project_id = $t_project_id;
 606      $t_bug_data->reporter_id = $t_reporter_id;
 607      $t_bug_data->handler_id = $t_handler_id;
 608      $t_bug_data->priority = $t_priority_id;
 609      $t_bug_data->severity = $t_severity_id;
 610      $t_bug_data->reproducibility = $t_reproducibility_id;
 611      $t_bug_data->status = $t_status_id;
 612      $t_bug_data->resolution = $t_resolution_id;
 613      $t_bug_data->projection = $t_projection_id;
 614      $t_bug_data->category_id = $t_category_id;
 615      $t_bug_data->date_submitted = isset( $p_issue['date_submitted'] ) ? $p_issue['date_submitted'] : '';
 616      $t_bug_data->last_updated = isset( $p_issue['last_updated'] ) ? $p_issue['last_updated'] : '';
 617      $t_bug_data->eta = $t_eta_id;
 618      $t_bug_data->os = isset( $p_issue['os'] ) ? $p_issue['os'] : '';
 619      $t_bug_data->os_build = isset( $p_issue['os_build'] ) ? $p_issue['os_build'] : '';
 620      $t_bug_data->platform = isset( $p_issue['platform'] ) ? $p_issue['platform'] : '';
 621      $t_bug_data->version = isset( $p_issue['version'] ) ? $p_issue['version'] : '';
 622      $t_bug_data->fixed_in_version = isset( $p_issue['fixed_in_version'] ) ? $p_issue['fixed_in_version'] : '';
 623      $t_bug_data->build = isset( $p_issue['build'] ) ? $p_issue['build'] : '';
 624      $t_bug_data->view_state = $t_view_state_id;
 625      $t_bug_data->summary = $t_summary;
 626      $t_bug_data->sponsorship_total = isset( $p_issue['sponsorship_total'] ) ? $p_issue['sponsorship_total'] : 0;
 627  
 628      if ( isset( $p_issue['due_date'] ) && access_has_global_level( config_get( 'due_date_update_threshold' ) ) ) {
 629          $t_bug_data->due_date = mci_iso8601_to_timestamp( $p_issue['due_date'] );
 630      } else {
 631          $t_bug_data->due_date = date_get_null();
 632      }
 633  
 634      if( access_has_project_level( config_get( 'roadmap_update_threshold' ), $t_bug_data->project_id, $t_user_id ) ) {
 635          $t_bug_data->target_version = isset( $p_issue['target_version'] ) ? $p_issue['target_version'] : '';
 636      }
 637      
 638      # omitted:
 639      # var $bug_text_id
 640      # $t_bug_data->profile_id;
 641      # extended info
 642      $t_bug_data->description = $t_description;
 643      $t_bug_data->steps_to_reproduce = isset( $p_issue['steps_to_reproduce'] ) ? $p_issue['steps_to_reproduce'] : '';
 644      $t_bug_data->additional_information = isset( $p_issue['additional_information'] ) ? $p_issue['additional_information'] : '';
 645  
 646      # submit the issue
 647      $t_issue_id = $t_bug_data->create();
 648  
 649      mci_issue_set_custom_fields( $t_issue_id, $p_issue['custom_fields'], false );
 650      if ( isset ( $p_issue['monitors'] ) )
 651          mci_issue_set_monitors( $t_issue_id , $t_user_id, $p_issue['monitors'] );
 652  
 653      if( isset( $t_notes ) && is_array( $t_notes ) ) {
 654          foreach( $t_notes as $t_note ) {
 655              if( isset( $t_note['view_state'] ) ) {
 656                  $t_view_state = $t_note['view_state'];
 657              } else {
 658                  $t_view_state = config_get( 'default_bugnote_view_status' );
 659              }
 660              
 661              $note_type = isset ( $t_note['note_type'] ) ? (int) $t_note['note_type'] : BUGNOTE;
 662              $note_attr = isset ( $t_note['note_type'] ) ? $t_note['note_attr'] : '';
 663  
 664              $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state );
 665              bugnote_add( $t_issue_id, $t_note['text'], mci_get_time_tracking_from_note( $t_issue_id, $t_note ), $t_view_state_id == VS_PRIVATE, $note_type, $note_attr, $t_user_id, FALSE );
 666          }
 667      }
 668  
 669      email_new_bug( $t_issue_id );
 670  
 671      return $t_issue_id;
 672  }
 673  
 674  /**
 675   * Update Issue in database
 676   *
 677   * Created By KGB
 678   * @param string $p_username The name of the user trying to add the issue.
 679   * @param string $p_password The password of the user.
 680   * @param Array $p_issue A IssueData structure containing information about the new issue.
 681   * @return integer The id of the created issue.
 682   */
 683  function mc_issue_update( $p_username, $p_password, $p_issue_id, $p_issue ) {
 684      $t_user_id = mci_check_login( $p_username, $p_password );
 685      if( $t_user_id === false ) {
 686          return mci_soap_fault_login_failed();
 687      }
 688  
 689      if( !bug_exists( $p_issue_id ) ) {
 690          return new soap_fault( 'Client', '', "Issue '$p_issue_id' does not exist." );
 691      }
 692  
 693      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
 694  
 695      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 696          return mci_soap_fault_access_denied( $t_user_id );
 697      }
 698  
 699      $t_project_id = mci_get_project_id( $p_issue['project'] );
 700      $t_reporter_id = isset( $p_issue['reporter'] ) ? mci_get_user_id( $p_issue['reporter'] )  : $t_user_id ;
 701      $t_handler_id = isset( $p_issue['handler'] ) ? mci_get_user_id( $p_issue['handler'] ) : 0;
 702      $t_project = $p_issue['project'];
 703      $t_summary = isset( $p_issue['summary'] ) ? $p_issue['summary'] : '';
 704      $t_description = isset( $p_issue['description'] ) ? $p_issue['description'] : '';
 705      
 706      
 707      if(( $t_project_id == 0 ) || !project_exists( $t_project_id ) ) {
 708          if( $t_project_id == 0 ) {
 709              return new soap_fault( 'Client', '', "Project '" . $t_project['name'] . "' does not exist." );
 710          }
 711          return new soap_fault( 'Client', '', "Project '$t_project_id' does not exist." );
 712      }
 713  
 714      if( !access_has_bug_level( config_get( 'update_bug_threshold' ), $p_issue_id, $t_user_id ) ) {
 715          return mci_soap_fault_access_denied( $t_user_id,  "Not enough rights to update issues" );
 716      }
 717  
 718      if(( $t_handler_id != 0 ) && !user_exists( $t_handler_id ) ) {
 719          return new soap_fault( 'Client', '', "User '$t_handler_id' does not exist." );
 720      }
 721  
 722      $t_category = isset ( $p_issue['category'] ) ? $p_issue['category'] : null;
 723  
 724      $t_category_id = translate_category_name_to_id( $t_category, $t_project_id );
 725      if ( $t_category_id == 0 && !config_get( 'allow_no_category' ) ) {
 726          if ( isset( $p_issue['category'] ) && !is_blank( $p_issue['category'] ) ) {
 727              return new soap_fault( 'Client', '', "Category field must be supplied." );
 728          } else {
 729              return new soap_fault( 'Client', '', "Category '" . $p_issue['category'] . "' not found for project '$t_project_name'." );
 730          }
 731      }
 732  
 733      if ( isset( $p_issue['version'] ) && !is_blank( $p_issue['version'] ) && !version_get_id( $p_issue['version'], $t_project_id ) ) {
 734          $t_error_when_version_not_found = config_get( 'mc_error_when_version_not_found' );
 735          if( $t_error_when_version_not_found == ON ) {
 736              $t_project_name = project_get_name( $t_project_id );
 737              return new soap_fault( 'Client', '', "Version '" . $p_issue['version'] . "' does not exist in project '$t_project_name'." );
 738          } else {
 739              $t_version_when_not_found = config_get( 'mc_version_when_not_found' );
 740              $p_issue['version'] = $t_version_when_not_found;
 741          }
 742      }
 743  
 744      if ( is_blank( $t_summary ) ) {
 745          return new soap_fault( 'Client', '', "Mandatory field 'summary' is missing." );
 746      }
 747  
 748      if ( is_blank( $t_description ) ) {
 749          return new soap_fault( 'Client', '', "Mandatory field 'description' is missing." );
 750      }
 751  
 752      // fields which we expect to always be set
 753      $t_bug_data = bug_get( $p_issue_id, true );
 754      $t_bug_data->project_id = $t_project_id;
 755      $t_bug_data->reporter_id = $t_reporter_id;
 756      $t_bug_data->handler_id = $t_handler_id;
 757      $t_bug_data->category_id = $t_category_id;
 758      $t_bug_data->summary = $t_summary;
 759      $t_bug_data->description = $t_description;
 760  
 761      // fields which might not be set
 762      if ( isset ( $p_issue['steps_to_reproduce'] ) )
 763          $t_bug_data->steps_to_reproduce = $p_issue['steps_to_reproduce'];
 764      if ( isset ( $p_issue['additional_information'] ) )
 765          $t_bug_data->additional_information = $p_issue['additional_information'];
 766      if ( isset( $p_issue['priority'] ) )
 767          $t_bug_data->priority = mci_get_priority_id( $p_issue['priority'] );
 768      if ( isset( $p_issue['severity'] ) )
 769          $t_bug_data->severity = mci_get_severity_id( $p_issue['severity'] );
 770      if ( isset( $p_issue['status'] ) )
 771          $t_bug_data->status = mci_get_status_id ( $p_issue['status'] );
 772      if ( isset ( $p_issue['reproducibility'] ) )
 773          $t_bug_data->reproducibility = mci_get_reproducibility_id( $p_issue['reproducibility'] );
 774      if ( isset ( $p_issue['resolution'] ) )
 775          $t_bug_data->resolution = mci_get_resolution_id( $p_issue['resolution'] );
 776      if ( isset ( $p_issue['projection'] ) )
 777          $t_bug_data->projection = mci_get_projection_id( $p_issue['projection'] );
 778      if ( isset ( $p_issue['eta'] ) )
 779          $t_bug_data->eta = mci_get_eta_id( $p_issue['eta'] );
 780      if ( isset ( $p_issue['view_state'] ) )
 781          $t_bug_data->view_state = mci_get_view_state_id( $p_issue['view_state'] );
 782      if ( isset ( $p_issue['date_submitted'] ) )
 783          $t_bug_data->date_submitted = $p_issue['date_submitted'];
 784      if ( isset ( $p_issue['date_updated'] ) )
 785          $t_bug_data->last_updated = $p_issue['last_updated'];
 786      if ( isset ( $p_issue['os'] ) )
 787          $t_bug_data->os = $p_issue['os'];
 788      if ( isset ( $p_issue['os_build'] ) )
 789          $t_bug_data->os_build = $p_issue['os_build'];
 790      if ( isset ( $p_issue['build'] ) )
 791          $t_bug_data->build = $p_issue['build'];
 792      if ( isset ( $p_issue['platform'] ) )
 793          $t_bug_data->platform = $p_issue['platform'];
 794      if ( isset ( $p_issue['version'] ) )
 795          $t_bug_data->version = $p_issue['version'];
 796      if ( isset ( $p_issue['fixed_in_version'] ) )
 797          $t_bug_data->fixed_in_version = $p_issue['fixed_in_version'];
 798  
 799      if ( isset( $p_issue['due_date'] ) && access_has_global_level( config_get( 'due_date_update_threshold' ) ) ) {
 800          $t_bug_data->due_date = mci_iso8601_to_timestamp( $p_issue['due_date'] );
 801      } else {
 802          $t_bug_data->due_date = date_get_null();
 803      }
 804  
 805      if( access_has_project_level( config_get( 'roadmap_update_threshold' ), $t_bug_data->project_id, $t_user_id ) ) {
 806          $t_bug_data->target_version = isset( $p_issue['target_version'] ) ? $p_issue['target_version'] : '';
 807      }
 808  
 809  
 810      # submit the issue
 811      $t_is_success = $t_bug_data->update( /* update_extended */ true, /* bypass_email */ true );
 812  
 813      mci_issue_set_custom_fields( $p_issue_id, $p_issue['custom_fields'], true );
 814      if ( isset ( $p_issue['monitors'] ) )
 815          mci_issue_set_monitors( $p_issue_id , $t_user_id, $p_issue['monitors'] );
 816  
 817      if ( isset( $p_issue['notes'] ) && is_array( $p_issue['notes'] ) ) {
 818          foreach ( $p_issue['notes'] as $t_note ) {
 819              if ( isset( $t_note['view_state'] ) ) {
 820                  $t_view_state = $t_note['view_state'];
 821              } else {
 822                  $t_view_state = config_get( 'default_bugnote_view_status' );
 823              }
 824  
 825              if ( isset( $t_note['id'] ) && ( (int)$t_note['id'] > 0 ) ) {
 826                  $t_bugnote_id = (integer)$t_note['id'];
 827                  
 828                  $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state );
 829  
 830                  if ( bugnote_exists( $t_bugnote_id ) ) {
 831                      bugnote_set_text( $t_bugnote_id, $t_note['text'] );
 832                      bugnote_set_view_state( $t_bugnote_id, $t_view_state_id == VS_PRIVATE );
 833      $t_eta_id = isset( $p_issue['eta'] ) ? mci_get_eta_id( $p_issue['eta'] ) : config_get('default_bug_eta');
 834                      bugnote_date_update( $t_bugnote_id );
 835                      if ( isset( $t_note['time_tracking'] ) )
 836                          bugnote_set_time_tracking( $t_bugnote_id, mci_get_time_tracking_from_note( $p_issue_id, $t_note ) );
 837                  }
 838              } else {
 839                  $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state );
 840                  
 841                  $note_type = isset ( $t_note['note_type'] ) ? (int) $t_note['note_type'] : BUGNOTE;
 842                  $note_attr = isset ( $t_note['note_type'] ) ? $t_note['note_attr'] : '';
 843                  
 844                  bugnote_add( $p_issue_id, $t_note['text'], mci_get_time_tracking_from_note( $p_issue_id, $t_note ), $t_view_state_id == VS_PRIVATE, $note_type, $note_attr, $t_user_id, FALSE );
 845              }
 846          }
 847      }
 848  
 849      return $t_is_success;
 850  }
 851  
 852  /**
 853   * Delete the specified issue.
 854   *
 855   * @param string $p_username  The name of the user trying to delete the issue.
 856   * @param string $p_password  The password of the user.
 857   * @param integer $p_issue_id  The id of the issue to delete.
 858   * @return boolean  True if the issue has been deleted successfully, false otherwise.
 859   */
 860  function mc_issue_delete( $p_username, $p_password, $p_issue_id ) {
 861      $t_user_id = mci_check_login( $p_username, $p_password );
 862      if( $t_user_id === false ) {
 863          return mci_soap_fault_login_failed();
 864      }
 865  
 866      if( !bug_exists( $p_issue_id ) ) {
 867          return new soap_fault( 'Client', '', "Issue '$p_issue_id' does not exist.");
 868      }
 869  
 870      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
 871      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 872          return mci_soap_fault_access_denied( $t_user_id );
 873      }
 874  
 875      return bug_delete( $p_issue_id );
 876  }
 877  
 878  /**
 879   * Add a note to an existing issue.
 880   *
 881   * @param string $p_username  The name of the user trying to add a note to an issue.
 882   * @param string $p_password  The password of the user.
 883   * @param integer $p_issue_id  The id of the issue to add the note to.
 884   * @param IssueNoteData $p_note  The note to add.
 885   * @return integer The id of the added note.
 886   */
 887  function mc_issue_note_add( $p_username, $p_password, $p_issue_id, $p_note ) {
 888      $t_user_id = mci_check_login( $p_username, $p_password );
 889      if( $t_user_id === false ) {
 890          return mci_soap_fault_login_failed();
 891      }
 892  
 893      if( (integer) $p_issue_id < 1 ) {
 894          return new soap_fault( 'Client', '', "Invalid issue id '$p_issue_id'" );
 895      }
 896  
 897      if( !bug_exists( $p_issue_id ) ) {
 898          return new soap_fault( 'Client', '', "Issue '$p_issue_id' does not exist." );
 899      }
 900  
 901      if ( !isset( $p_note['text'] ) || is_blank( $p_note['text'] ) ) {
 902          return new soap_fault( 'Client', '', "Issue note text must not be blank." );
 903      }
 904  
 905      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
 906      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 907          return mci_soap_fault_access_denied( $t_user_id );
 908      }
 909  
 910      if( !access_has_bug_level( config_get( 'add_bugnote_threshold' ), $p_issue_id, $t_user_id ) ) {
 911          return mci_soap_fault_access_denied( $t_user_id, "You do not have access rights to add notes to this issue" );
 912      }
 913  
 914      if( bug_is_readonly( $p_issue_id ) ) {
 915          return mci_soap_fault_access_denied( $t_user_id, "Issue '$p_issue_id' is readonly" );
 916      }
 917  
 918      if( isset( $p_note['view_state'] ) ) {
 919          $t_view_state = $p_note['view_state'];
 920      } else {
 921          $t_view_state = array(
 922              'id' => config_get( 'default_bug_view_status' ),
 923          );
 924      }
 925  
 926      $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state );
 927      
 928      $note_type = isset ( $p_note['note_type'] ) ? (int) $p_note['note_type'] : BUGNOTE;
 929      $note_attr = isset ( $p_note['note_type'] ) ? $p_note['note_attr'] : '';
 930  
 931      return bugnote_add( $p_issue_id, $p_note['text'], mci_get_time_tracking_from_note( $p_issue_id, $p_note ), $t_view_state_id == VS_PRIVATE, $note_type, $note_attr, $t_user_id );
 932  }
 933  
 934  /**
 935   * Delete a note given its id.
 936   *
 937   * @param string $p_username  The name of the user trying to add a note to an issue.
 938   * @param string $p_password  The password of the user.
 939   * @param integer $p_issue_note_id  The id of the note to be deleted.
 940   * @return true: success, false: failure
 941   */
 942  function mc_issue_note_delete( $p_username, $p_password, $p_issue_note_id ) {
 943      $t_user_id = mci_check_login( $p_username, $p_password );
 944      if( $t_user_id === false ) {
 945          return mci_soap_fault_login_failed();
 946      }
 947  
 948      if( (integer) $p_issue_note_id < 1 ) {
 949          return new soap_fault( 'Client', '', "Invalid issue note id '$p_issue_note_id'.");
 950      }
 951  
 952      if( !bugnote_exists( $p_issue_note_id ) ) {
 953          return new soap_fault( 'Client', '', "Issue note '$p_issue_note_id' does not exist.");
 954      }
 955  
 956      $t_issue_id = bugnote_get_field( $p_issue_note_id, 'bug_id' );
 957      $t_project_id = bug_get_field( $t_issue_id, 'project_id' );
 958      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 959          return mci_soap_fault_access_denied( $t_user_id );
 960      }
 961  
 962      return bugnote_delete( $p_issue_note_id );
 963  }
 964  
 965  /**
 966   * Update a note
 967   *
 968   * @param string $p_username  The name of the user trying to add a note to an issue.
 969   * param string $p_password  The password of the user.
 970   * @param IssueNoteData $p_note  The note to update.
 971   * @return true on success, false on failure
 972   */
 973  function mc_issue_note_update( $p_username, $p_password, $p_note ) {
 974      $t_user_id = mci_check_login( $p_username, $p_password );
 975      
 976      if( $t_user_id === false ) {
 977          return mci_soap_fault_login_failed();
 978      }
 979  
 980      if ( !isset( $p_note['id'] ) || is_blank( $p_note['id'] ) ) {
 981          return new soap_fault( 'Client', '', "Issue id must not be blank." );
 982      }
 983      
 984      if ( !isset( $p_note['text'] ) || is_blank( $p_note['text'] ) ) {
 985          return new soap_fault( 'Client', '', "Issue note text must not be blank." );
 986      }
 987      
 988      $t_issue_note_id = $p_note['id'];
 989  
 990      if( !bugnote_exists( $t_issue_note_id ) ) {
 991          return new soap_fault( 'Server', '', "Issue note '$t_issue_note_id' does not exist." );
 992      }
 993      
 994      $t_issue_id = bugnote_get_field( $t_issue_note_id, 'bug_id' );
 995      
 996      $t_project_id = bug_get_field( $t_issue_id, 'project_id' );
 997  
 998      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
 999          return mci_soap_fault_access_denied( $t_user_id );
1000      }
1001  
1002      if( !access_has_bug_level( config_get( 'add_bugnote_threshold' ), $t_issue_id, $t_user_id ) ) {
1003          return mci_soap_fault_access_denied( $t_user_id, "You do not have access rights to add notes to this issue" );
1004      }
1005  
1006      if( bug_is_readonly( $t_issue_id ) ) {
1007          return mci_soap_fault_access_denied( $t_user_id, "Issue ' . $t_issue_id . ' is readonly" );
1008      }
1009  
1010      if( isset( $p_note['view_state'] )) {
1011          $t_view_state = $p_note['view_state'];
1012          $t_view_state_id = mci_get_enum_id_from_objectref( 'view_state', $t_view_state );
1013          bugnote_set_view_state( $t_issue_note_id, $t_view_state_id );
1014      }
1015  
1016      bugnote_set_text( $t_issue_note_id, $p_note['text'] );
1017  
1018      return bugnote_date_update( $t_issue_note_id );
1019  }
1020  
1021  /**
1022   * Submit a new relationship.
1023   *
1024   * @param string $p_username  The name of the user trying to add a note to an issue.
1025   * @param string $p_password  The password of the user.
1026   * @param integer $p_issue_id  The id of the issue of the source issue.
1027   * @param RelationshipData $p_relationship  The relationship to add.
1028   * @return integer The id of the added relationship.
1029   */
1030  function mc_issue_relationship_add( $p_username, $p_password, $p_issue_id, $p_relationship ) {
1031      $t_user_id = mci_check_login( $p_username, $p_password );
1032      $t_dest_issue_id = $p_relationship['target_id'];
1033      $t_rel_type = $p_relationship['type'];
1034  
1035      if( $t_user_id === false ) {
1036          return mci_soap_fault_login_failed();
1037      }
1038  
1039      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
1040      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
1041          return mci_soap_fault_access_denied( $t_user_id );
1042      }
1043  
1044      # user has access to update the bug...
1045      if( !access_has_bug_level( config_get( 'update_bug_threshold' ), $p_issue_id, $t_user_id ) ) {
1046          return mci_soap_fault_access_denied( $t_user_id, "Active user does not have access level required to add a relationship to this issue" );
1047      }
1048  
1049      # source and destination bugs are the same bug...
1050      if( $p_issue_id == $t_dest_issue_id ) {
1051          return new soap_fault( 'Client', '', "An issue can't be related to itself." );
1052      }
1053  
1054      # the related bug exists...
1055      if( !bug_exists( $t_dest_issue_id ) ) {
1056          return new soap_fault( 'Client', '', "Issue '$t_dest_issue_id' not found." );
1057      }
1058  
1059      # bug is not read-only...
1060      if( bug_is_readonly( $p_issue_id ) ) {
1061          return new mci_soap_fault_access_denied( $t_user_id, "Issue '$p_issue_id' is readonly" );
1062      }
1063  
1064      # user can access to the related bug at least as viewer...
1065      if( !access_has_bug_level( VIEWER, $t_dest_issue_id, $t_user_id ) ) {
1066          return mci_soap_fault_access_denied( $t_user_id, "The issue '$t_dest_issue_id' requires higher access level" );
1067      }
1068  
1069      $t_old_id_relationship = relationship_same_type_exists( $p_issue_id, $t_dest_issue_id, $t_rel_type['id'] );
1070  
1071      if( $t_old_id_relationship == 0 ) {
1072          relationship_add( $p_issue_id, $t_dest_issue_id, $t_rel_type['id'] );
1073  
1074          // The above function call into MantisBT does not seem to return a valid BugRelationshipData object.
1075          // So we call db_insert_id in order to find the id of the created relationship.
1076          $t_relationship_id = db_insert_id( db_get_table( 'bug_relationship' ) );
1077  
1078          # Add log line to the history (both bugs)
1079          history_log_event_special( $p_issue_id, BUG_ADD_RELATIONSHIP, $t_rel_type['id'], $t_dest_issue_id );
1080          history_log_event_special( $t_dest_issue_id, BUG_ADD_RELATIONSHIP, relationship_get_complementary_type( $t_rel_type['id'] ), $p_issue_id );
1081  
1082          # update bug last updated for both bugs
1083          bug_update_date( $p_issue_id );
1084          bug_update_date( $t_dest_issue_id );
1085  
1086          # send email notification to the users addressed by both the bugs
1087          email_relationship_added( $p_issue_id, $t_dest_issue_id, $t_rel_type['id'] );
1088          email_relationship_added( $t_dest_issue_id, $p_issue_id, relationship_get_complementary_type( $t_rel_type['id'] ) );
1089  
1090          return $t_relationship_id;
1091      } else {
1092          return new soap_fault( 'Client', '', "Relationship already exists." );
1093      }
1094  }
1095  
1096  /**
1097   * Delete the relationship with the specified target id.
1098   *
1099   * @param string $p_username  The name of the user trying to add a note to an issue.
1100   * @param string $p_password  The password of the user.
1101   * @param integer $p_issue_id  The id of the source issue for the relationship
1102   * @param integer $p_relationship_id  The id of relationship to delete.
1103   * @return true: success, false: failure
1104   */
1105  function mc_issue_relationship_delete( $p_username, $p_password, $p_issue_id, $p_relationship_id ) {
1106      $t_user_id = mci_check_login( $p_username, $p_password );
1107  
1108      if( $t_user_id === false ) {
1109          return mci_soap_fault_login_failed();
1110      }
1111  
1112      $t_project_id = bug_get_field( $p_issue_id, 'project_id' );
1113      if( !mci_has_readwrite_access( $t_user_id, $t_project_id ) ) {
1114          return mci_soap_fault_access_denied( $t_user_id );
1115      }
1116  
1117      # user has access to update the bug...
1118      if( !access_has_bug_level( config_get( 'update_bug_threshold' ), $p_issue_id, $t_user_id ) ) {
1119          return mci_soap_fault_access_denied( $t_user_id , "Active user does not have access level required to remove a relationship from this issue." );
1120      }
1121  
1122      # bug is not read-only...
1123      if( bug_is_readonly( $p_issue_id ) ) {
1124          return mci_soap_fault_access_denied( $t_user_id , "Issue '$p_issue_id' is readonly." );
1125      }
1126  
1127      # retrieve the destination bug of the relationship
1128      $t_dest_issue_id = relationship_get_linked_bug_id( $p_relationship_id, $p_issue_id );
1129  
1130      # user can access to the related bug at least as viewer, if it's exist...
1131      if( bug_exists( $t_dest_issue_id ) ) {
1132          if( !access_has_bug_level( VIEWER, $t_dest_issue_id, $t_user_id ) ) {
1133              return mci_soap_fault_access_denied( $t_user_id , "The issue '$t_dest_issue_id' requires higher access level." );
1134          }
1135      }
1136  
1137      $t_bug_relationship_data = relationship_get( $p_relationship_id );
1138      $t_rel_type = $t_bug_relationship_data->type;
1139  
1140      # delete relationship from the DB
1141      relationship_delete( $p_relationship_id );
1142  
1143      # update bug last updated
1144      bug_update_date( $p_issue_id );
1145      bug_update_date ( $t_dest_issue_id );
1146  
1147      # set the rel_type for both bug and dest_bug based on $t_rel_type and on who is the dest bug
1148      if( $p_issue_id == $t_bug_relationship_data->src_bug_id ) {
1149          $t_bug_rel_type = $t_rel_type;
1150          $t_dest_bug_rel_type = relationship_get_complementary_type( $t_rel_type );
1151      } else {
1152          $t_bug_rel_type = relationship_get_complementary_type( $t_rel_type );
1153          $t_dest_bug_rel_type = $t_rel_type;
1154      }
1155  
1156      # send email and update the history for the src issue
1157      history_log_event_special( $p_issue_id, BUG_DEL_RELATIONSHIP, $t_bug_rel_type, $t_dest_issue_id );
1158      email_relationship_deleted( $p_issue_id, $t_dest_issue_id, $t_bug_rel_type );
1159  
1160      if( bug_exists( $t_dest_issue_id ) ) {
1161  
1162          # send email and update the history for the dest issue
1163          history_log_event_special( $t_dest_issue_id, BUG_DEL_RELATIONSHIP, $t_dest_bug_rel_type, $p_issue_id );
1164          email_relationship_deleted( $t_dest_issue_id, $p_issue_id, $t_dest_bug_rel_type );
1165      }
1166  
1167      return true;
1168  }
1169  
1170  /**
1171   * Returns the date in iso8601 format, with proper timezone offset applied
1172   *
1173   * @param string $p_date the date in iso8601 format
1174   * @return int the timestamp
1175   */
1176  function mci_iso8601_to_timestamp( $p_date ) {
1177  
1178      // retrieve the offset, seems to be lost by nusoap
1179      $t_utc_date = new DateTime( $p_date, new DateTimeZone( 'UTC' ) );
1180      $t_timezone = new DateTimeZone( date_default_timezone_get() );
1181      $t_offset = $t_timezone->getOffset( $t_utc_date );
1182  
1183      $t_raw_timestamp = iso8601_to_timestamp( $p_date );
1184  
1185      return $t_raw_timestamp - $t_offset;
1186  
1187  }
1188  
1189  
1190  /**
1191   * Returns an array for SOAP encoding from a BugData object
1192   *
1193   * @param BugData $p_issue_data
1194   * @param int $p_user_id
1195   * @param string $p_lang
1196   * @return array The issue as an array
1197   */
1198  function mci_issue_data_as_array( $p_issue_data, $p_user_id, $p_lang ) {
1199  
1200          $t_id = $p_issue_data->id;
1201  
1202          $t_issue = array();
1203          $t_issue['id'] = $t_id;
1204          $t_issue['view_state'] = mci_enum_get_array_by_id( $p_issue_data->view_state, 'view_state', $p_lang );
1205          $t_issue['last_updated'] = timestamp_to_iso8601( $p_issue_data->last_updated );
1206  
1207          $t_issue['project'] = mci_project_as_array_by_id( $p_issue_data->project_id );
1208          $t_issue['category'] = mci_get_category( $p_issue_data->category_id );
1209          $t_issue['priority'] = mci_enum_get_array_by_id( $p_issue_data->priority, 'priority', $p_lang );
1210          $t_issue['severity'] = mci_enum_get_array_by_id( $p_issue_data->severity, 'severity', $p_lang );
1211          $t_issue['status'] = mci_enum_get_array_by_id( $p_issue_data->status, 'status', $p_lang );
1212  
1213          $t_issue['reporter'] = mci_account_get_array_by_id( $p_issue_data->reporter_id );
1214          $t_issue['summary'] = $p_issue_data->summary;
1215          $t_issue['version'] = mci_null_if_empty( $p_issue_data->version );
1216          $t_issue['build'] = mci_null_if_empty( $p_issue_data->build );
1217          $t_issue['platform'] = mci_null_if_empty( $p_issue_data->platform );
1218          $t_issue['os'] = mci_null_if_empty( $p_issue_data->os );
1219          $t_issue['os_build'] = mci_null_if_empty( $p_issue_data->os_build );
1220          $t_issue['reproducibility'] = mci_enum_get_array_by_id( $p_issue_data->reproducibility, 'reproducibility', $p_lang );
1221          $t_issue['date_submitted'] = timestamp_to_iso8601( $p_issue_data->date_submitted );
1222          $t_issue['sponsorship_total'] = $p_issue_data->sponsorship_total;
1223  
1224          if( !empty( $p_issue_data->handler_id ) ) {
1225              $t_issue['handler'] = mci_account_get_array_by_id( $p_issue_data->handler_id );
1226          }
1227          $t_issue['projection'] = mci_enum_get_array_by_id( $p_issue_data->projection, 'projection', $p_lang );
1228          $t_issue['eta'] = mci_enum_get_array_by_id( $p_issue_data->eta, 'eta', $p_lang );
1229  
1230          $t_issue['resolution'] = mci_enum_get_array_by_id( $p_issue_data->resolution, 'resolution', $p_lang );
1231          $t_issue['fixed_in_version'] = mci_null_if_empty( $p_issue_data->fixed_in_version );
1232          $t_issue['target_version'] = mci_null_if_empty( $p_issue_data->target_version );
1233  
1234          $t_issue['description'] = bug_get_text_field( $t_id, 'description' );
1235  
1236          $t_steps_to_reproduce = bug_get_text_field( $t_id, 'steps_to_reproduce' );
1237          $t_issue['steps_to_reproduce'] = mci_null_if_empty( $t_steps_to_reproduce );
1238  
1239          $t_additional_information = bug_get_text_field( $t_id, 'additional_information' );
1240          $t_issue['additional_information'] = mci_null_if_empty( $t_additional_information );
1241  
1242          $t_issue['attachments'] = mci_issue_get_attachments( $p_issue_data->id );
1243          $t_issue['relationships'] = mci_issue_get_relationships( $p_issue_data->id, $p_user_id );
1244          $t_issue['notes'] = mci_issue_get_notes( $p_issue_data->id );
1245          $t_issue['custom_fields'] = mci_issue_get_custom_fields( $p_issue_data->id );
1246  
1247          return $t_issue;
1248  }


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7