Skip to content

Commit

Permalink
feat: add support for retrieving tickets using a set of specified fil…
Browse files Browse the repository at this point in the history
…ter property-value pairs.

This is opposed to the default mantis api which requires a saved filter and a filter id to be passed.  See the readme file for details.
  • Loading branch information
spmeesseman committed Aug 26, 2019
1 parent 001c0a4 commit 369cbee
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 15 deletions.
1 change: 1 addition & 0 deletions ApiExtend.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function init()

function config() {
return array(
'issues' => ON,
'issues_count' => ON,
'issues_countbadge' => ON,
'version' => ON,
Expand Down
173 changes: 173 additions & 0 deletions api/core/issues.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?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
*/

use Mantis\Exceptions\ClientException;

$g_app->group('/issues', function() use ( $g_app ) {
$g_app->get( '', 'issues_get' );
$g_app->get( '/', 'issues_get' );
$g_app->get('/{project}', 'issues_get');
$g_app->get('/{project}/', 'issues_get');
$g_app->get('/{project}/{type}', 'issues_get');
$g_app->get('/{project}/{type}/', 'issues_get');
});

/**
* A method that does the work to handle getting an issue via REST API.
*
* @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 issues_get( \Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args )
{
log_event(LOG_PLUGIN, "rest_issue_get");

$t_project_id = 0;

#
# Ensure valid project was provided by client
#
$p_project = isset($p_args['project']) ? $p_args['project'] : $p_request->getParam('project');
if (is_blank($p_project)) {
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "Mandatory field 'project' is missing.");
}
else {
$t_project_id = project_get_id_by_name($p_project, false);
if ($t_project_id == null) {
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "The field 'project' is invalid.");
}
}

#
# Ensure valid type was provided by client
#
$p_type = isset($p_args['type']) ? $p_args['type'] : $p_request->getParam('type');
if (is_blank($p_type)) {
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "Mandatory field 'type' is missing.");
}
else {
if ($p_type != 'closed' && $p_type != 'open' && $p_type != 'all') {
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "The field 'type' is invalid, must be one of 'closed' or 'open'.");
}
}

$t_result = null;
$t_user_id = null;

#
# Get current user and check if upload access is granted
#
$t_user_id = auth_get_current_user_id();
$t_current_user = user_get_username($t_user_id);
log_event(LOG_PLUGIN, "User is %s", $t_current_user);

$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 ) )
{
$t_result = null;
$t_message = "Project '$t_project_id' doesn't exist";
$p_response = $p_response->withStatus( HTTP_STATUS_NOT_FOUND, $t_message );
}
else
{
/*
$t_filter_id = trim( $p_request->getParam( 'filter_id', '' ) );
if( !empty( $t_filter_id ) ) {
$t_issues = mc_filter_get_issues(
'', '', $t_project_id, $t_filter_id, $t_page_number, $t_page_size );
} else {
$t_issues = mc_filter_get_issues(
'', '', $t_project_id, FILTER_STANDARD_ANY, $t_page_number, $t_page_size );
}
$t_result = array( 'issues' => $t_issues );
*/
$t_bug_count = 0;
$t_page_number = 1;
$t_per_page = -1;
$t_page_count = 1;
$t_bug_count_filtered = 0;

$t_status_closed_level = config_get("bug_resolved_status_threshold");

if ( $p_request->getParam('filters') )
{
$t_req_filters = $p_request->getParam('filters');
if ( is_string( $t_req_filters ) ) {
$t_req_filters = json_decode( $t_req_filters, true );
}
foreach ($t_req_filters as $t_filter_num => $t_filter_value ) {
log_event(LOG_PLUGIN, "Applying requested filter (%s) %s", $t_filter_num, implode(",",$t_filter_value));
$_POST[$t_filter_value['property']] = $t_filter_value['value'];
}
}

$_POST['type'] = '1';
$_POST['view_type'] = 'simple';
$_POST['per_page'] = '-1';
$_POST['hide_status'] = '-2';

$t_filter = filter_gpc_get();

$t_issues = array();
$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, true );
if ($t_rows != null)
{
log_event(LOG_PLUGIN, "Examine bugs");

$t_lang = mci_get_user_lang( $t_user_id );

foreach ($t_rows as $t_bug)
{
log_event(LOG_PLUGIN, "ID: %d Status: %s Res: %s", $t_bug->id, $t_bug->status, $t_bug->resolution);

if ($p_type == 'closed') {
if ($t_bug->status >= $t_status_closed_level) {
$t_issues[] = mci_issue_data_as_array( $t_bug, $t_user_id, $t_lang );
}
}
else if ($p_type == 'open') {
if ($t_bug->status < $t_status_closed_level) {
$t_issues[] = mci_issue_data_as_array( $t_bug, $t_user_id, $t_lang );
}
}
else { // 'all'
$t_issues[] = mci_issue_data_as_array( $t_bug, $t_user_id, $t_lang );
}
}
}

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

log_event(LOG_PLUGIN, "Total bug count is %d", count( $t_result ) );
}

