Skip to content

Commit

Permalink
Merge branch 'rest_api_improvements'
Browse files Browse the repository at this point in the history
# Conflicts:
#	api/soap/mc_issue_api.php
  • Loading branch information
vboctor committed May 4, 2017
2 parents 85f41b9 + 4fd21d0 commit 55fe1aa
Show file tree
Hide file tree
Showing 19 changed files with 1,503 additions and 310 deletions.
1 change: 1 addition & 0 deletions api/rest/index.php
Expand Up @@ -55,6 +55,7 @@
require_once( $t_restcore_dir . 'internal_rest.php' );
require_once( $t_restcore_dir . 'issues_rest.php' );
require_once( $t_restcore_dir . 'lang_rest.php' );
require_once( $t_restcore_dir . 'projects_rest.php' );
require_once( $t_restcore_dir . 'users_rest.php' );

event_signal( 'EVENT_REST_API_ROUTES', array( array( 'app' => $g_app ) ) );
Expand Down
40 changes: 36 additions & 4 deletions api/rest/restcore/issues_rest.php
Expand Up @@ -40,11 +40,43 @@
* @return \Slim\Http\Response The augmented response.
*/
function rest_issue_get( \Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args ) {
# Username and password below are ignored, since middleware already done the auth.
$t_result = mc_issue_get( /* username */ '', /* password */ '', $p_request->getParam( 'id' ) );
$t_issue_id = $p_request->getParam( 'id' );

if( ApiObjectFactory::isFault( $t_result ) ) {
return $p_response->withStatus( $t_result->status_code, $t_result->fault_string );
if( !is_blank( $t_issue_id ) ) {
# Get Issue By Id

# Username and password below are ignored, since middleware already done the auth.
$t_issue = mc_issue_get( /* username */ '', /* password */ '', $t_issue_id );

if( ApiObjectFactory::isFault( $t_issue ) ) {
return $p_response->withStatus( $t_result->status_code, $t_result->fault_string );
}

$t_result = array( 'issues' => array( $t_issue ) );
} else {
$t_page_number = $p_request->getParam( 'page', 1 );
$t_page_size = $p_request->getParam( 'page_size', 50 );

# Get a set of issues
$t_project_id = (int)$p_request->getParam( 'project_id', ALL_PROJECTS );
if( $t_project_id != ALL_PROJECTS && !project_exists( $t_project_id ) ) {
# TODO: What's best was to escape $t_project?
$t_message = "Project '$t_project_id' doesn't exist";
return $p_response->withStatus( HTTP_STATUS_NOT_FOUND, $t_message );
}

$t_filter_id = (int)$p_request->getParam( 'filter_id', 0 );
if( $t_filter_id !== 0 ) {
# TODO: we should have a better way to do this.
global $g_project_override;
$g_project_override = $t_project_id;

$t_issues = mc_filter_get_issues( '', '', $t_project_id, $t_filter_id, $t_page_number, $t_page_size );
} else {
$t_issues = mc_project_get_issues( '', '', $t_project_id, $t_page_number, $t_page_size );
}

$t_result = array( 'issues' => $t_issues );
}

return $p_response->withStatus( HTTP_STATUS_SUCCESS )->withJson( $t_result );
Expand Down
55 changes: 55 additions & 0 deletions api/rest/restcore/projects_rest.php
@@ -0,0 +1,55 @@
<?php
# MantisBT - A PHP based bugtracking system

# MantisBT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# MantisBT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MantisBT. If not, see <http://www.gnu.org/licenses/>.

/**
* A webservice interface to Mantis Bug Tracker
*
* @package MantisBT
* @copyright Copyright MantisBT Team - mantisbt-dev@lists.sourceforge.net
* @link http://www.mantisbt.org
*/

$g_app->group('/projects', function() use ( $g_app ) {
$g_app->get( '', 'rest_projects_get' );
$g_app->get( '/', 'rest_projects_get' );
});

/**
* A method to get list of projects accessible to user with all their related information.
*
* @param \Slim\Http\Request $p_request The request.
* @param \Slim\Http\Response $p_response The response.
* @param array $p_args Arguments
* @return \Slim\Http\Response The augmented response.
*/
function rest_projects_get( \Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args ) {
$t_user_id = auth_get_current_user_id();
$t_lang = mci_get_user_lang( $t_user_id );

$t_project_ids = user_get_accessible_projects( $t_user_id, /* disabled */ false );
$t_projects = array();

foreach( $t_project_ids as $t_project_id ) {
$t_project = mci_project_get( $t_project_id, $t_lang, /* detail */ true );
$t_projects[] = $t_project;
}

$t_result = array( 'projects' => $t_projects );

return $p_response->withStatus( HTTP_STATUS_SUCCESS )->withJson( $t_result );
}


2 changes: 1 addition & 1 deletion api/rest/restcore/users_rest.php
Expand Up @@ -35,7 +35,7 @@
* @return \Slim\Http\Response The augmented response.
*/
function rest_user_get_me( \Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args ) {
$t_result = mci_user_get( '', '', auth_get_current_user_id() );
$t_result = mci_user_get( auth_get_current_user_id() );
return $p_response->withStatus( HTTP_STATUS_SUCCESS )->withJson( $t_result );
}

Expand Down
166 changes: 124 additions & 42 deletions api/soap/mc_api.php
Expand Up @@ -230,86 +230,84 @@ function mc_login( $p_username, $p_password ) {
return mci_fault_login_failed();
}

return mci_user_get( $p_username, $p_password, $t_user_id );
return mci_user_get( $t_user_id );
}

/**
* Given an id, this method returns the user.
* When calling this method make sure that the caller has the right to retrieve
* information about the target user.
* @param string $p_username Login username.
* @param string $p_password Login password.
* @param integer $p_user_id A valid user identifier.
* @return array array of user data for the supplied user id
*/
function mci_user_get( $p_username, $p_password, $p_user_id ) {
function mci_user_get( $p_user_id ) {
$t_user_data = array();

# if user doesn't exist, then mci_account_get_array_by_id() will throw.
if( ApiObjectFactory::$soap ) {
$t_user_data['account_data'] = mci_account_get_array_by_id( $p_user_id );
$t_user_data['access_level'] = access_get_global_level( $p_user_id );
$t_user_data['timezone'] = user_pref_get_pref( $p_user_id, 'timezone' );
} else {
$t_account_data = mci_account_get_array_by_id( $p_user_id );
foreach( $t_account_data as $t_key => $t_value ) {
$t_user_data[$t_key] = $t_value;
}

$t_user_data['language'] = mci_get_user_lang( $p_user_id );
$t_user_data['timezone'] = user_pref_get_pref( $p_user_id, 'timezone' );

$t_access_level = access_get_global_level( $p_user_id );
$t_user_data['access_level'] = array(
'id' => $t_access_level,
'name' => MantisEnum::getLabel( config_get( 'access_levels_enum_string' ), $t_access_level ),
);
$t_user_data['access_level'] = mci_enum_get_array_by_id(
$t_access_level, 'access_levels', $t_user_data['language'] );

$t_project_ids = user_get_accessible_projects( $p_user_id, /* disabled */ true );
$t_project_ids = user_get_accessible_projects( $p_user_id, /* disabled */ false );
$t_projects = array();
foreach( $t_project_ids as $t_project_id ) {
$t_projects[] = mci_project_get( $t_project_id );
$t_projects[] = mci_project_get( $t_project_id, $t_user_data['language'], /* detail */ false );
}

$t_user_data['projects'] = $t_projects;
}

$t_user_data['timezone'] = user_pref_get_pref( $p_user_id, 'timezone' );

return $t_user_data;
}

/**
* Get project info for the specified id.
*
* @param int $p_project_id The project id to get info for.
* @param string $p_lang The user's language.
* @param bool @p_detail Include all project details vs. just reference info.
* @return array project info.
*/
function mci_project_get( $p_project_id ) {
function mci_project_get( $p_project_id, $p_lang, $p_detail ) {
$t_row = project_get_row( $p_project_id );

$t_user_id = auth_get_current_user_id();
$t_user_access_level = access_get_project_level( $p_project_id, $t_user_id );
$t_access_levels = config_get( 'access_levels_enum_string', /* default */ null, $t_user_id, $p_project_id );

# Get project info that makes sense to publish via API. For example, skip file_path.
$t_project = array(
'id' => $p_project_id,
'name' => $t_row['name'],
'description' => $t_row['description'],
'enabled' => (int)$t_row['enabled'] != 0,
'status' => array(
'id' => (int)$t_row['status'],
'name' => MantisEnum::getLabel( config_get( 'project_status_enum_string' ), (int)$t_row['status'] ) ),
'view_state' => array(
'id' => (int)$t_row['view_state'],
'name' => MantisEnum::getLabel( config_get( 'project_view_state_enum_string' ), (int)$t_row['view_state'] ) ),
'access_min' => array(
'id' => (int)$t_row['access_min'],
'name' => MantisEnum::getLabel( $t_access_levels, (int)$t_row['access_min'] ) ),
'access_level' => array(
'id' => $t_user_access_level,
'name' => MantisEnum::getLabel( $t_access_levels, $t_user_access_level ) ),
);

if( $p_detail ) {
$t_project['status'] = mci_enum_get_array_by_id( (int)$t_row['status'], 'project_status', $p_lang );
$t_project['description'] = $t_row['description'];
$t_project['enabled'] = (int)$t_row['enabled'] != 0;
$t_project['view_state'] = mci_enum_get_array_by_id( (int)$t_row['view_state'], 'view_state', $p_lang );

# access_min field is not used
# $t_project['access_min'] = mci_enum_get_array_by_id( (int)$t_row['access_min'], 'access_levels', $p_lang );

$t_project['access_level'] = mci_enum_get_array_by_id( $t_user_access_level, 'access_levels', $p_lang );
$t_project['custom_fields'] = mci_project_get_custom_fields( $p_project_id );
$t_project['versions'] = mci_project_versions( $p_project_id );
$t_project['categories'] = mci_project_categories( $p_project_id );
}

return $t_project;
}

Expand Down Expand Up @@ -667,20 +665,6 @@ function mci_get_mantis_path() {
return config_get( 'path' );
}

/**
* Given a enum string and num, return the appropriate localized string
* @param string $p_enum_name Enumeration name.
* @param string $p_val Enumeration value.
* @param string $p_lang Language string.
* @return string
*/
function mci_get_enum_element( $p_enum_name, $p_val, $p_lang ) {
$t_enum_string = config_get( $p_enum_name . '_enum_string' );
$t_localized_enum_string = lang_get( $p_enum_name . '_enum_string', $p_lang );

return MantisEnum::getLocalizedLabel( $t_enum_string, $t_localized_enum_string, $p_val );
}

/**
* Gets the sub-projects that are accessible to the specified user / project.
* @param integer $p_user_id User id.
Expand Down Expand Up @@ -714,6 +698,104 @@ function mci_user_get_accessible_subprojects( $p_user_id, $p_parent_project_id,
return $t_result;
}

/**
* Convert version into appropriate format for SOAP/REST.
*
* @param string $p_version The version
* @param int $p_project_id The project id
* @return array|null|string The converted version
*/
function mci_get_version( $p_version, $p_project_id ) {
$t_version_id = version_get_id( $p_version, $p_project_id );
if( $t_version_id === false ) {
return null;
}

if( is_blank( $p_version ) ) {
return null;
}

if( ApiObjectFactory::$soap ) {
return $p_version;
}

return array(
'id' => (int)$t_version_id,
'name' => $p_version,
);
}

/**
* Gets the version id based on version input from the API. This can be
* a string or an object (with id or name or both). If both id and name
* exist on the object, id takes precedence.
*
* @param string|object $p_version The version string or object with name or id or both.
* @param int $p_project_id The project id.
* @return int|RestFault|SoapFault The version id, 0 if not supplied.
*/
function mci_get_version_id( $p_version, $p_project_id ) {
$t_version_id = 0;
$t_version_for_error = '';

if( is_array( $p_version ) ) {
if( isset( $p_version['id'] ) && is_numeric( $p_version['id'] ) ) {
$t_version_id = (int)$p_version['id'];
$t_version_for_error = $p_version['id'];
if( !version_exists( $t_version_id ) ) {
$t_version_id = false;
}
} elseif( isset( $p_version['name'] ) ) {
$t_version_for_error = $p_version['name'];
$t_version_id = version_get_id( $p_version['name'], $p_project_id );
}
} elseif( is_string( $p_version ) && !is_blank( $p_version ) ) {
$t_version_for_error = $p_version;
$t_version_id = version_get_id( $p_version, $p_project_id );
}

# Error when supplied, but not found
if( $t_version_id === false ) {
$t_error_when_version_not_found = config_get( 'webservice_error_when_version_not_found' );
if( $t_error_when_version_not_found == ON ) {
$t_project_name = project_get_name( $p_project_id );
return ApiObjectFactory::faultBadRequest( "Version '$t_version_for_error' does not exist in project '$t_project_name'." );
}

$t_version_when_not_found = config_get( 'webservice_version_when_not_found' );
$t_version_id = version_get_id( $t_version_when_not_found );
}

return $t_version_id;
}


/**
* Returns the category name, possibly null if no category is assigned
*
* @param integer $p_category_id A category identifier.
* @return string
*/
function mci_get_category( $p_category_id ) {
if( ApiObjectFactory::$soap ) {
if( $p_category_id == 0 ) {
# This should be really null, but will leaving it to avoid changing the behavior
return '';
}

return mci_null_if_empty( category_get_name( $p_category_id ) );
}

if( $p_category_id == 0 ) {
return null;
}

return array(
'id' => $p_category_id,
'name' => mci_null_if_empty( category_get_name( $p_category_id ) ),
);
}

/**
* Convert a category name to a category id for a given project
* @param string|array $p_category Category name or array with id and/or name.
Expand Down
20 changes: 19 additions & 1 deletion api/soap/mc_enum_api.php
Expand Up @@ -280,7 +280,25 @@ function mci_validate_enum_access( $p_username, $p_password ) {
function mci_enum_get_array_by_id( $p_enum_id, $p_enum_type, $p_lang ) {
$t_result = array();
$t_result['id'] = (int)$p_enum_id;
$t_result['name'] = mci_get_enum_element( $p_enum_type, $p_enum_id, $p_lang );

$t_enum_name = $p_enum_type . '_enum_string';
$t_enum_string_value = config_get( $t_enum_name );
$t_enum_localized_value = lang_get( $t_enum_name, $p_lang );

if( ApiObjectFactory::$soap ) {
# Soap API returns the localized label as the name
$t_result['name'] = MantisEnum::getLocalizedLabel( $t_enum_string_value, $t_enum_localized_value, $p_enum_id );
} else {
$t_enum_array = MantisEnum::getAssocArrayIndexedByValues( $t_enum_string_value );
$t_result['name'] = $t_enum_array[$p_enum_id];
$t_result['label'] = MantisEnum::getLocalizedLabel( $t_enum_string_value, $t_enum_localized_value, $p_enum_id );

if( $p_enum_type == 'status' ) {
$t_status_colors = config_get( 'status_colors' );
$t_result['color'] = $t_status_colors[$t_result['name']];
}
}

return $t_result;
}

Expand Down

0 comments on commit 55fe1aa

Please sign in to comment.