RSS

(root)/bugzilla/trunk : /Bugzilla.pm (revision 8182)

To get this branch, use:
bzr branch /bugzilla/trunk
Line Revision Contents
1 8075
# 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 1990
8
package Bugzilla;
9
10
use strict;
11
12 5389
# We want any compile errors to get to the browser, if possible.
13
BEGIN {
14
    # This makes sure we're in a CGI.
15
    if ($ENV{SERVER_SOFTWARE} && !$ENV{MOD_PERL}) {
16
        require CGI::Carp;
17
        CGI::Carp->import('fatalsToBrowser');
18
    }
19
}
20
21 4406
use Bugzilla::Config;
22 4289
use Bugzilla::Constants;
23 2104
use Bugzilla::Auth;
24 4154
use Bugzilla::Auth::Persist::Cookie;
25 1990
use Bugzilla::CGI;
26 6854
use Bugzilla::Extension;
27 2026
use Bugzilla::DB;
28 4516
use Bugzilla::Install::Localconfig qw(read_localconfig);
29 6761
use Bugzilla::Install::Requirements qw(OPTIONAL_MODULES);
30 7257
use Bugzilla::Install::Util qw(init_console);
31 1990
use Bugzilla::Template;
32 2104
use Bugzilla::User;
33 3517
use Bugzilla::Error;
34
use Bugzilla::Util;
35 3966
use Bugzilla::Field;
36 5517
use Bugzilla::Flag;
37 7429
use Bugzilla::Token;
38 3517
39
use File::Basename;
40 5203
use File::Spec::Functions;
41 6197
use DateTime::TimeZone;
42 7429
use Date::Parse;
43 4175
use Safe;
44 3517
45
#####################################################################
46
# Constants
47
#####################################################################
48
49
# Scripts that are not stopped by shutdownhtml being in effect.
50 7138
use constant SHUTDOWNHTML_EXEMPT => qw(
51
    editparams.cgi
52
    checksetup.pl
53
    migrate.pl
54
    recode.pl
55
);
56 3517
57 3718
# Non-cgi scripts that should silently exit.
58 7138
use constant SHUTDOWNHTML_EXIT_SILENTLY => qw(
59
    whine.pl
60
);
61 3718
62 7758
# shutdownhtml pages are sent as an HTTP 503. After how many seconds
63
# should search engines attempt to index the page again?
64
use constant SHUTDOWNHTML_RETRY_AFTER => 3600;
65
66 3517
#####################################################################
67
# Global Code
68
#####################################################################
69
70 6263
# $::SIG{__DIE__} = i_am_cgi() ? \&CGI::Carp::confess : \&Carp::confess;
71 4325
72 5249
# Note that this is a raw subroutine, not a method, so $class isn't available.
73 4551
sub init_page {
74 7257
    if (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) {
75
        init_console();
76
    }
77
    elsif (Bugzilla->params->{'utf8'}) {
78
        binmode STDOUT, ':utf8';
79
    }
80 4551
81 6364
    if (${^TAINT}) {
82
        # Some environment variables are not taint safe
83
        delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
84
        # Some modules throw undefined errors (notably File::Spec::Win32) if
85
        # PATH is undefined.
86
        $ENV{'PATH'} = '';
87
    }
88 4551
89 6767
    # Because this function is run live from perl "use" commands of
90
    # other scripts, we're skipping the rest of this function if we get here
91
    # during a perl syntax check (perl -c, like we do during the
92
    # 001compile.t test).
93
    return if $^C;
94
95 5169
    # IIS prints out warnings to the webpage, so ignore them, or log them
96
    # to a file if the file exists.
97
    if ($ENV{SERVER_SOFTWARE} && $ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i) {
98
        $SIG{__WARN__} = sub {
99
            my ($msg) = @_;
100
            my $datadir = bz_locations()->{'datadir'};
101
            if (-w "$datadir/errorlog") {
102
                my $warning_log = new IO::File(">>$datadir/errorlog");
103
                print $warning_log $msg;
104
                $warning_log->close();
105
            }
106
        };
107
    }
108
109 7138
    my $script = basename($0);
110
111 6779
    # Because of attachment_base, attachment.cgi handles this itself.
112 7138
    if ($script ne 'attachment.cgi') {
113 6779
        do_ssl_redirect_if_required();
114
    }
115 6767
116 4551
    # If Bugzilla is shut down, do not allow anything to run, just display a
117
    # message to the user about the downtime and log out.  Scripts listed in 
118
    # SHUTDOWNHTML_EXEMPT are exempt from this message.
119
    #
120
    # This code must go here. It cannot go anywhere in Bugzilla::CGI, because
121
    # it uses Template, and that causes various dependency loops.
122 7138
    if (Bugzilla->params->{"shutdownhtml"}
123
        && !grep { $_ eq $script } SHUTDOWNHTML_EXEMPT)
124 3718
    {
125 4551
        # Allow non-cgi scripts to exit silently (without displaying any
126
        # message), if desired. At this point, no DBI call has been made
127
        # yet, and no error will be returned if the DB is inaccessible.
128 7138
        if (!i_am_cgi()
129
            && grep { $_ eq $script } SHUTDOWNHTML_EXIT_SILENTLY)
130 4551
        {
131
            exit;
132
        }
133
134
        # For security reasons, log out users when Bugzilla is down.
135
        # Bugzilla->login() is required to catch the logincookie, if any.
136 6247
        my $user;
137
        eval { $user = Bugzilla->login(LOGIN_OPTIONAL); };
138
        if ($@) {
139
            # The DB is not accessible. Use the default user object.
140
            $user = Bugzilla->user;
141
            $user->{settings} = {};
142
        }
143 4551
        my $userid = $user->id;
144
        Bugzilla->logout();
145
146
        my $template = Bugzilla->template;
147
        my $vars = {};
148
        $vars->{'message'} = 'shutdown';
149
        $vars->{'userid'} = $userid;
150
        # Generate and return a message about the downtime, appropriately
151
        # for if we're a command-line script or a CGI script.
152
        my $extension;
153
        if (i_am_cgi() && (!Bugzilla->cgi->param('ctype')
154
                           || Bugzilla->cgi->param('ctype') eq 'html')) {
155
            $extension = 'html';
156
        }
157
        else {
158
            $extension = 'txt';
159
        }
160 7758
        if (i_am_cgi()) {
161
            # Set the HTTP status to 503 when Bugzilla is down to avoid pages
162
            # being indexed by search engines.
163
            print Bugzilla->cgi->header(-status => 503, 
164
                -retry_after => SHUTDOWNHTML_RETRY_AFTER);
165
        }
166 4551
        my $t_output;
167
        $template->process("global/message.$extension.tmpl", $vars, \$t_output)
168
            || ThrowTemplateError($template->error);
169
        print $t_output . "\n";
170 3718
        exit;
171
    }
172 3517
}
173
174
#####################################################################
175
# Subroutines and Methods
176
#####################################################################
177 1990
178 2054
sub template {
179
    my $class = shift;
180 5249
    $class->request_cache->{template} ||= Bugzilla::Template->create();
181
    return $class->request_cache->{template};
182 2054
}
183
184 4563
sub template_inner {
185 4735
    my ($class, $lang) = @_;
186 7038
    my $cache = $class->request_cache;
187
    my $current_lang = $cache->{template_current_lang}->[0];
188
    $lang ||= $current_lang || '';
189 5249
    $class->request_cache->{"template_inner_$lang"}
190 7038
        ||= Bugzilla::Template->create(language => $lang);
191 5249
    return $class->request_cache->{"template_inner_$lang"};
192 4563
}
193
194 6854
our $extension_packages;
195
sub extensions {
196
    my ($class) = @_;
197
    my $cache = $class->request_cache;
198
    if (!$cache->{extensions}) {
199
        # Under mod_perl, mod_perl.pl populates $extension_packages for us.
200
        if (!$extension_packages) {
201
            $extension_packages = Bugzilla::Extension->load_all();
202
        }
203
        my @extensions;
204
        foreach my $package (@$extension_packages) {
205
            my $extension = $package->new();
206
            if ($extension->enabled) {
207
                push(@extensions, $extension);
208
            }        
209
        }
210
        $cache->{extensions} = \@extensions;
211
    }
212
    return $cache->{extensions};
213
}
214
215 6761
sub feature {
216
    my ($class, $feature) = @_;
217
    my $cache = $class->request_cache;
218
    return $cache->{feature}->{$feature}
219
        if exists $cache->{feature}->{$feature};
220
221
    my $feature_map = $cache->{feature_map};
222
    if (!$feature_map) {
223
        foreach my $package (@{ OPTIONAL_MODULES() }) {
224
            foreach my $f (@{ $package->{feature} }) {
225
                $feature_map->{$f} ||= [];
226
                push(@{ $feature_map->{$f} }, $package->{module});
227
            }
228
        }
229
        $cache->{feature_map} = $feature_map;
230
    }
231
232
    if (!$feature_map->{$feature}) {
233
        ThrowCodeError('invalid_feature', { feature => $feature });
234
    }
235
236
    my $success = 1;
237
    foreach my $module (@{ $feature_map->{$feature} }) {
238
        # We can't use a string eval and "use" here (it kills Template-Toolkit,
239
        # see https://rt.cpan.org/Public/Bug/Display.html?id=47929), so we have
240
        # to do a block eval.
241
        $module =~ s{::}{/}g;
242
        $module .= ".pm";
243
        eval { require $module; 1; } or $success = 0;
244
    }
245
    $cache->{feature}->{$feature} = $success;
246
    return $success;
247
}
248
249 2054
sub cgi {
250
    my $class = shift;
251 5249
    $class->request_cache->{cgi} ||= new Bugzilla::CGI();
252
    return $class->request_cache->{cgi};
253 2054
}
254
255 6813
sub input_params {
256
    my ($class, $params) = @_;
257
    my $cache = $class->request_cache;
258
    # This is how the WebService and other places set input_params.
259
    if (defined $params) {
260
        $cache->{input_params} = $params;
261
    }
262
    return $cache->{input_params} if defined $cache->{input_params};
263
264
    # Making this scalar makes it a tied hash to the internals of $cgi,
265
    # so if a variable is changed, then it actually changes the $cgi object
266
    # as well.
267
    $cache->{input_params} = $class->cgi->Vars;
268
    return $cache->{input_params};
269
}
270
271 8155
our $_localconfig;
272 4516
sub localconfig {
273 8155
    $_localconfig ||= read_localconfig();
274
    return $_localconfig;
275 4516
}
276
277 4175
sub params {
278
    my $class = shift;
279 5249
    $class->request_cache->{params} ||= Bugzilla::Config::read_param_file();
280
    return $class->request_cache->{params};
281 4175
}
282
283 2104
sub user {
284
    my $class = shift;
285 5249
    $class->request_cache->{user} ||= new Bugzilla::User;
286
    return $class->request_cache->{user};
287 2104
}
288
289 4620
sub set_user {
290
    my ($class, $user) = @_;
291
    $class->request_cache->{user} = $user;
292
}
293
294 3737
sub sudoer {
295
    my $class = shift;    
296 5249
    return $class->request_cache->{sudoer};
297 3737
}
298
299
sub sudo_request {
300 5249
    my ($class, $new_user, $new_sudoer) = @_;
301
    $class->request_cache->{user}   = $new_user;
302
    $class->request_cache->{sudoer} = $new_sudoer;
303 3737
    # NOTE: If you want to log the start of an sudo session, do it here.
304
}
305
306 6599
sub page_requires_login {
307
    return $_[0]->request_cache->{page_requires_login};
308
}
309
310 2104
sub login {
311
    my ($class, $type) = @_;
312 4154
313 5249
    return $class->user if $class->user->id;
314 4620
315 4154
    my $authorizer = new Bugzilla::Auth();
316 5249
    $type = LOGIN_REQUIRED if $class->cgi->param('GoAheadAndLogIn');
317 6599
318 6610
    if (!defined $type || $type == LOGIN_NORMAL) {
319
        $type = $class->params->{'requirelogin'} ? LOGIN_REQUIRED : LOGIN_NORMAL;
320
    }
321
322 6599
    # Allow templates to know that we're in a page that always requires
323
    # login.
324
    if ($type == LOGIN_REQUIRED) {
325
        $class->request_cache->{page_requires_login} = 1;
326
    }
327
328 4154
    my $authenticated_user = $authorizer->login($type);
329 3737
    
330
    # At this point, we now know if a real person is logged in.
331
    # We must now check to see if an sudo session is in progress.
332
    # For a session to be in progress, the following must be true:
333
    # 1: There must be a logged in user
334
    # 2: That user must be in the 'bz_sudoer' group
335
    # 3: There must be a valid value in the 'sudo' cookie
336
    # 4: A Bugzilla::User object must exist for the given cookie value
337
    # 5: That user must NOT be in the 'bz_sudo_protect' group
338 7429
    my $token = $class->cgi->cookie('sudo');
339
    if (defined $authenticated_user && $token) {
340
        my ($user_id, $date, $sudo_target_id) = Bugzilla::Token::GetTokenData($token);
341
        if (!$user_id
342
            || $user_id != $authenticated_user->id
343
            || !detaint_natural($sudo_target_id)
344
            || (time() - str2time($date) > MAX_SUDO_TOKEN_AGE))
345
        {
346
            $class->cgi->remove_cookie('sudo');
347
            ThrowUserError('sudo_invalid_cookie');
348
        }
349
350
        my $sudo_target = new Bugzilla::User($sudo_target_id);
351
        if ($authenticated_user->in_group('bz_sudoers')
352
            && defined $sudo_target
353
            && !$sudo_target->in_group('bz_sudo_protect'))
354
        {
355
            $class->set_user($sudo_target);
356
            $class->request_cache->{sudoer} = $authenticated_user;
357
            # And make sure that both users have the same Auth object,
358
            # since we never call Auth::login for the sudo target.
359
            $sudo_target->set_authorizer($authenticated_user->authorizer);
360
361
            # NOTE: If you want to do any special logging, do it here.
362
        }
363
        else {
364
            delete_token($token);
365
            $class->cgi->remove_cookie('sudo');
366
            ThrowUserError('sudo_illegal_action', { sudoer => $authenticated_user,
367
                                                    target_user => $sudo_target });
368
        }
369 3737
    }
370
    else {
371 5249
        $class->set_user($authenticated_user);
372 3737
    }
373 6171
374 8088
    if ($class->sudoer) {
375
        $class->sudoer->update_last_seen_date();
376
    } else {
377
        $class->user->update_last_seen_date();
378
    }
379
380 5249
    return $class->user;
381 2178
}
382
383
sub logout {
384 2535
    my ($class, $option) = @_;
385 2741
386
    # If we're not logged in, go away
387 5253
    return unless $class->user->id;
388 2741
389 2535
    $option = LOGOUT_CURRENT unless defined $option;
390 4154
    Bugzilla::Auth::Persist::Cookie->logout({type => $option});
391 5249
    $class->logout_request() unless $option eq LOGOUT_KEEP_CURRENT;
392 2535
}
393
394
sub logout_user {
395
    my ($class, $user) = @_;
396
    # When we're logging out another user we leave cookies alone, and
397 2704
    # therefore avoid calling Bugzilla->logout() directly.
398 4154
    Bugzilla::Auth::Persist::Cookie->logout({user => $user});
399 2535
}
400
401
# just a compatibility front-end to logout_user that gets a user by id
402
sub logout_user_by_id {
403
    my ($class, $id) = @_;
404
    my $user = new Bugzilla::User($id);
405
    $class->logout_user($user);
406
}
407
408
# hack that invalidates credentials for a single request
409 2352
sub logout_request {
410 5249
    my $class = shift;
411
    delete $class->request_cache->{user};
412
    delete $class->request_cache->{sudoer};
413 2733
    # We can't delete from $cgi->cookie, so logincookie data will remain
414
    # there. Don't rely on it: use Bugzilla->user->login instead!
415 2104
}
416
417 6365
sub job_queue {
418
    my $class = shift;
419 6819
    require Bugzilla::JobQueue;
420 6365
    $class->request_cache->{job_queue} ||= Bugzilla::JobQueue->new();
421
    return $class->request_cache->{job_queue};
422
}
423
424 2054
sub dbh {
425
    my $class = shift;
426
    # If we're not connected, then we must want the main db
427 6843
    $class->request_cache->{dbh} ||= $class->dbh_main;
428 2054
429 5249
    return $class->request_cache->{dbh};
430 2054
}
431 2026
432 6843
sub dbh_main {
433
    my $class = shift;
434
    $class->request_cache->{dbh_main} ||= Bugzilla::DB::connect_main();
435
    return $class->request_cache->{dbh_main};
436
}
437
438 5203
sub languages {
439 5249
    my $class = shift;
440 7034
    return Bugzilla::Install::Util::supported_languages();
441 5203
}
442
443 4471
sub error_mode {
444 5249
    my ($class, $newval) = @_;
445 4471
    if (defined $newval) {
446 5249
        $class->request_cache->{error_mode} = $newval;
447 4471
    }
448 5249
    return $class->request_cache->{error_mode}
449 6404
        || (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_DIE);
450 4471
}
451
452 6534
# This is used only by Bugzilla::Error to throw errors.
453
sub _json_server {
454
    my ($class, $newval) = @_;
455
    if (defined $newval) {
456
        $class->request_cache->{_json_server} = $newval;
457
    }
458
    return $class->request_cache->{_json_server};
459
}
460
461 4471
sub usage_mode {
462 5249
    my ($class, $newval) = @_;
463 4471
    if (defined $newval) {
464
        if ($newval == USAGE_MODE_BROWSER) {
465
            $class->error_mode(ERROR_MODE_WEBPAGE);
466
        }
467
        elsif ($newval == USAGE_MODE_CMDLINE) {
468
            $class->error_mode(ERROR_MODE_DIE);
469
        }
470 6534
        elsif ($newval == USAGE_MODE_XMLRPC) {
471 4471
            $class->error_mode(ERROR_MODE_DIE_SOAP_FAULT);
472
        }
473 6534
        elsif ($newval == USAGE_MODE_JSON) {
474
            $class->error_mode(ERROR_MODE_JSON_RPC);
475
        }
476 4620
        elsif ($newval == USAGE_MODE_EMAIL) {
477
            $class->error_mode(ERROR_MODE_DIE);
478
        }
479 7288
        elsif ($newval == USAGE_MODE_TEST) {
480
            $class->error_mode(ERROR_MODE_TEST);
481
        }
482 4471
        else {
483
            ThrowCodeError('usage_mode_invalid',
484
                           {'invalid_usage_mode', $newval});
485
        }
486 5249
        $class->request_cache->{usage_mode} = $newval;
487 4471
    }
488 5249
    return $class->request_cache->{usage_mode}
489 6353
        || (i_am_cgi()? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
490 2867
}
491
492 4731
sub installation_mode {
493
    my ($class, $newval) = @_;
494
    ($class->request_cache->{installation_mode} = $newval) if defined $newval;
495
    return $class->request_cache->{installation_mode}
496
        || INSTALLATION_MODE_INTERACTIVE;
497
}
498
499
sub installation_answers {
500
    my ($class, $filename) = @_;
501
    if ($filename) {
502
        my $s = new Safe;
503
        $s->rdo($filename);
504
505
        die "Error reading $filename: $!" if $!;
506
        die "Error evaluating $filename: $@" if $@;
507
508
        # Now read the param back out from the sandbox
509
        $class->request_cache->{installation_answers} = $s->varglob('answer');
510
    }
511
    return $class->request_cache->{installation_answers} || {};
512
}
513
514 2026
sub switch_to_shadow_db {
515 2054
    my $class = shift;
516 2026
517 5249
    if (!$class->request_cache->{dbh_shadow}) {
518
        if ($class->params->{'shadowdb'}) {
519
            $class->request_cache->{dbh_shadow} = Bugzilla::DB::connect_shadow();
520 2026
        } else {
521 6843
            $class->request_cache->{dbh_shadow} = $class->dbh_main;
522 2026
        }
523
    }
524
525 5249
    $class->request_cache->{dbh} = $class->request_cache->{dbh_shadow};
526 4304
    # we have to return $class->dbh instead of {dbh} as
527
    # {dbh_shadow} may be undefined if no shadow DB is used
528 3813
    # and no connection to the main DB has been established yet.
529
    return $class->dbh;
530 2026
}
531
532
sub switch_to_main_db {
533 1990
    my $class = shift;
534
535 6843
    $class->request_cache->{dbh} = $class->dbh_main;
536
    return $class->dbh_main;
537 2054
}
538
539 7314
sub fields {
540
    my ($class, $criteria) = @_;
541
    $criteria ||= {};
542
    my $cache = $class->request_cache;
543
544
    # We create an advanced cache for fields by type, so that we
545
    # can avoid going back to the database for every fields() call.
546
    # (And most of our fields() calls are for getting fields by type.)
547
    #
548
    # We also cache fields by name, because calling $field->name a few
549
    # million times can be slow in calling code, but if we just do it
550
    # once here, that makes things a lot faster for callers.
551
    if (!defined $cache->{fields}) {
552
        my @all_fields = Bugzilla::Field->get_all;
553
        my (%by_name, %by_type);
554
        foreach my $field (@all_fields) {
555
            my $name = $field->name;
556
            $by_type{$field->type}->{$name} = $field;
557
            $by_name{$name} = $field;
558
        }
559
        $cache->{fields} = { by_type => \%by_type, by_name => \%by_name };
560
    }
561
562
    my $fields = $cache->{fields};
563
    my %requested;
564 7444
    if (my $types = delete $criteria->{type}) {
565 7314
        $types = ref($types) ? $types : [$types];
566
        %requested = map { %{ $fields->{by_type}->{$_} || {} } } @$types;
567
    }
568
    else {
569
        %requested = %{ $fields->{by_name} };
570
    }
571 7444
572
    my $do_by_name = delete $criteria->{by_name};
573
574
    # Filtering before returning the fields based on
575
    # the criterias.
576
    foreach my $filter (keys %$criteria) {
577
        foreach my $field (keys %requested) {
578
            if ($requested{$field}->$filter != $criteria->{$filter}) {
579
                delete $requested{$field};
580
            }
581
        }
582
    }
583 7314
584
    return $do_by_name ? \%requested : [values %requested];
585
}
586
587 5493
sub active_custom_fields {
588
    my $class = shift;
589
    if (!exists $class->request_cache->{active_custom_fields}) {
590
        $class->request_cache->{active_custom_fields} =
591
          Bugzilla::Field->match({ custom => 1, obsolete => 0 });
592
    }
593
    return @{$class->request_cache->{active_custom_fields}};
594 3966
}
595
596 5517
sub has_flags {
597
    my $class = shift;
598
599
    if (!defined $class->request_cache->{has_flags}) {
600 7102
        $class->request_cache->{has_flags} = Bugzilla::Flag->any_exist;
601 5517
    }
602
    return $class->request_cache->{has_flags};
603
}
604
605 6197
sub local_timezone {
606
    my $class = shift;
607
608
    if (!defined $class->request_cache->{local_timezone}) {
609
        $class->request_cache->{local_timezone} =
610
          DateTime::TimeZone->new(name => 'local');
611
    }
612
    return $class->request_cache->{local_timezone};
613
}
614
615 6854
# This creates the request cache for non-mod_perl installations.
616
# This is identical to Install::Util::_cache so that things loaded
617
# into Install::Util::_cache during installation can be read out
618
# of request_cache later in installation.
619
our $_request_cache = $Bugzilla::Install::Util::_cache;
620
621 4304
sub request_cache {
622
    if ($ENV{MOD_PERL}) {
623
        require Apache2::RequestUtil;
624 6827
        # Sometimes (for example, during mod_perl.pl), the request
625
        # object isn't available, and we should use $_request_cache instead.
626
        my $request = eval { Apache2::RequestUtil->request };
627
        return $_request_cache if !$request;
628
        return $request->pnotes();
629 4304
    }
630
    return $_request_cache;
631
}
632
633 2054
# Private methods
634
635 5249
# Per-process cleanup. Note that this is a plain subroutine, not a method,
636
# so we don't have $class available.
637 1990
sub _cleanup {
638 5249
    my $main   = Bugzilla->request_cache->{dbh_main};
639
    my $shadow = Bugzilla->request_cache->{dbh_shadow};
640 4981
    foreach my $dbh ($main, $shadow) {
641
        next if !$dbh;
642
        $dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
643
        $dbh->disconnect;
644
    }
645 4304
    undef $_request_cache;
646 7751
647
    # These are both set by CGI.pm but need to be undone so that
648
    # Apache can actually shut down its children if it needs to.
649 7752
    foreach my $signal (qw(TERM PIPE)) {
650
        $SIG{$signal} = 'DEFAULT' if $SIG{$signal} && $SIG{$signal} eq 'IGNORE';
651
    }
652 1990
}
653
654 2054
sub END {
655 4551
    # Bugzilla.pm cannot compile in mod_perl.pl if this runs.
656
    _cleanup() unless $ENV{MOD_PERL};
657 1990
}
658
659 6854
init_page() if !$ENV{MOD_PERL};
660
661 1990
1;
662
663
__END__
664
665
=head1 NAME
666
667
Bugzilla - Semi-persistent collection of various objects used by scripts
668
and modules
669
670
=head1 SYNOPSIS
671
672
  use Bugzilla;
673
674
  sub someModulesSub {
675 2054
    Bugzilla->dbh->prepare(...);
676
    Bugzilla->template->process(...);
677 1990
  }
678
679
=head1 DESCRIPTION
680
681
Several Bugzilla 'things' are used by a variety of modules and scripts. This
682
includes database handles, template objects, and so on.
683
684
This module is a singleton intended as a central place to store these objects.
685
This approach has several advantages:
686
687
=over 4
688
689
=item *
690
691 3840
They're not global variables, so we don't have issues with them staying around
692 1990
with mod_perl
693
694
=item *
695
696 4330
Everything is in one central place, so it's easy to access, modify, and maintain
697 1990
698
=item *
699
700
Code in modules can get access to these objects without having to have them
701
all passed from the caller, and the caller's caller, and....
702
703
=item *
704
705
We can reuse objects across requests using mod_perl where appropriate (eg
706
templates), whilst destroying those which are only valid for a single request
707
(such as the current user)
708
709
=back
710
711 2054
Note that items accessible via this object are demand-loaded when requested.
712 1990
713
For something to be added to this object, it should either be able to benefit
714
from persistence when run under mod_perl (such as the a C<template> object),
715
or should be something which is globally required by a large ammount of code
716
(such as the current C<user> object).
717
718 2054
=head1 METHODS
719
720 3176
Note that all C<Bugzilla> functionality is method based; use C<Bugzilla-E<gt>dbh>
721 2054
rather than C<Bugzilla::dbh>. Nothing cares about this now, but don't rely on
722
that.
723 1990
724
=over 4
725
726
=item C<template>
727
728
The current C<Template> object, to be used for output
729
730 4563
=item C<template_inner>
731
732
If you ever need a L<Bugzilla::Template> object while you're already
733 4735
processing a template, use this. Also use it if you want to specify
734
the language to use. If no argument is passed, it uses the last
735
language set. If the argument is "" (empty string), the language is
736
reset to the current one (the one used by Bugzilla->template).
737 4563
738 1990
=item C<cgi>
739
740
The current C<cgi> object. Note that modules should B<not> be using this in
741
general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
742
method for those scripts/templates which are only use via CGI, though.
743
744 6813
=item C<input_params>
745
746
When running under the WebService, this is a hashref containing the arguments
747
passed to the WebService method that was called. When running in a normal
748
script, this is a hashref containing the contents of the CGI parameters.
749
750
Modifying this hashref will modify the CGI parameters or the WebService
751
arguments (depending on what C<input_params> currently represents).
752
753
This should be used instead of L</cgi> in situations where your code
754
could be being called by either a normal CGI script or a WebService method,
755
such as during a code hook.
756
757
B<Note:> When C<input_params> represents the CGI parameters, any
758
parameter specified more than once (like C<foo=bar&foo=baz>) will appear
759
as an arrayref in the hash, but any value specified only once will appear
760
as a scalar. This means that even if a value I<can> appear multiple times,
761
if it only I<does> appear once, then it will be a scalar in C<input_params>,
762
not an arrayref.
763
764 2104
=item C<user>
765
766 3737
C<undef> if there is no currently logged in user or if the login code has not
767
yet been run.  If an sudo session is in progress, the C<Bugzilla::User>
768
corresponding to the person who is being impersonated.  If no session is in
769
progress, the current C<Bugzilla::User>.
770
771 4620
=item C<set_user>
772
773
Allows you to directly set what L</user> will return. You can use this
774
if you want to bypass L</login> for some reason and directly "log in"
775
a specific L<Bugzilla::User>. Be careful with it, though!
776
777 3737
=item C<sudoer>
778
779
C<undef> if there is no currently logged in user, the currently logged in user
780
is not in the I<sudoer> group, or there is no session in progress.  If an sudo
781
session is in progress, returns the C<Bugzilla::User> object corresponding to
782
the person who logged in and initiated the session.  If no session is in
783
progress, returns the C<Bugzilla::User> object corresponding to the currently
784
logged in user.
785
786
=item C<sudo_request>
787
This begins an sudo session for the current request.  It is meant to be 
788
used when a session has just started.  For normal use, sudo access should 
789
normally be set at login time.
790 2104
791
=item C<login>
792
793 2178
Logs in a user, returning a C<Bugzilla::User> object, or C<undef> if there is
794 2704
no logged in user. See L<Bugzilla::Auth|Bugzilla::Auth>, and
795 2178
L<Bugzilla::User|Bugzilla::User>.
796
797 6599
=item C<page_requires_login>
798
799
If the current page always requires the user to log in (for example,
800
C<enter_bug.cgi> or any page called with C<?GoAheadAndLogIn=1>) then
801
this will return something true. Otherwise it will return false. (This is
802
set when you call L</login>.)
803
804 2535
=item C<logout($option)>
805
806
Logs out the current user, which involves invalidating user sessions and
807
cookies. Three options are available from
808
L<Bugzilla::Constants|Bugzilla::Constants>: LOGOUT_CURRENT (the
809
default), LOGOUT_ALL or LOGOUT_KEEP_CURRENT.
810
811
=item C<logout_user($user)>
812
813
Logs out the specified user (invalidating all his sessions), taking a
814
Bugzilla::User instance.
815
816
=item C<logout_by_id($id)>
817
818
Logs out the user with the id specified. This is a compatibility
819
function to be used in callsites where there is only a userid and no
820
Bugzilla::User instance.
821 2352
822
=item C<logout_request>
823
824 3176
Essentially, causes calls to C<Bugzilla-E<gt>user> to return C<undef>. This has the
825 2352
effect of logging out a user for the current request only; cookies and
826 2704
database sessions are left intact.
827 2104
828 7314
=item C<fields>
829
830
This is the standard way to get arrays or hashes of L<Bugzilla::Field>
831
objects when you need them. It takes the following named arguments
832
in a hashref:
833
834
=over
835
836
=item C<by_name>
837
838
If false (or not specified), this method will return an arrayref of
839
the requested fields. The order of the returned fields is random.
840
841
If true, this method will return a hashref of fields, where the keys
842
are field names and the valules are L<Bugzilla::Field> objects.
843
844
=item C<type>
845
846
Either a single C<FIELD_TYPE_*> constant or an arrayref of them. If specified,
847
the returned fields will be limited to the types in the list. If you don't
848
specify this argument, all fields will be returned.
849
850
=back
851
852 4471
=item C<error_mode>
853
854
Call either C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE)>
855
or C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE_SOAP_FAULT)> to
856
change this flag's default of C<Bugzilla::Constants::ERROR_MODE_WEBPAGE> and to
857
indicate that errors should be passed to error mode specific error handlers
858
rather than being sent to a browser and finished with an exit().
859
860
This is useful, for example, to keep C<eval> blocks from producing wild HTML
861
on errors, making it easier for you to catch them.
862
(Remember to reset the error mode to its previous value afterwards, though.)
863
864
C<Bugzilla->error_mode> will return the current state of this flag.
865
866
Note that C<Bugzilla->error_mode> is being called by C<Bugzilla->usage_mode> on
867
usage mode changes.
868
869
=item C<usage_mode>
870
871
Call either C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE)>
872 6534
or C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_XMLRPC)> near the
873 4471
beginning of your script to change this flag's default of
874
C<Bugzilla::Constants::USAGE_MODE_BROWSER> and to indicate that Bugzilla is
875
being called in a non-interactive manner.
876 6534
877 4471
This influences error handling because on usage mode changes, C<usage_mode>
878
calls C<Bugzilla->error_mode> to set an error mode which makes sense for the
879
usage mode.
880
881
C<Bugzilla->usage_mode> will return the current state of this flag.
882 2867
883 4731
=item C<installation_mode>
884
885
Determines whether or not installation should be silent. See 
886
L<Bugzilla::Constants> for the C<INSTALLATION_MODE> constants.
887
888
=item C<installation_answers>
889
890
Returns a hashref representing any "answers" file passed to F<checksetup.pl>,
891
used to automatically answer or skip prompts.
892
893 2026
=item C<dbh>
894
895
The current database handle. See L<DBI>.
896
897 6843
=item C<dbh_main>
898
899
The main database handle. See L<DBI>.
900
901 5203
=item C<languages>
902
903
Currently installed languages.
904
Returns a reference to a list of RFC 1766 language tags of installed languages.
905
906 2026
=item C<switch_to_shadow_db>
907
908
Switch from using the main database to using the shadow database.
909
910
=item C<switch_to_main_db>
911
912
Change the database object to refer to the main database.
913
914 4175
=item C<params>
915
916
The current Parameters of Bugzilla, as a hashref. If C<data/params>
917
does not exist, then we return an empty hashref. If C<data/params>
918
is unreadable or is not valid perl, we C<die>.
919
920 6197
=item C<local_timezone>
921
922
Returns the local timezone of the Bugzilla installation,
923
as a DateTime::TimeZone object. This detection is very time
924
consuming, so we cache this information for future references.
925
926 6365
=item C<job_queue>
927
928
Returns a L<Bugzilla::JobQueue> that you can use for queueing jobs.
929
Will throw an error if job queueing is not correctly configured on
930
this Bugzilla installation.
931
932 6761
=item C<feature>
933
934
Tells you whether or not a specific feature is enabled. For names
935
of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
936
937 1990
=back

Loggerhead 1.18.1 is a web-based interface for Bazaar branches