1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4# 5# This Source Code Form is "Incompatible With Secondary Licenses", as 6# defined by the Mozilla Public License, v. 2.0. 7 8package Bugzilla::WebService::Constants; 9 10use 5.10.1; 11use strict; 12use warnings; 13 14use parent qw(Exporter); 15 16our @EXPORT = qw( 17 WS_ERROR_CODE 18 19 STATUS_OK 20 STATUS_CREATED 21 STATUS_ACCEPTED 22 STATUS_NO_CONTENT 23 STATUS_MULTIPLE_CHOICES 24 STATUS_BAD_REQUEST 25 STATUS_NOT_FOUND 26 STATUS_GONE 27 REST_STATUS_CODE_MAP 28 29 ERROR_UNKNOWN_FATAL 30 ERROR_UNKNOWN_TRANSIENT 31 32 XMLRPC_CONTENT_TYPE_WHITELIST 33 REST_CONTENT_TYPE_WHITELIST 34 35 WS_DISPATCH 36); 37 38# This maps the error names in global/*-error.html.tmpl to numbers. 39# Generally, transient errors should have a number above 0, and 40# fatal errors should have a number below 0. 41# 42# This hash should generally contain any error that could be thrown 43# by the WebService interface. If it's extremely unlikely that the 44# error could be thrown (like some CodeErrors), it doesn't have to 45# be listed here. 46# 47# "Transient" means "If you resubmit that request with different data, 48# it may work." 49# 50# "Fatal" means, "There's something wrong with Bugzilla, probably 51# something an administrator would have to fix." 52# 53# NOTE: Numbers must never be recycled. If you remove a number, leave a 54# comment that it was retired. Also, if an error changes its name, you'll 55# have to fix it here. 56use constant WS_ERROR_CODE => { 57 # Generic errors (Bugzilla::Object and others) are 50-99. 58 object_not_specified => 50, 59 reassign_to_empty => 50, 60 param_required => 50, 61 params_required => 50, 62 undefined_field => 50, 63 object_does_not_exist => 51, 64 param_must_be_numeric => 52, 65 number_not_numeric => 52, 66 param_invalid => 53, 67 number_too_large => 54, 68 number_too_small => 55, 69 illegal_date => 56, 70 param_integer_required => 57, 71 param_scalar_array_required => 58, 72 # Bug errors usually occupy the 100-200 range. 73 improper_bug_id_field_value => 100, 74 bug_id_does_not_exist => 101, 75 bug_access_denied => 102, 76 bug_access_query => 102, 77 # These all mean "invalid alias" 78 alias_too_long => 103, 79 alias_in_use => 103, 80 alias_is_numeric => 103, 81 alias_has_comma_or_space => 103, 82 multiple_alias_not_allowed => 103, 83 # Misc. bug field errors 84 illegal_field => 104, 85 freetext_too_long => 104, 86 # Component errors 87 require_component => 105, 88 component_name_too_long => 105, 89 product_unknown_component => 105, 90 # Invalid Product 91 no_products => 106, 92 entry_access_denied => 106, 93 product_access_denied => 106, 94 product_disabled => 106, 95 # Invalid Summary 96 require_summary => 107, 97 # Invalid field name 98 invalid_field_name => 108, 99 # Not authorized to edit the bug 100 product_edit_denied => 109, 101 # Comment-related errors 102 comment_is_private => 110, 103 comment_id_invalid => 111, 104 comment_too_long => 114, 105 comment_invalid_isprivate => 117, 106 # Comment tagging 107 comment_tag_disabled => 125, 108 comment_tag_invalid => 126, 109 comment_tag_too_long => 127, 110 comment_tag_too_short => 128, 111 # See Also errors 112 bug_url_invalid => 112, 113 bug_url_too_long => 112, 114 # Insidergroup Errors 115 user_not_insider => 113, 116 # Note: 114 is above in the Comment-related section. 117 # Bug update errors 118 illegal_change => 115, 119 # Dependency errors 120 dependency_loop_single => 116, 121 dependency_loop_multi => 116, 122 # Note: 117 is above in the Comment-related section. 123 # Dup errors 124 dupe_loop_detected => 118, 125 dupe_id_required => 119, 126 # Bug-related group errors 127 group_invalid_removal => 120, 128 group_restriction_not_allowed => 120, 129 # Status/Resolution errors 130 missing_resolution => 121, 131 resolution_not_allowed => 122, 132 illegal_bug_status_transition => 123, 133 # Flag errors 134 flag_status_invalid => 129, 135 flag_update_denied => 130, 136 flag_type_requestee_disabled => 131, 137 flag_not_unique => 132, 138 flag_type_not_unique => 133, 139 flag_type_inactive => 134, 140 141 # Authentication errors are usually 300-400. 142 invalid_login_or_password => 300, 143 account_disabled => 301, 144 auth_invalid_email => 302, 145 extern_id_conflict => -303, 146 auth_failure => 304, 147 password_too_short => 305, 148 password_not_complex => 305, 149 api_key_not_valid => 306, 150 api_key_revoked => 306, 151 auth_invalid_token => 307, 152 153 # Except, historically, AUTH_NODATA, which is 410. 154 login_required => 410, 155 156 # User errors are 500-600. 157 account_exists => 500, 158 illegal_email_address => 501, 159 auth_cant_create_account => 501, 160 account_creation_disabled => 501, 161 account_creation_restricted => 501, 162 password_too_short => 502, 163 # Error 503 password_too_long no longer exists. 164 invalid_username => 504, 165 # This is from strict_isolation, but it also basically means 166 # "invalid user." 167 invalid_user_group => 504, 168 user_access_by_id_denied => 505, 169 user_access_by_match_denied => 505, 170 171 # Attachment errors are 600-700. 172 file_too_large => 600, 173 invalid_content_type => 601, 174 # Error 602 attachment_illegal_url no longer exists. 175 file_not_specified => 603, 176 missing_attachment_description => 604, 177 # Error 605 attachment_url_disabled no longer exists. 178 zero_length_file => 606, 179 180 # Product erros are 700-800 181 product_blank_name => 700, 182 product_name_too_long => 701, 183 product_name_already_in_use => 702, 184 product_name_diff_in_case => 702, 185 product_must_have_description => 703, 186 product_must_have_version => 704, 187 product_must_define_defaultmilestone => 705, 188 189 # Group errors are 800-900 190 empty_group_name => 800, 191 group_exists => 801, 192 empty_group_description => 802, 193 invalid_regexp => 803, 194 invalid_group_name => 804, 195 group_cannot_view => 805, 196 197 # Classification errors are 900-1000 198 auth_classification_not_enabled => 900, 199 200 # Search errors are 1000-1100 201 buglist_parameters_required => 1000, 202 203 # Flag type errors are 1100-1200 204 flag_type_name_invalid => 1101, 205 flag_type_description_invalid => 1102, 206 flag_type_cc_list_invalid => 1103, 207 flag_type_sortkey_invalid => 1104, 208 flag_type_not_editable => 1105, 209 210 # Component errors are 1200-1300 211 component_already_exists => 1200, 212 component_is_last => 1201, 213 component_has_bugs => 1202, 214 215 # Errors thrown by the WebService itself. The ones that are negative 216 # conform to http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php 217 xmlrpc_invalid_value => -32600, 218 unknown_method => -32601, 219 json_rpc_post_only => 32610, 220 json_rpc_invalid_callback => 32611, 221 xmlrpc_illegal_content_type => 32612, 222 json_rpc_illegal_content_type => 32613, 223 rest_invalid_resource => 32614, 224}; 225 226# RESTful webservices use the http status code 227# to describe whether a call was successful or 228# to describe the type of error that occurred. 229use constant STATUS_OK => 200; 230use constant STATUS_CREATED => 201; 231use constant STATUS_ACCEPTED => 202; 232use constant STATUS_NO_CONTENT => 204; 233use constant STATUS_MULTIPLE_CHOICES => 300; 234use constant STATUS_BAD_REQUEST => 400; 235use constant STATUS_NOT_AUTHORIZED => 401; 236use constant STATUS_NOT_FOUND => 404; 237use constant STATUS_GONE => 410; 238 239# The integer value is the error code above returned by 240# the related webvservice call. We choose the appropriate 241# http status code based on the error code or use the 242# default STATUS_BAD_REQUEST. 243sub REST_STATUS_CODE_MAP { 244 my $status_code_map = { 245 51 => STATUS_NOT_FOUND, 246 101 => STATUS_NOT_FOUND, 247 102 => STATUS_NOT_AUTHORIZED, 248 106 => STATUS_NOT_AUTHORIZED, 249 109 => STATUS_NOT_AUTHORIZED, 250 110 => STATUS_NOT_AUTHORIZED, 251 113 => STATUS_NOT_AUTHORIZED, 252 115 => STATUS_NOT_AUTHORIZED, 253 120 => STATUS_NOT_AUTHORIZED, 254 300 => STATUS_NOT_AUTHORIZED, 255 301 => STATUS_NOT_AUTHORIZED, 256 302 => STATUS_NOT_AUTHORIZED, 257 303 => STATUS_NOT_AUTHORIZED, 258 304 => STATUS_NOT_AUTHORIZED, 259 410 => STATUS_NOT_AUTHORIZED, 260 504 => STATUS_NOT_AUTHORIZED, 261 505 => STATUS_NOT_AUTHORIZED, 262 32614 => STATUS_NOT_FOUND, 263 _default => STATUS_BAD_REQUEST 264 }; 265 266 Bugzilla::Hook::process('webservice_status_code_map', 267 { status_code_map => $status_code_map }); 268 269 return $status_code_map; 270}; 271 272# These are the fallback defaults for errors not in ERROR_CODE. 273use constant ERROR_UNKNOWN_FATAL => -32000; 274use constant ERROR_UNKNOWN_TRANSIENT => 32000; 275 276use constant ERROR_GENERAL => 999; 277 278use constant XMLRPC_CONTENT_TYPE_WHITELIST => qw( 279 text/xml 280 application/xml 281); 282 283# The first content type specified is used as the default. 284use constant REST_CONTENT_TYPE_WHITELIST => qw( 285 application/json 286 application/javascript 287 text/javascript 288 text/html 289); 290 291sub WS_DISPATCH { 292 # We "require" here instead of "use" above to avoid a dependency loop. 293 require Bugzilla::Hook; 294 my %hook_dispatch; 295 Bugzilla::Hook::process('webservice', { dispatch => \%hook_dispatch }); 296 297 my $dispatch = { 298 'Bugzilla' => 'Bugzilla::WebService::Bugzilla', 299 'Bug' => 'Bugzilla::WebService::Bug', 300 'Classification' => 'Bugzilla::WebService::Classification', 301 'Component' => 'Bugzilla::WebService::Component', 302 'FlagType' => 'Bugzilla::WebService::FlagType', 303 'Group' => 'Bugzilla::WebService::Group', 304 'Product' => 'Bugzilla::WebService::Product', 305 'User' => 'Bugzilla::WebService::User', 306 'BugUserLastVisit' => 'Bugzilla::WebService::BugUserLastVisit', 307 %hook_dispatch 308 }; 309 return $dispatch; 310}; 311 3121; 313 314=head1 B<Methods in need of POD> 315 316=over 317 318=item REST_STATUS_CODE_MAP 319 320=item WS_DISPATCH 321 322=back 323