enter_bug.cgi 12.5 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
# Corporation. Portions created by Netscape are Copyright (C) 1998
# Netscape Communications Corporation. All Rights Reserved.
# 
terry%netscape.com's avatar
terry%netscape.com committed
20
# Contributor(s): Terry Weissman <terry@mozilla.org>
21
#                 Dave Miller <justdave@syndicomm.com>
22
#                 Joe Robins <jmrobins@tgix.com>
23
#                 Gervase Markham <gerv@gerv.net>
terry%netscape.com's avatar
terry%netscape.com committed
24

25
##############################################################################
26 27 28 29
#
# enter_bug.cgi
# -------------
# Displays bug entry form. Bug fields are specified through popup menus, 
30 31
# drop-down lists, or text fields. Default for these values can be 
# passed in as parameters to the cgi.
32
#
33
##############################################################################
34

35
use strict;
terry%netscape.com's avatar
terry%netscape.com committed
36

37 38
use lib qw(.);

39
use Bugzilla::Constants;
40
require "CGI.pl";
41

42 43 44 45 46
use vars qw(
  $unconfirmedstate
  $template
  $vars
  %COOKIE
47
  @enterable_products
48 49 50 51
  @legal_opsys
  @legal_platform
  @legal_priority
  @legal_severity
52
  $userid
53
  %MFORM
54
  %versions
55
  $proddesc
56 57
);

58 59 60 61 62
# We have to connect to the database, even though we don't use it in this code,
# because we might occasionally rebuild the version cache, which causes tokens
# to get deleted from the database, which needs a database connection.
ConnectToDatabase();

63 64
# If we're using bug groups to restrict bug entry, we need to know who the 
# user is right from the start. 
65
confirm_login() if AnyEntryGroups();
66 67 68

if (!defined $::FORM{'product'}) {
    GetVersionTable();
69
    quietly_check_login();
70

71 72 73
    my %products;

    foreach my $p (@enterable_products) {
74
        if (CanEnterProduct($p))
75
        {
76
            $products{$p} = $::proddesc{$p};
77
        }
78
    }
79
 
80
    my $prodsize = scalar(keys %products);
81
    if ($prodsize == 0) {
82
        ThrowUserError("no_products");
83 84
    } 
    elsif ($prodsize > 1) {
85
        $vars->{'proddesc'} = \%products;
86 87

        $vars->{'target'} = "enter_bug.cgi";
88
        $vars->{'format'} = $::FORM{'format'};
89
        
90
        print "Content-type: text/html\n\n";
91 92
        $template->process("global/choose-product.html.tmpl", $vars)
          || ThrowTemplateError($template->error());
93
        exit;        
94 95
    }

96
    $::FORM{'product'} = (keys %products)[0];
97
    $::MFORM{'product'} = [$::FORM{'product'}];
terry%netscape.com's avatar
terry%netscape.com committed
98

99
}
terry%netscape.com's avatar
terry%netscape.com committed
100

101
my $product = $::FORM{'product'};
terry%netscape.com's avatar
terry%netscape.com committed
102

103 104 105
##############################################################################
# Useful Subroutines
##############################################################################
106 107
sub formvalue {
    my ($name, $default) = (@_);
108
    return $::FORM{$name} || $default || "";
109
}
terry%netscape.com's avatar
terry%netscape.com committed
110

