aboutsummaryrefslogtreecommitdiffstats
path: root/Bugzilla/WebService/Constants.pm
blob: e32b9ad0f03e4d064f9cf42c6140dd578aca8b3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# 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_integer_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