2008-12-15 15:53:33 +03:00
|
|
|
|
# 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 <bbaetz@student.usyd.edu.au>
|
|
|
|
|
# Erik Stambaugh <erik@dasbistro.com>
|
|
|
|
|
# A. Karl Kornel <karl@kornel.name>
|
|
|
|
|
# Marc Schumann <wurblzap@gmail.com>
|
|
|
|
|
|
|
|
|
|
package Bugzilla;
|
|
|
|
|
|
2009-12-28 15:08:44 +03:00
|
|
|
|
use utf8;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
use strict;
|
2011-04-13 18:26:06 +04:00
|
|
|
|
use Encode;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
|
|
|
|
use Bugzilla::Config;
|
|
|
|
|
use Bugzilla::Constants;
|
|
|
|
|
use Bugzilla::Auth;
|
|
|
|
|
use Bugzilla::Auth::Persist::Cookie;
|
|
|
|
|
use Bugzilla::CGI;
|
2010-05-15 00:02:34 +04:00
|
|
|
|
use Bugzilla::Extension;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
use Bugzilla::DB;
|
|
|
|
|
use Bugzilla::Install::Localconfig qw(read_localconfig);
|
2010-05-15 00:02:34 +04:00
|
|
|
|
use Bugzilla::Install::Requirements qw(OPTIONAL_MODULES);
|
|
|
|
|
use Bugzilla::Install::Util;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
use Bugzilla::Template;
|
|
|
|
|
use Bugzilla::User;
|
|
|
|
|
use Bugzilla::Error;
|
|
|
|
|
use Bugzilla::Util;
|
|
|
|
|
use Bugzilla::Field;
|
|
|
|
|
use Bugzilla::Flag;
|
2010-08-10 15:15:39 +04:00
|
|
|
|
use Bugzilla::Token;
|
2013-05-31 16:46:26 +04:00
|
|
|
|
use Bugzilla::Keyword;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
|
|
|
|
use File::Basename;
|
|
|
|
|
use File::Spec::Functions;
|
2009-07-29 15:21:49 +04:00
|
|
|
|
use DateTime::TimeZone;
|
2010-08-10 15:15:39 +04:00
|
|
|
|
use Date::Parse;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
use Safe;
|
2014-07-28 12:57:30 +04:00
|
|
|
|
use JSON;
|
2009-09-04 21:40:06 +04:00
|
|
|
|
use Encode::MIME::Header ();
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
2009-12-25 16:43:40 +03:00
|
|
|
|
# We want any compile errors to get to the browser, if possible.
|
2009-12-25 16:59:14 +03:00
|
|
|
|
BEGIN
|
|
|
|
|
{
|
2010-11-22 16:51:55 +03:00
|
|
|
|
$SIG{__DIE__} = \&_die_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub _die_error
|
|
|
|
|
{
|
2014-10-29 20:28:07 +03:00
|
|
|
|
# We are in some eval(), or we are passed the exception object
|
2014-11-03 00:23:22 +03:00
|
|
|
|
if (${^GLOBAL_PHASE} ne 'RUN' ||
|
|
|
|
|
Bugzilla::Error::_in_eval() ||
|
2014-10-29 20:28:07 +03:00
|
|
|
|
ref $_[0] eq 'Bugzilla::Error' ||
|
|
|
|
|
ref $_[0] eq 'Bugzilla::HTTPServerSimple::FakeExit')
|
2010-11-22 16:51:55 +03:00
|
|
|
|
{
|
2010-11-23 15:46:08 +03:00
|
|
|
|
# Bugzilla::Error has overloaded conversion to string
|
2014-10-29 20:28:07 +03:00
|
|
|
|
# Bugzilla::HTTPServerSimple::FakeExit only terminates the request
|
2010-11-23 15:46:08 +03:00
|
|
|
|
die @_;
|
2010-11-22 16:51:55 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
my $msg = $_[0];
|
2013-10-02 16:19:52 +04:00
|
|
|
|
utf8::decode($msg);
|
2010-11-22 16:51:55 +03:00
|
|
|
|
$msg =~ s/\s*$//so;
|
|
|
|
|
# We are not interested in getting "Software caused connection abort" errors
|
|
|
|
|
# on each "Stop" click in the browser.
|
2013-08-12 18:56:49 +04:00
|
|
|
|
if ($msg !~ /^(Apache2::RequestIO::print|:Apache2 IO write): \(103\)|^[^\n]*(Программа вызвала сброс соединения|Software caused connection abort) at /iso)
|
2009-12-25 16:43:40 +03:00
|
|
|
|
{
|
2013-09-05 20:36:47 +04:00
|
|
|
|
if ($msg =~ /lock wait|deadlock found/i)
|
|
|
|
|
{
|
|
|
|
|
# Log active InnoDB locks
|
|
|
|
|
my $locks = Bugzilla->dbh->selectall_arrayref('SELECT * FROM information_schema.innodb_locks', {Slice=>{}});
|
|
|
|
|
$msg = "InnoDB locks:\n".Dumper($locks)."\n".$msg;
|
|
|
|
|
# Also log full InnoDB Status
|
|
|
|
|
($locks) = Bugzilla->dbh->selectrow_array('SHOW ENGINE INNODB STATUS');
|
|
|
|
|
$msg = "InnoDB status:\n$locks\n$msg";
|
2013-09-05 20:52:21 +04:00
|
|
|
|
# Also log full processlist
|
|
|
|
|
$locks = Bugzilla->dbh->selectall_arrayref('SHOW FULL PROCESSLIST', {Slice=>{}});
|
|
|
|
|
$msg = "All processes:\n".Dumper($locks)."\n".$msg;
|
2013-09-05 20:36:47 +04:00
|
|
|
|
}
|
2010-11-22 16:51:55 +03:00
|
|
|
|
$msg = { eval_error => $msg };
|
|
|
|
|
Bugzilla::Error::ThrowCodeError('eval_error', $msg);
|
2009-12-25 16:43:40 +03:00
|
|
|
|
}
|
2010-11-22 16:51:55 +03:00
|
|
|
|
}
|
|
|
|
|
};
|
2009-12-25 16:43:40 +03:00
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
#####################################################################
|
|
|
|
|
# Constants
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
|
|
# Scripts that are not stopped by shutdownhtml being in effect.
|
|
|
|
|
use constant SHUTDOWNHTML_EXEMPT => [
|
|
|
|
|
'editparams.cgi',
|
|
|
|
|
'checksetup.pl',
|
2010-05-15 00:02:34 +04:00
|
|
|
|
'migrate.pl',
|
2008-12-15 15:53:33 +03:00
|
|
|
|
'recode.pl',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
# Non-cgi scripts that should silently exit.
|
|
|
|
|
use constant SHUTDOWNHTML_EXIT_SILENTLY => [
|
|
|
|
|
'whine.pl'
|
|
|
|
|
];
|
|
|
|
|
|
2009-09-04 21:40:06 +04:00
|
|
|
|
#####################################################################
|
|
|
|
|
# Hack into buggy Encode::MIME::Header
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
|
|
{ # Block taken directly from Encode::MIME::Header v2.11
|
|
|
|
|
my $especials =
|
|
|
|
|
join( '|' => map { quotemeta( chr($_) ) }
|
2010-10-14 14:31:30 +04:00
|
|
|
|
unpack( "C*", qq{()<>@,;:\"\'/[]?.=} ) );
|
2009-09-04 21:40:06 +04:00
|
|
|
|
|
|
|
|
|
my $re_encoded_word = qr{
|
|
|
|
|
=\? # begin encoded word
|
|
|
|
|
(?:[-0-9A-Za-z_]+) # charset (encoding)
|
|
|
|
|
(?:\*[A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*)? # language (RFC 2231)
|
|
|
|
|
\?(?:[QqBb])\? # delimiter
|
|
|
|
|
(?:.*?) # Base64-encodede contents
|
|
|
|
|
\?= # end encoded word
|
|
|
|
|
}xo;
|
|
|
|
|
|
|
|
|
|
# And changed only here: <<<
|
|
|
|
|
my $re_especials = qr{$re_encoded_word}xo;
|
|
|
|
|
# >>>
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
sub encode_mime_header($$;$) {
|
2009-09-04 21:40:06 +04:00
|
|
|
|
my ( $obj, $str, $chk ) = @_;
|
|
|
|
|
my @line = ();
|
|
|
|
|
for my $line ( split /\r\n|[\r\n]/o, $str ) {
|
|
|
|
|
my ( @word, @subline );
|
|
|
|
|
for my $word ( split /($re_especials)/o, $line ) {
|
|
|
|
|
if ( $word =~ /[^\x00-\x7f]/o
|
|
|
|
|
or $word =~ /^$re_encoded_word$/o )
|
|
|
|
|
{
|
|
|
|
|
push @word, $obj->_encode($word);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
push @word, $word;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
my $subline = '';
|
|
|
|
|
for my $word (@word) {
|
|
|
|
|
use bytes ();
|
|
|
|
|
if ( bytes::length($subline) + bytes::length($word) >
|
|
|
|
|
$obj->{bpl} )
|
|
|
|
|
{
|
|
|
|
|
push @subline, $subline;
|
|
|
|
|
$subline = '';
|
|
|
|
|
}
|
|
|
|
|
$subline .= $word;
|
|
|
|
|
}
|
|
|
|
|
$subline and push @subline, $subline;
|
|
|
|
|
push @line, join( "\n " => @subline );
|
|
|
|
|
}
|
|
|
|
|
$_[1] = '' if $chk;
|
|
|
|
|
return join( "\n", @line );
|
|
|
|
|
}
|
2010-05-15 00:02:34 +04:00
|
|
|
|
|
2010-12-15 21:20:20 +03:00
|
|
|
|
*Encode::MIME::Header::encode = *Bugzilla::encode_mime_header;
|
2009-09-04 21:40:06 +04:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-13 18:26:06 +04:00
|
|
|
|
#####################################################################
|
|
|
|
|
# Hack for Template Toolkit (or maybe Perl) bug 67431
|
|
|
|
|
# https://rt.cpan.org/Public/Bug/Display.html?id=67431
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub _tt_provider_load_compiled
|
|
|
|
|
{
|
2011-04-13 18:26:06 +04:00
|
|
|
|
my ($self, $file) = @_;
|
|
|
|
|
my $compiled;
|
|
|
|
|
|
|
|
|
|
# load compiled template via require(); we zap any
|
|
|
|
|
# %INC entry to ensure it is reloaded (we don't
|
|
|
|
|
# want 1 returned by require() to say it's in memory)
|
|
|
|
|
Encode::_utf8_off($file);
|
|
|
|
|
delete $INC{ $file };
|
|
|
|
|
eval { $compiled = require $file; };
|
|
|
|
|
return $@
|
2014-03-24 19:51:59 +04:00
|
|
|
|
? $self->error("compiled template ".($compiled||$file).": $@")
|
2011-04-13 18:26:06 +04:00
|
|
|
|
: $compiled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*Template::Provider::_load_compiled = *Bugzilla::_tt_provider_load_compiled;
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
#####################################################################
|
|
|
|
|
# Global Code
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
|
|
# Note that this is a raw subroutine, not a method, so $class isn't available.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub init_page
|
|
|
|
|
{
|
|
|
|
|
(binmode STDOUT, ':utf8') if Bugzilla->params->{utf8};
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (${^TAINT})
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# Some environment variables are not taint safe
|
2013-08-14 20:25:56 +04:00
|
|
|
|
delete @::ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
|
|
|
|
|
# It's a very stupid idea to remove ENV{PATH}.
|
|
|
|
|
trick_taint($ENV{PATH});
|
2009-07-29 15:21:49 +04:00
|
|
|
|
}
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# Because this function is run live from perl "use" commands of
|
|
|
|
|
# other scripts, we're skipping the rest of this function if we get here
|
|
|
|
|
# during a perl syntax check (perl -c, like we do during the
|
|
|
|
|
# 001compile.t test).
|
|
|
|
|
return if $^C;
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# IIS prints out warnings to the webpage, so ignore them, or log them
|
|
|
|
|
# to a file if the file exists.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if ($ENV{SERVER_SOFTWARE} && $ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
|
|
|
|
|
{
|
|
|
|
|
$SIG{__WARN__} = sub
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($msg) = @_;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
my $datadir = bz_locations()->{datadir};
|
|
|
|
|
if (-w "$datadir/errorlog")
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $warning_log = new IO::File(">>$datadir/errorlog");
|
|
|
|
|
print $warning_log $msg;
|
|
|
|
|
$warning_log->close();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# Because of attachment_base, attachment.cgi handles this itself.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (basename($0) ne 'attachment.cgi')
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
do_ssl_redirect_if_required();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# 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.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (Bugzilla->params->{shutdownhtml}
|
2008-12-15 15:53:33 +03:00
|
|
|
|
&& lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1)
|
|
|
|
|
{
|
|
|
|
|
# Allow non-cgi scripts to exit silently (without displaying any
|
|
|
|
|
# message), if desired. At this point, no DBI call has been made
|
|
|
|
|
# yet, and no error will be returned if the DB is inaccessible.
|
|
|
|
|
if (lsearch(SHUTDOWNHTML_EXIT_SILENTLY, basename($0)) > -1
|
|
|
|
|
&& !i_am_cgi())
|
|
|
|
|
{
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# For security reasons, log out users when Bugzilla is down.
|
|
|
|
|
# Bugzilla->login() is required to catch the logincookie, if any.
|
|
|
|
|
my $user;
|
|
|
|
|
eval { $user = Bugzilla->login(LOGIN_OPTIONAL); };
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if ($@)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# The DB is not accessible. Use the default user object.
|
|
|
|
|
$user = Bugzilla->user;
|
|
|
|
|
$user->{settings} = {};
|
|
|
|
|
}
|
|
|
|
|
my $userid = $user->id;
|
|
|
|
|
Bugzilla->logout();
|
|
|
|
|
|
|
|
|
|
my $template = Bugzilla->template;
|
|
|
|
|
my $vars = {};
|
2014-04-09 19:12:48 +04:00
|
|
|
|
$vars->{message} = 'shutdown';
|
|
|
|
|
$vars->{userid} = $userid;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# Generate and return a message about the downtime, appropriately
|
|
|
|
|
# for if we're a command-line script or a CGI script.
|
|
|
|
|
my $extension;
|
2014-10-10 15:15:48 +04:00
|
|
|
|
if (i_am_cgi() && (!Bugzilla->input_params->{ctype} || Bugzilla->input_params->{ctype} eq 'html'))
|
2014-04-09 19:12:48 +04:00
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$extension = 'html';
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$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
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
2014-07-28 12:57:30 +04:00
|
|
|
|
sub add_result_message
|
2014-04-09 19:12:48 +04:00
|
|
|
|
{
|
2014-07-28 12:57:30 +04:00
|
|
|
|
my $class = shift;
|
|
|
|
|
push @{$class->result_messages}, @_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub result_messages
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
2013-07-12 15:59:55 +04:00
|
|
|
|
my $cache = $class->request_cache;
|
2014-07-28 12:57:30 +04:00
|
|
|
|
if (!$cache->{send_mail_result})
|
|
|
|
|
{
|
|
|
|
|
my $s = $class->session_data && $class->session_data;
|
|
|
|
|
$cache->{send_mail_result} = $s ? ($s->{result_messages} ||= []) : [];
|
|
|
|
|
}
|
|
|
|
|
return $cache->{send_mail_result};
|
2013-07-12 16:51:41 +04:00
|
|
|
|
}
|
2013-07-12 11:23:30 +04:00
|
|
|
|
|
2014-07-28 12:57:30 +04:00
|
|
|
|
sub send_mail
|
2014-04-09 19:12:48 +04:00
|
|
|
|
{
|
2013-07-12 15:59:55 +04:00
|
|
|
|
my $class = shift;
|
|
|
|
|
my $cache = $class->request_cache;
|
2014-07-28 12:57:30 +04:00
|
|
|
|
for (@{$cache->{send_mail_result} || []})
|
|
|
|
|
{
|
|
|
|
|
Bugzilla::BugMail::send_results($_);
|
|
|
|
|
}
|
2013-07-12 11:23:30 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub template
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{language} = "";
|
|
|
|
|
$class->request_cache->{template} ||= Bugzilla::Template->create();
|
|
|
|
|
return $class->request_cache->{template};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub template_inner
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $lang) = @_;
|
|
|
|
|
$lang = defined($lang) ? $lang : ($class->request_cache->{language} || "");
|
|
|
|
|
$class->request_cache->{language} = $lang;
|
|
|
|
|
$class->request_cache->{"template_inner_$lang"}
|
|
|
|
|
||= Bugzilla::Template->create();
|
|
|
|
|
return $class->request_cache->{"template_inner_$lang"};
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 23:09:20 +04:00
|
|
|
|
sub session
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{session} = shift || $class->request_cache->{session};
|
|
|
|
|
return $class->request_cache->{session};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub session_data
|
|
|
|
|
{
|
|
|
|
|
my ($class, $s) = @_;
|
|
|
|
|
my $c = $class->request_cache;
|
|
|
|
|
$c->{session} || return undef;
|
2014-07-28 12:57:30 +04:00
|
|
|
|
if (!$c->{session}->{_session_data_decoded})
|
|
|
|
|
{
|
2014-11-08 01:57:46 +03:00
|
|
|
|
Encode::_utf8_off($c->{session}->{session_data});
|
2014-07-28 12:57:30 +04:00
|
|
|
|
$c->{session}->{_session_data_decoded} = ($c->{session}->{session_data}
|
|
|
|
|
? JSON::decode_json($c->{session}->{session_data}) : {});
|
|
|
|
|
}
|
|
|
|
|
my $d = $c->{session}->{_session_data_decoded};
|
2010-06-04 23:09:20 +04:00
|
|
|
|
if ($s && %$s)
|
|
|
|
|
{
|
|
|
|
|
for (keys %$s)
|
|
|
|
|
{
|
|
|
|
|
$d->{$_} = $s->{$_};
|
|
|
|
|
defined $d->{$_} or delete $d->{$_};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $d;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-28 12:57:30 +04:00
|
|
|
|
sub delete_session_data
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->save_session_data({ map { ($_ => undef) } @_ });
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 23:09:20 +04:00
|
|
|
|
sub save_session_data
|
|
|
|
|
{
|
|
|
|
|
my ($class, $s) = @_;
|
|
|
|
|
my $c = $class->request_cache;
|
2014-07-28 12:57:30 +04:00
|
|
|
|
$class->session_data({ result_messages => $class->result_messages });
|
2010-06-04 23:09:20 +04:00
|
|
|
|
$class->session_data($s) || return undef;
|
2014-10-20 19:48:44 +04:00
|
|
|
|
my $a = JSON::encode_json($c->{session}->{_session_data_decoded});
|
|
|
|
|
Encode::_utf8_on($a);
|
2014-07-28 12:57:30 +04:00
|
|
|
|
Bugzilla->dbh->do(
|
|
|
|
|
'UPDATE logincookies SET session_data=? WHERE cookie=?', undef,
|
2014-10-20 19:48:44 +04:00
|
|
|
|
$a, $c->{session}->{cookie}
|
2014-07-28 12:57:30 +04:00
|
|
|
|
);
|
2010-06-04 23:09:20 +04:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
our $extension_packages;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub extensions
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
my ($class) = @_;
|
2010-06-01 22:15:50 +04:00
|
|
|
|
return { map { $_ => extension_info($_) } Bugzilla::Extension::loaded() };
|
2010-05-15 00:02:34 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub feature
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
my ($class, $feature) = @_;
|
|
|
|
|
my $cache = $class->request_cache;
|
|
|
|
|
return $cache->{feature}->{$feature}
|
|
|
|
|
if exists $cache->{feature}->{$feature};
|
|
|
|
|
|
|
|
|
|
my $feature_map = $cache->{feature_map};
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!$feature_map)
|
|
|
|
|
{
|
|
|
|
|
foreach my $package (@{ OPTIONAL_MODULES() })
|
|
|
|
|
{
|
2010-05-17 15:20:32 +04:00
|
|
|
|
my $ff = $package->{feature};
|
|
|
|
|
ref $ff or $ff = [ $ff ];
|
2014-04-09 19:12:48 +04:00
|
|
|
|
foreach my $f (@$ff)
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
$feature_map->{$f} ||= [];
|
|
|
|
|
push(@{ $feature_map->{$f} }, $package->{module});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$cache->{feature_map} = $feature_map;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!$feature_map->{$feature})
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
ThrowCodeError('invalid_feature', { feature => $feature });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $success = 1;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
foreach my $module (@{ $feature_map->{$feature} })
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# We can't use a string eval and "use" here (it kills Template-Toolkit,
|
|
|
|
|
# see https://rt.cpan.org/Public/Bug/Display.html?id=47929), so we have
|
|
|
|
|
# to do a block eval.
|
|
|
|
|
$module =~ s{::}{/}g;
|
|
|
|
|
$module .= ".pm";
|
|
|
|
|
eval { require $module; 1; } or $success = 0;
|
|
|
|
|
}
|
|
|
|
|
$cache->{feature}->{$feature} = $success;
|
|
|
|
|
return $success;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub cgi
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{cgi} ||= new Bugzilla::CGI();
|
|
|
|
|
return $class->request_cache->{cgi};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub send_header
|
|
|
|
|
{
|
2010-06-11 21:31:17 +04:00
|
|
|
|
my $class = shift;
|
2011-10-04 16:02:49 +04:00
|
|
|
|
return undef if $class->usage_mode != USAGE_MODE_BROWSER;
|
|
|
|
|
$class->cgi->send_header(@_);
|
2010-06-11 21:31:17 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub input_params
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
my ($class, $params) = @_;
|
|
|
|
|
my $cache = $class->request_cache;
|
|
|
|
|
# This is how the WebService and other places set input_params.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (defined $params)
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
$cache->{input_params} = $params;
|
|
|
|
|
}
|
|
|
|
|
return $cache->{input_params} if defined $cache->{input_params};
|
2014-10-16 20:05:42 +04:00
|
|
|
|
my $cgi = $class->cgi;
|
|
|
|
|
if (($cgi->request_method || 'GET') eq 'POST')
|
|
|
|
|
{
|
|
|
|
|
$cgi->url_param;
|
|
|
|
|
$params = { %{$cgi->{'.url_param'}}, %{$cgi->{param}} };
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$params = { %{$cgi->{param}} };
|
|
|
|
|
}
|
2014-10-15 17:48:19 +04:00
|
|
|
|
my $utf8 = Bugzilla->params->{utf8};
|
2014-10-10 15:15:48 +04:00
|
|
|
|
for (keys %$params)
|
2014-07-30 19:13:58 +04:00
|
|
|
|
{
|
2014-10-15 17:48:19 +04:00
|
|
|
|
if ($utf8)
|
|
|
|
|
{
|
2014-10-27 12:39:48 +03:00
|
|
|
|
for (@{$params->{$_}})
|
|
|
|
|
{
|
|
|
|
|
utf8::decode($_) unless ref $_;
|
|
|
|
|
}
|
2014-10-15 17:48:19 +04:00
|
|
|
|
}
|
2014-10-10 15:15:48 +04:00
|
|
|
|
($params->{$_}) = @{$params->{$_}} if @{$params->{$_}} <= 1;
|
2014-07-30 19:13:58 +04:00
|
|
|
|
}
|
2014-10-10 15:15:48 +04:00
|
|
|
|
$cache->{input_params} = $params;
|
2010-05-15 00:02:34 +04:00
|
|
|
|
return $cache->{input_params};
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-08 14:16:31 +04:00
|
|
|
|
sub cookies
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
return $class->cgi->get_cookies;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub localconfig
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{localconfig} ||= read_localconfig();
|
|
|
|
|
return $class->request_cache->{localconfig};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub params
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{params} ||= Bugzilla::Config::read_param_file();
|
|
|
|
|
return $class->request_cache->{params};
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-03 16:10:39 +04:00
|
|
|
|
sub params_modified
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{params} ||= Bugzilla::Config::param_file_mtime();
|
|
|
|
|
return $class->request_cache->{params};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub user
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{user} ||= new Bugzilla::User;
|
|
|
|
|
return $class->request_cache->{user};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub set_user
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $user) = @_;
|
|
|
|
|
$class->request_cache->{user} = $user;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub sudoer
|
|
|
|
|
{
|
2010-12-09 20:16:43 +03:00
|
|
|
|
my $class = shift;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
return $class->request_cache->{sudoer};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub sudo_request
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $new_user, $new_sudoer) = @_;
|
|
|
|
|
$class->request_cache->{user} = $new_user;
|
|
|
|
|
$class->request_cache->{sudoer} = $new_sudoer;
|
|
|
|
|
# NOTE: If you want to log the start of an sudo session, do it here.
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub page_requires_login
|
|
|
|
|
{
|
2009-07-29 15:21:49 +04:00
|
|
|
|
return $_[0]->request_cache->{page_requires_login};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub login
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $type) = @_;
|
|
|
|
|
|
|
|
|
|
return $class->user if $class->user->id;
|
|
|
|
|
|
|
|
|
|
my $authorizer = new Bugzilla::Auth();
|
2014-10-10 15:15:48 +04:00
|
|
|
|
$type = LOGIN_REQUIRED if Bugzilla->input_params->{GoAheadAndLogIn};
|
2010-05-15 00:02:34 +04:00
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!defined $type || $type == LOGIN_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
$type = $class->params->{requirelogin} ? LOGIN_REQUIRED : LOGIN_NORMAL;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
2009-07-29 15:21:49 +04:00
|
|
|
|
|
|
|
|
|
# Allow templates to know that we're in a page that always requires
|
|
|
|
|
# login.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if ($type == LOGIN_REQUIRED)
|
|
|
|
|
{
|
2009-07-29 15:21:49 +04:00
|
|
|
|
$class->request_cache->{page_requires_login} = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $authenticated_user = $authorizer->login($type);
|
2010-12-08 19:06:25 +03:00
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# At this point, we now know if a real person is logged in.
|
|
|
|
|
# We must now check to see if an sudo session is in progress.
|
|
|
|
|
# For a session to be in progress, the following must be true:
|
|
|
|
|
# 1: There must be a logged in user
|
|
|
|
|
# 2: That user must be in the 'bz_sudoer' group
|
|
|
|
|
# 3: There must be a valid value in the 'sudo' cookie
|
|
|
|
|
# 4: A Bugzilla::User object must exist for the given cookie value
|
|
|
|
|
# 5: That user must NOT be in the 'bz_sudo_protect' group
|
2014-10-10 15:15:48 +04:00
|
|
|
|
my $token = $class->cookies->{sudo};
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (defined $authenticated_user && $token)
|
|
|
|
|
{
|
2010-08-10 15:15:39 +04:00
|
|
|
|
my ($user_id, $date, $sudo_target_id) = Bugzilla::Token::GetTokenData($token);
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!$user_id || $user_id != $authenticated_user->id
|
2010-08-10 15:15:39 +04:00
|
|
|
|
|| !detaint_natural($sudo_target_id)
|
|
|
|
|
|| (time() - str2time($date) > MAX_SUDO_TOKEN_AGE))
|
|
|
|
|
{
|
|
|
|
|
$class->cgi->remove_cookie('sudo');
|
|
|
|
|
ThrowUserError('sudo_invalid_cookie');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $sudo_target = new Bugzilla::User($sudo_target_id);
|
|
|
|
|
if ($authenticated_user->in_group('bz_sudoers')
|
|
|
|
|
&& defined $sudo_target
|
|
|
|
|
&& !$sudo_target->in_group('bz_sudo_protect'))
|
|
|
|
|
{
|
|
|
|
|
$class->set_user($sudo_target);
|
|
|
|
|
$class->request_cache->{sudoer} = $authenticated_user;
|
|
|
|
|
# And make sure that both users have the same Auth object,
|
|
|
|
|
# since we never call Auth::login for the sudo target.
|
|
|
|
|
$sudo_target->set_authorizer($authenticated_user->authorizer);
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
2010-08-10 15:15:39 +04:00
|
|
|
|
# NOTE: If you want to do any special logging, do it here.
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-08-10 15:15:39 +04:00
|
|
|
|
delete_token($token);
|
|
|
|
|
$class->cgi->remove_cookie('sudo');
|
|
|
|
|
ThrowUserError('sudo_illegal_action', { sudoer => $authenticated_user,
|
|
|
|
|
target_user => $sudo_target });
|
|
|
|
|
}
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->set_user($authenticated_user);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-07 20:38:25 +04:00
|
|
|
|
if ($class->sudoer)
|
|
|
|
|
{
|
|
|
|
|
$class->sudoer->update_last_seen_date();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$class->user->update_last_seen_date();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
return $class->user;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub logout
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $option) = @_;
|
|
|
|
|
|
|
|
|
|
# If we're not logged in, go away
|
|
|
|
|
return unless $class->user->id;
|
|
|
|
|
|
|
|
|
|
$option = LOGOUT_CURRENT unless defined $option;
|
|
|
|
|
Bugzilla::Auth::Persist::Cookie->logout({type => $option});
|
|
|
|
|
$class->logout_request() unless $option eq LOGOUT_KEEP_CURRENT;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub logout_user
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $user) = @_;
|
|
|
|
|
# When we're logging out another user we leave cookies alone, and
|
|
|
|
|
# therefore avoid calling Bugzilla->logout() directly.
|
|
|
|
|
Bugzilla::Auth::Persist::Cookie->logout({user => $user});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# just a compatibility front-end to logout_user that gets a user by id
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub logout_user_by_id
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $id) = @_;
|
|
|
|
|
my $user = new Bugzilla::User($id);
|
|
|
|
|
$class->logout_user($user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# hack that invalidates credentials for a single request
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub logout_request
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
delete $class->request_cache->{user};
|
|
|
|
|
delete $class->request_cache->{sudoer};
|
2014-10-10 15:15:48 +04:00
|
|
|
|
delete $class->cookies->{Bugzilla_login};
|
|
|
|
|
delete $class->cookies->{Bugzilla_logincokie};
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# We can't delete from $cgi->cookie, so logincookie data will remain
|
|
|
|
|
# there. Don't rely on it: use Bugzilla->user->login instead!
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub job_queue
|
|
|
|
|
{
|
2009-07-29 15:21:49 +04:00
|
|
|
|
my $class = shift;
|
2010-05-15 00:02:34 +04:00
|
|
|
|
require Bugzilla::JobQueue;
|
2009-07-29 15:21:49 +04:00
|
|
|
|
$class->request_cache->{job_queue} ||= Bugzilla::JobQueue->new();
|
|
|
|
|
return $class->request_cache->{job_queue};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub dbh
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
# If we're not connected, then we must want the main db
|
2010-03-09 20:12:04 +03:00
|
|
|
|
$class->request_cache->{dbh} ||= $class->dbh_main;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
|
|
|
|
|
return $class->request_cache->{dbh};
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-23 19:06:20 +04:00
|
|
|
|
sub dbh_sphinx
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
if (!exists $class->request_cache->{dbh_sphinx})
|
|
|
|
|
{
|
|
|
|
|
$class->request_cache->{dbh_sphinx} = Bugzilla::DB::connect_sphinx();
|
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{dbh_sphinx};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub dbh_main
|
|
|
|
|
{
|
2010-03-09 20:12:04 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
$class->request_cache->{dbh_main} ||= Bugzilla::DB::connect_main();
|
|
|
|
|
return $class->request_cache->{dbh_main};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub languages
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
return $class->request_cache->{languages}
|
|
|
|
|
if $class->request_cache->{languages};
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
my @files = glob(catdir(bz_locations->{templatedir}, '*'));
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my @languages;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
foreach my $dir_entry (@files)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# It's a language directory only if it contains "default" or
|
|
|
|
|
# "custom". This auto-excludes CVS directories as well.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
next unless (-d catdir($dir_entry, 'default') || -d catdir($dir_entry, 'custom'));
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$dir_entry = basename($dir_entry);
|
|
|
|
|
# Check for language tag format conforming to RFC 1766.
|
|
|
|
|
next unless $dir_entry =~ /^[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?$/;
|
|
|
|
|
push(@languages, $dir_entry);
|
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{languages} = \@languages;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub error_mode
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $newval) = @_;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (defined $newval)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->request_cache->{error_mode} = $newval;
|
|
|
|
|
}
|
2014-10-30 02:05:05 +03:00
|
|
|
|
return $class->request_cache->{error_mode} || (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_CONSOLE);
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# This is used only by Bugzilla::Error to throw errors.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub _json_server
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
my ($class, $newval) = @_;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (defined $newval)
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
$class->request_cache->{_json_server} = $newval;
|
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{_json_server};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub usage_mode
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $newval) = @_;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (defined $newval)
|
|
|
|
|
{
|
|
|
|
|
if ($newval == USAGE_MODE_BROWSER)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->error_mode(ERROR_MODE_WEBPAGE);
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
elsif ($newval == USAGE_MODE_CMDLINE)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->error_mode(ERROR_MODE_DIE);
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
elsif ($newval == USAGE_MODE_XMLRPC)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->error_mode(ERROR_MODE_DIE_SOAP_FAULT);
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
elsif ($newval == USAGE_MODE_JSON)
|
|
|
|
|
{
|
2010-05-15 00:02:34 +04:00
|
|
|
|
$class->error_mode(ERROR_MODE_JSON_RPC);
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
elsif ($newval == USAGE_MODE_EMAIL)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->error_mode(ERROR_MODE_DIE);
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ThrowCodeError('usage_mode_invalid', { invalid_usage_mode => $newval });
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
$class->request_cache->{usage_mode} = $newval;
|
|
|
|
|
}
|
2014-04-09 19:12:48 +04:00
|
|
|
|
return $class->request_cache->{usage_mode} || (i_am_cgi() ? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub installation_mode
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $newval) = @_;
|
|
|
|
|
($class->request_cache->{installation_mode} = $newval) if defined $newval;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
return $class->request_cache->{installation_mode} || INSTALLATION_MODE_INTERACTIVE;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub installation_answers
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my ($class, $filename) = @_;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if ($filename)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $s = new Safe;
|
|
|
|
|
$s->rdo($filename);
|
|
|
|
|
|
|
|
|
|
die "Error reading $filename: $!" if $!;
|
|
|
|
|
die "Error evaluating $filename: $@" if $@;
|
|
|
|
|
|
|
|
|
|
# Now read the param back out from the sandbox
|
|
|
|
|
$class->request_cache->{installation_answers} = $s->varglob('answer');
|
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{installation_answers} || {};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub switch_to_shadow_db
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!$class->request_cache->{dbh_shadow})
|
|
|
|
|
{
|
|
|
|
|
if ($class->params->{shadowdb})
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->request_cache->{dbh_shadow} = Bugzilla::DB::connect_shadow();
|
2014-04-09 19:12:48 +04:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-03-09 20:12:04 +03:00
|
|
|
|
$class->request_cache->{dbh_shadow} = $class->dbh_main;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$class->request_cache->{dbh} = $class->request_cache->{dbh_shadow};
|
|
|
|
|
# we have to return $class->dbh instead of {dbh} as
|
|
|
|
|
# {dbh_shadow} may be undefined if no shadow DB is used
|
|
|
|
|
# and no connection to the main DB has been established yet.
|
|
|
|
|
return $class->dbh;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-20 16:48:26 +04:00
|
|
|
|
sub switch_to_main_db
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
2010-03-09 20:12:04 +03:00
|
|
|
|
$class->request_cache->{dbh} = $class->dbh_main;
|
|
|
|
|
return $class->dbh_main;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-20 16:48:26 +04:00
|
|
|
|
sub messages
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
2014-10-10 15:15:48 +04:00
|
|
|
|
my $lc = $class->cookies->{LANG} || 'en';
|
2011-07-20 16:48:26 +04:00
|
|
|
|
$lc =~ s/\W+//so;
|
|
|
|
|
if (!$INC{'Bugzilla::Language::'.$lc})
|
|
|
|
|
{
|
|
|
|
|
eval { require 'Bugzilla/Language/'.$lc.'.pm' };
|
|
|
|
|
if ($@)
|
|
|
|
|
{
|
|
|
|
|
$lc = 'en';
|
|
|
|
|
require 'Bugzilla/Language/en.pm';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $Bugzilla::messages->{$lc};
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 14:31:30 +04:00
|
|
|
|
sub cache_fields
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
2010-12-10 02:53:33 +03:00
|
|
|
|
my $rc = $class->request_cache;
|
|
|
|
|
if (!$rc->{fields_delta_ts})
|
|
|
|
|
{
|
|
|
|
|
($rc->{fields_delta_ts}) = Bugzilla->dbh->selectrow_array(
|
|
|
|
|
"SELECT MAX(delta_ts) FROM fielddefs");
|
|
|
|
|
}
|
|
|
|
|
$Bugzilla::CACHE_FIELDS ||= {};
|
|
|
|
|
if (!$Bugzilla::CACHE_FIELDS->{_cache_ts} ||
|
|
|
|
|
$rc->{fields_delta_ts} gt $Bugzilla::CACHE_FIELDS->{_cache_ts})
|
|
|
|
|
{
|
|
|
|
|
%{$Bugzilla::CACHE_FIELDS} = ();
|
|
|
|
|
_fill_fields_cache($Bugzilla::CACHE_FIELDS);
|
|
|
|
|
}
|
|
|
|
|
return $Bugzilla::CACHE_FIELDS;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 21:02:52 +03:00
|
|
|
|
sub rc_cache_fields
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
return ($class->request_cache->{cache_fields} ||= {});
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 02:53:33 +03:00
|
|
|
|
sub refresh_cache_fields
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
delete $class->request_cache->{fields_delta_ts};
|
2010-12-10 21:02:52 +03:00
|
|
|
|
delete $class->request_cache->{cache_fields};
|
2012-03-14 17:51:21 +04:00
|
|
|
|
$Bugzilla::CACHE_FIELDS = {};
|
2010-12-10 02:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub _fill_fields_cache
|
|
|
|
|
{
|
|
|
|
|
my ($r) = @_;
|
|
|
|
|
if (!$r->{id})
|
2010-10-14 14:31:30 +04:00
|
|
|
|
{
|
2011-11-11 19:14:03 +04:00
|
|
|
|
# FIXME take field descriptions from Bugzilla->messages->{field_descs}
|
|
|
|
|
# FIXME and remove ugly hacks from templates (field_descs.${f.name} || f.description)
|
2010-12-10 21:02:52 +03:00
|
|
|
|
my $f = [ Bugzilla::Field->get_all ];
|
2010-10-14 14:31:30 +04:00
|
|
|
|
for (@$f)
|
|
|
|
|
{
|
|
|
|
|
$r->{id}->{$_->id} = $_;
|
|
|
|
|
$r->{name}->{$_->name} = $_;
|
2010-12-10 02:53:33 +03:00
|
|
|
|
if (!$r->{_cache_ts} || $r->{_cache_ts} lt $_->{delta_ts})
|
|
|
|
|
{
|
|
|
|
|
$r->{_cache_ts} = $_->{delta_ts};
|
|
|
|
|
}
|
2010-10-14 14:31:30 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-12-10 02:53:33 +03:00
|
|
|
|
return $r;
|
2010-12-09 20:16:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 14:31:30 +04:00
|
|
|
|
sub get_field
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
2010-10-14 14:31:30 +04:00
|
|
|
|
my ($id_or_name, $throw_error) = @_;
|
2010-11-24 16:41:09 +03:00
|
|
|
|
return $id_or_name if ref $id_or_name;
|
2010-10-14 14:31:30 +04:00
|
|
|
|
my $c = $class->cache_fields;
|
|
|
|
|
$c = $id_or_name =~ /^\d+$/so ? $c->{id}->{$id_or_name} : $c->{name}->{$id_or_name};
|
|
|
|
|
if (!$c && $throw_error)
|
|
|
|
|
{
|
|
|
|
|
ThrowUserError('object_does_not_exist', {
|
|
|
|
|
($id_or_name =~ /^\d+$/so ? 'id' : 'name') => $id_or_name,
|
|
|
|
|
class => 'Bugzilla::Field',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return $c;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 14:31:30 +04:00
|
|
|
|
sub get_fields
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
2010-10-14 14:31:30 +04:00
|
|
|
|
my $criteria = shift || {};
|
|
|
|
|
my $cache = $class->cache_fields;
|
|
|
|
|
my @fields = values %{$cache->{id}};
|
2011-06-22 20:18:45 +04:00
|
|
|
|
my $sort = delete $criteria->{sort};
|
2010-10-14 14:31:30 +04:00
|
|
|
|
for my $k (keys %$criteria)
|
|
|
|
|
{
|
|
|
|
|
my %v = map { $_ => 1 } (ref $criteria->{$k} ? @{$criteria->{$k}} : $criteria->{$k});
|
|
|
|
|
@fields = grep { $v{$_->$k} } @fields;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
2011-06-22 20:18:45 +04:00
|
|
|
|
if ($sort)
|
|
|
|
|
{
|
2011-07-20 16:48:26 +04:00
|
|
|
|
# Support sorting on different fields
|
|
|
|
|
if ($sort eq 'name' || $sort eq 'description')
|
|
|
|
|
{
|
|
|
|
|
@fields = sort { $a->{$sort} cmp $b->{$sort} } @fields;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$sort = 'sortkey' if $sort ne 'id';
|
|
|
|
|
@fields = sort { $a->{$sort} <=> $b->{$sort} } @fields;
|
|
|
|
|
}
|
2011-06-22 20:18:45 +04:00
|
|
|
|
}
|
2010-10-14 14:31:30 +04:00
|
|
|
|
return @fields;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-27 19:53:21 +04:00
|
|
|
|
# Cache for fieldvaluecontrol table
|
|
|
|
|
sub fieldvaluecontrol
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
2010-12-10 02:53:33 +03:00
|
|
|
|
my $cache = $class->cache_fields;
|
|
|
|
|
if (!$cache->{fieldvaluecontrol})
|
2010-10-27 19:53:21 +04:00
|
|
|
|
{
|
2014-06-30 19:31:24 +04:00
|
|
|
|
my $rows = $class->dbh->selectall_arrayref(
|
2014-07-08 15:44:05 +04:00
|
|
|
|
'SELECT c.*, (CASE WHEN c.value_id='.FLAG_CLONED.' THEN f.clone_field_id'.
|
|
|
|
|
' WHEN c.value_id='.FLAG_NULLABLE.' THEN f.null_field_id'.
|
2014-07-09 17:22:17 +04:00
|
|
|
|
' WHEN c.value_id='.FLAG_VISIBLE.' THEN f.visibility_field_id ELSE f.value_field_id END) dep_field_id'.
|
2014-07-01 18:05:29 +04:00
|
|
|
|
' FROM fieldvaluecontrol c, fielddefs f WHERE f.id=c.field_id', {Slice=>{}}
|
2010-10-27 19:53:21 +04:00
|
|
|
|
);
|
2014-07-08 15:44:05 +04:00
|
|
|
|
my $keys = {
|
|
|
|
|
FLAG_VISIBLE() => 'fields',
|
|
|
|
|
FLAG_NULLABLE() => 'null',
|
|
|
|
|
FLAG_CLONED() => 'clone',
|
|
|
|
|
};
|
2010-10-27 19:53:21 +04:00
|
|
|
|
my $has = {};
|
2014-06-30 19:31:24 +04:00
|
|
|
|
for (@$rows)
|
2010-10-27 19:53:21 +04:00
|
|
|
|
{
|
2014-07-30 16:02:24 +04:00
|
|
|
|
next if !defined $_->{dep_field_id}; # FIXME: means fieldvaluecontrol table has inconsistent data
|
2014-06-23 19:57:26 +04:00
|
|
|
|
if ($_->{value_id} > 0)
|
2010-10-27 19:53:21 +04:00
|
|
|
|
{
|
2014-06-23 19:57:26 +04:00
|
|
|
|
# Show value_id if value_field==visibility_value_id
|
2014-07-09 17:22:17 +04:00
|
|
|
|
$has->{$_->{dep_field_id}}
|
2010-10-27 19:53:21 +04:00
|
|
|
|
->{values}
|
|
|
|
|
->{$_->{field_id}}
|
|
|
|
|
->{$_->{value_id}}
|
2014-06-30 19:31:24 +04:00
|
|
|
|
->{$_->{visibility_value_id}} = 1;
|
2010-12-09 20:16:43 +03:00
|
|
|
|
}
|
2014-07-08 15:44:05 +04:00
|
|
|
|
else
|
2014-06-23 19:57:26 +04:00
|
|
|
|
{
|
2014-07-09 17:22:17 +04:00
|
|
|
|
# Show field / allow NULL / clone value if dep_field==visibility_value_id
|
|
|
|
|
$has->{$_->{dep_field_id}}
|
2014-07-08 15:44:05 +04:00
|
|
|
|
->{$keys->{$_->{value_id}}}
|
2014-06-23 19:57:26 +04:00
|
|
|
|
->{$_->{field_id}}
|
|
|
|
|
->{$_->{visibility_value_id}} = 1;
|
|
|
|
|
}
|
2010-10-27 19:53:21 +04:00
|
|
|
|
}
|
2014-06-30 19:31:24 +04:00
|
|
|
|
# Dependent defaults
|
|
|
|
|
$rows = $class->dbh->selectall_arrayref(
|
2014-07-01 18:05:29 +04:00
|
|
|
|
'SELECT d.field_id, f.default_field_id, d.visibility_value_id, d.default_value'.
|
2014-06-30 19:31:24 +04:00
|
|
|
|
' FROM field_defaults d, fielddefs f WHERE f.id=d.field_id', {Slice=>{}}
|
|
|
|
|
);
|
|
|
|
|
for (@$rows)
|
|
|
|
|
{
|
2014-07-30 19:13:58 +04:00
|
|
|
|
next if !defined $_->{default_field_id}; # FIXME: means field_defaults table has inconsistent data
|
2014-07-01 18:05:29 +04:00
|
|
|
|
$has->{$_->{default_field_id}}
|
2014-06-30 19:31:24 +04:00
|
|
|
|
->{defaults}
|
|
|
|
|
->{$_->{field_id}}
|
|
|
|
|
->{$_->{visibility_value_id}} = $_->{default_value};
|
|
|
|
|
}
|
|
|
|
|
$cache->{fieldvaluecontrol} = $has;
|
2010-10-27 19:53:21 +04:00
|
|
|
|
}
|
2010-12-10 02:53:33 +03:00
|
|
|
|
return $cache->{fieldvaluecontrol};
|
2010-10-27 19:53:21 +04:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 14:31:30 +04:00
|
|
|
|
sub active_custom_fields
|
|
|
|
|
{
|
|
|
|
|
my $class = shift;
|
|
|
|
|
my $criteria = shift || {};
|
|
|
|
|
$criteria->{custom} = 1;
|
|
|
|
|
$criteria->{obsolete} = 0;
|
2012-11-27 15:07:17 +04:00
|
|
|
|
$criteria->{sort} ||= 'sortkey';
|
2010-10-14 14:31:30 +04:00
|
|
|
|
return $class->get_fields($criteria);
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 16:39:49 +04:00
|
|
|
|
sub has_keywords
|
|
|
|
|
{
|
|
|
|
|
return Bugzilla::Keyword->any_exist;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub has_flags
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $class = shift;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!defined $class->request_cache->{has_flags})
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$class->request_cache->{has_flags} = Bugzilla::Flag::has_flags();
|
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{has_flags};
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub local_timezone
|
|
|
|
|
{
|
2009-07-29 15:21:49 +04:00
|
|
|
|
my $class = shift;
|
2014-04-09 19:12:48 +04:00
|
|
|
|
if (!defined $class->request_cache->{local_timezone})
|
|
|
|
|
{
|
|
|
|
|
$class->request_cache->{local_timezone} = DateTime::TimeZone->new(name => 'local');
|
2009-07-29 15:21:49 +04:00
|
|
|
|
}
|
|
|
|
|
return $class->request_cache->{local_timezone};
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# This creates the request cache for non-mod_perl installations.
|
|
|
|
|
# This is identical to Install::Util::_cache so that things loaded
|
|
|
|
|
# into Install::Util::_cache during installation can be read out
|
|
|
|
|
# of request_cache later in installation.
|
|
|
|
|
our $_request_cache = $Bugzilla::Install::Util::_cache;
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub request_cache
|
|
|
|
|
{
|
|
|
|
|
if ($ENV{MOD_PERL})
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
require Apache2::RequestUtil;
|
2010-05-15 00:02:34 +04:00
|
|
|
|
# Sometimes (for example, during mod_perl.pl), the request
|
|
|
|
|
# object isn't available, and we should use $_request_cache instead.
|
|
|
|
|
my $request = eval { Apache2::RequestUtil->request };
|
|
|
|
|
return $_request_cache if !$request;
|
|
|
|
|
return $request->pnotes();
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
2009-12-29 20:26:54 +03:00
|
|
|
|
return $_request_cache ||= {};
|
2008-12-15 15:53:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Private methods
|
|
|
|
|
|
|
|
|
|
# Per-process cleanup. Note that this is a plain subroutine, not a method,
|
|
|
|
|
# so we don't have $class available.
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub _cleanup
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
my $main = Bugzilla->request_cache->{dbh_main};
|
|
|
|
|
my $shadow = Bugzilla->request_cache->{dbh_shadow};
|
2014-04-09 19:12:48 +04:00
|
|
|
|
foreach my $dbh ($main, $shadow)
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
next if !$dbh;
|
|
|
|
|
$dbh->bz_rollback_transaction() if $dbh->bz_in_transaction;
|
2014-11-01 00:18:57 +03:00
|
|
|
|
$dbh->write_query_log;
|
2008-12-15 15:53:33 +03:00
|
|
|
|
$dbh->disconnect;
|
|
|
|
|
}
|
|
|
|
|
undef $_request_cache;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-09 19:12:48 +04:00
|
|
|
|
sub END
|
|
|
|
|
{
|
2008-12-15 15:53:33 +03:00
|
|
|
|
# Bugzilla.pm cannot compile in mod_perl.pl if this runs.
|
|
|
|
|
_cleanup() unless $ENV{MOD_PERL};
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
init_page() if !$ENV{MOD_PERL};
|
2010-12-08 19:06:25 +03:00
|
|
|
|
Bugzilla::Extension->load_all() if !$ENV{MOD_PERL};
|
2010-05-15 00:02:34 +04:00
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
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 around
|
|
|
|
|
with mod_perl
|
|
|
|
|
|
|
|
|
|
=item *
|
|
|
|
|
|
|
|
|
|
Everything is in one central place, so it's 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<template> object),
|
|
|
|
|
or should be something which is globally required by a large ammount of code
|
|
|
|
|
(such as the current C<user> object).
|
|
|
|
|
|
|
|
|
|
=head1 METHODS
|
|
|
|
|
|
|
|
|
|
Note that all C<Bugzilla> functionality is method based; use C<Bugzilla-E<gt>dbh>
|
|
|
|
|
rather than C<Bugzilla::dbh>. Nothing cares about this now, but don't rely on
|
|
|
|
|
that.
|
|
|
|
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
|
|
|
|
=item C<template>
|
|
|
|
|
|
|
|
|
|
The current C<Template> object, to be used for output
|
|
|
|
|
|
|
|
|
|
=item C<template_inner>
|
|
|
|
|
|
|
|
|
|
If you ever need a L<Bugzilla::Template> object while you're already
|
|
|
|
|
processing a template, use this. Also use it if you want to specify
|
|
|
|
|
the language to use. If no argument is passed, it uses the last
|
|
|
|
|
language set. If the argument is "" (empty string), the language is
|
|
|
|
|
reset to the current one (the one used by Bugzilla->template).
|
|
|
|
|
|
|
|
|
|
=item C<cgi>
|
|
|
|
|
|
|
|
|
|
The current C<cgi> object. Note that modules should B<not> be using this in
|
|
|
|
|
general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
|
|
|
|
|
method for those scripts/templates which are only use via CGI, though.
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
=item C<input_params>
|
|
|
|
|
|
|
|
|
|
When running under the WebService, this is a hashref containing the arguments
|
|
|
|
|
passed to the WebService method that was called. When running in a normal
|
|
|
|
|
script, this is a hashref containing the contents of the CGI parameters.
|
|
|
|
|
|
|
|
|
|
Modifying this hashref will modify the CGI parameters or the WebService
|
|
|
|
|
arguments (depending on what C<input_params> currently represents).
|
|
|
|
|
|
|
|
|
|
This should be used instead of L</cgi> in situations where your code
|
|
|
|
|
could be being called by either a normal CGI script or a WebService method,
|
|
|
|
|
such as during a code hook.
|
|
|
|
|
|
|
|
|
|
B<Note:> When C<input_params> represents the CGI parameters, any
|
|
|
|
|
parameter specified more than once (like C<foo=bar&foo=baz>) will appear
|
|
|
|
|
as an arrayref in the hash, but any value specified only once will appear
|
|
|
|
|
as a scalar. This means that even if a value I<can> appear multiple times,
|
|
|
|
|
if it only I<does> appear once, then it will be a scalar in C<input_params>,
|
|
|
|
|
not an arrayref.
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
=item C<user>
|
|
|
|
|
|
|
|
|
|
C<undef> if there is no currently logged in user or if the login code has not
|
|
|
|
|
yet been run. If an sudo session is in progress, the C<Bugzilla::User>
|
|
|
|
|
corresponding to the person who is being impersonated. If no session is in
|
|
|
|
|
progress, the current C<Bugzilla::User>.
|
|
|
|
|
|
|
|
|
|
=item C<set_user>
|
|
|
|
|
|
|
|
|
|
Allows you to directly set what L</user> will return. You can use this
|
|
|
|
|
if you want to bypass L</login> for some reason and directly "log in"
|
|
|
|
|
a specific L<Bugzilla::User>. Be careful with it, though!
|
|
|
|
|
|
|
|
|
|
=item C<sudoer>
|
|
|
|
|
|
|
|
|
|
C<undef> if there is no currently logged in user, the currently logged in user
|
|
|
|
|
is not in the I<sudoer> group, or there is no session in progress. If an sudo
|
|
|
|
|
session is in progress, returns the C<Bugzilla::User> object corresponding to
|
|
|
|
|
the person who logged in and initiated the session. If no session is in
|
|
|
|
|
progress, returns the C<Bugzilla::User> object corresponding to the currently
|
|
|
|
|
logged in user.
|
|
|
|
|
|
|
|
|
|
=item C<sudo_request>
|
|
|
|
|
This begins an sudo session for the current request. It is meant to be
|
|
|
|
|
used when a session has just started. For normal use, sudo access should
|
|
|
|
|
normally be set at login time.
|
|
|
|
|
|
|
|
|
|
=item C<login>
|
|
|
|
|
|
|
|
|
|
Logs in a user, returning a C<Bugzilla::User> object, or C<undef> if there is
|
|
|
|
|
no logged in user. See L<Bugzilla::Auth|Bugzilla::Auth>, and
|
|
|
|
|
L<Bugzilla::User|Bugzilla::User>.
|
|
|
|
|
|
2009-07-29 15:21:49 +04:00
|
|
|
|
=item C<page_requires_login>
|
|
|
|
|
|
|
|
|
|
If the current page always requires the user to log in (for example,
|
|
|
|
|
C<enter_bug.cgi> or any page called with C<?GoAheadAndLogIn=1>) then
|
|
|
|
|
this will return something true. Otherwise it will return false. (This is
|
|
|
|
|
set when you call L</login>.)
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
=item C<logout($option)>
|
|
|
|
|
|
|
|
|
|
Logs out the current user, which involves invalidating user sessions and
|
|
|
|
|
cookies. Three options are available from
|
|
|
|
|
L<Bugzilla::Constants|Bugzilla::Constants>: LOGOUT_CURRENT (the
|
|
|
|
|
default), LOGOUT_ALL or LOGOUT_KEEP_CURRENT.
|
|
|
|
|
|
|
|
|
|
=item C<logout_user($user)>
|
|
|
|
|
|
|
|
|
|
Logs out the specified user (invalidating all his sessions), taking a
|
|
|
|
|
Bugzilla::User instance.
|
|
|
|
|
|
|
|
|
|
=item C<logout_by_id($id)>
|
|
|
|
|
|
|
|
|
|
Logs out the user with the id specified. This is a compatibility
|
|
|
|
|
function to be used in callsites where there is only a userid and no
|
|
|
|
|
Bugzilla::User instance.
|
|
|
|
|
|
|
|
|
|
=item C<logout_request>
|
|
|
|
|
|
|
|
|
|
Essentially, causes calls to C<Bugzilla-E<gt>user> to return C<undef>. This has the
|
|
|
|
|
effect of logging out a user for the current request only; cookies and
|
|
|
|
|
database sessions are left intact.
|
|
|
|
|
|
|
|
|
|
=item C<error_mode>
|
|
|
|
|
|
|
|
|
|
Call either C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE)>
|
|
|
|
|
or C<Bugzilla->error_mode(Bugzilla::Constants::ERROR_MODE_DIE_SOAP_FAULT)> to
|
|
|
|
|
change this flag's default of C<Bugzilla::Constants::ERROR_MODE_WEBPAGE> and to
|
|
|
|
|
indicate that errors should be passed to error mode specific error handlers
|
|
|
|
|
rather than being sent to a browser and finished with an exit().
|
|
|
|
|
|
|
|
|
|
This is useful, for example, to keep C<eval> blocks from producing wild HTML
|
|
|
|
|
on errors, making it easier for you to catch them.
|
|
|
|
|
(Remember to reset the error mode to its previous value afterwards, though.)
|
|
|
|
|
|
|
|
|
|
C<Bugzilla->error_mode> will return the current state of this flag.
|
|
|
|
|
|
|
|
|
|
Note that C<Bugzilla->error_mode> is being called by C<Bugzilla->usage_mode> on
|
|
|
|
|
usage mode changes.
|
|
|
|
|
|
|
|
|
|
=item C<usage_mode>
|
|
|
|
|
|
|
|
|
|
Call either C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE)>
|
2010-05-15 00:02:34 +04:00
|
|
|
|
or C<Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_XMLRPC)> near the
|
2008-12-15 15:53:33 +03:00
|
|
|
|
beginning of your script to change this flag's default of
|
|
|
|
|
C<Bugzilla::Constants::USAGE_MODE_BROWSER> and to indicate that Bugzilla is
|
|
|
|
|
being called in a non-interactive manner.
|
2010-05-15 00:02:34 +04:00
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
This influences error handling because on usage mode changes, C<usage_mode>
|
|
|
|
|
calls C<Bugzilla->error_mode> to set an error mode which makes sense for the
|
|
|
|
|
usage mode.
|
|
|
|
|
|
|
|
|
|
C<Bugzilla->usage_mode> will return the current state of this flag.
|
|
|
|
|
|
|
|
|
|
=item C<installation_mode>
|
|
|
|
|
|
|
|
|
|
Determines whether or not installation should be silent. See
|
|
|
|
|
L<Bugzilla::Constants> for the C<INSTALLATION_MODE> constants.
|
|
|
|
|
|
|
|
|
|
=item C<installation_answers>
|
|
|
|
|
|
|
|
|
|
Returns a hashref representing any "answers" file passed to F<checksetup.pl>,
|
|
|
|
|
used to automatically answer or skip prompts.
|
|
|
|
|
|
|
|
|
|
=item C<dbh>
|
|
|
|
|
|
|
|
|
|
The current database handle. See L<DBI>.
|
|
|
|
|
|
2010-03-09 20:12:04 +03:00
|
|
|
|
=item C<dbh_main>
|
|
|
|
|
|
|
|
|
|
The main database handle. See L<DBI>.
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
=item C<languages>
|
|
|
|
|
|
|
|
|
|
Currently installed languages.
|
|
|
|
|
Returns a reference to a list of RFC 1766 language tags of installed languages.
|
|
|
|
|
|
|
|
|
|
=item C<switch_to_shadow_db>
|
|
|
|
|
|
|
|
|
|
Switch from using the main database to using the shadow database.
|
|
|
|
|
|
|
|
|
|
=item C<switch_to_main_db>
|
|
|
|
|
|
|
|
|
|
Change the database object to refer to the main database.
|
|
|
|
|
|
|
|
|
|
=item C<params>
|
|
|
|
|
|
|
|
|
|
The current Parameters of Bugzilla, as a hashref. If C<data/params>
|
|
|
|
|
does not exist, then we return an empty hashref. If C<data/params>
|
|
|
|
|
is unreadable or is not valid perl, we C<die>.
|
|
|
|
|
|
2009-07-29 15:21:49 +04:00
|
|
|
|
=item C<local_timezone>
|
|
|
|
|
|
|
|
|
|
Returns the local timezone of the Bugzilla installation,
|
|
|
|
|
as a DateTime::TimeZone object. This detection is very time
|
|
|
|
|
consuming, so we cache this information for future references.
|
|
|
|
|
|
|
|
|
|
=item C<job_queue>
|
|
|
|
|
|
|
|
|
|
Returns a L<Bugzilla::JobQueue> that you can use for queueing jobs.
|
|
|
|
|
Will throw an error if job queueing is not correctly configured on
|
|
|
|
|
this Bugzilla installation.
|
|
|
|
|
|
2010-05-15 00:02:34 +04:00
|
|
|
|
=item C<feature>
|
|
|
|
|
|
|
|
|
|
Tells you whether or not a specific feature is enabled. For names
|
|
|
|
|
of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
|
|
|
|
|
|
2008-12-15 15:53:33 +03:00
|
|
|
|
=back
|