post_bug.cgi 10.2 KB
Newer Older
1
#!/usr/bonsaitools/bin/perl -wT
2
# -*- Mode: perl; indent-tabs-mode: nil -*-
terry%netscape.com's avatar
terry%netscape.com committed
3
#
4 5 6 7 8 9 10 11 12 13
# 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.
#
terry%netscape.com's avatar
terry%netscape.com committed
14
# The Original Code is the Bugzilla Bug Tracking System.
15
#
terry%netscape.com's avatar
terry%netscape.com committed
16
# The Initial Developer of the Original Code is Netscape Communications
17 18 19 20
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
terry%netscape.com's avatar
terry%netscape.com committed
21
# Contributor(s): Terry Weissman <terry@mozilla.org>
22
#                 Dan Mosedale <dmose@mozilla.org>
23
#                 Joe Robins <jmrobins@tgix.com>
24
#                 Gervase Markham <gerv@gerv.net>
terry%netscape.com's avatar
terry%netscape.com committed
25

26 27
use diagnostics;
use strict;
28 29
use lib qw(.);

30
require "CGI.pl";
31
require "bug_form.pl";
terry%netscape.com's avatar
terry%netscape.com committed
32

33
# Shut up misguided -w warnings about "used only once". For some reason,
34
# "use vars" chokes on me when I try it here.
35 36 37
sub sillyness {
    my $zz;
    $zz = $::buffer;
38
    $zz = $::usergroupset;
39
    $zz = %::COOKIE;
40 41 42 43 44 45 46
    $zz = %::components;
    $zz = %::versions;
    $zz = @::legal_opsys;
    $zz = @::legal_platform;
    $zz = @::legal_priority;
    $zz = @::legal_product;
    $zz = @::legal_severity;
47
    $zz = %::target_milestone;
48
}
49

50 51 52
# Use global template variables.
use vars qw($vars $template);

53
ConnectToDatabase();
54
confirm_login();
terry%netscape.com's avatar
terry%netscape.com committed
55

56 57 58 59 60 61

# The format of the initial comment can be structured by adding fields to the
# enter_bug template and then referencing them in the comment template.
my $comment;

$vars->{'form'} = \%::FORM;
62

63 64 65 66 67
# We can't use ValidateOutputFormat here because it defaults to HTML.
my $template_name = "bug/create/comment";
$template_name .= ($::FORM{'format'} ? "-$::FORM{'format'}" : "");

$template->process("$template_name.txt.tmpl", $vars, \$comment)
68 69 70
  || ThrowTemplateError($template->error());

ValidateComment($comment);
71

72
my $product = $::FORM{'product'};
dmose%mozilla.org's avatar
dmose%mozilla.org committed
73

74 75 76 77 78 79 80 81
# Set cookies
my $cookiepath = Param("cookiepath");
if (exists $::FORM{'product'}) {
    if (exists $::FORM{'version'}) {           
        print "Set-Cookie: VERSION-$product=$::FORM{'version'} ; \
               path=$cookiepath ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n"; 
    }
}
terry%netscape.com's avatar
terry%netscape.com committed
82

83
if (defined $::FORM{'maketemplate'}) {
84
    $vars->{'url'} = $::buffer;
terry%netscape.com's avatar
terry%netscape.com committed
85
    
86
    print "Content-type: text/html\n\n";
87 88
    $template->process("bug/create/make-template.html.tmpl", $vars)
      || ThrowTemplateError($template->error());
89
    exit;
terry%netscape.com's avatar
terry%netscape.com committed
90 91
}

92
umask 0;
terry%netscape.com's avatar
terry%netscape.com committed
93

