Skip to content
Snippets Groups Projects
Commit 1b54d4a2 authored by Anton Soldatov's avatar Anton Soldatov
Browse files

* RedMiner::API 0.04: added @no_wrapper_object@ parameter

* redminer.pl corrected for the latest version of RedMiner::API
parent 3664870e
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,9 @@ key=xxx
# http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication
# You can find your API key on your account page ( /my/account ) when logged in, on the right-hand pane of the default layout.
# Impersonation settings:
work_as=real_user
# User+Password auth is also possible:
# [redmine]
# host=redmine.example.com
......
......@@ -4,9 +4,7 @@ use 5.010;
use strict;
use warnings;
our $VERSION = '0.03';
# 2DO: implement (un)?wrapping
our $VERSION = '0.04';
use URI;
use URI::QueryParam;
......@@ -169,8 +167,42 @@ B<user>, B<pass>: User name and password for password-based authentication
B<work_as>: User login for impersonation. For details, please refer to http://www.redmine.org/projects/redmine/wiki/Rest_api#User-Impersonation.
=item *
B<no_wrapper_object>: Automatically add/remove wrapper object for data. See below.
=back
=head3 no_wrapper_object
By default RedMine API requires you to wrap you object data like this:
my $project = $redminer->createProject({
project => {
identifier => 'some-id',
name => 'Some Name',
}
});
# $project contains something like
# { project => { id => 42, identifier => 'some-id', name => 'Some Name' ... } }
By default this module follows this convention. However, if you specify something like
my $redminer = RedMiner::API->new(
host => 'example.com/redmine',
key => 'xxx',
no_wrapper_object => 1,
);
you can skip "wrapping" object data like this:
my $project = $redminer->createProject({
identifier => 'some-id',
name => 'Some Name',
});
# $project contains something like
# { id => 42, identifier => 'some-id', name => 'Some Name' ... }
=cut
sub new
......@@ -184,7 +216,7 @@ sub new
ua => LWP::UserAgent->new,
};
foreach my $param (qw/host user pass key work_as/) {
foreach my $param (qw/host user pass key work_as no_wrapper_object/) {
$self->{$param} = $arg{$param} // '';
}
......@@ -321,6 +353,10 @@ sub _response
return $self->_set_error($@);
}
if ($self->{expect_single_object} && $self->{no_wrapper_object}) {
$content = delete $content->{$self->{expect_single_object}};
}
return $content;
}
......@@ -369,6 +405,7 @@ sub _dispatch_name
}
$objects = $self->_normalize_objects($objects);
delete $self->{expect_single_object};
my $i = 0;
my @objects;
......@@ -393,9 +430,12 @@ sub _dispatch_name
push @objects, $object_id;
}
# Add wrapping object, if necessary:
if (defined $data->{content} && pos($objects) == length($objects)) {
if (!exists $data->{content}{$object}) {
if (pos($objects) == length($objects)) { # Last object in the chain:
if ($action eq 'get' || $action eq 'create') {
$self->{expect_single_object} = $object;
}
if (defined $data->{content} && $self->{no_wrapper_object}) {
# Automatically wrap object data, otherwise we pass everything as is:
$data->{content} = {
$object => $data->{content}
};
......
......@@ -49,6 +49,8 @@ my $redminer = RedMiner::API->new(
user => $conf->val('redmine', 'user') // '',
pass => $conf->val('redmine', 'pass') // '',
key => $conf->val('redmine', 'key') // '',
work_as => $conf->val('redmine', 'work_as') // '',
no_wrapper_object => 1,
);
my $description = $layout? $layout->val('project', 'description') // '' : '';
......@@ -67,10 +69,10 @@ if (!$project) {
exit 255;
}
my $pid = $project->{project}{id};
my $pid = $project->{id};
say 'Project created with ID ' . $pid;
$redminer->updateProject($project->{project}{id}, {
$redminer->updateProject($pid, {
inherit_members => 1,
});
......@@ -93,8 +95,8 @@ if ($layout) {
next;
}
say 'Subproject created with ID ' . $subproject->{project}{id};
$redminer->updateProject($subproject->{project}{id}, {
say 'Subproject created with ID ' . $subproject->{id};
$redminer->updateProject($subproject->{id}, {
parent_id => $pid,
inherit_members => 1,
});
......
......@@ -109,7 +109,7 @@ is_deeply($r, {
query => undef,
}, 'project');
$r = $redminer->_dispatch_name('createProject', { name => 'My Project' });
$r = $redminer->_dispatch_name('createProject', { project => { name => 'My Project' } });
is_deeply($r, {
method => 'POST',
path => 'projects',
......@@ -117,7 +117,7 @@ is_deeply($r, {
query => undef,
}, 'createProject');
$r = $redminer->_dispatch_name('updateProject', 1, { name => 'My Project' });
$r = $redminer->_dispatch_name('updateProject', 1, { project => { name => 'My Project' } });
is_deeply($r, {
method => 'PUT',
path => 'projects/1',
......@@ -145,7 +145,7 @@ is_deeply($r, {
query => { limit => 10, offset => 9 },
}, 'projectMemberships');
$r = $redminer->_dispatch_name('createProjectMembership', 1, { user_id => 1, role_ids => [ 1 ] });
$r = $redminer->_dispatch_name('createProjectMembership', 1, { membership => { user_id => 1, role_ids => [ 1 ] } });
is_deeply($r, {
method => 'POST',
path => 'projects/1/memberships',
......@@ -153,7 +153,7 @@ is_deeply($r, {
query => undef,
}, 'createProjectMembership');
$r = $redminer->_dispatch_name('createIssueWatcher', 1, { user_id => 1 });
$r = $redminer->_dispatch_name('createIssueWatcher', 1, { watcher => { user_id => 1 } });
is_deeply($r, {
method => 'POST',
path => 'issues/1/watchers',
......@@ -189,7 +189,7 @@ is_deeply($r, {
query => undef,
}, 'timeEntry');
$r = $redminer->_dispatch_name('createTimeEntry', { issue_id => 42, hours => 1 });
$r = $redminer->_dispatch_name('createTimeEntry', { time_entry => { issue_id => 42, hours => 1 } });
is_deeply($r, {
method => 'POST',
path => 'time_entries',
......@@ -197,7 +197,7 @@ is_deeply($r, {
query => undef,
}, 'createTimeEntry');
$r = $redminer->_dispatch_name('updateTimeEntry', 1, { issue_id => 42, hours => 1 });
$r = $redminer->_dispatch_name('updateTimeEntry', 1, { time_entry => { issue_id => 42, hours => 1 } });
is_deeply($r, {
method => 'PUT',
path => 'time_entries/1',
......@@ -225,7 +225,7 @@ is_deeply($r, {
query => { limit => 10, offset => 9 },
}, 'projectIssueCategories');
$r = $redminer->_dispatch_name('createProjectIssueCategory', 1, { name => 'My Category', assign_to_id => 1 });
$r = $redminer->_dispatch_name('createProjectIssueCategory', 1, { issue_category => { name => 'My Category', assign_to_id => 1 } });
is_deeply($r, {
method => 'POST',
path => 'projects/1/issue_categories',
......
......@@ -7,7 +7,7 @@ use JSON::XS qw/encode_json/;
if ($ENV{REDMINER_API_DEVEL}) {
plan tests => 5;
} else{
plan skip_all => 'Tests require RedMine installation';
plan skip_all => 'Development tests (REDMINER_API_DEVEL not set)';
}
eval 'use RedMiner::API';
......@@ -34,25 +34,25 @@ my $redminer = RedMiner::API->new(
key => $key,
);
my $project = $redminer->createProject({
my $project = $redminer->createProject({ project => {
identifier => 'redminer-api-test',
name => 'RedMiner API test',
});
}});
my $project_id = $project->{project}{id};
ok(defined $project_id, 'New project created with internal ID ' . $project_id);
ok(!defined $redminer->createProject({
ok(!defined $redminer->createProject({ project => {
identifier => 'redminer-api-test',
name => 'RedMiner API test',
}), 'Project already exists, error object is ' . JSON::XS::encode_json($redminer->errorDetails));
}}), 'Project already exists, error object is ' . JSON::XS::encode_json($redminer->errorDetails));
ok($redminer->updateProject($project_id, { inherit_members => 1 }), 'Project updated');
ok($redminer->updateProject($project_id, { project => { inherit_members => 1 } }), 'Project updated');
my $issue = $redminer->createIssue({
my $issue = $redminer->createIssue({ issue => {
project_id => $project_id,
subject => 'Test issue for RedMiner::API',
description => 'Test description',
});
}});
ok(defined $issue->{issue}{id}, 'Issue created with ID #' . $issue->{issue}{id});
ok($redminer->deleteProject($project_id), 'Project deleted');
......
use strict;
use warnings;
use Test::More;
use JSON::XS qw/encode_json/;
if ($ENV{REDMINER_API_DEVEL}) {
plan tests => 5;
} else{
plan skip_all => 'Development tests (REDMINER_API_DEVEL not set)';
}
eval 'use RedMiner::API';
#
# Read API key from a simple config file in the format 'host;key'
#
my $host = '';
my $key = '';
my $key_fname = $ENV{HOME} . '/.redminer/key';
if (!-e $key_fname) {
BAIL_OUT('REDMINER_API_DEVEL set, but key file is not accessible');
}
open my $FH_key, '<', $key_fname;
my $key_data = <$FH_key>;
($host, $key) = split /\s*;\s*/, $key_data;
chomp $key_data;
close $FH_key;
my $redminer = RedMiner::API->new(
host => $host,
key => $key,
no_wrapper_object => 1,
);
my $project = $redminer->createProject({
identifier => 'redminer-api-test',
name => 'RedMiner API test',
});
my $project_id = $project->{id};
ok(defined $project_id, 'New project created with internal ID ' . $project_id);
ok(!defined $redminer->createProject({
identifier => 'redminer-api-test',
name => 'RedMiner API test',
}), 'Project already exists, error object is ' . JSON::XS::encode_json($redminer->errorDetails));
ok($redminer->updateProject($project_id, { inherit_members => 1 }), 'Project updated');
my $issue = $redminer->createIssue({
project_id => $project_id,
subject => 'Test issue for RedMiner::API',
description => 'Test description',
});
ok(defined $issue->{id}, 'Issue created with ID #' . $issue->{id});
ok($redminer->deleteProject($project_id), 'Project deleted');
exit;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment