diff --git a/Bugzilla/API/V1/Bugzilla.pm b/Bugzilla/API/V1/Bugzilla.pm new file mode 100644 index 0000000000..a2bc90179a --- /dev/null +++ b/Bugzilla/API/V1/Bugzilla.pm @@ -0,0 +1,143 @@ +# 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::V1::Bugzilla; + +use 5.10.1; +use Mojo::Base qw( Mojolicious::Controller ); + +use DateTime; +use Try::Tiny; + +use Bugzilla::Constants; +use Bugzilla::Logging; +use Bugzilla::Util qw(datetime_from); + +sub setup_routes { + my ($class, $r) = @_; + + $r->get('/version')->to('V1::Bugzilla#version'); + $r->get('/extensions')->to('V1::Bugzilla#extensions'); + $r->get('/timezone')->to('V1::Bugzilla#timezone'); + $r->get('/time')->to('V1::Bugzilla#time'); + $r->get('/jobqueue_status')->to('V1::Bugzilla#jobqueue_status'); + + foreach my $path (qw(/version /extensions /timezone /time /jobqueue_status)) { + $r->options($path)->to('V1::Bugzilla#options'); + } +} + +sub options { + my ($self) = @_; + + $self->res->headers->header('Allow' => 'GET'); + $self->res->headers->header('Access-Control-Allow-Methods' => 'GET'); + + return $self->rendered(200); +} + +sub version { + my ($self) = @_; + Bugzilla->usage_mode(USAGE_MODE_MOJO_REST); + + return $self->render(json => {version => BUGZILLA_VERSION}); +} + +sub extensions { + my ($self) = @_; + Bugzilla->usage_mode(USAGE_MODE_MOJO_REST); + + my %extensions; + foreach my $extension (@{Bugzilla->extensions}) { + $extensions{$extension->NAME} = {version => $extension->VERSION || 0}; + } + + return $self->render(json => {extensions => \%extensions}); +} + +sub timezone { + my ($self) = @_; + Bugzilla->usage_mode(USAGE_MODE_MOJO_REST); + + # All Webservices return times in UTC; Use UTC here for backwards compat. + return $self->render(json => {timezone => '+0000'}); +} + +sub time { + my ($self) = @_; + Bugzilla->usage_mode(USAGE_MODE_MOJO_REST); + + # All Webservices return times in UTC; Use UTC here for backwards compat. + my $dbh = Bugzilla->dbh; + my $db_time = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); + $db_time = datetime_from($db_time, 'UTC')->iso8601(); + my $now_utc = DateTime->now()->iso8601(); + + return $self->render( + json => { + db_time => $db_time, + web_time => $now_utc, + web_time_utc => $now_utc, + tz_name => 'UTC', + tz_offset => '+0000', + tz_short_name => 'UTC', + } + ); +} + +sub jobqueue_status { + my ($self) = @_; + + my $user = $self->bugzilla->login; + $user->id || return $self->user_error('login_required'); + + Bugzilla->usage_mode(USAGE_MODE_MOJO_REST); + + my $dbh = Bugzilla->dbh; + my $query = q{ + SELECT + COUNT(*) AS total, + COALESCE( + (SELECT COUNT(*) + FROM ts_error + WHERE ts_error.jobid = j.jobid + ) + , 0) AS errors + FROM ts_job j + INNER JOIN ts_funcmap f + ON f.funcid = j.funcid + GROUP BY errors + }; + + my $status; + try { + $status = $dbh->selectrow_hashref($query); + } + catch { + ERROR($_); + return $self->code_error('jobqueue_status_error'); + }; + + return $self->render( + json => { + errors => 0 + ($status->{errors} // 0), + total => 0 + ($status->{total} // 0), + } + ); +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::API::V1::Bugzilla - Global functions for the webservice interface. + +=head1 DESCRIPTION + +This provides functions that tell you about Bugzilla in general. diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm index d20ef76d29..6df5c9f6a3 100644 --- a/Bugzilla/WebService.pm +++ b/Bugzilla/WebService.pm @@ -413,8 +413,6 @@ objects. =item L -=item L - =item L =item L diff --git a/Bugzilla/WebService/Bugzilla.pm b/Bugzilla/WebService/Bugzilla.pm deleted file mode 100644 index 8c368d9bd5..0000000000 --- a/Bugzilla/WebService/Bugzilla.pm +++ /dev/null @@ -1,352 +0,0 @@ -# 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::Bugzilla; - -use 5.10.1; -use strict; -use warnings; - -use base qw(Bugzilla::WebService); -use Bugzilla::Constants; -use Bugzilla::Error; -use Bugzilla::Logging; -use Bugzilla::Util qw(datetime_from); -use JSON::XS; -use Try::Tiny; - -use DateTime; - -# Basic info that is needed before logins -use constant LOGIN_EXEMPT => {timezone => 1, version => 1,}; - -use constant READ_ONLY => qw( - extensions - timezone - time - version - jobqueue_status -); - -use constant PUBLIC_METHODS => qw( - extensions - time - timezone - version - jobqueue_status -); - -sub version { - my $self = shift; - return {version => $self->type('string', BUGZILLA_VERSION)}; -} - -sub extensions { - my $self = shift; - - my %retval; - foreach my $extension (@{Bugzilla->extensions}) { - my $version = $extension->VERSION || 0; - my $name = $extension->NAME; - $retval{$name}->{version} = $self->type('string', $version); - } - return {extensions => \%retval}; -} - -sub timezone { - my $self = shift; - - # All Webservices return times in UTC; Use UTC here for backwards compat. - return {timezone => $self->type('string', "+0000")}; -} - -sub time { - my ($self) = @_; - - # All Webservices return times in UTC; Use UTC here for backwards compat. - # Hardcode values where appropriate - my $dbh = Bugzilla->dbh; - - my $db_time = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); - $db_time = datetime_from($db_time, 'UTC'); - my $now_utc = DateTime->now(); - - return { - db_time => $self->type('dateTime', $db_time), - web_time => $self->type('dateTime', $now_utc), - web_time_utc => $self->type('dateTime', $now_utc), - tz_name => $self->type('string', 'UTC'), - tz_offset => $self->type('string', '+0000'), - tz_short_name => $self->type('string', 'UTC'), - }; -} - -sub jobqueue_status { - my ($self, $params) = @_; - - Bugzilla->login(LOGIN_REQUIRED); - - my $dbh = Bugzilla->dbh; - my $query = q{ - SELECT - COUNT(*) AS total, - COALESCE( - (SELECT COUNT(*) - FROM ts_error - WHERE ts_error.jobid = j.jobid - ) - , 0) AS errors - FROM ts_job j - INNER JOIN ts_funcmap f - ON f.funcid = j.funcid - GROUP BY errors - }; - - my $status; - try { - $status = $dbh->selectrow_hashref($query); - } - catch { - ERROR($_); - ThrowCodeError('jobqueue_status_error'); - }; - - return { - errors => $self->type('int', $status->{errors} // 0), - total => $self->type('int', $status->{total} // 0), - }; -} - -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. - -=head1 METHODS - -See L for a description of how parameters are passed, -and what B, B, and B mean. - -Although the data input and output is the same for JSON-RPC and REST, -the directions for how to access the data via REST is noted in each method -where applicable. - -=head2 version - -B - -=over - -=item B - -Returns the current version of Bugzilla. - -=item B - -GET /version - -The returned data format is the same as below. - -=item B (none) - -=item B - -A hash with a single item, C, that is the version as a -string. - -=item B (none) - -=item B - -=over - -=item REST API call added in Bugzilla B<5.0>. - -=back - -=back - -=head2 extensions - -B - -=over - -=item B - -Gets information about the extensions that are currently installed and enabled -in this Bugzilla. - -=item B - -GET /extensions - -The returned data format is the same as below. - -=item B (none) - -=item B - -A hash with a single item, C. This points to a hash. I hash -contains the names of extensions as keys, and the values are a hash. -That hash contains a single key C, which is the version of the -extension, or C<0> if the extension hasn't defined a version. - -The return value looks something like this: - - extensions => { - Example => { - version => '3.6', - }, - BmpConvert => { - version => '1.0', - }, - } - -=item B - -=over - -=item Added in Bugzilla B<3.2>. - -=item As of Bugzilla B<3.6>, the names of extensions are canonical names -that the extensions define themselves. Before 3.6, the names of the -extensions depended on the directory they were in on the Bugzilla server. - -=item REST API call added in Bugzilla B<5.0>. - -=back - -=back - -=head2 timezone - -B This method may be removed in a future version of Bugzilla. -Use L instead. - -=over - -=item B - -Returns the timezone that Bugzilla expects dates and times in. - -=item B - -GET /timezone - -The returned data format is the same as below. - -=item B (none) - -=item B - -A hash with a single item, C, that is the timezone offset as a -string in (+/-)XXXX (RFC 2822) format. - -=item B - -=over - -=item As of Bugzilla B<3.6>, the timezone returned is always C<+0000> -(the UTC timezone). - -=item REST API call added in Bugzilla B<5.0>. - -=back - -=back - - -=head2 time - -B - -=over - -=item B - -Gets information about what time the Bugzilla server thinks it is, and -what timezone it's running in. - -=item B - -GET /time - -The returned data format is the same as below. - -=item B (none) - -=item B - -A struct with the following items: - -=over - -=item C - -C The current time in UTC, according to the Bugzilla -I. - -Note that Bugzilla assumes that the database and the webserver are running -in the same time zone. However, if the web server and the database server -aren't synchronized for some reason, I is the time that you should -rely on for doing searches and other input to the WebService. - -=item C - -C This is the current time in UTC, according to Bugzilla's -I. - -This might be different by a second from C since this comes from -a different source. If it's any more different than a second, then there is -likely some problem with this Bugzilla instance. In this case you should -rely on the C, not the C. - -=item C - -Identical to C. (Exists only for backwards-compatibility with -versions of Bugzilla before 3.6.) - -=item C - -C The literal string C. (Exists only for backwards-compatibility -with versions of Bugzilla before 3.6.) - -=item C - -C The literal string C. (Exists only for backwards-compatibility -with versions of Bugzilla before 3.6.) - -=item C - -C The literal string C<+0000>. (Exists only for backwards-compatibility -with versions of Bugzilla before 3.6.) - -=back - -=item B - -=over - -=item Added in Bugzilla B<3.4>. - -=item As of Bugzilla B<3.6>, this method returns all data as though the server -were in the UTC timezone, instead of returning information in the server's -local timezone. - -=item REST API call added in Bugzilla B<5.0>. - -=back - -=back diff --git a/Bugzilla/WebService/Constants.pm b/Bugzilla/WebService/Constants.pm index 1986c9a479..7b53afe215 100644 --- a/Bugzilla/WebService/Constants.pm +++ b/Bugzilla/WebService/Constants.pm @@ -313,7 +313,6 @@ sub WS_DISPATCH { Bugzilla::Hook::process('webservice', {dispatch => \%hook_dispatch}); my $dispatch = { - 'Bugzilla' => 'Bugzilla::WebService::Bugzilla', 'Bug' => 'Bugzilla::WebService::Bug', 'User' => 'Bugzilla::WebService::User', 'Product' => 'Bugzilla::WebService::Product', diff --git a/Bugzilla/WebService/Server/REST.pm b/Bugzilla/WebService/Server/REST.pm index b9ae7b9a3e..862a8a35b0 100644 --- a/Bugzilla/WebService/Server/REST.pm +++ b/Bugzilla/WebService/Server/REST.pm @@ -23,7 +23,6 @@ use Bugzilla::WebService::Util qw(fix_credentials set_rest_cors_headers taint_da # Load resource modules use Bugzilla::WebService::Server::REST::Resources::Bug; -use Bugzilla::WebService::Server::REST::Resources::Bugzilla; use Bugzilla::WebService::Server::REST::Resources::Group; use Bugzilla::WebService::Server::REST::Resources::Product; use Bugzilla::WebService::Server::REST::Resources::User; diff --git a/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm b/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm deleted file mode 100644 index 868e2f4f67..0000000000 --- a/Bugzilla/WebService/Server/REST/Resources/Bugzilla.pm +++ /dev/null @@ -1,45 +0,0 @@ -# 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{^/jobqueue_status$}, {GET => {method => 'jobqueue_status'}}, - ]; - 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 for more details on how to use this part -of the REST API. diff --git a/qa/t/rest_user_login_logout.t b/qa/t/rest_user_login_logout.t index 4c02296945..b5a68f4998 100644 --- a/qa/t/rest_user_login_logout.t +++ b/qa/t/rest_user_login_logout.t @@ -44,11 +44,6 @@ my $token = $t->tx->res->json->{token}; $t->get_ok(rest_get_url($url, 'rest/logout', {Bugzilla_token => $token})) ->status_is(200); -# Authenticating any call via Bugzilla_login/Bugzilla_password works. -$t->get_ok( - rest_get_url($url, 'rest/version', {Bugzilla_login => $user, Bugzilla_password => $pass})) - ->status_is(200)->json_has('/version'); - my @tests = ( {args => {login => $user, password => ''}, error => $error, test => "Empty password can't log in"}, {args => {login => '', password => $pass}, error => $error, test => "Empty login can't log in"}, @@ -76,15 +71,6 @@ foreach my $test (@tests) { $t->get_ok(rest_get_url($url, 'rest/login', $args))->status_isnt(200); like($t->tx->res->json->{message}, qr/\Q$test->{error}\E/, "$test->{test}"); - - # Authenticating another call with the same (bad) credentials must also fail. - if (defined $args->{login} && defined $args->{password}) { - $t->get_ok(rest_get_url($url, 'rest/version', - {Bugzilla_login => $args->{login}, Bugzilla_password => $args->{password}})) - ->status_isnt(200); - like($t->tx->res->json->{message}, qr/\Q$test->{error}\E/, - "Bugzilla_login: $test->{test}"); - } } done_testing();