1998-09-15 21:49:26 +00:00
|
|
|
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
|
|
|
#
|
1999-11-01 23:33:56 +00: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.
|
|
|
|
#
|
1998-09-15 21:49:26 +00:00
|
|
|
# The Original Code is the Bugzilla Bug Tracking System.
|
1999-11-01 23:33:56 +00:00
|
|
|
#
|
1998-09-15 21:49:26 +00:00
|
|
|
# The Initial Developer of the Original Code is Netscape Communications
|
1999-11-01 23:33:56 +00:00
|
|
|
# Corporation. Portions created by Netscape are
|
|
|
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
# Rights Reserved.
|
|
|
|
#
|
1998-09-15 21:49:26 +00:00
|
|
|
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
1999-12-02 23:21:42 +00:00
|
|
|
# Dan Mosedale <dmose@mozilla.org>
|
2000-09-15 18:35:18 +00:00
|
|
|
# Joe Robins <jmrobins@tgix.com>
|
2001-06-07 20:26:40 +00:00
|
|
|
# Dave Miller <justdave@syndicomm.com>
|
2001-08-26 18:51:45 +00:00
|
|
|
# Christopher Aillon <christopher@aillon.com>
|
2001-09-10 21:26:05 +00:00
|
|
|
# Gervase Markham <gerv@gerv.net>
|
2001-10-10 23:36:29 +00:00
|
|
|
# Christian Reis <kiko@async.com.br>
|
1998-09-15 21:49:26 +00:00
|
|
|
|
|
|
|
# Contains some global routines used throughout the CGI scripts of Bugzilla.
|
|
|
|
|
|
|
|
use strict;
|
2001-11-18 22:23:31 +00:00
|
|
|
use lib ".";
|
|
|
|
|
2000-03-10 17:45:09 +00:00
|
|
|
# use Carp; # for confess
|
2000-10-24 00:44:21 +00:00
|
|
|
|
2002-08-19 13:59:45 +00:00
|
|
|
use Bugzilla::Util;
|
2002-08-29 09:25:54 +00:00
|
|
|
use Bugzilla::Config;
|
2003-03-22 04:47:35 +00:00
|
|
|
use Bugzilla::Constants;
|
2003-04-02 12:35:07 +00:00
|
|
|
use Bugzilla::Error;
|
2000-10-24 00:44:21 +00:00
|
|
|
|
2001-11-18 03:54:54 +00:00
|
|
|
# Shut up misguided -w warnings about "used only once". For some reason,
|
|
|
|
# "use vars" chokes on me when I try it here.
|
1999-10-18 23:57:58 +00:00
|
|
|
|
1999-10-19 00:04:59 +00:00
|
|
|
sub CGI_pl_sillyness {
|
1999-10-18 23:57:58 +00:00
|
|
|
my $zz;
|
2000-01-20 21:36:20 +00:00
|
|
|
$zz = %::dontchange;
|
1999-10-18 23:57:58 +00:00
|
|
|
}
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
use CGI::Carp qw(fatalsToBrowser);
|
|
|
|
|
|
|
|
require 'globals.pl';
|
|
|
|
|
2002-04-03 23:00:29 +00:00
|
|
|
use vars qw($template $vars);
|
|
|
|
|
2002-02-03 09:28:48 +00:00
|
|
|
# If Bugzilla is shut down, do not go any further, just display a message
|
|
|
|
# to the user about the downtime. (do)editparams.cgi is exempted from
|
|
|
|
# this message, of course, since it needs to be available in order for
|
|
|
|
# the administrator to open Bugzilla back up.
|
|
|
|
if (Param("shutdownhtml") && $0 !~ m:[\\/](do)?editparams.cgi$:) {
|
2002-08-19 22:34:32 +00:00
|
|
|
$::vars->{'message'} = "shutdown";
|
2002-02-03 09:28:48 +00:00
|
|
|
|
|
|
|
# Return the appropriate HTTP response headers.
|
|
|
|
print "Content-Type: text/html\n\n";
|
|
|
|
|
|
|
|
# Generate and return an HTML message about the downtime.
|
|
|
|
$::template->process("global/message.html.tmpl", $::vars)
|
2002-04-24 07:24:50 +00:00
|
|
|
|| ThrowTemplateError($::template->error());
|
2002-02-03 09:28:48 +00:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
# Implementations of several of the below were blatently stolen from CGI.pm,
|
|
|
|
# by Lincoln D. Stein.
|
|
|
|
|
|
|
|
# Get rid of all the %xx encoding and the like from the given URL.
|
|
|
|
sub url_decode {
|
|
|
|
my ($todecode) = (@_);
|
|
|
|
$todecode =~ tr/+/ /; # pluses become spaces
|
|
|
|
$todecode =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
|
|
|
|
return $todecode;
|
|
|
|
}
|
|
|
|
|
1999-12-02 23:21:42 +00:00
|
|
|
# check and see if a given field exists, is non-empty, and is set to a
|
|
|
|
# legal value. assume a browser bug and abort appropriately if not.
|
|
|
|
# if $legalsRef is not passed, just check to make sure the value exists and
|
|
|
|
# is non-NULL
|
|
|
|
sub CheckFormField (\%$;\@) {
|
|
|
|
my ($formRef, # a reference to the form to check (a hash)
|
|
|
|
$fieldname, # the fieldname to check
|
|
|
|
$legalsRef # (optional) ref to a list of legal values
|
|
|
|
) = @_;
|
|
|
|
|
|
|
|
if ( !defined $formRef->{$fieldname} ||
|
|
|
|
trim($formRef->{$fieldname}) eq "" ||
|
|
|
|
(defined($legalsRef) &&
|
|
|
|
lsearch($legalsRef, $formRef->{$fieldname})<0) ){
|
|
|
|
|
2001-10-20 00:50:27 +00:00
|
|
|
SendSQL("SELECT description FROM fielddefs WHERE name=" . SqlQuote($fieldname));
|
|
|
|
my $result = FetchOneColumn();
|
|
|
|
if ($result) {
|
2002-08-15 06:43:47 +00:00
|
|
|
$vars->{'field'} = $result;
|
2001-10-20 00:50:27 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-08-15 06:43:47 +00:00
|
|
|
$vars->{'field'} = $fieldname;
|
2001-10-20 00:50:27 +00:00
|
|
|
}
|
2002-08-15 06:43:47 +00:00
|
|
|
|
2002-09-23 07:12:12 +00:00
|
|
|
ThrowCodeError("illegal_field", undef, "abort");
|
1999-12-02 23:21:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# check and see if a given field is defined, and abort if not
|
|
|
|
sub CheckFormFieldDefined (\%$) {
|
|
|
|
my ($formRef, # a reference to the form to check (a hash)
|
|
|
|
$fieldname, # the fieldname to check
|
|
|
|
) = @_;
|
|
|
|
|
2002-04-28 21:57:10 +00:00
|
|
|
if (!defined $formRef->{$fieldname}) {
|
2002-08-15 06:43:47 +00:00
|
|
|
$vars->{'field'} = $fieldname;
|
|
|
|
ThrowCodeError("undefined_field");
|
|
|
|
}
|
1999-12-02 23:21:42 +00:00
|
|
|
}
|
1999-04-08 14:40:46 +00:00
|
|
|
|
2002-07-03 23:07:14 +00:00
|
|
|
sub BugAliasToID {
|
|
|
|
# Queries the database for the bug with a given alias, and returns
|
|
|
|
# the ID of the bug if it exists or the undefined value if it doesn't.
|
|
|
|
|
|
|
|
my ($alias) = @_;
|
|
|
|
|
|
|
|
return undef unless Param("usebugaliases");
|
|
|
|
|
|
|
|
PushGlobalSQLState();
|
|
|
|
SendSQL("SELECT bug_id FROM bugs WHERE alias = " . SqlQuote($alias));
|
|
|
|
my $id = FetchOneColumn();
|
|
|
|
PopGlobalSQLState();
|
|
|
|
|
|
|
|
return $id;
|
|
|
|
}
|
|
|
|
|
2001-05-31 15:52:25 +00:00
|
|
|
sub ValidateBugID {
|
2001-06-02 22:02:02 +00:00
|
|
|
# Validates and verifies a bug ID, making sure the number is a
|
|
|
|
# positive integer, that it represents an existing bug in the
|
|
|
|
# database, and that the user is authorized to access that bug.
|
2002-01-20 01:44:52 +00:00
|
|
|
# We detaint the number here, too
|
2001-06-02 22:02:02 +00:00
|
|
|
|
2002-07-03 23:07:14 +00:00
|
|
|
my ($id, $skip_authorization) = @_;
|
|
|
|
|
|
|
|
# Get rid of white-space around the ID.
|
|
|
|
$id = trim($id);
|
|
|
|
|
|
|
|
# If the ID isn't a number, it might be an alias, so try to convert it.
|
2002-07-06 18:27:18 +00:00
|
|
|
my $alias = $id;
|
|
|
|
if (!detaint_natural($id)) {
|
|
|
|
$id = BugAliasToID($alias);
|
2002-09-28 21:44:27 +00:00
|
|
|
$id || ThrowUserError("invalid_bug_id_or_alias", {'bug_id' => $id});
|
2002-07-03 23:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Modify the calling code's original variable to contain the trimmed,
|
|
|
|
# converted-from-alias ID.
|
|
|
|
$_[0] = $id;
|
|
|
|
|
2001-10-23 15:44:53 +00:00
|
|
|
# First check that the bug exists
|
|
|
|
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $id");
|
2001-08-13 00:46:20 +00:00
|
|
|
|
2001-10-23 15:44:53 +00:00
|
|
|
FetchOneColumn()
|
2002-09-28 21:44:27 +00:00
|
|
|
|| ThrowUserError("invalid_bug_id_non_existent", {'bug_id' => $id});
|
2001-08-26 18:51:45 +00:00
|
|
|
|
2002-07-03 23:07:14 +00:00
|
|
|
return if $skip_authorization;
|
|
|
|
|
2002-09-22 17:15:13 +00:00
|
|
|
return if CanSeeBug($id, $::userid);
|
2001-08-13 00:46:20 +00:00
|
|
|
|
|
|
|
# The user did not pass any of the authorization tests, which means they
|
|
|
|
# are not authorized to see the bug. Display an error and stop execution.
|
|
|
|
# The error the user sees depends on whether or not they are logged in
|
2001-10-23 15:44:53 +00:00
|
|
|
# (i.e. $::userid contains the user's positive integer ID).
|
|
|
|
if ($::userid) {
|
2002-09-28 21:44:27 +00:00
|
|
|
ThrowUserError("bug_access_denied", {'bug_id' => $id});
|
2001-08-13 00:46:20 +00:00
|
|
|
} else {
|
2002-09-28 21:44:27 +00:00
|
|
|
ThrowUserError("bug_access_query", {'bug_id' => $id});
|
2001-08-13 00:46:20 +00:00
|
|
|
}
|
2001-05-31 15:52:25 +00:00
|
|
|
}
|
|
|
|
|
2002-03-11 07:33:03 +00:00
|
|
|
sub ValidateComment {
|
|
|
|
# Make sure a comment is not too large (greater than 64K).
|
|
|
|
|
|
|
|
my ($comment) = @_;
|
|
|
|
|
|
|
|
if (defined($comment) && length($comment) > 65535) {
|
2002-09-28 21:44:27 +00:00
|
|
|
ThrowUserError("comment_too_long");
|
2002-03-11 07:33:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
sub PasswordForLogin {
|
|
|
|
my ($login) = (@_);
|
|
|
|
SendSQL("select cryptpassword from profiles where login_name = " .
|
2001-10-13 01:36:17 +00:00
|
|
|
SqlQuote($login));
|
1998-10-13 18:15:37 +00:00
|
|
|
my $result = FetchOneColumn();
|
|
|
|
if (!defined $result) {
|
|
|
|
$result = "";
|
|
|
|
}
|
|
|
|
return $result;
|
1998-09-15 21:49:26 +00:00
|
|
|
}
|
|
|
|
|
2002-11-27 14:46:06 +00:00
|
|
|
sub quietly_check_login {
|
2003-03-22 04:47:35 +00:00
|
|
|
return Bugzilla->login($_[0] ? LOGIN_OPTIONAL : LOGIN_NORMAL);
|
1999-03-11 16:30:54 +00:00
|
|
|
}
|
|
|
|
|
2002-05-07 21:28:52 +00:00
|
|
|
# Populate a hash with information about this user.
|
|
|
|
sub GetUserInfo {
|
|
|
|
my ($userid) = (@_);
|
|
|
|
my %user;
|
|
|
|
my @queries;
|
|
|
|
my %groups;
|
2002-11-09 01:58:07 +00:00
|
|
|
my @groupids;
|
2002-05-07 21:28:52 +00:00
|
|
|
|
|
|
|
# No info if not logged in
|
|
|
|
return \%user if ($userid == 0);
|
|
|
|
|
|
|
|
$user{'login'} = $::COOKIE{"Bugzilla_login"};
|
|
|
|
$user{'userid'} = $userid;
|
|
|
|
|
2002-09-22 17:15:13 +00:00
|
|
|
SendSQL("SELECT mybugslink, realname " .
|
2002-05-25 10:35:53 +00:00
|
|
|
"FROM profiles WHERE userid = $userid");
|
2002-09-22 17:15:13 +00:00
|
|
|
($user{'showmybugslink'}, $user{'realname'}) = FetchSQLData();
|
2002-05-07 21:28:52 +00:00
|
|
|
|
|
|
|
SendSQL("SELECT name, query, linkinfooter FROM namedqueries " .
|
|
|
|
"WHERE userid = $userid");
|
|
|
|
while (MoreSQLData()) {
|
|
|
|
my %query;
|
|
|
|
($query{'name'}, $query{'query'}, $query{'linkinfooter'}) =
|
|
|
|
FetchSQLData();
|
|
|
|
push(@queries, \%query);
|
|
|
|
}
|
|
|
|
|
|
|
|
$user{'queries'} = \@queries;
|
|
|
|
|
2002-09-22 17:15:13 +00:00
|
|
|
$user{'canblessany'} = UserCanBlessAnything();
|
|
|
|
|
2002-11-09 01:58:07 +00:00
|
|
|
SendSQL("SELECT DISTINCT id, name FROM groups, user_group_map " .
|
2002-09-22 17:15:13 +00:00
|
|
|
"WHERE groups.id = user_group_map.group_id " .
|
|
|
|
"AND user_id = $userid " .
|
|
|
|
"AND NOT isbless");
|
2002-05-07 21:28:52 +00:00
|
|
|
while (MoreSQLData()) {
|
2002-11-09 01:58:07 +00:00
|
|
|
my ($id, $name) = FetchSQLData();
|
|
|
|
push(@groupids,$id);
|
2002-09-22 17:15:13 +00:00
|
|
|
$groups{$name} = 1;
|
2002-05-07 21:28:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$user{'groups'} = \%groups;
|
2002-11-09 01:58:07 +00:00
|
|
|
$user{'groupids'} = \@groupids;
|
2002-05-07 21:28:52 +00:00
|
|
|
|
|
|
|
return \%user;
|
|
|
|
}
|
|
|
|
|
1999-03-27 02:28:51 +00:00
|
|
|
sub CheckEmailSyntax {
|
|
|
|
my ($addr) = (@_);
|
1999-06-14 17:33:52 +00:00
|
|
|
my $match = Param('emailregexp');
|
2001-07-04 07:06:00 +00:00
|
|
|
if ($addr !~ /$match/ || $addr =~ /[\\\(\)<>&,;:"\[\] \t\r\n]/) {
|
2003-04-02 12:35:07 +00:00
|
|
|
ThrowUserError("illegal_email_address", { addr => $addr });
|
1999-03-27 02:28:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-05-07 22:07:21 +00:00
|
|
|
sub MailPassword {
|
|
|
|
my ($login, $password) = (@_);
|
|
|
|
my $urlbase = Param("urlbase");
|
2000-02-07 22:11:55 +00:00
|
|
|
my $template = Param("passwordmail");
|
|
|
|
my $msg = PerformSubsts($template,
|
|
|
|
{"mailaddress" => $login . Param('emailsuffix'),
|
|
|
|
"login" => $login,
|
|
|
|
"password" => $password});
|
1999-05-07 22:07:21 +00:00
|
|
|
|
2002-02-17 08:22:31 +00:00
|
|
|
open SENDMAIL, "|/usr/lib/sendmail -t -i";
|
1999-05-07 22:07:21 +00:00
|
|
|
print SENDMAIL $msg;
|
|
|
|
close SENDMAIL;
|
|
|
|
}
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
sub confirm_login {
|
2003-03-22 04:47:35 +00:00
|
|
|
return Bugzilla->login(LOGIN_REQUIRED);
|
1998-09-15 21:49:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub PutHeader {
|
2002-05-06 19:30:21 +00:00
|
|
|
($vars->{'title'}, $vars->{'h1'}, $vars->{'h2'}) = (@_);
|
2002-04-28 21:57:10 +00:00
|
|
|
|
|
|
|
$::template->process("global/header.html.tmpl", $::vars)
|
|
|
|
|| ThrowTemplateError($::template->error());
|
2002-10-16 23:09:31 +00:00
|
|
|
$vars->{'header_done'} = 1;
|
1998-09-15 21:49:26 +00:00
|
|
|
}
|
|
|
|
|
2000-01-14 22:35:49 +00:00
|
|
|
sub PutFooter {
|
2002-04-28 21:57:10 +00:00
|
|
|
$::template->process("global/footer.html.tmpl", $::vars)
|
|
|
|
|| ThrowTemplateError($::template->error());
|
2000-01-14 22:35:49 +00:00
|
|
|
}
|
|
|
|
|
2002-04-03 23:00:29 +00:00
|
|
|
###############################################################################
|
|
|
|
# Error handling
|
|
|
|
#
|
|
|
|
# If you are doing incremental output, set $vars->{'header_done'} once you've
|
|
|
|
# done the header.
|
2002-09-23 07:12:12 +00:00
|
|
|
#
|
|
|
|
# You can call Throw*Error with extra template variables in one pass by using
|
|
|
|
# the $extra_vars hash reference parameter:
|
|
|
|
# ThrowUserError("some_tag", { bug_id => $bug_id, size => 127 });
|
2002-04-03 23:00:29 +00:00
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
# For "this shouldn't happen"-type places in the code.
|
2002-09-23 07:12:12 +00:00
|
|
|
# The contents of $extra_vars get printed out in the template - useful for
|
|
|
|
# debugging info.
|
2002-04-05 20:03:09 +00:00
|
|
|
sub ThrowCodeError {
|
2002-09-23 07:12:12 +00:00
|
|
|
($vars->{'error'}, my $extra_vars, my $unlock_tables) = (@_);
|
2002-04-03 23:00:29 +00:00
|
|
|
|
2002-04-26 06:13:41 +00:00
|
|
|
SendSQL("UNLOCK TABLES") if $unlock_tables;
|
2003-03-22 04:47:35 +00:00
|
|
|
|
|
|
|
# If we don't have this test here, then the %@extra_vars vivifies
|
|
|
|
# the hashref, and then setting $vars->{'variables'} uses an empty hashref
|
|
|
|
# so the error template prints out a bogus header for the empty hash
|
|
|
|
if (defined $extra_vars) {
|
|
|
|
# Copy the extra_vars into the vars hash
|
|
|
|
foreach my $var (keys %$extra_vars) {
|
|
|
|
$vars->{$var} = $extra_vars->{$var};
|
|
|
|
}
|
|
|
|
|
|
|
|
# We may one day log something to file here also.
|
|
|
|
$vars->{'variables'} = $extra_vars;
|
2002-09-26 23:25:12 +00:00
|
|
|
}
|
|
|
|
|
2002-04-03 23:00:29 +00:00
|
|
|
print "Content-type: text/html\n\n" if !$vars->{'header_done'};
|
|
|
|
$template->process("global/code-error.html.tmpl", $vars)
|
2002-04-05 20:03:09 +00:00
|
|
|
|| ThrowTemplateError($template->error());
|
2002-04-03 23:00:29 +00:00
|
|
|
|
|
|
|
exit;
|
|
|
|
}
|
2001-05-10 02:53:22 +00:00
|
|
|
|
2002-07-26 20:39:17 +00:00
|
|
|
# This function should only be called if a template->process() fails.
|
|
|
|
# It tries another template first, because often one template being
|
|
|
|
# broken or missing doesn't mean that they all are. But it falls back on
|
|
|
|
# a print statement.
|
2002-04-03 23:00:29 +00:00
|
|
|
# The Content-Type will already have been printed.
|
2002-04-05 20:03:09 +00:00
|
|
|
sub ThrowTemplateError {
|
2002-07-26 20:39:17 +00:00
|
|
|
($vars->{'template_error_msg'}) = (@_);
|
|
|
|
$vars->{'error'} = "template_error";
|
2002-04-03 23:00:29 +00:00
|
|
|
|
2002-04-28 22:09:38 +00:00
|
|
|
# Try a template first; but if this one fails too, fall back
|
|
|
|
# on plain old print statements.
|
|
|
|
if (!$template->process("global/code-error.html.tmpl", $vars)) {
|
|
|
|
my $maintainer = Param('maintainer');
|
2002-07-26 20:39:17 +00:00
|
|
|
my $error = html_quote($vars->{'template_error_msg'});
|
2002-04-28 22:09:38 +00:00
|
|
|
my $error2 = html_quote($template->error());
|
|
|
|
print <<END;
|
|
|
|
<tt>
|
|
|
|
<p>
|
|
|
|
Bugzilla has suffered an internal error. Please save this page and
|
|
|
|
send it to $maintainer with details of what you were doing at the
|
|
|
|
time this message appeared.
|
|
|
|
</p>
|
2002-06-28 00:18:32 +00:00
|
|
|
<script type="text/javascript"> <!--
|
2002-04-28 22:09:38 +00:00
|
|
|
document.write("<p>URL: " + document.location + "</p>");
|
|
|
|
// -->
|
|
|
|
</script>
|
|
|
|
<p>Template->process() failed twice.<br>
|
|
|
|
First error: $error<br>
|
|
|
|
Second error: $error2</p>
|
|
|
|
</tt>
|
2002-04-05 20:03:09 +00:00
|
|
|
END
|
2002-04-28 22:09:38 +00:00
|
|
|
}
|
|
|
|
|
2002-04-03 23:00:29 +00:00
|
|
|
exit;
|
2001-05-10 02:53:22 +00:00
|
|
|
}
|
|
|
|
|
2000-02-17 05:15:23 +00:00
|
|
|
sub CheckIfVotedConfirmed {
|
|
|
|
my ($id, $who) = (@_);
|
|
|
|
SendSQL("SELECT bugs.votes, bugs.bug_status, products.votestoconfirm, " .
|
|
|
|
" bugs.everconfirmed " .
|
|
|
|
"FROM bugs, products " .
|
2002-10-02 00:46:22 +00:00
|
|
|
"WHERE bugs.bug_id = $id AND products.id = bugs.product_id");
|
2000-02-17 05:15:23 +00:00
|
|
|
my ($votes, $status, $votestoconfirm, $everconfirmed) = (FetchSQLData());
|
|
|
|
if ($votes >= $votestoconfirm && $status eq $::unconfirmedstate) {
|
|
|
|
SendSQL("UPDATE bugs SET bug_status = 'NEW', everconfirmed = 1 " .
|
|
|
|
"WHERE bug_id = $id");
|
|
|
|
my $fieldid = GetFieldID("bug_status");
|
|
|
|
SendSQL("INSERT INTO bugs_activity " .
|
2001-07-20 15:18:30 +00:00
|
|
|
"(bug_id,who,bug_when,fieldid,removed,added) VALUES " .
|
2000-02-17 05:15:23 +00:00
|
|
|
"($id,$who,now(),$fieldid,'$::unconfirmedstate','NEW')");
|
|
|
|
if (!$everconfirmed) {
|
|
|
|
$fieldid = GetFieldID("everconfirmed");
|
|
|
|
SendSQL("INSERT INTO bugs_activity " .
|
2001-07-20 15:18:30 +00:00
|
|
|
"(bug_id,who,bug_when,fieldid,removed,added) VALUES " .
|
2000-02-17 05:15:23 +00:00
|
|
|
"($id,$who,now(),$fieldid,'0','1')");
|
|
|
|
}
|
2002-04-28 21:57:10 +00:00
|
|
|
|
2000-02-17 05:15:23 +00:00
|
|
|
AppendComment($id, DBID_to_name($who),
|
2002-08-19 21:17:28 +00:00
|
|
|
"*** This bug has been confirmed by popular vote. ***", 0);
|
2002-04-28 21:57:10 +00:00
|
|
|
|
|
|
|
$vars->{'type'} = "votes";
|
|
|
|
$vars->{'id'} = $id;
|
2003-02-09 22:04:25 +00:00
|
|
|
$vars->{'mailrecipients'} = { 'changer' => $who };
|
2002-04-28 21:57:10 +00:00
|
|
|
|
|
|
|
$template->process("bug/process/results.html.tmpl", $vars)
|
|
|
|
|| ThrowTemplateError($template->error());
|
2000-02-17 05:15:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2002-10-17 04:31:56 +00:00
|
|
|
sub LogActivityEntry {
|
|
|
|
my ($i,$col,$removed,$added,$whoid,$timestamp) = @_;
|
|
|
|
# in the case of CCs, deps, and keywords, there's a possibility that someone # might try to add or remove a lot of them at once, which might take more
|
|
|
|
# space than the activity table allows. We'll solve this by splitting it
|
|
|
|
# into multiple entries if it's too long.
|
|
|
|
while ($removed || $added) {
|
|
|
|
my ($removestr, $addstr) = ($removed, $added);
|
|
|
|
if (length($removestr) > 254) {
|
|
|
|
my $commaposition = FindWrapPoint($removed, 254);
|
|
|
|
$removestr = substr($removed,0,$commaposition);
|
|
|
|
$removed = substr($removed,$commaposition);
|
|
|
|
$removed =~ s/^[,\s]+//; # remove any comma or space
|
|
|
|
} else {
|
|
|
|
$removed = ""; # no more entries
|
|
|
|
}
|
|
|
|
if (length($addstr) > 254) {
|
|
|
|
my $commaposition = FindWrapPoint($added, 254);
|
|
|
|
$addstr = substr($added,0,$commaposition);
|
|
|
|
$added = substr($added,$commaposition);
|
|
|
|
$added =~ s/^[,\s]+//; # remove any comma or space
|
|
|
|
} else {
|
|
|
|
$added = ""; # no more entries
|
|
|
|
}
|
|
|
|
$addstr = SqlQuote($addstr);
|
|
|
|
$removestr = SqlQuote($removestr);
|
|
|
|
my $fieldid = GetFieldID($col);
|
|
|
|
SendSQL("INSERT INTO bugs_activity " .
|
|
|
|
"(bug_id,who,bug_when,fieldid,removed,added) VALUES " .
|
|
|
|
"($i,$whoid," . SqlQuote($timestamp) . ",$fieldid,$removestr,$addstr)");
|
|
|
|
}
|
|
|
|
}
|
2000-02-17 05:15:23 +00:00
|
|
|
|
2002-04-03 18:54:18 +00:00
|
|
|
sub GetBugActivity {
|
1999-05-25 19:22:31 +00:00
|
|
|
my ($id, $starttime) = (@_);
|
|
|
|
my $datepart = "";
|
2000-03-07 18:23:00 +00:00
|
|
|
|
|
|
|
die "Invalid id: $id" unless $id=~/^\s*\d+\s*$/;
|
|
|
|
|
1999-05-25 19:22:31 +00:00
|
|
|
if (defined $starttime) {
|
2001-11-27 15:04:52 +00:00
|
|
|
$datepart = "and bugs_activity.bug_when > " . SqlQuote($starttime);
|
1999-05-25 19:22:31 +00:00
|
|
|
}
|
2002-04-03 18:54:18 +00:00
|
|
|
|
1999-05-25 19:22:31 +00:00
|
|
|
my $query = "
|
2001-08-31 03:54:37 +00:00
|
|
|
SELECT IFNULL(fielddefs.description, bugs_activity.fieldid),
|
2002-10-13 04:26:24 +00:00
|
|
|
fielddefs.name,
|
2001-08-31 03:54:37 +00:00
|
|
|
bugs_activity.attach_id,
|
2002-11-27 16:00:44 +00:00
|
|
|
DATE_FORMAT(bugs_activity.bug_when,'%Y.%m.%d %H:%i'),
|
2001-07-20 15:18:30 +00:00
|
|
|
bugs_activity.removed, bugs_activity.added,
|
1999-05-25 19:22:31 +00:00
|
|
|
profiles.login_name
|
2000-01-22 21:43:30 +00:00
|
|
|
FROM bugs_activity LEFT JOIN fielddefs ON
|
|
|
|
bugs_activity.fieldid = fielddefs.fieldid,
|
|
|
|
profiles
|
2000-01-22 04:24:42 +00:00
|
|
|
WHERE bugs_activity.bug_id = $id $datepart
|
|
|
|
AND profiles.userid = bugs_activity.who
|
|
|
|
ORDER BY bugs_activity.bug_when";
|
1999-05-25 19:22:31 +00:00
|
|
|
|
|
|
|
SendSQL($query);
|
|
|
|
|
2002-04-03 18:54:18 +00:00
|
|
|
my @operations;
|
|
|
|
my $operation = {};
|
|
|
|
my $changes = [];
|
2001-08-09 06:12:18 +00:00
|
|
|
my $incomplete_data = 0;
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
while (my ($field, $fieldname, $attachid, $when, $removed, $added, $who)
|
2002-04-03 18:54:18 +00:00
|
|
|
= FetchSQLData())
|
|
|
|
{
|
|
|
|
my %change;
|
2002-10-13 04:26:24 +00:00
|
|
|
my $activity_visible = 1;
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
# check if the user should see this field's activity
|
|
|
|
if ($fieldname eq 'remaining_time' ||
|
|
|
|
$fieldname eq 'estimated_time' ||
|
|
|
|
$fieldname eq 'work_time') {
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
if (!UserInGroup(Param('timetrackinggroup'))) {
|
|
|
|
$activity_visible = 0;
|
|
|
|
} else {
|
|
|
|
$activity_visible = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$activity_visible = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($activity_visible) {
|
|
|
|
# This gets replaced with a hyperlink in the template.
|
|
|
|
$field =~ s/^Attachment// if $attachid;
|
|
|
|
|
|
|
|
# Check for the results of an old Bugzilla data corruption bug
|
|
|
|
$incomplete_data = 1 if ($added =~ /^\?/ || $removed =~ /^\?/);
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
# An operation, done by 'who' at time 'when', has a number of
|
|
|
|
# 'changes' associated with it.
|
|
|
|
# If this is the start of a new operation, store the data from the
|
|
|
|
# previous one, and set up the new one.
|
|
|
|
if ($operation->{'who'}
|
|
|
|
&& ($who ne $operation->{'who'}
|
|
|
|
|| $when ne $operation->{'when'}))
|
|
|
|
{
|
|
|
|
$operation->{'changes'} = $changes;
|
|
|
|
push (@operations, $operation);
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
# Create new empty anonymous data structures.
|
|
|
|
$operation = {};
|
|
|
|
$changes = [];
|
|
|
|
}
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
$operation->{'who'} = $who;
|
|
|
|
$operation->{'when'} = $when;
|
2002-04-03 18:54:18 +00:00
|
|
|
|
2002-10-13 04:26:24 +00:00
|
|
|
$change{'field'} = $field;
|
|
|
|
$change{'fieldname'} = $fieldname;
|
|
|
|
$change{'attachid'} = $attachid;
|
|
|
|
$change{'removed'} = $removed;
|
|
|
|
$change{'added'} = $added;
|
|
|
|
push (@$changes, \%change);
|
|
|
|
}
|
2001-08-09 06:12:18 +00:00
|
|
|
}
|
2002-04-03 18:54:18 +00:00
|
|
|
|
|
|
|
if ($operation->{'who'}) {
|
|
|
|
$operation->{'changes'} = $changes;
|
|
|
|
push (@operations, $operation);
|
1999-05-25 19:22:31 +00:00
|
|
|
}
|
2002-04-03 18:54:18 +00:00
|
|
|
|
|
|
|
return(\@operations, $incomplete_data);
|
1999-05-25 19:22:31 +00:00
|
|
|
}
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
############# Live code below here (that is, not subroutine defs) #############
|
|
|
|
|
2002-12-20 07:21:43 +00:00
|
|
|
use Bugzilla;
|
1998-09-15 21:49:26 +00:00
|
|
|
|
2002-12-20 07:21:43 +00:00
|
|
|
# XXX - mod_perl - reset this between runs
|
2003-02-07 07:19:15 +00:00
|
|
|
$::cgi = Bugzilla->cgi;
|
1998-09-15 21:49:26 +00:00
|
|
|
|
2002-10-26 01:57:09 +00:00
|
|
|
# Set up stuff for compatibility with the old CGI.pl code
|
|
|
|
# This code will be removed as soon as possible, in favour of
|
|
|
|
# using the CGI.pm stuff directly
|
1998-09-15 21:49:26 +00:00
|
|
|
|
2002-10-26 01:57:09 +00:00
|
|
|
# XXX - mod_perl - reset these between runs
|
|
|
|
|
|
|
|
foreach my $name ($::cgi->param()) {
|
|
|
|
my @val = $::cgi->param($name);
|
|
|
|
$::FORM{$name} = join('', @val);
|
|
|
|
$::MFORM{$name} = \@val;
|
1998-09-15 21:49:26 +00:00
|
|
|
}
|
|
|
|
|
2002-10-26 01:57:09 +00:00
|
|
|
$::buffer = $::cgi->query_string();
|
|
|
|
|
|
|
|
foreach my $name ($::cgi->cookie()) {
|
|
|
|
$::COOKIE{$name} = $::cgi->cookie($name);
|
1998-09-15 21:49:26 +00:00
|
|
|
}
|
|
|
|
|
2002-11-26 21:11:23 +00:00
|
|
|
# This could be needed in any CGI, so we set it here.
|
|
|
|
$vars->{'help'} = $::cgi->param('help') ? 1 : 0;
|
|
|
|
|
1998-09-15 21:49:26 +00:00
|
|
|
1;
|