Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
perl-WebService-Redmine
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Gerhard Gonter
perl-WebService-Redmine
Commits
4fed452a
Commit
4fed452a
authored
Apr 9, 2014
by
Anton Soldatov
Browse files
Options
Downloads
Patches
Plain Diff
Going to 0.03:
* API requests are now AUTOLOAD'ed * Makefile.PL updated * Started writing tests
parent
870cb94e
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
Makefile.PL
+15
-9
15 additions, 9 deletions
Makefile.PL
lib/RedMiner/API.pm
+131
-154
131 additions, 154 deletions
lib/RedMiner/API.pm
t/RedMiner-API.t
+32
-10
32 additions, 10 deletions
t/RedMiner-API.t
with
178 additions
and
173 deletions
Makefile.PL
+
15
−
9
View file @
4fed452a
use
5.01
4004
;
use
5.01
0
;
use ExtUtils
::
MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME
=>
'RedMiner::API'
,
VERSION_FROM
=>
'lib/RedMiner/API.pm'
,
# finds $VERSION
PREREQ_PM
=>
{}
,
# e.g., Module::Name => 1.1
($]
>=
5.005
?
## Add these new keywords supported since 5.005
(ABSTRACT_FROM
=>
'lib/RedMiner/API.pm'
,
# retrieve abstract from module
AUTHOR
=>
'Anton Soldatov <anton@local>'
)
:
())
,
VERSION_FROM
=>
'lib/RedMiner/API.pm'
,
PREREQ_PM
=>
{
'Encode'
=>
0,
'URI'
=>
0,
'URI::QueryParam'
=>
0,
'LWP::UserAgent'
=>
0,
'JSON::XS'
=>
0,
},
($]
>=
5.005
?
(
## Add these new keywords supported since 5.005
ABSTRACT_FROM
=>
'lib/RedMiner/API.pm'
,
AUTHOR
=>
'Anton Soldatov <igelhaus@gmail.com>'
)
:
()),
);
This diff is collapsed.
Click to expand it.
lib/RedMiner/API.pm
+
131
−
154
View file @
4fed452a
package
RedMiner::
API
;
use
5.01
4004
;
use
5.01
0
;
use
strict
;
use
warnings
;
our
$VERSION
=
'
0.01
';
# 2DO: fully implement project API
# 2DO: fully implement issues API
# 2DO: fully implement membership API
our
$VERSION
=
'
0.02
';
use
URI
;
use
URI::
QueryParam
;
use
LWP::
UserAgent
;
use
JSON::
XS
qw/encode_json decode_json/
;
use
Encode
qw/decode/
;
...
...
@@ -18,9 +16,23 @@ use Encode qw/decode/;
=encoding UTF-8
=head1 RedMiner::API
=head1 NAME
RedMiner::API - Wrapper for RedMine REST API (http://www.redmine.org/projects/redmine/wiki/Rest_api).
Wrapper package for RedMine REST API (http://www.redmine.org/projects/redmine/wiki/Rest_api).
=head1 SYNOPSIS
use RedMiner::API;
=head1 DESCRIPTION
Stub documentation for RedMiner::API, created by h2xs. It looks like the
author of the extension was negligent enough to leave the stub
unedited.
=head2 EXPORT
None.
=cut
...
...
@@ -66,43 +78,51 @@ sub new
}
sub
error
{
$_
[
0
]
->
{
error
}
}
sub
errorDetails
{
$_
[
0
]
->
{
error_details
}
}
sub
_set_error
{
$_
[
0
]
->
{
error
}
=
$_
[
1
]
//
'';
return
;
}
sub
_set_
arg
_error
sub
_set_
client
_error
{
my
$self
=
shift
;
my
$error
=
shift
;
$self
->
{
raw_response
}
=
'';
$self
->
{
raw_content
}
=
'';
$self
->
{
error_details
}
=
{
client_error
=>
1
};
return
$self
->
_set_error
(
$error
);
}
sub
rawResponse
{
$_
[
0
]
->
{
raw_response
}
//
''
}
sub
rawContent
{
$_
[
0
]
->
{
raw_content
}
//
''
}
sub
AUTOLOAD
{
our
$AUTOLOAD
;
my
$self
=
shift
;
my
$method
=
substr
(
$AUTOLOAD
,
length
(
__PACKAGE__
)
+
2
);
return
if
$method
eq
'
DESTROY
';
return
$self
->
_response
(
$self
->
_request
(
$method
,
@
_
));
}
sub
_request
{
my
$self
=
shift
;
my
$method
=
shift
//
return
$self
->
_set_arg_error
('
Request method missing
');
my
$path
=
shift
//
return
$self
->
_set_arg_error
('
Request path missing
');
my
$data
=
shift
;
if
(
$method
!~
/^(?:GET|POST|PUT|DELETE)$/
)
{
$method
=
'
GET
';
}
my
$r
=
$self
->
_dispatch_name
(
@
_
)
//
return
;
$self
->
_set_error
;
my
$request
=
HTTP::
Request
->
new
(
$method
,
sprintf
('
%s/%s.json
',
$self
->
{
uri
},
$path
)
);
my
$uri
=
URI
->
new
(
sprintf
('
%s/%s.json
',
$self
->
{
uri
},
$r
->
{
path
}));
if
(
$r
->
{
method
}
eq
'
GET
'
&&
ref
$r
->
{
query
}
eq
'
HASH
')
{
foreach
my
$param
(
keys
%
{
$r
->
{
query
}
})
{
# 2DO: implement passing arrays as foo=1&foo=2&foo=3 if needed
$uri
->
query_param
(
$param
=>
$r
->
{
query
}{
$param
});
}
}
my
$request
=
HTTP::
Request
->
new
(
$r
->
{
method
},
$uri
);
if
(
$method
ne
'
GET
'
&&
defined
$
data
)
{
my
$json
=
eval
{
Encode::
decode
('
UTF-8
',
JSON::XS::
encode_json
(
$
data
))
};
if
(
$
r
->
{
method
}
ne
'
GET
'
&&
defined
$
r
->
{
content
}
)
{
my
$json
=
eval
{
Encode::
decode
('
UTF-8
',
JSON::XS::
encode_json
(
$
r
->
{
content
}
))
};
if
(
$@
)
{
return
$self
->
_set_
arg
_error
('
Malformed input data:
'
.
$@
);
return
$self
->
_set_
client
_error
('
Malformed input data:
'
.
$@
);
}
$request
->
header
('
Content-Length
'
=>
length
$json
);
$request
->
content
(
$json
);
...
...
@@ -117,11 +137,10 @@ sub _response
my
$request
=
shift
//
return
;
my
$response
=
$self
->
{
ua
}
->
request
(
$request
);
$self
->
{
raw_response
}
=
$response
->
as_string
;
$self
->
{
raw_content
}
=
$response
->
content
;
if
(
!
$response
->
is_success
)
{
# FIXME: decode into error object
$self
->
{
error_details
}
=
eval
{
JSON::XS::
decode_json
(
$response
->
decoded_content
)
}
//
{};
return
$self
->
_set_error
(
$response
->
status_line
);
}
...
...
@@ -130,153 +149,111 @@ sub _response
}
//
$self
->
_set_error
(
$@
);
}
sub
createProject
sub
_dispatch_name
{
my
$self
=
shift
;
my
$data
=
shift
;
$self
->
_response
(
$self
->
_request
('
POST
',
'
projects
',
{
project
=>
$data
})
);
}
my
$name
=
shift
//
return
$self
->
_set_client_error
('
Undefined method name
');
my
@args
=
@_
;
# TESTME
sub
project
{
my
$self
=
shift
;
my
$project_id
=
shift
//
return
$self
->
_set_arg_error
('
Incorrect project ID
');
$self
->
_response
(
$self
->
_request
('
GET
',
'
projects/
'
.
$project_id
)
);
}
my
(
$action
,
$objects
)
=
(
$name
=~
/^(get|read|create|update|delete)?(.+?)$/
);
# FIXME: implement handling of limit+offset+total_count parameters
# TESTME
sub
projects
{
my
$self
=
shift
;
$self
->
_response
(
$self
->
_request
('
GET
',
'
projects
')
);
if
(
!
$action
||
$action
eq
'
read
')
{
$action
=
'
get
';
}
# Undocumented: parent_id, inherit_members
sub
updateProject
{
my
$self
=
shift
;
my
$project_id
=
shift
//
return
$self
->
_set_arg_error
('
Incorrect project ID
');
my
$data
=
shift
;
$self
->
_response
(
$self
->
_request
('
PUT
',
'
projects/
'
.
$project_id
,
{
project
=>
$data
})
);
if
(
!
$objects
)
{
return
$self
->
_set_client_error
("
Malformed method name '
$name
'
");
}
# TESTME
sub
deleteProject
{
my
$self
=
shift
;
my
$project_id
=
shift
//
return
$self
->
_set_arg_error
('
Incorrect project ID
');
$self
->
_response
(
$self
->
_request
('
DELETE
',
'
projects/
'
.
$project_id
)
$objects
=
ucfirst
$objects
;
my
%METHOD
=
(
get
=>
'
GET
'
,
create
=>
'
POST
'
,
update
=>
'
PUT
'
,
delete
=>
'
DELETE
',
);
}
# FIXME: implement handling of limit+offset+total_count parameters
sub
projectMemberships
{
my
$self
=
shift
;
my
$project_id
=
shift
//
return
$self
->
_set_arg_error
('
Incorrect project ID
');
$self
->
_response
(
$self
->
_request
('
GET
',
'
projects/
'
.
$project_id
.
'
/memberships
')
);
}
my
$data
=
{
method
=>
$METHOD
{
$action
},
path
=>
'',
content
=>
undef
,
query
=>
undef
,
};
# FIXME: set*, not update*
# Setting membership for a group: group_id
sub
updateProjectMembership
{
my
$self
=
shift
;
my
$project_id
=
shift
//
return
$self
->
_set_arg_error
('
Incorrect project ID
');
my
$data
=
shift
;
$self
->
_response
(
$self
->
_request
('
POST
',
'
projects/
'
.
$project_id
.
'
/memberships
',
{
membership
=>
$data
})
if
(
$action
eq
'
get
')
{
if
(
ref
$args
[
-
1
]
eq
'
HASH
')
{
# If last argument is a hash reference, treat it as a filtering clause:
$data
->
{
query
}
=
pop
@args
;
}
}
elsif
(
$action
eq
'
create
'
||
$action
eq
'
update
')
{
# If last argument is an array/hash reference, treat it as a request body:
if
(
ref
$args
[
-
1
]
ne
'
ARRAY
'
&&
ref
$args
[
-
1
]
ne
'
HASH
')
{
return
$self
->
_set_client_error
(
'
No data provided for create/update query
'
);
}
$data
->
{
content
}
=
pop
@args
;
}
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR
Anton Soldatov, E<lt>anton@localE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2014 by Anton Soldatov
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.14.4 or,
at your option, any later version of Perl 5 you may have available.
=cut
1
;
__END__
=head1 NAME
RedMiner::API - Perl extension for blah blah blah
my
$i
=
0
;
my
@objects
;
while
(
$objects
=~
/([A-Z][a-z]+)/g
)
{
my
$object
=
lc
$
1
;
my
$category
=
$object
;
=head1 SYNOPSIS
# If an object is singular, pluralize to make its category name: user -> users
if
(
$object
!~
/s$/
)
{
$category
.=
'
s
';
}
use RedMiner::API;
blah blah blah
push
@objects
,
$category
;
=head1 DESCRIPTION
# We need to attach an object ID to the path if an object is singular and
# we either perform anything but creation or we create a new object inside
# another object (createProjectMembership)
if
(
$object
!~
/s$/
)
{
if
(
$action
ne
'
create
'
||
pos
(
$objects
)
!=
length
(
$objects
))
{
my
$object_id
=
$args
[
$i
++
];
Stub documentation for RedMiner::API, created by h2xs. It looks like the
author of the extension was negligent enough to leave the stub
unedited.
Blah blah blah.
=head2 EXPORT
return
$self
->
_set_client_error
(
sprintf
'
Incorrect object ID for %s in query %s
',
$object
,
$name
)
if
!
defined
$object_id
||
ref
\
$object_id
ne
'
SCALAR
';
None by default.
push
@objects
,
$object_id
;
}
if
(
defined
$data
->
{
content
}
&&
pos
(
$objects
)
==
length
(
$objects
))
{
# Add wrapping object, if necessary:
if
(
!
exists
$data
->
{
content
}{
$object
})
{
$data
->
{
content
}
=
{
$object
=>
$data
->
{
content
}
};
}
}
}
}
$data
->
{
path
}
=
join
'
/
',
@objects
;
return
$data
;
}
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
RedMine::API: http://search.cpan.org/~celogeek/Redmine-API-0.04/
=head1 AUTHOR
Anton Soldatov, E<lt>
anton@local
E<gt>
Anton Soldatov, E<lt>
igelhaus@gmail.com
E<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2014 by Anton Soldatov
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.1
4.4
or,
it under the same terms as Perl itself, either Perl version 5.1
0.0
or,
at your option, any later version of Perl 5 you may have available.
=cut
1
;
__END__
This diff is collapsed.
Click to expand it.
t/RedMiner-API.t
+
32
−
10
View file @
4fed452a
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl RedMiner-API.t'
#########################
# change 'tests => 1' to 'tests => last_test_to_print';
use
strict
;
use
warnings
;
use
Test::
More
tests
=>
1
;
BEGIN
{
use_ok
('
RedMiner::API
')
};
#########################
my
$host
=
'';
my
$key
=
'';
my
$key_fname
=
$ENV
{
HOME
}
.
'
/.redminer/key
';
if
(
-
e
$key_fname
)
{
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
,
);
my
$response
=
$redminer
->
createProject
({
identifier
=>
'
test-ru
',
name
=>
'
test.ru
',
});
use
JSON::
XS
qw/encode_json/
;
if
(
$response
)
{
say
STDERR
JSON::XS::
encode_json
(
$response
);
}
else
{
say
STDERR
JSON::XS::
encode_json
(
$redminer
->
errorDetails
);
}
# Insert your test code below, the Test::More module is use()ed here so read
# its man page ( perldoc Test::More ) for help writing this test script.
#SKIP: {
# skip 'Development tests skipped', 2 if !$ENV{REDMINER_API_DEVEL};
#}
exit
;
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment