323 lines
10 KiB
Perl
323 lines
10 KiB
Perl
# 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::Constants;
|
|
|
|
use 5.10.1;
|
|
use strict;
|
|
use warnings;
|
|
|
|
use parent qw(Exporter);
|
|
|
|
our @EXPORT = qw(
|
|
WS_ERROR_CODE
|
|
|
|
STATUS_OK
|
|
STATUS_CREATED
|
|
STATUS_ACCEPTED
|
|
STATUS_NO_CONTENT
|
|
STATUS_MULTIPLE_CHOICES
|
|
STATUS_BAD_REQUEST
|
|
STATUS_NOT_FOUND
|
|
STATUS_GONE
|
|
REST_STATUS_CODE_MAP
|
|
|
|
ERROR_UNKNOWN_FATAL
|
|
ERROR_UNKNOWN_TRANSIENT
|
|
|
|
XMLRPC_CONTENT_TYPE_WHITELIST
|
|
REST_CONTENT_TYPE_WHITELIST
|
|
|
|
WS_DISPATCH
|
|
);
|
|
|
|
# This maps the error names in global/*-error.html.tmpl to numbers.
|
|
# Generally, transient errors should have a number above 0, and
|
|
# fatal errors should have a number below 0.
|
|
#
|
|
# This hash should generally contain any error that could be thrown
|
|
# by the WebService interface. If it's extremely unlikely that the
|
|
# error could be thrown (like some CodeErrors), it doesn't have to
|
|
# be listed here.
|
|
#
|
|
# "Transient" means "If you resubmit that request with different data,
|
|
# it may work."
|
|
#
|
|
# "Fatal" means, "There's something wrong with Bugzilla, probably
|
|
# something an administrator would have to fix."
|
|
#
|
|
# NOTE: Numbers must never be recycled. If you remove a number, leave a
|
|
# comment that it was retired. Also, if an error changes its name, you'll
|
|
# have to fix it here.
|
|
use constant WS_ERROR_CODE => {
|
|
# Generic errors (Bugzilla::Object and others) are 50-99.
|
|
object_not_specified => 50,
|
|
reassign_to_empty => 50,
|
|
param_required => 50,
|
|
params_required => 50,
|
|
undefined_field => 50,
|
|
object_does_not_exist => 51,
|
|
param_must_be_numeric => 52,
|
|
number_not_numeric => 52,
|
|
param_invalid => 53,
|
|
number_too_large => 54,
|
|
number_too_small => 55,
|
|
illegal_date => 56,
|
|
param_integer_required => 57,
|
|
param_scalar_array_required => 58,
|
|
# Bug errors usually occupy the 100-200 range.
|
|
improper_bug_id_field_value => 100,
|
|
bug_id_does_not_exist => 101,
|
|
bug_access_denied => 102,
|
|
bug_access_query => 102,
|
|
# These all mean "invalid alias"
|
|
alias_too_long => 103,
|
|
alias_in_use => 103,
|
|
alias_is_numeric => 103,
|
|
alias_has_comma_or_space => 103,
|
|
multiple_alias_not_allowed => 103,
|
|
# Misc. bug field errors
|
|
illegal_field => 104,
|
|
freetext_too_long => 104,
|
|
# Component errors
|
|
require_component => 105,
|
|
component_name_too_long => 105,
|
|
product_unknown_component => 105,
|
|
# Invalid Product
|
|
no_products => 106,
|
|
entry_access_denied => 106,
|
|
product_access_denied => 106,
|
|
product_disabled => 106,
|
|
# Invalid Summary
|
|
require_summary => 107,
|
|
# Invalid field name
|
|
invalid_field_name => 108,
|
|
# Not authorized to edit the bug
|
|
product_edit_denied => 109,
|
|
# Comment-related errors
|
|
comment_is_private => 110,
|
|
comment_id_invalid => 111,
|
|
comment_too_long => 114,
|
|
comment_invalid_isprivate => 117,
|
|
# Comment tagging
|
|
comment_tag_disabled => 125,
|
|
comment_tag_invalid => 126,
|
|
comment_tag_too_long => 127,
|
|
comment_tag_too_short => 128,
|
|
# See Also errors
|
|
bug_url_invalid => 112,
|
|
bug_url_too_long => 112,
|
|
# Insidergroup Errors
|
|
user_not_insider => 113,
|
|
# Note: 114 is above in the Comment-related section.
|
|
# Bug update errors
|
|
illegal_change => 115,
|
|
# Dependency errors
|
|
dependency_loop_single => 116,
|
|
dependency_loop_multi => 116,
|
|
# Note: 117 is above in the Comment-related section.
|
|
# Dup errors
|
|
dupe_loop_detected => 118,
|
|
dupe_id_required => 119,
|
|
# Bug-related group errors
|
|
group_invalid_removal => 120,
|
|
group_restriction_not_allowed => 120,
|
|
# Status/Resolution errors
|
|
missing_resolution => 121,
|
|
resolution_not_allowed => 122,
|
|
illegal_bug_status_transition => 123,
|
|
# Flag errors
|
|
flag_status_invalid => 129,
|
|
flag_update_denied => 130,
|
|
flag_type_requestee_disabled => 131,
|
|
flag_not_unique => 132,
|
|
flag_type_not_unique => 133,
|
|
flag_type_inactive => 134,
|
|
|
|
# Authentication errors are usually 300-400.
|
|
invalid_login_or_password => 300,
|
|
account_disabled => 301,
|
|
auth_invalid_email => 302,
|
|
extern_id_conflict => -303,
|
|
auth_failure => 304,
|
|
password_too_short => 305,
|
|
password_not_complex => 305,
|
|
api_key_not_valid => 306,
|
|
api_key_revoked => 306,
|
|
auth_invalid_token => 307,
|
|
|
|
# Except, historically, AUTH_NODATA, which is 410.
|
|
login_required => 410,
|
|
|
|
# User errors are 500-600.
|
|
account_exists => 500,
|
|
illegal_email_address => 501,
|
|
auth_cant_create_account => 501,
|
|
account_creation_disabled => 501,
|
|
account_creation_restricted => 501,
|
|
password_too_short => 502,
|
|
# Error 503 password_too_long no longer exists.
|
|
invalid_username => 504,
|
|
# This is from strict_isolation, but it also basically means
|
|
# "invalid user."
|
|
invalid_user_group => 504,
|
|
user_access_by_id_denied => 505,
|
|
user_access_by_match_denied => 505,
|
|
|
|
# Attachment errors are 600-700.
|
|
file_too_large => 600,
|
|
invalid_content_type => 601,
|
|
# Error 602 attachment_illegal_url no longer exists.
|
|
file_not_specified => 603,
|
|
missing_attachment_description => 604,
|
|
# Error 605 attachment_url_disabled no longer exists.
|
|
zero_length_file => 606,
|
|
|
|
# Product erros are 700-800
|
|
product_blank_name => 700,
|
|
product_name_too_long => 701,
|
|
product_name_already_in_use => 702,
|
|
product_name_diff_in_case => 702,
|
|
product_must_have_description => 703,
|
|
product_must_have_version => 704,
|
|
product_must_define_defaultmilestone => 705,
|
|
|
|
# Group errors are 800-900
|
|
empty_group_name => 800,
|
|
group_exists => 801,
|
|
empty_group_description => 802,
|
|
invalid_regexp => 803,
|
|
invalid_group_name => 804,
|
|
group_cannot_view => 805,
|
|
|
|
# Classification errors are 900-1000
|
|
auth_classification_not_enabled => 900,
|
|
|
|
# Search errors are 1000-1100
|
|
buglist_parameters_required => 1000,
|
|
|
|
# Flag type errors are 1100-1200
|
|
flag_type_name_invalid => 1101,
|
|
flag_type_description_invalid => 1102,
|
|
flag_type_cc_list_invalid => 1103,
|
|
flag_type_sortkey_invalid => 1104,
|
|
flag_type_not_editable => 1105,
|
|
|
|
# Component errors are 1200-1300
|
|
component_already_exists => 1200,
|
|
component_is_last => 1201,
|
|
component_has_bugs => 1202,
|
|
|
|
# Errors thrown by the WebService itself. The ones that are negative
|
|
# conform to http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
|
|
xmlrpc_invalid_value => -32600,
|
|
unknown_method => -32601,
|
|
json_rpc_post_only => 32610,
|
|
json_rpc_invalid_callback => 32611,
|
|
xmlrpc_illegal_content_type => 32612,
|
|
json_rpc_illegal_content_type => 32613,
|
|
rest_invalid_resource => 32614,
|
|
};
|
|
|
|
# RESTful webservices use the http status code
|
|
# to describe whether a call was successful or
|
|
# to describe the type of error that occurred.
|
|
use constant STATUS_OK => 200;
|
|
use constant STATUS_CREATED => 201;
|
|
use constant STATUS_ACCEPTED => 202;
|
|
use constant STATUS_NO_CONTENT => 204;
|
|
use constant STATUS_MULTIPLE_CHOICES => 300;
|
|
use constant STATUS_BAD_REQUEST => 400;
|
|
use constant STATUS_NOT_AUTHORIZED => 401;
|
|
use constant STATUS_NOT_FOUND => 404;
|
|
use constant STATUS_GONE => 410;
|
|
|
|
# The integer value is the error code above returned by
|
|
# the related webvservice call. We choose the appropriate
|
|
# http status code based on the error code or use the
|
|
# default STATUS_BAD_REQUEST.
|
|
sub REST_STATUS_CODE_MAP {
|
|
my $status_code_map = {
|
|
51 => STATUS_NOT_FOUND,
|
|
101 => STATUS_NOT_FOUND,
|
|
102 => STATUS_NOT_AUTHORIZED,
|
|
106 => STATUS_NOT_AUTHORIZED,
|
|
109 => STATUS_NOT_AUTHORIZED,
|
|
110 => STATUS_NOT_AUTHORIZED,
|
|
113 => STATUS_NOT_AUTHORIZED,
|
|
115 => STATUS_NOT_AUTHORIZED,
|
|
120 => STATUS_NOT_AUTHORIZED,
|
|
300 => STATUS_NOT_AUTHORIZED,
|
|
301 => STATUS_NOT_AUTHORIZED,
|
|
302 => STATUS_NOT_AUTHORIZED,
|
|
303 => STATUS_NOT_AUTHORIZED,
|
|
304 => STATUS_NOT_AUTHORIZED,
|
|
410 => STATUS_NOT_AUTHORIZED,
|
|
504 => STATUS_NOT_AUTHORIZED,
|
|
505 => STATUS_NOT_AUTHORIZED,
|
|
32614 => STATUS_NOT_FOUND,
|
|
_default => STATUS_BAD_REQUEST
|
|
};
|
|
|
|
Bugzilla::Hook::process('webservice_status_code_map',
|
|
{ status_code_map => $status_code_map });
|
|
|
|
return $status_code_map;
|
|
};
|
|
|
|
# These are the fallback defaults for errors not in ERROR_CODE.
|
|
use constant ERROR_UNKNOWN_FATAL => -32000;
|
|
use constant ERROR_UNKNOWN_TRANSIENT => 32000;
|
|
|
|
use constant ERROR_GENERAL => 999;
|
|
|
|
use constant XMLRPC_CONTENT_TYPE_WHITELIST => qw(
|
|
text/xml
|
|
application/xml
|
|
);
|
|
|
|
# The first content type specified is used as the default.
|
|
use constant REST_CONTENT_TYPE_WHITELIST => qw(
|
|
application/json
|
|
application/javascript
|
|
text/javascript
|
|
text/html
|
|
);
|
|
|
|
sub WS_DISPATCH {
|
|
# We "require" here instead of "use" above to avoid a dependency loop.
|
|
require Bugzilla::Hook;
|
|
my %hook_dispatch;
|
|
Bugzilla::Hook::process('webservice', { dispatch => \%hook_dispatch });
|
|
|
|
my $dispatch = {
|
|
'Bugzilla' => 'Bugzilla::WebService::Bugzilla',
|
|
'Bug' => 'Bugzilla::WebService::Bug',
|
|
'Classification' => 'Bugzilla::WebService::Classification',
|
|
'Component' => 'Bugzilla::WebService::Component',
|
|
'FlagType' => 'Bugzilla::WebService::FlagType',
|
|
'Group' => 'Bugzilla::WebService::Group',
|
|
'Product' => 'Bugzilla::WebService::Product',
|
|
'User' => 'Bugzilla::WebService::User',
|
|
'BugUserLastVisit' => 'Bugzilla::WebService::BugUserLastVisit',
|
|
%hook_dispatch
|
|
};
|
|
return $dispatch;
|
|
};
|
|
|
|
1;
|
|
|
|
=head1 B<Methods in need of POD>
|
|
|
|
=over
|
|
|
|
=item REST_STATUS_CODE_MAP
|
|
|
|
=item WS_DISPATCH
|
|
|
|
=back
|