# -*- 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. # # The Initial Developer of the Original Code is Netscape Communications # Corporation. Portions created by Netscape are # Copyright (C) 1998 Netscape Communications Corporation. All # Rights Reserved. # # Contributor(s): Bradley Baetz # Erik Stambaugh # package Bugzilla; use strict; use Bugzilla::Auth; use Bugzilla::Auth::Login::WWW; use Bugzilla::CGI; use Bugzilla::Config; use Bugzilla::Constants; use Bugzilla::DB; use Bugzilla::Template; use Bugzilla::User; use Bugzilla::Error; use Bugzilla::Util; use File::Basename; ##################################################################### # Constants ##################################################################### # Scripts that are not stopped by shutdownhtml being in effect. use constant SHUTDOWNHTML_EXEMPT => [ 'doeditparams.cgi', 'editparams.cgi', 'checksetup.pl', ]; ##################################################################### # Global Code ##################################################################### # If Bugzilla is shut down, do not allow anything to run, just display a # message to the user about the downtime and log out. Scripts listed in # SHUTDOWNHTML_EXEMPT are exempt from this message. # # This code must go here. It cannot go anywhere in Bugzilla::CGI, because # it uses Template, and that causes various dependency loops. if (Param("shutdownhtml") && lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1) { # For security reasons, log out users when Bugzilla is down. # Bugzilla->login() is required to catch the logincookie, if any. my $user = Bugzilla->login(LOGIN_OPTIONAL); my $userid = $user->id; Bugzilla->logout(); my $template = Bugzilla->template; my $vars = {}; $vars->{'message'} = 'shutdown'; $vars->{'userid'} = $userid; # Generate and return a message about the downtime, appropriately # for if we're a command-line script or a CGI sript. my $extension; if (i_am_cgi() && (!Bugzilla->cgi->param('format') || Bugzilla->cgi->param('format') eq 'html')) { $extension = 'html'; } else { $extension = 'txt'; } print Bugzilla->cgi->header() if i_am_cgi(); my $t_output; $template->process("global/message.$extension.tmpl", $vars, \$t_output) || ThrowTemplateError($template->error); print $t_output . "\n"; exit; } ##################################################################### # Subroutines and Methods ##################################################################### my $_template; sub template { my $class = shift; $_template ||= Bugzilla::Template->create(); return $_template; } my $_cgi; sub cgi { my $class = shift; $_cgi ||= new Bugzilla::CGI(); return $_cgi; } my $_user; sub user { my $class = shift; if (not defined $_user) { $_user = new Bugzilla::User; } return $_user; } sub login { my ($class, $type) = @_; $_user = Bugzilla::Auth::Login::WWW->login($type); } sub logout { my ($class, $option) = @_; # If we're not logged in, go away return unless user->id; $option = LOGOUT_CURRENT unless defined $option; Bugzilla::Auth::Login::WWW->logout($_user, $option); } sub logout_user { my ($class, $user) = @_; # When we're logging out another user we leave cookies alone, and # therefore avoid calling Bugzilla->logout() directly. Bugzilla::Auth::Login::WWW->logout($user, LOGOUT_ALL); } # just a compatibility front-end to logout_user that gets a user by id sub logout_user_by_id { my ($class, $id) = @_; my $user = new Bugzilla::User($id); $class->logout_user($user); } # hack that invalidates credentials for a single request sub logout_request { undef $_user; # XXX clean this up eventually $::userid = 0; # We can't delete from $cgi->cookie, so logincookie data will remain # there. Don't rely on it: use Bugzilla->user->login instead! } my $_dbh; my $_dbh_main; my $_dbh_shadow; sub dbh { my $class = shift; # If we're not connected, then we must want the main db if (!$_dbh) { $_dbh = $_dbh_main = Bugzilla::DB::connect_main(); } return $_dbh; } my $_batch; sub batch { my $class = shift; my $newval = shift; if ($newval) { $_batch = $newval; } return $_batch || 0; } sub dbwritesallowed { my $class = shift; # We can write if we are connected to the main database. # Note that if we don't have a shadowdb, then we claim that its ok # to write even if we're nominally connected to the shadowdb. # This is OK because this method is only used to test if misc # updates can be done, rather than anything complicated. return $class->dbh == $_dbh_main; } sub switch_to_shadow_db { my $class = shift; if (!$_dbh_shadow) { if (Param('shadowdb')) { $_dbh_shadow = Bugzilla::DB::connect_shadow(); } else { $_dbh_shadow = $_dbh_main; } } $_dbh = $_dbh_shadow; } sub switch_to_main_db { my $class = shift; $_dbh = $_dbh_main; } # Private methods # Per process cleanup sub _cleanup { undef $_cgi; undef $_user; # See bug 192531. If we don't clear the possibly active statement handles, # then when this is called from the END block, it happens _before_ the # destructors in Bugzilla::DB have happened. # See http://rt.perl.org/rt2/Ticket/Display.html?id=17450#38810 # Without disconnecting explicitly here, noone notices, because DBI::END # ends up calling DBD::mysql's $drh->disconnect_all, which is a noop. # This code is evil, but it needs to be done, at least until SendSQL and # friends can be removed @Bugzilla::DB::SQLStateStack = (); undef $Bugzilla::DB::_current_sth; # When we support transactions, need to ->rollback here $_dbh_main->disconnect if $_dbh_main; $_dbh_shadow->disconnect if $_dbh_shadow and Param("shadowdb"); undef $_dbh_main; undef $_dbh_shadow; undef $_dbh; } sub END { _cleanup(); } 1; __END__ =head1 NAME Bugzilla - Semi-persistent collection of various objects used by scripts and modules =head1 SYNOPSIS use Bugzilla; sub someModulesSub { Bugzilla->dbh->prepare(...); Bugzilla->template->process(...); } =head1 DESCRIPTION Several Bugzilla 'things' are used by a variety of modules and scripts. This includes database handles, template objects, and so on. This module is a singleton intended as a central place to store these objects. This approach has several advantages: =over 4 =item * They're not global variables, so we don't have issues with them staying arround with mod_perl =item * Everything is in one central place, so its easy to access, modify, and maintain =item * Code in modules can get access to these objects without having to have them all passed from the caller, and the caller's caller, and.... =item * We can reuse objects across requests using mod_perl where appropriate (eg templates), whilst destroying those which are only valid for a single request (such as the current user) =back Note that items accessible via this object are demand-loaded when requested. For something to be added to this object, it should either be able to benefit from persistence when run under mod_perl (such as the a C