94
# Some sanity checking
95
if(Param("usebuggroupsentry") && GroupExists($product)) {
96 97 98 99 100
    if(!UserInGroup($product)) {
        DisplayError("Sorry; you do not have the permissions necessary to enter
                      a bug against this product.", "Permission Denied");
        exit;
    }
101 102
}

103 104 105 106
if (!$::FORM{'component'}) {
    DisplayError("You must choose a component that corresponds to this bug.
                  If necessary, just guess.");
    exit;                  
107
}
terry%netscape.com's avatar
terry%netscape.com committed
108

109
if (!defined $::FORM{'short_desc'} || trim($::FORM{'short_desc'}) eq "") {
110 111
    DisplayError("You must enter a summary for this bug.");
    exit;
112 113
}

114 115 116 117 118 119 120 121
# If bug_file_loc is "http://", the default, strip it out and use an empty
# value. 
$::FORM{'bug_file_loc'} = "" if $::FORM{'bug_file_loc'} eq 'http://';
    
my $sql_product = SqlQuote($::FORM{'product'});
my $sql_component = SqlQuote($::FORM{'component'});

# Default assignee is the component owner.
122
if ($::FORM{'assigned_to'} eq "") {
123 124
    SendSQL("SELECT initialowner FROM components " .
            "WHERE program=$sql_product AND value=$sql_component");
125
    $::FORM{'assigned_to'} = FetchOneColumn();
126
} else {
127
    $::FORM{'assigned_to'} = DBNameToIdAndCheck(trim($::FORM{'assigned_to'}));
terry%netscape.com's avatar
terry%netscape.com committed
128 129
}

130
my @bug_fields = ("product", "version", "rep_platform",
131
                  "bug_severity", "priority", "op_sys", "assigned_to",
132 133
                  "bug_status", "bug_file_loc", "short_desc", "component",
                  "target_milestone");
134 135

if (Param("useqacontact")) {
136 137 138 139 140
    SendSQL("SELECT initialqacontact FROM components " .
            "WHERE program=$sql_product AND value=$sql_component");
    my $qa_contact = FetchOneColumn();
    if (defined $qa_contact && $qa_contact != 0) {
        $::FORM{'qa_contact'} = $qa_contact;
141 142 143 144
        push(@bug_fields, "qa_contact");
    }
}

145
if (exists $::FORM{'bug_status'}) {
146 147 148 149
    # Ignore the given status, so that we can set it to UNCONFIRMED
    # or NEW, depending on votestoconfirm if either the given state was
    # unconfirmed (so that a user can't override the below check), or if
    # the user doesn't have permission to change the default status anyway
150
    if ($::FORM{'bug_status'} eq $::unconfirmedstate
151
        || (!UserInGroup("canedit") && !UserInGroup("canconfirm"))) {
152 153 154 155 156 157
        delete $::FORM{'bug_status'};
    }
}

if (!exists $::FORM{'bug_status'}) {
    $::FORM{'bug_status'} = $::unconfirmedstate;
158
    SendSQL("SELECT votestoconfirm FROM products WHERE product=$sql_product");
159 160 161 162 163
    if (!FetchOneColumn()) {
        $::FORM{'bug_status'} = "NEW";
    }
}

164
if (!exists $::FORM{'target_milestone'}) {
165
    SendSQL("SELECT defaultmilestone FROM products WHERE product=$sql_product");
166 167 168
    $::FORM{'target_milestone'} = FetchOneColumn();
}

169
if (!Param('letsubmitterchoosepriority')) {
170
    $::FORM{'priority'} = Param('defaultpriority');
171 172
}

173
GetVersionTable();
174 175 176

# Some more sanity checking
CheckFormField(\%::FORM, 'product',      \@::legal_product);
177 178
CheckFormField(\%::FORM, 'rep_platform', \@::legal_platform);
CheckFormField(\%::FORM, 'bug_severity', \@::legal_severity);
179 180 181 182 183 184
CheckFormField(\%::FORM, 'priority',     \@::legal_priority);
CheckFormField(\%::FORM, 'op_sys',       \@::legal_opsys);
CheckFormField(\%::FORM, 'bug_status',   [$::unconfirmedstate, 'NEW']);
CheckFormField(\%::FORM, 'version',          $::versions{$product});
CheckFormField(\%::FORM, 'component',        $::components{$product});
CheckFormField(\%::FORM, 'target_milestone', $::target_milestone{$product});
185 186 187
CheckFormFieldDefined(\%::FORM, 'assigned_to');
CheckFormFieldDefined(\%::FORM, 'bug_file_loc');
CheckFormFieldDefined(\%::FORM, 'comment');
188

189
my @used_fields;
190 191 192
foreach my $field (@bug_fields) {
    if (exists $::FORM{$field}) {
        push (@used_fields, $field);
193 194
    }
}
195 196 197 198

if (exists $::FORM{'bug_status'} 
    && $::FORM{'bug_status'} ne $::unconfirmedstate) 
{
199 200 201
    push(@used_fields, "everconfirmed");
    $::FORM{'everconfirmed'} = 1;
}
202

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
my %ccids;
my @cc;

# Create the ccid hash for inserting into the db
# and the list for passing to processmail
# use a hash rather than a list to avoid adding users twice
if (defined $::FORM{'cc'}) {
    foreach my $person (split(/[ ,]/, $::FORM{'cc'})) {
        if ($person ne "") {
            my $ccid = DBNameToIdAndCheck($person);
            if ($ccid && !$ccids{$ccid}) {
                $ccids{$ccid} = 1;
                push(@cc, $person);
            }
        }
    }
}

221 222 223 224
# Build up SQL string to add bug.
my $sql = "INSERT INTO bugs " . 
  "(" . join(",", @used_fields) . ", reporter, creation_ts, groupset) " . 
  "VALUES (";
terry%netscape.com's avatar
terry%netscape.com committed
225

226
foreach my $field (@used_fields) {
227
    $sql .= SqlQuote($::FORM{$field}) . ",";
terry%netscape.com's avatar
terry%netscape.com committed
228 229
}

230
$comment =~ s/\r\n?/\n/g;     # Get rid of \r.
231
$comment = trim($comment);
232
# If comment is all whitespace, it'll be null at this point. That's
233 234
# OK except for the fact that it causes e-mail to be suppressed.
$comment = $comment ? $comment : " ";
235

236
$sql .= "$::userid, now(), (0";
237

238
# Groups
239 240 241
foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
    if ($::FORM{$b}) {
        my $v = substr($b, 4);
242
        $v =~ /^(\d+)$/
243 244
          || ThrowCodeError("One of the group bits submitted was invalid.",
                                                                undef, "abort");
245 246 247 248 249
        if (!GroupIsActive($v)) {
            # Prevent the user from adding the bug to an inactive group.
            # Should only happen if there is a bug in Bugzilla or the user
            # hacked the "enter bug" form since otherwise the UI 
            # for adding the bug to the group won't appear on that form.
250 251
            ThrowCodeError("Attempted to add bug to an inactive group, " . 
                           "identified by the bit '$v'.", undef, "abort");
252
        }
253 254 255
        $sql .= " + $v";    # Carefully written so that the math is
                            # done by MySQL, which can handle 64-bit math,
                            # and not by Perl, which I *think* can not.
256 257 258
    }
}

259
$sql .= ") & $::usergroupset)\n";
260

261 262 263
# Lock tables before inserting records for the new bug into the database
# if we are using a shadow database to prevent shadow database corruption
# when two bugs get created at the same time.
264
SendSQL("LOCK TABLES bugs WRITE, longdescs WRITE, cc WRITE, profiles READ") if Param("shadowdb");
265

266 267
# Add the bug report to the DB.
SendSQL($sql);
268

269 270 271
# Get the bug ID back.
SendSQL("select LAST_INSERT_ID()");
my $id = FetchOneColumn();
terry%netscape.com's avatar
terry%netscape.com committed
272

273 274 275
# Add the comment
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) 
         VALUES ($id, $::userid, now(), " . SqlQuote($comment) . ")");