111
sub pickplatform {
112 113
    return formvalue("rep_platform") if formvalue("rep_platform");

114
    if ( Param('usebrowserinfo') ) {
115
        for ($ENV{'HTTP_USER_AGENT'}) {
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        #PowerPC
            /\(.*PowerPC.*\)/i && do {return "Macintosh";};
            /\(.*PPC.*\)/ && do {return "Macintosh";};
            /\(.*AIX.*\)/ && do {return "Macintosh";};
        #Intel x86
            /\(.*[ix0-9]86.*\)/ && do {return "PC";};
        #Versions of Windows that only run on Intel x86
            /\(.*Windows 9.*\)/ && do {return "PC";};
            /\(.*Win9.*\)/ && do {return "PC";};
            /\(.*Windows 3.*\)/ && do {return "PC";};
            /\(.*Win16.*\)/ && do {return "PC";};
        #Sparc
            /\(.*sparc.*\)/ && do {return "Sun";};
            /\(.*sun4.*\)/ && do {return "Sun";};
        #Alpha
            /\(.*Alpha.*\)/i && do {return "DEC";};
        #MIPS
            /\(.*IRIX.*\)/i && do {return "SGI";};
            /\(.*MIPS.*\)/i && do {return "SGI";};
        #68k
            /\(.*68K.*\)/ && do {return "Macintosh";};
            /\(.*680[x0]0.*\)/ && do {return "Macintosh";};
        #ARM
#            /\(.*ARM.*\) && do {return "ARM";};
        #Stereotypical and broken
            /\(.*Macintosh.*\)/ && do {return "Macintosh";};
            /\(.*Mac OS [89].*\)/ && do {return "Macintosh";};
            /\(Win.*\)/ && do {return "PC";};
            /\(.*Windows NT.*\)/ && do {return "PC";};
            /\(.*OSF.*\)/ && do {return "DEC";};
            /\(.*HP-?UX.*\)/i && do {return "HP";};
            /\(.*IRIX.*\)/i && do {return "SGI";};
            /\(.*(SunOS|Solaris).*\)/ && do {return "Sun";};
        #Braindead old browsers who didn't follow convention:
            /Amiga/ && do {return "Macintosh";};
151
        }
terry%netscape.com's avatar
terry%netscape.com committed
152
    }
153 154
    # default
    return "Other";
terry%netscape.com's avatar
terry%netscape.com committed
155 156
}

157 158 159
sub pickos {
    if (formvalue('op_sys') ne "") {
        return formvalue('op_sys');
terry%netscape.com's avatar
terry%netscape.com committed
160
    }
161
    if ( Param('usebrowserinfo') ) {
162
        for ($ENV{'HTTP_USER_AGENT'}) {
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
            /\(.*IRIX.*\)/ && do {return "IRIX";};
            /\(.*OSF.*\)/ && do {return "OSF/1";};
            /\(.*Linux.*\)/ && do {return "Linux";};
            /\(.*SunOS 5.*\)/ && do {return "Solaris";};
            /\(.*SunOS.*\)/ && do {return "SunOS";};
            /\(.*HP-?UX.*\)/ && do {return "HP-UX";};
            /\(.*BSD\/OS.*\)/ && do {return "BSDI";};
            /\(.*FreeBSD.*\)/ && do {return "FreeBSD";};
            /\(.*OpenBSD.*\)/ && do {return "OpenBSD";};
            /\(.*NetBSD.*\)/ && do {return "NetBSD";};
            /\(.*BeOS.*\)/ && do {return "BeOS";};
            /\(.*AIX.*\)/ && do {return "AIX";};
            /\(.*IBM.*\)/ && do {return "OS/2";};
            /\(.*QNX.*\)/ && do {return "Neutrino";};
            /\(.*VMS.*\)/ && do {return "OpenVMS";};
178 179
            /\(.*Windows XP.*\)/ && do {return "Windows XP";};
            /\(.*Windows NT 5\.1.*\)/ && do {return "Windows XP";};
180
            /\(.*Windows 2000.*\)/ && do {return "Windows 2000";};
181 182
            /\(.*Windows NT 5.*\)/ && do {return "Windows 2000";};
            /\(.*Windows.*NT.*\)/ && do {return "Windows NT";};
183
            /\(.*Win.*9[8x].*4\.9.*\)/ && do {return "Windows ME";};
184 185 186 187 188 189 190 191
            /\(.*Win98.*\)/ && do {return "Windows 98";};
            /\(.*Win95.*\)/ && do {return "Windows 95";};
            /\(.*Win16.*\)/ && do {return "Windows 3.1";};
            /\(.*WinNT.*\)/ && do {return "Windows NT";};
            /\(.*32bit.*\)/ && do {return "Windows 95";};
            /\(.*16bit.*\)/ && do {return "Windows 3.1";};
            /\(.*Mac OS 9.*\)/ && do {return "Mac System 9.x";};
            /\(.*Mac OS 8\.6.*\)/ && do {return "Mac System 8.6";};
192
            /\(.*Mac OS 8\.5.*\)/ && do {return "Mac System 8.5";};
193
        # Bugzilla doesn't have an entry for 8.1
194 195 196 197
            /\(.*Mac OS 8\.1.*\)/ && do {return "Mac System 8.0";};
            /\(.*Mac OS 8\.0.*\)/ && do {return "Mac System 8.0";};
            /\(.*Mac OS 8[^.].*\)/ && do {return "Mac System 8.0";};
            /\(.*Mac OS 8.*\)/ && do {return "Mac System 8.6";};
198
            /\(.*Mac OS X.*\)/ && do {return "MacOS X";};
199
            /\(.*Darwin.*\)/ && do {return "MacOS X";};
200
        # Silly
201 202 203
            /\(.*Mac.*PowerPC.*\)/ && do {return "Mac System 9.x";};
            /\(.*Mac.*PPC.*\)/ && do {return "Mac System 9.x";};
            /\(.*Mac.*68k.*\)/ && do {return "Mac System 8.0";};
204
        # Evil
205
            /Amiga/i && do {return "other";};
206 207 208
            /\(.*PowerPC.*\)/ && do {return "Mac System 9.x";};
            /\(.*PPC.*\)/ && do {return "Mac System 9.x";};
            /\(.*68K.*\)/ && do {return "Mac System 8.0";};
209
        }
terry%netscape.com's avatar
terry%netscape.com committed
210
    }
211 212
    # default
    return "other";
terry%netscape.com's avatar
terry%netscape.com committed
213
}
214 215 216
##############################################################################
# End of subroutines
##############################################################################
terry%netscape.com's avatar
terry%netscape.com committed
217

218
confirm_login() if (!(AnyEntryGroups()));
terry%netscape.com's avatar
terry%netscape.com committed
219

220
# We need to check and make sure
221
# that the user has permission to enter a bug against this product.
222
if(!CanEnterProduct($product))
223
{
224
    ThrowUserError("entry_access_denied", { product => $product});         
225
}
226

227
GetVersionTable();
terry%netscape.com's avatar
terry%netscape.com committed
228

229
if (lsearch(\@::enterable_products, $product) == -1) {
230
    ThrowUserError("invalid_product_name", { product => $product});
231
}
232 233 234

my $product_id = get_product_id($product);

235 236
if (0 == @{$::components{$product}}) {        
    ThrowUserError("no_components");   
237 238
} 
elsif (1 == @{$::components{$product}}) {
239 240 241 242
    # Only one component; just pick it.
    $::FORM{'component'} = $::components{$product}->[0];
}

243
my @components;
244 245
SendSQL("SELECT name, description FROM components " . 
        "WHERE product_id = $product_id ORDER BY name");
246 247 248 249 250 251 252 253 254 255 256
while (MoreSQLData()) {
    my ($name, $description) = FetchSQLData();

    my %component;

    $component{'name'} = $name;
    $component{'description'} = $description;

    push @components, \%component;
}

257
my %default;
terry%netscape.com's avatar
terry%netscape.com committed
258

259
$vars->{'component_'} = \@components;
260
$default{'component_'} = formvalue('component');
terry%netscape.com's avatar
terry%netscape.com committed
261

262 263 264 265 266 267 268
$vars->{'assigned_to'} = formvalue('assigned_to');
$vars->{'cc'} = formvalue('cc');
$vars->{'reporter'} = $::COOKIE{'Bugzilla_login'};
$vars->{'product'} = $product;
$vars->{'bug_file_loc'} = formvalue('bug_file_loc', "http://");
$vars->{'short_desc'} = formvalue('short_desc');
$vars->{'comment'} = formvalue('comment');
269