return $p_response = $p_response->withStatus( HTTP_STATUS_SUCCESS )->withJson( $t_result );
}
75 changes: 60 additions & 15 deletions api/core/issues_count.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@

function bugcount_svg_get(\Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args)
{
log_event(LOG_PLUGIN, "bugcount_svg_get");
$rsp = bugcount_base($p_request, $p_response, $p_args);
return $p_response->withRedirect($rsp['url']);
}

function bugcount_get(\Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args)
{
log_event(LOG_PLUGIN, "bugcount_get");

$rsp = bugcount_base($p_request, $p_response, $p_args);

#$p_response->write(''.$rsp['count']);
Expand All @@ -43,7 +46,7 @@ function bugcount_get(\Slim\Http\Request $p_request, \Slim\Http\Response $p_resp
'count' => $rsp['count']
);

return $p_response->withStatus(HTTP_STATUS_CREATED, "Success")->withJson($response);
return $p_response->withStatus(HTTP_STATUS_SUCCESS, "Success")->withJson($response);
}

function bugcount_base(\Slim\Http\Request $p_request, \Slim\Http\Response $p_response, array $p_args)
Expand Down Expand Up @@ -72,7 +75,7 @@ function bugcount_base(\Slim\Http\Request $p_request, \Slim\Http\Response $p_res
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "Mandatory field 'type' is missing.");
}
else {
if ($p_type != 'closed' && $p_type != 'open') {
if ($p_type != 'closed' && $p_type != 'open' && $p_type != 'all') {
return $p_response->withStatus(HTTP_STATUS_BAD_REQUEST, "The field 'type' is invalid, must be one of 'closed' or 'open'.");
}
}
Expand All @@ -84,7 +87,7 @@ function bugcount_base(\Slim\Http\Request $p_request, \Slim\Http\Response $p_res
#
$t_user_id = auth_get_current_user_id();
$t_current_user = user_get_username($t_user_id);
log_event(LOG_PLUGIN, "ApiExtend: User is %s", $t_current_user);
log_event(LOG_PLUGIN, "User is %s", $t_current_user);

#
# Parse payload
Expand All @@ -110,37 +113,79 @@ function bugcount_base(\Slim\Http\Request $p_request, \Slim\Http\Response $p_res
$t_per_page = -1;
$t_page_count = 1;
$t_bug_count_filtered = 0;
$t_status_closed_level = config_get("bug_resolved_status_threshold");

$t_rows = filter_get_bug_rows( $t_page_number, $t_per_page, $t_page_count, $t_bug_count, null, $t_project_id, $t_user_id, true );
if ($t_rows != null)
if ( $p_request->getParam('filters') )
{
$status_closed_level = config_get("bug_resolved_status_threshold");
$t_req_filters = $p_request->getParam('filters');
if ( is_string( $t_req_filters ) ) {
$t_req_filters = json_decode( $t_req_filters, true );
}
foreach ($t_req_filters as $t_filter_num => $t_filter_value ) {
log_event(LOG_PLUGIN, "Applying requested filter (%s) %s", $t_filter_num, implode(",",$t_filter_value));
$_POST[$t_filter_value['property']] = $t_filter_value['value'];
}
}

log_event(LOG_PLUGIN, "ApiExtend: Examine bugs");
$_POST['type'] = '1';
$_POST['view_type'] = 'simple';
$_POST['per_page'] = '-1';
$_POST['hide_status'] = '-2';
if ( $p_type == 'open' ) {

}
else if ( $p_type == 'closed' ) {

}

$t_filter = filter_gpc_get();

/*
$t_filter = filter_ensure_valid_filter( $t_filter );
# build a filter query, here for counting results
$t_filter_query = new BugFilterQuery(
$t_filter,
array(
'query_type' => BugFilterQuery::QUERY_TYPE_LIST,
'project_id' => $t_project_id,
'user_id' => $t_user_id,
'use_sticky' => true
)
);
$t_bug_count_filtered = $t_filter_query->get_bug_count();
*/

$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, true );
if ($t_rows != null)
{
log_event(LOG_PLUGIN, "Examine bugs");

foreach ($t_rows as $bug)
{
log_event(LOG_PLUGIN, "ApiExtend: ID: %d Status: %s Res: %s", $bug->id, $bug->status, $bug->resolution);
log_event(LOG_PLUGIN, "ID: %d Status: %s Res: %s", $bug->id, $bug->status, $bug->resolution);

if ($p_type == 'closed') {
if ($bug->status >= $status_closed_level) {
if ($bug->status >= $t_status_closed_level) {
$t_bug_count_filtered++;
}
}
else {
if ($bug->status < $status_closed_level) {
else if ($p_type == 'open') {
if ($bug->status < $t_status_closed_level) {
$t_bug_count_filtered++;
}
}
else { // 'all'
$t_bug_count_filtered++;
}
}

log_event(LOG_PLUGIN, "ApiExtend: Total bug count is %d", $t_bug_count);
log_event(LOG_PLUGIN, "ApiExtend: Filtered bug count is %d", $t_bug_count_filtered);
log_event(LOG_PLUGIN, "Total bug count is %d", $t_bug_count);
log_event(LOG_PLUGIN, "Filtered bug count is %d", $t_bug_count_filtered);
}

$t_badge_text = plugin_lang_get("api_badge_text_issues_$p_type") . "%20" . plugin_lang_get("api_badge_text_issues");
$t_img_url = "https://img.shields.io/badge/" . $t_badge_text . "-" . $t_bug_count_filtered . "-" . $t_badge_color . ".svg?logo=codeigniter&logoColor=f5f5f5&cacheSeconds=3600";

return array ( 'url' => $t_img_url, 'count' => $t_bug_count_filtered);
return array ( 'url' => $t_img_url, 'count' => (int)$t_bug_count_filtered);
}

6 changes: 6 additions & 0 deletions api/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@
require_once($t_restlocal_dir . 'issues_count.php' );
}

if (plugin_config_get("issues") == ON)
{
$routes_registered = true;
require_once($t_restlocal_dir . 'issues.php' );
}

if (plugin_config_get("version") == ON || plugin_config_get("versionbadge") == ON)
{
$routes_registered = true;
Expand Down
2 changes: 2 additions & 0 deletions lang/strings_english.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $s_plugin_ApiExtend_description = 'REST API Extensions';
$s_plugin_ApiExtend_api_badge_text_issues = 'issues';
$s_plugin_ApiExtend_api_badge_text_issues_open = 'open';
$s_plugin_ApiExtend_api_badge_text_issues_closed = 'closed';
$s_plugin_ApiExtend_api_badge_text_issues_all = 'all';

$s_plugin_ApiExtend_api_badge_text_version = 'version';
$s_plugin_ApiExtend_api_badge_text_version_current= 'current';
Expand All @@ -29,6 +30,7 @@ $s_plugin_ApiExtend_config_section_version = 'Version Endpoints';
$s_plugin_ApiExtend_api_user = 'API User';
$s_plugin_ApiExtend_api_token = 'API Token';
$s_plugin_ApiExtend_config_page_title = '%%project%% ApiExtend Configuration';
$s_plugin_ApiExtend_config_issues = '/issues';
$s_plugin_ApiExtend_config_issues_count = '/issues/count';
$s_plugin_ApiExtend_config_issues_countbadge = '/issues/countbadge';
$s_plugin_ApiExtend_config_version = '/version';
Expand Down
9 changes: 9 additions & 0 deletions pages/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@

<table class="width100 table table-striped table-bordered table-condensed" cellspacing="1">

<tr <?php echo helper_alternate_class() ?>>
<td class="category" width="150">
<?php echo plugin_lang_get('config_issues'); ?>
</td>
<td>
<input type="checkbox" name="issues" <?php if (plugin_config_get('issues', ON) == ON) echo ' checked="checked"' ?> />
</td>
</tr>

<!-- issues/count enable -->
<tr <?php echo helper_alternate_class() ?>>
<td class="category" width="150">
Expand Down
2 changes: 2 additions & 0 deletions pages/config_update.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
if ( $t_action == 'update' ) {
$api_user = gpc_get_string( 'api_user' );
$api_token = gpc_get_string( 'api_token' );
$issues = gpc_get_bool( 'issues' );
$issues_count = gpc_get_bool( 'issues_count' );
$issues_countbadge = gpc_get_bool( 'issues_countbadge' );
$version = gpc_get_bool( 'version' );
$versionbadge = gpc_get_bool( 'versionbadge' );
$versionnexttype = gpc_get_int( 'next_version_type' );
plugin_config_set( 'api_user', $api_user, NO_USER, $t_project_id );
plugin_config_set( 'api_token', $api_token, NO_USER, $t_project_id );
plugin_config_set( 'issues', $issues, NO_USER, $t_project_id );
plugin_config_set( 'issues_count', $issues_count, NO_USER, $t_project_id );
plugin_config_set( 'issues_countbadge', $issues_countbadge, NO_USER, $t_project_id );
plugin_config_set( 'version', $version, NO_USER, $t_project_id );
Expand Down

0 comments on commit 369cbee

Please sign in to comment.