diff options
author | wurblzap%gmail.com <> | 2006-08-20 02:20:23 +0200 |
---|---|---|
committer | wurblzap%gmail.com <> | 2006-08-20 02:20:23 +0200 |
commit | 0ee4621e7828a205189368aa9b8a515574d9c030 (patch) | |
tree | 93caacf40fc87a27e224e8fefa6b7284e686e918 | |
parent | 79c7d0e961d9adf2c3a0459594745afb41b19e4c (diff) | |
download | bugzilla-0ee4621e7828a205189368aa9b8a515574d9c030.tar.gz bugzilla-0ee4621e7828a205189368aa9b8a515574d9c030.tar.xz |
Bug 224577: Bugzilla could use a web services interface.
Patch by Marc Schumann <wurblzap@gmail.com>;
r=mkanat; a=myk
-rw-r--r-- | Bugzilla.pm | 64 | ||||
-rw-r--r-- | Bugzilla/Auth/Login/CGI.pm | 7 | ||||
-rw-r--r-- | Bugzilla/Constants.pm | 20 | ||||
-rw-r--r-- | Bugzilla/Error.pm | 20 | ||||
-rw-r--r-- | Bugzilla/Install/Requirements.pm | 14 | ||||
-rw-r--r-- | Bugzilla/Util.pm | 13 | ||||
-rwxr-xr-x | Bugzilla/WebService.pm | 47 | ||||
-rwxr-xr-x | Bugzilla/WebService/Bug.pm | 36 | ||||
-rwxr-xr-x | Bugzilla/WebService/Bugzilla.pm | 27 | ||||
-rwxr-xr-x | Bugzilla/WebService/Constants.pm | 32 | ||||
-rwxr-xr-x | Bugzilla/WebService/Product.pm | 36 | ||||
-rwxr-xr-x | Bugzilla/WebService/User.pm | 55 | ||||
-rwxr-xr-x | collectstats.pl | 5 | ||||
-rwxr-xr-x | contrib/bz_webservice_demo.pl | 260 | ||||
-rw-r--r-- | docs/xml/installation.xml | 17 | ||||
-rwxr-xr-x | importxml.pl | 2 | ||||
-rwxr-xr-x | post_bug.cgi | 7 | ||||
-rw-r--r-- | template/en/default/global/code-error.html.tmpl | 19 | ||||
-rw-r--r-- | template/en/default/global/user-error.html.tmpl | 6 | ||||
-rwxr-xr-x | xmlrpc.cgi | 38 |
20 files changed, 692 insertions, 33 deletions
diff --git a/Bugzilla.pm b/Bugzilla.pm index 21a741e59..19c52ee2f 100644 --- a/Bugzilla.pm +++ b/Bugzilla.pm @@ -20,6 +20,7 @@ # Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au> # Erik Stambaugh <erik@dasbistro.com> # A. Karl Kornel <karl@kornel.name> +# Marc Schumann <wurblzap@gmail.com> package Bugzilla; @@ -263,13 +264,37 @@ sub dbh { return request_cache()->{dbh}; } -sub batch { +sub error_mode { my $class = shift; my $newval = shift; if (defined $newval) { - request_cache()->{batch} = $newval; + request_cache()->{error_mode} = $newval; } - return request_cache()->{batch} || 0; + return request_cache()->{error_mode} + || Bugzilla::Constants::ERROR_MODE_WEBPAGE; +} + +sub usage_mode { + my $class = shift; + my $newval = shift; + if (defined $newval) { + if ($newval == USAGE_MODE_BROWSER) { + $class->error_mode(ERROR_MODE_WEBPAGE); + } + elsif ($newval == USAGE_MODE_CMDLINE) { + $class->error_mode(ERROR_MODE_DIE); + } + elsif ($newval == USAGE_MODE_WEBSERVICE) { + $class->error_mode(ERROR_MODE_DIE_SOAP_FAULT); + } + else { + ThrowCodeError('usage_mode_invalid', + {'invalid_usage_mode', $newval}); + } + request_cache()->{usage_mode} = $newval; + } + return request_cache()->{usage_mode} + || Bugzilla::Constants::USAGE_MODE_BROWSER; } sub switch_to_shadow_db { @@ -477,12 +502,35 @@ Essentially, causes calls to C<Bugzilla-E<gt>user> to return C<undef>. This has effect of logging out a user for the current request only; cookies and database sessions are left intact. -=item C<batch> +=item C<error_mode> + +Call either C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE)> +or C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE_SOAP_FAULT)> to +change this flag's default of C<Bugzilla::Constants::ERROR_MODE_WEBPAGE> and to +indicate that errors should be passed to error mode specific error handlers +rather than being sent to a browser and finished with an exit(). + +This is useful, for example, to keep C<eval> blocks from producing wild HTML +on errors, making it easier for you to catch them. +(Remember to reset the error mode to its previous value afterwards, though.) + +C<Bugzilla->error_mode> will return the current state of this flag. + +Note that C<Bugzilla->error_mode> is being called by C<Bugzilla->usage_mode> on +usage mode changes. + +=item C<usage_mode> + +Call either C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE)> +or C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_WEBSERVICE)> near the +beginning of your script to change this flag's default of +C<Bugzilla::Constants::USAGE_MODE_BROWSER> and to indicate that Bugzilla is +being called in a non-interactive manner. +This influences error handling because on usage mode changes, C<usage_mode> +calls C<Bugzilla->error_mode> to set an error mode which makes sense for the +usage mode. -Set to true, by calling Bugzilla->batch(1), to indicate that Bugzilla is -being called in a non-interactive manner and errors should be passed to -die() rather than being sent to a browser and finished with an exit(). -Bugzilla->batch will return the current state of this flag. +C<Bugzilla->usage_mode> will return the current state of this flag. =item C<dbh> diff --git a/Bugzilla/Auth/Login/CGI.pm b/Bugzilla/Auth/Login/CGI.pm index 033cb992b..2a61a54f7 100644 --- a/Bugzilla/Auth/Login/CGI.pm +++ b/Bugzilla/Auth/Login/CGI.pm @@ -34,6 +34,7 @@ use base qw(Bugzilla::Auth::Login); use constant user_can_create_account => 1; use Bugzilla::Constants; +use Bugzilla::WebService::Constants; use Bugzilla::Util; use Bugzilla::Error; @@ -58,6 +59,12 @@ sub fail_nodata { my $cgi = Bugzilla->cgi; my $template = Bugzilla->template; + if (Bugzilla->error_mode == Bugzilla::Constants::ERROR_MODE_DIE_SOAP_FAULT) { + die SOAP::Fault + ->faultcode(ERROR_AUTH_NODATA) + ->faultstring('Login Required'); + } + # Redirect to SSL if required if (Bugzilla->params->{'sslbase'} ne '' and Bugzilla->params->{'ssl'} ne 'never') diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 197c1d70a..9493ea400 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -27,6 +27,7 @@ # Christopher Aillon <christopher@aillon.com> # Shane H. W. Travis <travis@sedsystems.ca> # Max Kanat-Alexander <mkanat@bugzilla.org> +# Marc Schumann <wurblzap@gmail.com> package Bugzilla::Constants; use strict; @@ -108,6 +109,14 @@ use File::Basename; BUG_STATE_OPEN + USAGE_MODE_BROWSER + USAGE_MODE_CMDLINE + USAGE_MODE_WEBSERVICE + + ERROR_MODE_WEBPAGE + ERROR_MODE_DIE + ERROR_MODE_DIE_SOAP_FAULT + DB_MODULE ROOT_USER ON_WINDOWS @@ -290,6 +299,17 @@ use constant FIELD_TYPE_FREETEXT => 1; use constant BUG_STATE_OPEN => ('NEW', 'REOPENED', 'ASSIGNED', 'UNCONFIRMED'); +# Usage modes. Default USAGE_MODE_BROWSER. Use with Bugzilla->usage_mode. +use constant USAGE_MODE_BROWSER => 0; +use constant USAGE_MODE_CMDLINE => 1; +use constant USAGE_MODE_WEBSERVICE => 2; + +# Error modes. Default set by Bugzilla->usage_mode (so ERROR_MODE_WEBPAGE +# usually). Use with Bugzilla->error_mode. +use constant ERROR_MODE_WEBPAGE => 0; +use constant ERROR_MODE_DIE => 1; +use constant ERROR_MODE_DIE_SOAP_FAULT => 2; + # Data about what we require for different databases. use constant DB_MODULE => { 'mysql' => {db => 'Bugzilla::DB::Mysql', db_version => '4.0.14', diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm index b88c4eeb8..1bb0556af 100644 --- a/Bugzilla/Error.pm +++ b/Bugzilla/Error.pm @@ -18,6 +18,7 @@ # Rights Reserved. # # Contributor(s): Bradley Baetz <bbaetz@acm.org> +# Marc Schumann <wurblzap@gmail.com> package Bugzilla::Error; @@ -27,6 +28,7 @@ use base qw(Exporter); @Bugzilla::Error::EXPORT = qw(ThrowCodeError ThrowTemplateError ThrowUserError); use Bugzilla::Constants; +use Bugzilla::WebService::Constants; use Bugzilla::Util; use Date::Format; @@ -74,15 +76,21 @@ sub _throw_error { } my $template = Bugzilla->template; - if (Bugzilla->batch) { + if (Bugzilla->error_mode == ERROR_MODE_WEBPAGE) { + print Bugzilla->cgi->header(); + $template->process($name, $vars) + || ThrowTemplateError($template->error()); + } + elsif (Bugzilla->error_mode == ERROR_MODE_DIE) { my $message; $template->process($name, $vars, \$message) || ThrowTemplateError($template->error()); die("$message\n"); - } else { - print Bugzilla->cgi->header(); - $template->process($name, $vars) - || ThrowTemplateError($template->error()); + } + elsif (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT) { + die SOAP::Fault + ->faultcode(ERROR_GENERAL) + ->faultstring($error); } exit; } @@ -103,7 +111,7 @@ sub ThrowTemplateError { Bugzilla->dbh->bz_unlock_tables(UNLOCK_ABORT); my $vars = {}; - if (Bugzilla->batch) { + if (Bugzilla->error_mode == ERROR_MODE_DIE) { die("error: template error: $template_err"); } diff --git a/Bugzilla/Install/Requirements.pm b/Bugzilla/Install/Requirements.pm index e521f6e11..3a27bb2e4 100644 --- a/Bugzilla/Install/Requirements.pm +++ b/Bugzilla/Install/Requirements.pm @@ -13,6 +13,7 @@ # The Original Code is the Bugzilla Bug Tracking System. # # Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org> +# Marc Schumann <wurblzap@gmail.com> package Bugzilla::Install::Requirements; @@ -117,6 +118,10 @@ use constant OPTIONAL_MODULES => [ name => 'Net::LDAP', version => 0 }, + { + name => 'SOAP::Lite', + version => 0 + }, ]; # These are only required if you want to use Bugzilla with @@ -252,6 +257,15 @@ sub check_requirements { " " . install_command("Image::Magick") . "\n\n"; } + # Web Services + if (!$have_mod{'SOAP::Lite'}) { + print "If you want your Bugzilla installation to be accessible\n", + "via its Web Service interface, you will need to install\n", + "the SOAP::Lite module by running (as $root):\n\n"; + print " SOAP::Lite: " . + install_command("SOAP::Lite") . "\n\n"; + } + # Graphical Reports if (!$have_mod{'GD'} || !$have_mod{'GD::Graph'} || !$have_mod{'GD::Text::Align'} diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm index 24debb1d6..8821a6c66 100644 --- a/Bugzilla/Util.pm +++ b/Bugzilla/Util.pm @@ -24,6 +24,7 @@ # Christopher Aillon <christopher@aillon.com> # Max Kanat-Alexander <mkanat@bugzilla.org> # Frédéric Buclin <LpSolit@gmail.com> +# Marc Schumann <wurblzap@gmail.com> package Bugzilla::Util; @@ -63,20 +64,20 @@ sub is_tainted { sub trick_taint { require Carp; Carp::confess("Undef to trick_taint") unless defined $_[0]; - my ($match) = $_[0] =~ /^(.*)$/s; - $_[0] = $match; + my $match = $_[0] =~ /^(.*)$/s; + $_[0] = $match ? $1 : undef; return (defined($_[0])); } sub detaint_natural { - my ($match) = $_[0] =~ /^(\d+)$/; - $_[0] = $match; + my $match = $_[0] =~ /^(\d+)$/; + $_[0] = $match ? $1 : undef; return (defined($_[0])); } sub detaint_signed { - my ($match) = $_[0] =~ /^([-+]?\d+)$/; - $_[0] = $match; + my $match = $_[0] =~ /^([-+]?\d+)$/; + $_[0] = $match ? $1 : undef; # Remove any leading plus sign. if (defined($_[0]) && $_[0] =~ /^\+(\d+)$/) { $_[0] = $1; diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm new file mode 100755 index 000000000..9e100c12a --- /dev/null +++ b/Bugzilla/WebService.pm @@ -0,0 +1,47 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService; + +use strict; +use Bugzilla::WebService::Constants; + +sub fail_unimplemented { + my $this = shift; + + die SOAP::Fault + ->faultcode(ERROR_UNIMPLEMENTED) + ->faultstring('Service Unimplemented'); +} + +package Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI; + +use strict; +eval 'use base qw(XMLRPC::Transport::HTTP::CGI)'; + +sub make_response { + my $self = shift; + + $self->SUPER::make_response(@_); + + # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around + # its cookies in Bugzilla::CGI, so we need to copy them over. + foreach (@{Bugzilla->cgi->{'Bugzilla_cookie_list'}}) { + $self->response->headers->push_header('Set-Cookie', $_); + } +} + +1; diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm new file mode 100755 index 000000000..6698fdc97 --- /dev/null +++ b/Bugzilla/WebService/Bug.pm @@ -0,0 +1,36 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService::Bug; + +use strict; +use base qw(Bugzilla::WebService); + +use Bugzilla::WebService::Constants; +use Bugzilla::Util qw(detaint_natural); +use Bugzilla::Bug; + +sub get_bug { + my $self = shift; + my ($bug_id) = @_; + + Bugzilla->login; + + ValidateBugID($bug_id); + return new Bugzilla::Bug($bug_id); +} + +1; diff --git a/Bugzilla/WebService/Bugzilla.pm b/Bugzilla/WebService/Bugzilla.pm new file mode 100755 index 000000000..0caf5fab2 --- /dev/null +++ b/Bugzilla/WebService/Bugzilla.pm @@ -0,0 +1,27 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService::Bugzilla; + +use strict; +use base qw(Bugzilla::WebService); +use Bugzilla::Constants; + +sub get_version { + return BUGZILLA_VERSION; +} + +1; diff --git a/Bugzilla/WebService/Constants.pm b/Bugzilla/WebService/Constants.pm new file mode 100755 index 000000000..2e9457add --- /dev/null +++ b/Bugzilla/WebService/Constants.pm @@ -0,0 +1,32 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService::Constants; + +use strict; +use base qw(Exporter); + +@Bugzilla::WebService::Constants::EXPORT = qw( + ERROR_AUTH_NODATA + ERROR_UNIMPLEMENTED + ERROR_GENERAL +); + +use constant ERROR_AUTH_NODATA => 410; +use constant ERROR_UNIMPLEMENTED => 910; +use constant ERROR_GENERAL => 999; + +1; diff --git a/Bugzilla/WebService/Product.pm b/Bugzilla/WebService/Product.pm new file mode 100755 index 000000000..b56abb588 --- /dev/null +++ b/Bugzilla/WebService/Product.pm @@ -0,0 +1,36 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService::Product; + +use strict; +use base qw(Bugzilla::WebService); +use Bugzilla::Product; + +sub get_product { + my $self = shift; + my ($product_name) = @_; + + Bugzilla->login; + + # Bugzilla::Product doesn't do permissions checks, so we can't do the call + # to Bugzilla::Product::new until a permissions check happens here. + $self->fail_unimplemented(); + + return new Bugzilla::Product({'name' => $product_name}); +} + +1; diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm new file mode 100755 index 000000000..813b2fc2a --- /dev/null +++ b/Bugzilla/WebService/User.pm @@ -0,0 +1,55 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +package Bugzilla::WebService::User; + +use strict; +use base qw(Bugzilla::WebService); +use Bugzilla; +use Bugzilla::Constants; + +sub login { + my $self = shift; + my ($login, $password, $remember) = @_; + + # Convert $remember from a boolean 0/1 value to a CGI-compatible one. + if (defined($remember)) { + $remember = $remember? 'on': ''; + } + else { + # Use Bugzilla's default if $remember is not supplied. + $remember = + Bugzilla->params->{'rememberlogin'} eq 'defaulton'? 'on': ''; + } + + # Make sure the CGI user info class works if necessary. + my $cgi = Bugzilla->cgi; + $cgi->param('Bugzilla_login', $login); + $cgi->param('Bugzilla_password', $password); + $cgi->param('Bugzilla_remember', $remember); + + Bugzilla->login; + return Bugzilla->user->id; +} + +sub logout { + my $self = shift; + + Bugzilla->login(LOGIN_OPTIONAL); + Bugzilla->logout; +} + +1; diff --git a/collectstats.pl b/collectstats.pl index 1672f679a..50bbf6425 100755 --- a/collectstats.pl +++ b/collectstats.pl @@ -55,8 +55,9 @@ if (chdir("graphs")) { chdir(".."); } -# Let Throw*Error() work correctly outside a web browser. -Bugzilla->batch(1); +# This is a pure command line script. +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + my $dbh = Bugzilla->switch_to_shadow_db(); # To recreate the daily statistics, run "collectstats.pl --regenerate" . diff --git a/contrib/bz_webservice_demo.pl b/contrib/bz_webservice_demo.pl new file mode 100755 index 000000000..a74274cab --- /dev/null +++ b/contrib/bz_webservice_demo.pl @@ -0,0 +1,260 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the “License”); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an “AS +# IS” basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +=head1 NAME + +bz_webservice_demo.pl - Show how to talk to Bugzilla via XMLRPC + +=head1 SYNOPSIS + +C<bz_webservice_demo.pl [options]> + +C<bz_webservice_demo.pl --help> for detailed help + +=cut + +use strict; +use Getopt::Long; +use Pod::Usage; +use File::Basename qw(dirname); +use File::Spec; +use HTTP::Cookies; +use XMLRPC::Lite; + +# If you want, say “use Bugzilla::WebService::Constants” here to get access +# to Bugzilla's web service error code constants. +# If you do this, remember to issue a “use lib” pointing to your Bugzilla +# installation directory, too. + +my $help; +my $Bugzilla_uri; +my $Bugzilla_login; +my $Bugzilla_password; +my $Bugzilla_remember; +my $bug_id; +my $product_name; + +GetOptions('help|h|?' => \$help, + 'uri=s' => \$Bugzilla_uri, + 'login:s' => \$Bugzilla_login, + 'password=s' => \$Bugzilla_password, + 'rememberlogin!' => \$Bugzilla_remember, + 'bug_id:s' => \$bug_id, + 'product_name:s' => \$product_name, + ) or pod2usage({'-verbose' => 0, '-exitval' => 1}); + +=head1 OPTIONS + +=over + +=item --help, -h, -? + +Print a short help message and exit. + +=item --uri + +URI to Bugzilla's C<xmlrpc.cgi> script, along the lines of +C<http://your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>. + +=item --login + +Bugzilla login name. Specify this together with B<--password> in order to log in. + +Specify this without a value in order to log out. + +=item --password + +Bugzilla password. Specify this together with B<--login> in order to log in. + +=item --rememberlogin + +Gives access to Bugzilla's “Bugzilla_remember” option. +Specify this option while logging in to do the same thing as ticking the +C<Bugzilla_remember> box on Bugilla's log in form. +Don't specify this option to do the same thing as unchecking the box. + +See Bugzilla's rememberlogin parameter for details. + +=item --bug_id + +Pass a bug ID to have C<bz_webservice_demo.pl> do some bug-related test calls. + +=item --product_name + +Pass a product name to have C<bz_webservice_demo.pl> do some product-related +test calls. + +=back + +=head1 DESCRIPTION + +=cut + +pod2usage({'-verbose' => 1, '-exitval' => 0}) if $help; +_syntaxhelp('URI unspecified') unless $Bugzilla_uri; + +# We will use this variable for SOAP call results. +my $soapresult; + +# We will use this variable for function call results. +my $result; + +# Open our cookie jar. We save it into a file so that we may re-use cookies +# to avoid the need of logging in every time. You're encouraged, but not +# required, to do this in your applications, too. +# Cookies are only saved if Bugzilla's rememberlogin parameter is set to one of +# - on +# - defaulton (and you didn't pass 0 as third parameter to User.login) +# - defaultoff (and you passed 1 as third parameter to User.login) +my $cookie_jar = + new HTTP::Cookies('file' => File::Spec->catdir(dirname($0), 'cookies.txt'), + 'autosave' => 1); + +=head2 Initialization + +Using the XMLRPC::Lite class, you set up a proxy, as shown in this script. +Bugzilla's XMLRPC URI ends in C<xmlrpc.cgi>, so your URI looks along the lines +of C<http://your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>. + +=cut + +my $proxy = XMLRPC::Lite->proxy($Bugzilla_uri, + 'cookie_jar' => $cookie_jar); + +=head2 Checking Bugzilla's version + +To make sure the Bugzilla you're connecting to supports the methods you wish to +call, you may want to compare the result of C<Bugzilla.get_version> to the +minimum required version your application needs. + +=cut + +$soapresult = $proxy->call('Bugzilla.get_version'); +_die_on_fault($soapresult); +print 'Connecting to a Bugzilla of version ' . $soapresult->result() . ".\n"; + +=head2 Logging In and Out + +=head3 Using Bugzilla's Environment Authentication + +Use a +C<http://login:password@your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi> +style URI. +You don't log out if you're using this kind of authentication. + +=head3 Using Bugzilla's CGI Variable Authentication + +Use the C<User.login> and C<User.logout> calls to log in and out, as shown +in this script. + +The C<Bugzilla_remember> parameter is optional. +If omitted, Bugzilla's defaults apply (as specified by its C<rememberlogin> +parameter). + +Bugzilla hands back cookies you'll need to pass along during your work calls. + +=cut + +if (defined($Bugzilla_login)) { + if ($Bugzilla_login ne '') { + # Log in. + $soapresult = $proxy->call('User.login', + $Bugzilla_login, $Bugzilla_password, + $Bugzilla_remember); + _die_on_fault($soapresult); + print "Login successful.\n"; + } + else { + # Log out. + $soapresult = $proxy->call('User.logout'); + _die_on_fault($soapresult); + print "Logout successful.\n"; + } +} + +=head2 Retrieving Bug Information + +Call C<Bug.get_bug> with the ID of the bug you want to know more of. +The call will return a C<Bugzilla::Bug> object. + +=cut + +if ($bug_id) { + $soapresult = $proxy->call('Bug.get_bug', $bug_id); + _die_on_fault($soapresult); + $result = $soapresult->result; + + foreach (keys(%$result)) { + print "$_: $$result{$_}\n"; + } +} + +=head2 Retrieving Product Information + +Call C<Product.get_product> with the name of the product you want to know more +of. +The call will return a C<Bugzilla::Product> object. + +=cut + +if ($product_name) { + $soapresult = $proxy->call('Product.get_product', $product_name); + _die_on_fault($soapresult); + $result = $soapresult->result; + + if (ref($result) eq 'HASH') { + foreach (keys(%$result)) { + print "$_: $$result{$_}\n"; + } + } + else { + print "$result\n"; + } +} + +=head1 NOTES + +=head2 Character Set Encoding + +Make sure that your application either uses the same character set +encoding as Bugzilla does, or that it converts correspondingly when using the +web service API. +By default, Bugzilla uses UTF-8 as its character set encoding. + +=head1 SEE ALSO + +There are code comments in C<bz_webservice_demo.pl> which might be of further +help to you. + +=cut + +sub _die_on_fault { + my $soapresult = shift; + + if ($soapresult->fault) { + my ($package, $filename, $line) = caller; + die $soapresult->faultcode . ' ' . $soapresult->faultstring . + " in SOAP call near $filename line $line.\n"; + } +} + +sub _syntaxhelp { + my $msg = shift; + + print "Error: $msg\n"; + pod2usage({'-verbose' => 0, '-exitval' => 1}); +} diff --git a/docs/xml/installation.xml b/docs/xml/installation.xml index ec71726f6..a5a3f3035 100644 --- a/docs/xml/installation.xml +++ b/docs/xml/installation.xml @@ -1,5 +1,5 @@ <!-- <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"> --> -<!-- $Id: installation.xml,v 1.127 2006/08/14 15:54:25 lpsolit%gmail.com Exp $ --> +<!-- $Id: installation.xml,v 1.128 2006/08/19 17:20:24 wurblzap%gmail.com Exp $ --> <chapter id="installing-bugzilla"> <title>Installing Bugzilla</title> @@ -387,6 +387,13 @@ <listitem> <para> + <link linkend="install-modules-soap-lite">SOAP::Lite</link> + (&min-soap-lite-ver;) for the web service interface + </para> + </listitem> + + <listitem> + <para> <link linkend="install-modules-patchreader">PatchReader</link> (&min-patchreader-ver;) for pretty HTML view of patches </para> @@ -488,6 +495,14 @@ </para> </section> + <section id="install-modules-soap"> + <title>SOAP::Lite (&min-soap-lite-ver;)</title> + <para>Installing SOAP::Lite enables your Bugzilla installation to be + accessible at a standardized Web Service interface (SOAP/XML-RPC) + by third-party applications via HTTP(S). + </para> + </section> + <section id="install-modules-patchreader"> <title>PatchReader (&min-patchreader-ver;)</title> diff --git a/importxml.pl b/importxml.pl index 68b2cd34f..b637f98fd 100755 --- a/importxml.pl +++ b/importxml.pl @@ -96,7 +96,7 @@ use XML::Twig; # We want to capture errors and handle them here rather than have the Template # code barf all over the place. -Bugzilla->batch(1); +Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE); my $debug = 0; my $mail = ''; diff --git a/post_bug.cgi b/post_bug.cgi index aac15f3bf..d8f2150e9 100755 --- a/post_bug.cgi +++ b/post_bug.cgi @@ -559,10 +559,11 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl')) { # Add flags, if any. To avoid dying if something goes wrong # while processing flags, we will eval() flag validation. -# This requires to be in batch mode. +# This requires errors to die(). # XXX: this can go away as soon as flag validation is able to # fail without dying. -Bugzilla->batch(1); +my $error_mode_cache = Bugzilla->error_mode; +Bugzilla->error_mode(ERROR_MODE_DIE); eval { # Make sure no flags have already been set for this bug. # Impossible? - Well, depends if you hack the URL or not. @@ -571,7 +572,7 @@ eval { Bugzilla::FlagType::validate($cgi, $id); Bugzilla::Flag::process($bug, undef, $timestamp, $cgi); }; -Bugzilla->batch(0); +Bugzilla->error_mode($error_mode_cache); if ($@) { $vars->{'message'} = 'flag_creation_failed'; $vars->{'flag_creation_error'} = $@; diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl index 0fbc16249..bf91160cf 100644 --- a/template/en/default/global/code-error.html.tmpl +++ b/template/en/default/global/code-error.html.tmpl @@ -104,7 +104,7 @@ Unable to open the chart datafile <tt>[% filename FILTER html %]</tt>. [% ELSIF error == "chart_lines_not_installed" %] - [% admindocslinks = {'installation.html#install-perlmodules' => 'Installing perl modules necessary for Charting'} %] + [% admindocslinks = {'installation.html#install-perlmodules' => 'Installing Perl modules necessary for Charting'} %] Charts will not work without the Chart::Lines Perl module being installed. Run checksetup.pl for installation instructions. @@ -137,7 +137,7 @@ and <code>[% type FILTER html %]</code> together. [% ELSIF error == "gd_not_installed" %] - [% admindocslinks = {'installation.html#install-perlmodules' => 'Installing perl modules necessary for Charting'} %] + [% admindocslinks = {'installation.html#install-perlmodules' => 'Installing Perl modules necessary for Charting'} %] Charts will not work without the GD Perl module being installed. Run checksetup.pl for installation instructions. @@ -321,6 +321,12 @@ The value "<code>[% value FILTER html %]</code>" is not in the list of legal values for the <em>[% name FILTER html %]</em> setting. + [% ELSIF error == "soap_not_installed" %] + [% admindocslinks = {'installation.html#install-perlmodules' => 'Installing Perl modules'} %] + The XMLRPC interface will not work without the SOAP::Lite Perl module being + installed. + Run checksetup.pl for installation instructions. + [% ELSIF error == "token_generation_error" %] Something is seriously wrong with the token generation system. @@ -347,6 +353,9 @@ I could not figure out what you wanted to do. [% END %] + [% ELSIF error == "usage_mode_invalid" %] + '[% invalid_usage_mode %]' is not a valid usage mode. + [% ELSIF error == "must_be_patch" %] [% title = "Attachment Must Be Patch" %] Attachment #[% attach_id FILTER html %] must be a patch. @@ -383,9 +392,11 @@ [% END %] [% END %] -[%# If we are in batch mode, we want the error message to be plain text, not HTML %] +[%# If we are in ERROR_MODE_DIE, we want the error message to be plain text, + # not HTML +%] [% USE Bugzilla %] -[% IF Bugzilla.batch %] +[% IF Bugzilla.error_mode == ERROR_MODE_DIE %] [% error_message FILTER none %] [% RETURN %] [% END %] diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index c1bb099cf..53fb3ae27 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1422,9 +1422,11 @@ [% END %] [% END %] -[%# If we are in batch mode, we want the error message to be plain text, not HTML %] +[%# If we are in ERROR_MODE_DIE, we want the error message to be plain text, + # not HTML +%] [% USE Bugzilla %] -[% IF Bugzilla.batch %] +[% IF Bugzilla.error_mode == ERROR_MODE_DIE %] [% error_message FILTER none %] [% RETURN %] [% END %] diff --git a/xmlrpc.cgi b/xmlrpc.cgi new file mode 100755 index 000000000..e4dfacc43 --- /dev/null +++ b/xmlrpc.cgi @@ -0,0 +1,38 @@ +#!/usr/bin/perl -wT +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Marc Schumann <wurblzap@gmail.com> + +use strict; +use lib qw(.); + +use Bugzilla; +use Bugzilla::Constants; + +# Use an eval here so that runtests.pl accepts this script even if SOAP-Lite +# is not installed. +eval 'use XMLRPC::Transport::HTTP; + use Bugzilla::WebService;'; +$@ && ThrowCodeError('soap_not_installed'); + +Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_WEBSERVICE); + +my $response = Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI + ->dispatch_with({'Bugzilla' => 'Bugzilla::WebService::Bugzilla', + 'Bug' => 'Bugzilla::WebService::Bug', + 'User' => 'Bugzilla::WebService::User', + 'Product' => 'Bugzilla::WebService::Product', + }) + ->handle; |