terry%netscape.com's avatar
terry%netscape.com committed
276

277 278 279
# Insert the cclist into the database
foreach my $ccid (keys(%ccids)) {
    SendSQL("INSERT INTO cc (bug_id, who) VALUES ($id, $ccid)");
terry%netscape.com's avatar
terry%netscape.com committed
280 281
}

282 283
SendSQL("UNLOCK TABLES") if Param("shadowdb");

284 285 286 287 288 289 290 291
# Assemble the -force* strings so this counts as "Added to this capacity"
my @ARGLIST = ();
if (@cc) {
    push (@ARGLIST, "-forcecc", join(",", @cc));
}

push (@ARGLIST, "-forceowner", DBID_to_name($::FORM{assigned_to}));

292 293
if (defined $::FORM{'qa_contact'}) {
    push (@ARGLIST, "-forceqacontact", DBID_to_name($::FORM{'qa_contact'}));
294 295 296 297 298 299
}

push (@ARGLIST, "-forcereporter", DBID_to_name($::userid));

push (@ARGLIST, $id, $::COOKIE{'Bugzilla_login'});

300 301 302
# Send mail to let people know the bug has been created.
# See attachment.cgi for explanation of why it's done this way.
my $mailresults = '';
303
open(PMAIL, "-|") or exec('./processmail', @ARGLIST);
304 305
$mailresults .= $_ while <PMAIL>;
close(PMAIL);
terry%netscape.com's avatar
terry%netscape.com committed
306

307
# Tell the user all about it
308 309 310
$vars->{'id'} = $id;
$vars->{'mail'} = $mailresults;
$vars->{'type'} = "created";
terry%netscape.com's avatar
terry%netscape.com committed
311

312
print "Content-type: text/html\n\n";
313 314
$template->process("bug/create/created.html.tmpl", $vars)
  || ThrowTemplateError($template->error());
315 316 317 318

$::FORM{'id'} = $id;

show_bug("header is already done");