270 271
$vars->{'priority'} = \@legal_priority;
$default{'priority'} = formvalue('priority', Param('defaultpriority'));
272

273 274
$vars->{'bug_severity'} = \@legal_severity;
$default{'bug_severity'} = formvalue('bug_severity', 'normal');
275

276 277 278 279 280 281
$vars->{'rep_platform'} = \@legal_platform;
$default{'rep_platform'} = pickplatform();

$vars->{'op_sys'} = \@legal_opsys; 
$default{'op_sys'} = pickos();

282 283 284 285 286 287
# Use the version specified in the URL, if one is supplied. If not,
# then use the cookie-specified value. (Posting a bug sets a cookie
# for the current version.) If no URL or cookie version, the default
# version is the last one in the list (hopefully the latest one).
# Eventually maybe each product should have a "current version"
# parameter.
288
$vars->{'version'} = $::versions{$product} || [];
289 290 291
if (formvalue('version')) {
    $default{'version'} = formvalue('version');
} elsif (exists $::COOKIE{"VERSION-$product"} &&
292 293 294 295 296
    lsearch($vars->{'version'}, $::COOKIE{"VERSION-$product"}) != -1) {
    $default{'version'} = $::COOKIE{"VERSION-$product"};
} else {
    $default{'version'} = $vars->{'version'}->[$#{$vars->{'version'}}];
}
297 298 299

# There must be at least one status in @status.
my @status = "NEW";
300

301
if (UserInGroup("editbugs") || UserInGroup("canconfirm")) {
302
    SendSQL("SELECT votestoconfirm FROM products WHERE name = " .
303
            SqlQuote($product));
304
    push(@status, $unconfirmedstate) if (FetchOneColumn());
305 306
}

307 308
$vars->{'bug_status'} = \@status; 
$default{'bug_status'} = $status[0];
309

310 311 312 313 314
SendSQL("SELECT DISTINCT groups.id, groups.name, groups.description, " .
        "membercontrol, othercontrol " .
        "FROM groups LEFT JOIN group_control_map " .
        "ON group_id = id AND product_id = $product_id " .
        "WHERE isbuggroup != 0 AND isactive != 0 ORDER BY description");
315

316
my @groups;
317

318
while (MoreSQLData()) {
319 320 321 322 323 324 325 326 327 328
    my ($id, $groupname, $description, $membercontrol, $othercontrol) 
        = FetchSQLData();
    # Only include groups if the entering user will have an option.
    next if ((!$membercontrol) 
               || ($membercontrol == CONTROLMAPNA) 
               || ($membercontrol == CONTROLMAPMANDATORY)
               || (($othercontrol != CONTROLMAPSHOWN) 
                    && ($othercontrol != CONTROLMAPDEFAULT)
                    && (!UserInGroup($groupname)))
             );
329 330 331
    my $check;

    # If this is the group for this product, make it checked.
332
    if(formvalue("maketemplate") ne "") 
333 334 335 336 337 338
    {
        # If this is a bookmarked template, then we only want to set the
        # bit for those bits set in the template.        
        $check = formvalue("bit-$id", 0);
    }
    else {
339 340 341 342
        # Checkbox is checked by default if $control is a default state.
        $check = (($membercontrol == CONTROLMAPDEFAULT)
                 || (($othercontrol == CONTROLMAPDEFAULT)
                      && (!UserInGroup($groupname))));
343 344
    }

345 346 347 348 349 350 351 352
    my $group = 
    {
        'bit' => $id , 
        'checked' => $check , 
        'description' => $description 
    };

    push @groups, $group;        
353
}
terry%netscape.com's avatar
terry%netscape.com committed
354

355 356
$vars->{'group'} = \@groups;

357
$vars->{'default'} = \%default;
terry%netscape.com's avatar
terry%netscape.com committed
358

359 360
my $format = 
  GetFormat("bug/create/create", $::FORM{'format'}, $::FORM{'ctype'});
361

362 363
print "Content-type: $format->{'ctype'}\n\n";
$template->process($format->{'template'}, $vars)
364
  || ThrowTemplateError($template->error());          
365