Commit dbfd6207 authored by David Lawrence's avatar David Lawrence

Bug 1051056: The REST API needs to be versioned so that new changes can be made…

Bug 1051056: The REST API needs to be versioned so that new changes can be made that do not break compatibility r=dylan,a=glob
parent e6d2fb75
......@@ -209,6 +209,20 @@ sub extensions {
return $cache->{extensions};
}
sub api_server {
my $class = shift;
my $cache = $class->request_cache;
return $cache->{api_server} if defined $cache->{api_server};
require Bugzilla::API::Server;
$cache->{api_server} = Bugzilla::API::Server->server;
if (my $load_error = $cache->{api_server}->load_error) {
my @error_params = ($load_error->{error}, $load_error->{vars});
ThrowCodeError(@error_params) if $load_error->{type} eq 'code';
ThrowUserError(@error_params) if $load_error->{type} eq 'user';
}
return $cache->{api_server};
}
sub feature {
my ($class, $feature) = @_;
my $cache = $class->request_cache;
......@@ -980,6 +994,11 @@ this Bugzilla installation.
Tells you whether or not a specific feature is enabled. For names
of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
=item C<api_server>
Returns a cached instance of the WebService API server object used for
manipulating Bugzilla resources.
=back
=head1 B<CACHING>
......
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
# This is the base class for $self in WebService API method calls. For the
# actual RPC server, see Bugzilla::API::Server and its subclasses.
package Bugzilla::API::1_0::Resource;
use 5.10.1;
use strict;
use warnings;
use Moo;
#####################
# Default Constants #
#####################
# Used by the server to convert incoming date fields apprpriately.
use constant DATE_FIELDS => {};
# Used by the server to convert incoming base64 fields appropriately.
use constant BASE64_FIELDS => {};
# For some methods, we shouldn't call Bugzilla->login before we call them
use constant LOGIN_EXEMPT => { };
# Used to allow methods to be called in the JSON-RPC WebService via GET.
# Methods that can modify data MUST not be listed here.
use constant READ_ONLY => ();
# Whitelist of methods that a client is allowed to access when making
# an API call.
use constant PUBLIC_METHODS => ();
# Array of path mappings for method names for the API. Also describes
# how path values are mapped to method parameters values.
use constant REST_RESOURCES => [];
##################
# Public Methods #
##################
sub login_exempt {
my ($class, $method) = @_;
return $class->LOGIN_EXEMPT->{$method};
}
1;
__END__
=head1 NAME
Bugzilla::API::1_0::Resource - The Web Service Resource interface to Bugzilla
=head1 DESCRIPTION
This is the standard API for external programs that want to interact
with Bugzilla. It provides endpoints or methods in various modules.
You can interact with this API via L<REST|Bugzilla::API::1_0::Server>.
=head1 CALLING METHODS
Methods are grouped into "packages", like C<Bug> for
L<Bugzilla::API::1_0::Resource::Bug>. So, for example,
L<Bugzilla::API::1_0::Resource::Bug/get>, is called as C<Bug.get>.
For REST, the "package" is more determined by the path used to access the
resource. See each relevant method for specific details on how to access via REST.
=head1 USAGE
Full documentation on how to use the Bugzilla API can be found at
L<https://bugzilla.readthedocs.org/en/latest/api/index.html>.
=head1 ERRORS
If a particular API call fails, it will throw an error in the appropriate format
providing at least a numeric error code and descriptive text for the error.
The various errors that functions can throw are specified by the
documentation of those functions.
Each error that Bugzilla can throw has a specific numeric code that will
not change between versions of Bugzilla. If your code needs to know what
error Bugzilla threw, use the numeric code. Don't try to parse the
description, because that may change from version to version of Bugzilla.
Note that if you display the error to the user in an HTML program, make
sure that you properly escape the error, as it will not be HTML-escaped.
=head2 Transient vs. Fatal Errors
If the error code is a number greater than 0, the error is considered
"transient," which means that it was an error made by the user, not
some problem with Bugzilla itself.
If the error code is a number less than 0, the error is "fatal," which
means that it's some error in Bugzilla itself that probably requires
administrative attention.
Negative numbers and positive numbers don't overlap. That is, if there's
an error 302, there won't be an error -302.
=head2 Unknown Errors
Sometimes a function will throw an error that doesn't have a specific
error code. In this case, the code will be C<-32000> if it's a "fatal"
error, and C<32000> if it's a "transient" error.
=head1 SEE ALSO
=head2 API Resource Modules
=over
=item L<Bugzilla::API::1_0::Resource::Bug>
=item L<Bugzilla::API::1_0::Resource::Bugzilla>
=item L<Bugzilla::API::1_0::Resource::Classification>
=item L<Bugzilla::API::1_0::Resource::FlagType>
=item L<Bugzilla::API::1_0::Resource::Component>
=item L<Bugzilla::API::1_0::Resource::Group>
=item L<Bugzilla::API::1_0::Resource::Product>
=item L<Bugzilla::API::1_0::Resource::User>
=back
=head1 B<Methods in need of POD>
=over
=item login_exempt
=back
This source diff could not be displayed because it is too large. You can view the blob instead.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::API::1_0::Resource::BugUserLastVisit;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::API::1_0::Util;
use Bugzilla::Bug;
use Bugzilla::Error;
use Bugzilla::Constants;
use Moo;
extends 'Bugzilla::API::1_0::Resource';
##############
# Constants #
##############
use constant READ_ONLY => qw(
get
);
use constant PUBLIC_METHODS => qw(
get
update
);
sub REST_RESOURCES {
return [
# bug-id
qr{^/bug_user_last_visit/(\d+)$}, {
GET => {
method => 'get',
params => sub {
return { ids => $_[0] };
},
},
POST => {
method => 'update',
params => sub {
return { ids => $_[0] };
},
},
},
];
}
############
# Methods #
############
sub update {
my ($self, $params) = validate(@_, 'ids');
my $user = Bugzilla->user;
my $dbh = Bugzilla->dbh;
$user->login(LOGIN_REQUIRED);
my $ids = $params->{ids} // [];
ThrowCodeError('param_required', { param => 'ids' }) unless @$ids;
# Cache permissions for bugs. This highly reduces the number of calls to the
# DB. visible_bugs() is only able to handle bug IDs, so we have to skip
# aliases.
$user->visible_bugs([grep /^[0-9]$/, @$ids]);
$dbh->bz_start_transaction();
my @results;
my $last_visit_ts = $dbh->selectrow_array('SELECT NOW()');
foreach my $bug_id (@$ids) {
my $bug = Bugzilla::Bug->check({ id => $bug_id, cache => 1 });
ThrowUserError('user_not_involved', { bug_id => $bug->id })
unless $user->is_involved_in_bug($bug);
$bug->update_user_last_visit($user, $last_visit_ts);
push(
@results,
$self->_bug_user_last_visit_to_hash(
$bug, $last_visit_ts, $params
));
}
$dbh->bz_commit_transaction();
return \@results;
}
sub get {
my ($self, $params) = validate(@_, 'ids');
my $user = Bugzilla->user;
my $ids = $params->{ids};
$user->login(LOGIN_REQUIRED);
if ($ids) {
# Cache permissions for bugs. This highly reduces the number of calls to
# the DB. visible_bugs() is only able to handle bug IDs, so we have to
# skip aliases.
$user->visible_bugs([grep /^[0-9]$/, @$ids]);
}
my @last_visits = @{ $user->last_visited };
if ($ids) {
# remove bugs that we are not interested in if ids is passed in.
my %id_set = map { ($_ => 1) } @$ids;
@last_visits = grep { $id_set{ $_->bug_id } } @last_visits;
}
return [
map {
$self->_bug_user_last_visit_to_hash($_->bug_id, $_->last_visit_ts,
$params)
} @last_visits
];
}
sub _bug_user_last_visit_to_hash {
my ($self, $bug_id, $last_visit_ts, $params) = @_;
my %result = (id => as_int($bug_id),
last_visit_ts => as_datetime($last_visit_ts));
return filter($params, \%result);
}
1;
__END__
=head1 NAME
Bugzilla::API::1_0::Resource::BugUserLastVisit - Find and Store the last time a
user visited a bug.
=head1 METHODS
=head2 update
=over
=item B<Description>
Update the last visit time for the specified bug and current user.
=item B<REST>
To add a single bug id:
POST /rest/bug_user_last_visit/<bug-id>
Tp add one or more bug ids at once:
POST /rest/bug_user_last_visit
The returned data format is the same as below.
=item B<Params>
=over
=item C<ids> (array) - One or more bug ids to add.
=back
=item B<Returns>
=over
=item C<array> - An array of hashes containing the following:
=over
=item C<id> - (int) The bug id.
=item C<last_visit_ts> - (string) The timestamp the user last visited the bug.
=back
=back
=back
=head2 get
=over
=item B<Description>
Get the last visited timestamp for one or more specified bug ids.
=item B<REST>
To return the last visited timestamp for a single bug id:
GET /rest/bug_user_last_visit/<bug-id>
=item B<Params>
=over
=item C<ids> (integer) - One or more optional bug ids to get.
=back
=item B<Returns>
=over
=item C<array> - An array of hashes containing the following:
=over
=item C<id> - (int) The bug id.
=item C<last_visit_ts> - (string) The timestamp the user last visited the bug.
=back
=back
=back
=head1 B<Methods in need of POD>
=over
=item REST_RESOURCES
=back
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::API::1_0::Resource::Classification;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::API::1_0::Util;
use Bugzilla::Classification;
use Bugzilla::Error;
use Moo;
extends 'Bugzilla::API::1_0::Resource';
##############
# Constants #
##############
use constant READ_ONLY => qw(
get
);
use constant PUBLIC_METHODS => qw(
get
);
sub REST_RESOURCES {
my $rest_resources = [
qr{^/classification/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
}
];
return $rest_resources;
}
############
# Methods #
############
sub get {
my ($self, $params) = validate(@_, 'names', 'ids');
defined $params->{names} || defined $params->{ids}
|| ThrowCodeError('params_required', { function => 'Classification.get',
params => ['names', 'ids'] });
my $user = Bugzilla->user;
Bugzilla->params->{'useclassification'}
|| $user->in_group('editclassifications')
|| ThrowUserError('auth_classification_not_enabled');
Bugzilla->switch_to_shadow_db;
my @classification_objs = @{ params_to_objects($params, 'Bugzilla::Classification') };
unless ($user->in_group('editclassifications')) {
my %selectable_class = map { $_->id => 1 } @{$user->get_selectable_classifications};
@classification_objs = grep { $selectable_class{$_->id} } @classification_objs;
}
my @classifications = map { $self->_classification_to_hash($_, $params) } @classification_objs;
return { classifications => \@classifications };
}
sub _classification_to_hash {
my ($self, $classification, $params) = @_;
my $user = Bugzilla->user;
return unless (Bugzilla->params->{'useclassification'} || $user->in_group('editclassifications'));
my $products = $user->in_group('editclassifications') ?
$classification->products : $user->get_selectable_products($classification->id);
return filter $params, {
id => as_int($classification->id),
name => as_string($classification->name),
description => as_string($classification->description),
sort_key => as_int($classification->sortkey),
products => [ map { $self->_product_to_hash($_, $params) } @$products ],
};
}
sub _product_to_hash {
my ($self, $product, $params) = @_;
return filter $params, {
id => as_int($product->id),
name => as_string($product->name),
description => as_string($product->description),
}, undef, 'products';
}
1;
__END__
=head1 NAME
Bugzilla::API::1_0::Resource::Classification - The Classification API
=head1 DESCRIPTION
This part of the Bugzilla API allows you to deal with the available Classifications.
You will be able to get information about them as well as manipulate them.
=head1 METHODS
=head2 get
=over
=item B<Description>
Returns a hash containing information about a set of classifications.
=item B<REST>
To return information on a single classification:
GET /rest/classification/<classification_id_or_name>
The returned data format will be the same as below.
=item B<Params>
In addition to the parameters below, this method also accepts the
standard L<include_fields|Bugzilla::API::1_0::Resource/include_fields> and
L<exclude_fields|Bugzilla::API::1_0::Resource/exclude_fields> arguments.
You could get classifications info by supplying their names and/or ids.
So, this method accepts the following parameters:
=over
=item C<ids>
An array of classification ids.
=item C<names>
An array of classification names.
=back
=item B<Returns>
A hash with the key C<classifications> and an array of hashes as the corresponding value.
Each element of the array represents a classification that the user is authorized to see
and has the following keys:
=over
=item C<id>
C<int> The id of the classification.
=item C<name>
C<string> The name of the classification.
=item C<description>
C<string> The description of the classificaion.
=item C<sort_key>
C<int> The value which determines the order the classification is sorted.
=item C<products>
An array of hashes. The array contains the products the user is authorized to
access within the classification. Each hash has the following keys:
=over
=item C<name>
C<string> The name of the product.
=item C<id>
C<int> The id of the product.
=item C<description>
C<string> The description of the product.
=back
=back
=item B<Errors>
=over
=item 900 (Classification not enabled)
Classification is not enabled on this installation.
=back
=item B<History>
=over
=item Added in Bugzilla B<4.4>.
=item REST API call added in Bugzilla B<5.0>.
=back
=back
=head1 B<Methods in need of POD>
=over
=item REST_RESOURCES
=back
......@@ -123,19 +123,13 @@ sub _throw_error {
if (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT) {
die SOAP::Fault->faultcode($code)->faultstring($message);
}
else {
elsif (Bugzilla->error_mode == ERROR_MODE_JSON_RPC) {
my $server = Bugzilla->_json_server;
my $status_code = 0;
if (Bugzilla->error_mode == ERROR_MODE_REST) {
my %status_code_map = %{ REST_STATUS_CODE_MAP() };
$status_code = $status_code_map{$code} || $status_code_map{'_default'};
}
# Technically JSON-RPC isn't allowed to have error numbers
# higher than 999, but we do this to avoid conflicts with
# the internal JSON::RPC error codes.
$server->raise_error(code => 100000 + $code,
status_code => $status_code,
message => $message,
id => $server->{_bz_request_id},
version => $server->version);
......@@ -146,6 +140,13 @@ sub _throw_error {
die if _in_eval();
$server->response($server->error_response_header);
}
else {
my $server = Bugzilla->api_server;
my %status_code_map = %{ $server->constants->{REST_STATUS_CODE_MAP} };
my $status_code = $status_code_map{$code} || $status_code_map{'_default'};
$server->return_error($status_code, $message, $code);
$server->response;
}
}
exit;
}
......
......@@ -301,7 +301,7 @@ sub OPTIONAL_MODULES {
package => 'JSON-RPC',
module => 'JSON::RPC',
version => 0,
feature => ['jsonrpc', 'rest'],
feature => ['jsonrpc'],
},
{
package => 'Test-Taint',
......@@ -311,6 +311,36 @@ sub OPTIONAL_MODULES {
feature => ['jsonrpc', 'xmlrpc', 'rest'],
},
{
package => 'Moo',
module => 'Moo',
version => 2,
feature => ['rest']
},
{
package => 'Module-Runtime',
module => 'Module::Runtime',
version => 0,
feature => ['rest']
},
{
package => 'HTTP-Request',
module => 'HTTP::Request',
version => 0,
feature => ['rest']
},
{
package => 'HTTP-Response',
module => 'HTTP::Response',
version => 0,
feature => ['rest']
},
{
package => 'URI-Escape',
module => 'URI::Escape',
version => 0,
feature => ['rest']
},
{
# We need the 'utf8_mode' method of HTML::Parser, for HTML::Scrubber.
package => 'HTML-Parser',
module => 'HTML::Parser',
......
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Bug;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Bug;
BEGIN {
*Bugzilla::WebService::Bug::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/bug$}, {
GET => {
method => 'search',
},
POST => {
method => 'create',
status_code => STATUS_CREATED
}
},
qr{^/bug/$}, {
GET => {
method => 'get'
}
},
qr{^/bug/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
return { ids => [ $_[0] ] };
}
},
PUT => {
method => 'update',
params => sub {
return { ids => [ $_[0] ] };
}
}
},
qr{^/bug/([^/]+)/comment$}, {
GET => {
method => 'comments',
params => sub {
return { ids => [ $_[0] ] };
}
},
POST => {
method => 'add_comment',
params => sub {
return { id => $_[0] };
},
success_code => STATUS_CREATED
}
},
qr{^/bug/comment/([^/]+)$}, {
GET => {
method => 'comments',
params => sub {
return { comment_ids => [ $_[0] ] };
}
}
},
qr{^/bug/comment/tags/([^/]+)$}, {
GET => {
method => 'search_comment_tags',
params => sub {
return { query => $_[0] };
},
},
},
qr{^/bug/comment/([^/]+)/tags$}, {
PUT => {
method => 'update_comment_tags',
params => sub {
return { comment_id => $_[0] };
},
},
},
qr{^/bug/([^/]+)/history$}, {
GET => {
method => 'history',
params => sub {
return { ids => [ $_[0] ] };
},
}
},
qr{^/bug/([^/]+)/attachment$}, {
GET => {
method => 'attachments',
params => sub {
return { ids => [ $_[0] ] };
}
},
POST => {
method => 'add_attachment',
params => sub {
return { ids => [ $_[0] ] };
},
success_code => STATUS_CREATED
}
},
qr{^/bug/attachment/([^/]+)$}, {
GET => {
method => 'attachments',
params => sub {
return { attachment_ids => [ $_[0] ] };
}
},
PUT => {
method => 'update_attachment',
params => sub {
return { ids => [ $_[0] ] };
}
}
},
qr{^/field/bug$}, {
GET => {
method => 'fields',
}
},
qr{^/field/bug/([^/]+)$}, {
GET => {
method => 'fields',
params => sub {
my $value = $_[0];
my $param = 'names';
$param = 'ids' if $value =~ /^\d+$/;
return { $param => [ $_[0] ] };
}
}
},
qr{^/field/bug/([^/]+)/values$}, {
GET => {
method => 'legal_values',
params => sub {
return { field => $_[0] };
}
}
},
qr{^/field/bug/([^/]+)/([^/]+)/values$}, {
GET => {
method => 'legal_values',
params => sub {
return { field => $_[0],
product_id => $_[1] };
}
}
},
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::Bug - The REST API for creating,
changing, and getting the details of bugs.
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to file a new bug in Bugzilla,
or get information about bugs that have already been filed.
See L<Bugzilla::WebService::Bug> for more details on how to use this part of
the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::BugUserLastVisit;
use 5.10.1;
use strict;
use warnings;
BEGIN {
*Bugzilla::WebService::BugUserLastVisit::rest_resources = \&_rest_resources;
}
sub _rest_resources {
return [
# bug-id
qr{^/bug_user_last_visit/(\d+)$}, {
GET => {
method => 'get',
params => sub {
return { ids => $_[0] };
},
},
POST => {
method => 'update',
params => sub {
return { ids => $_[0] };
},
},
},
];
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::BugUserLastVisit - The
BugUserLastVisit REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to lookup and update the last time
a user visited a bug.
See L<Bugzilla::WebService::BugUserLastVisit> for more details on how to use
this part of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Bugzilla;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Bugzilla;
BEGIN {
*Bugzilla::WebService::Bugzilla::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/version$}, {
GET => {
method => 'version'
}
},
qr{^/extensions$}, {
GET => {
method => 'extensions'
}
},
qr{^/timezone$}, {
GET => {
method => 'timezone'
}
},
qr{^/time$}, {
GET => {
method => 'time'
}
},
qr{^/last_audit_time$}, {
GET => {
method => 'last_audit_time'
}
},
qr{^/parameters$}, {
GET => {
method => 'parameters'
}
}
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::WebService::Bugzilla - Global functions for the webservice interface.
=head1 DESCRIPTION
This provides functions that tell you about Bugzilla in general.
See L<Bugzilla::WebService::Bugzilla> for more details on how to use this part
of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Classification;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Classification;
BEGIN {
*Bugzilla::WebService::Classification::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/classification/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
}
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::Classification - The Classification REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to deal with the available Classifications.
You will be able to get information about them as well as manipulate them.
See L<Bugzilla::WebService::Classification> for more details on how to use this part
of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Component;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Component;
use Bugzilla::Error;
BEGIN {
*Bugzilla::WebService::Component::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/component$}, {
POST => {
method => 'create',
success_code => STATUS_CREATED
}
},
qr{^/component/(\d+)$}, {
PUT => {
method => 'update',
params => sub {
return { ids => [ $_[0] ] };
}
},
DELETE => {
method => 'delete',
params => sub {
return { ids => [ $_[0] ] };
}
},
},
qr{^/component/([^/]+)/([^/]+)$}, {
PUT => {
method => 'update',
params => sub {
return { names => [ { product => $_[0], component => $_[1] } ] };
}
},
DELETE => {
method => 'delete',
params => sub {
return { names => [ { product => $_[0], component => $_[1] } ] };
}
},
},
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::Component - The Component REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you create Components.
See L<Bugzilla::WebService::Component> for more details on how to use this
part of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::FlagType;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::FlagType;
use Bugzilla::Error;
BEGIN {
*Bugzilla::WebService::FlagType::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/flag_type$}, {
POST => {
method => 'create',
success_code => STATUS_CREATED
}
},
qr{^/flag_type/([^/]+)/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
return { product => $_[0],
component => $_[1] };
}
}
},
qr{^/flag_type/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
return { product => $_[0] };
}
},
PUT => {
method => 'update',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
},
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::FlagType - The Flag Type REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to create and update Flag types.
See L<Bugzilla::WebService::FlagType> for more details on how to use this
part of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Group;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Group;
BEGIN {
*Bugzilla::WebService::Group::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/group$}, {
GET => {
method => 'get'
},
POST => {
method => 'create',
success_code => STATUS_CREATED
}
},
qr{^/group/([^/]+)$}, {
PUT => {
method => 'update',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
}
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::Group - The REST API for
creating, changing, and getting information about Groups.
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to create Groups and
get information about them.
See L<Bugzilla::WebService::Group> for more details on how to use this part
of the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::Product;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Product;
use Bugzilla::Error;
BEGIN {
*Bugzilla::WebService::Product::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/product_accessible$}, {
GET => {
method => 'get_accessible_products'
}
},
qr{^/product_enterable$}, {
GET => {
method => 'get_enterable_products'
}
},
qr{^/product_selectable$}, {
GET => {
method => 'get_selectable_products'
}
},
qr{^/product$}, {
GET => {
method => 'get'
},
POST => {
method => 'create',
success_code => STATUS_CREATED
}
},
qr{^/product/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
},
PUT => {
method => 'update',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
},
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::Product - The Product REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to list the available Products and
get information about them.
See L<Bugzilla::WebService::Product> for more details on how to use this part of
the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::WebService::Server::REST::Resources::User;
use 5.10.1;
use strict;
use warnings;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::User;
BEGIN {
*Bugzilla::WebService::User::rest_resources = \&_rest_resources;
};
sub _rest_resources {
my $rest_resources = [
qr{^/login$}, {
GET => {
method => 'login'
}
},
qr{^/logout$}, {
GET => {
method => 'logout'
}
},
qr{^/valid_login$}, {
GET => {
method => 'valid_login'
}
},
qr{^/user$}, {
GET => {
method => 'get'
},
POST => {
method => 'create',
success_code => STATUS_CREATED
}
},
qr{^/user/([^/]+)$}, {
GET => {
method => 'get',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
},
PUT => {
method => 'update',
params => sub {
my $param = $_[0] =~ /^\d+$/ ? 'ids' : 'names';
return { $param => [ $_[0] ] };
}
}
}
];
return $rest_resources;
}
1;
__END__
=head1 NAME
Bugzilla::Webservice::Server::REST::Resources::User - The User Account REST API
=head1 DESCRIPTION
This part of the Bugzilla REST API allows you to get User information as well
as create User Accounts.
See L<Bugzilla::WebService::User> for more details on how to use this part of
the REST API.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::API::1_0::Resource::Example;
use 5.10.1;
use strict;
use warnings;
use parent qw(Bugzilla::API::1_0::Resource);
use Bugzilla::Error;
#############
# Constants #
#############
use constant READ_ONLY => qw(
hello
throw_an_error
);
use constant PUBLIC_METHODS => qw(
hello
throw_an_error
);
sub REST_RESOURCES {
my $rest_resources = [
qr{^/hello$}, {
GET => {
method => 'hello'
}
},
qr{^/throw_an_error$}, {
GET => {
method => 'throw_an_error'
}
}
];
return $rest_resources;
}
###########
# Methods #
###########
# This can be called as Example.hello() from the WebService.
sub hello {
return {
message => 'Hello!'
};
}
sub throw_an_error { ThrowUserError('example_my_error') }
1;
......@@ -29,4 +29,12 @@ use constant OPTIONAL_MODULES => [
},
];
# The map determines which verion of
# the Core API an extension's API modules
# were written to work with.
use constant API_VERSION_MAP => {
'1_0' => '1_0',
'2_0' => '1_0'
};
__PACKAGE__->NAME;
......@@ -1058,29 +1058,34 @@ sub webservice_rest_resources {
my $resources = $args->{'resources'};
# Add a new resource that allows for /rest/example/hello
# to call Example.hello
$resources->{'Bugzilla::Extension::Example::WebService'} = [
qr{^/example/hello$}, {
GET => {
method => 'hello',
}
}
];
#$resources->{'Bugzilla::Extension::Example::WebService'} = [
# qr{^/example/hello$}, {
# GET => {
# method => 'hello',
# }
# }
#];
}
sub webservice_rest_response {
sub webservice_rest_result {
my ($self, $args) = @_;
my $rpc = $args->{'rpc'};
my $result = $args->{'result'};
my $response = $args->{'response'};
my $result = $args->{'result'};
# Convert a list of bug hashes to a single bug hash if only one is
# being returned.
if (ref $$result eq 'HASH'
&& exists $$result->{'bugs'}
&& ref $$result->{'bugs'} eq 'ARRAY'
&& scalar @{ $$result->{'bugs'} } == 1)
{
$$result = $$result->{'bugs'}->[0];
}
}
sub webservice_rest_response {
my ($self, $args) = @_;
my $response = $args->{'response'};
$response->header('X-Example-Header', 'This is an example header');
}
# This must be the last line of your extension.
__PACKAGE__->NAME;
......@@ -15,17 +15,10 @@ use lib qw(. lib);
use Bugzilla;
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::WebService::Constants;
BEGIN {
if (!Bugzilla->feature('rest')
|| !Bugzilla->feature('jsonrpc'))
{
if (!Bugzilla->feature('rest')) {
ThrowUserError('feature_disabled', { feature => 'rest' });
}
}
use Bugzilla::WebService::Server::REST;
Bugzilla->usage_mode(USAGE_MODE_REST);
local @INC = (bz_locations()->{extensionsdir}, @INC);
my $server = new Bugzilla::WebService::Server::REST;
$server->version('1.1');
$server->handle();
Bugzilla->api_server->handle();
......@@ -1150,6 +1150,13 @@
[% ELSIF error == "rest_invalid_resource" %]
A REST API resource was not found for '[% method FILTER html +%] [%+ path FILTER html %]'.
[% ELSIF error == "unknown_api_version" %]
A REST API version was not found for '[% api_version FILTER html +%]'
[%- IF api_namespace %] in namespace '[% api_namespace FILTER html %]'[% END %].
[% ELSIF error == "unknown_api_namespace" %]
A REST API namespace was not found for '[% api_namespace FILTER html +%]'.
[% ELSIF error == "get_products_invalid_type" %]
The product type '[% type FILTER html %]' is invalid. Valid choices
are 'accessible', 'selectable', and 'enterable'.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment