Rubber-stamped by Brady Eidson.
[webbrowser.git] / BugsSite / enter_bug.cgi
blob66a040aa3c15586f82b492ab7e88b5b17ee44a4e
1 #!/usr/bin/env perl -wT
2 # -*- Mode: perl; indent-tabs-mode: nil -*-
4 # The contents of this file are subject to the Mozilla Public
5 # License Version 1.1 (the "License"); you may not use this file
6 # except in compliance with the License. You may obtain a copy of
7 # the License at http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS
10 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 # implied. See the License for the specific language governing
12 # rights and limitations under the License.
14 # The Original Code is the Bugzilla Bug Tracking System.
16 # The Initial Developer of the Original Code is Netscape Communications
17 # Corporation. Portions created by Netscape are Copyright (C) 1998
18 # Netscape Communications Corporation. All Rights Reserved.
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>
24 # Shane H. W. Travis <travis@sedsystems.ca>
26 ##############################################################################
28 # enter_bug.cgi
29 # -------------
30 # Displays bug entry form. Bug fields are specified through popup menus,
31 # drop-down lists, or text fields. Default for these values can be
32 # passed in as parameters to the cgi.
34 ##############################################################################
36 use strict;
38 use lib qw(. lib);
40 use Bugzilla;
41 use Bugzilla::Constants;
42 use Bugzilla::Util;
43 use Bugzilla::Error;
44 use Bugzilla::Bug;
45 use Bugzilla::User;
46 use Bugzilla::Hook;
47 use Bugzilla::Product;
48 use Bugzilla::Classification;
49 use Bugzilla::Keyword;
50 use Bugzilla::Token;
51 use Bugzilla::Field;
52 use Bugzilla::Status;
54 my $user = Bugzilla->login(LOGIN_REQUIRED);
56 my $cloned_bug;
57 my $cloned_bug_id;
59 my $cgi = Bugzilla->cgi;
60 my $dbh = Bugzilla->dbh;
61 my $template = Bugzilla->template;
62 my $vars = {};
64 # All pages point to the same part of the documentation.
65 $vars->{'doc_section'} = 'bugreports.html';
67 my $product_name = trim($cgi->param('product') || '');
68 # Will contain the product object the bug is created in.
69 my $product;
71 if ($product_name eq '') {
72 # If the user cannot enter bugs in any product, stop here.
73 my @enterable_products = @{$user->get_enterable_products};
74 ThrowUserError('no_products') unless scalar(@enterable_products);
76 my $classification = Bugzilla->params->{'useclassification'} ?
77 scalar($cgi->param('classification')) : '__all';
79 # Unless a real classification name is given, we sort products
80 # by classification.
81 my @classifications;
83 unless ($classification && $classification ne '__all') {
84 if (Bugzilla->params->{'useclassification'}) {
85 my $class;
86 # Get all classifications with at least one enterable product.
87 foreach my $product (@enterable_products) {
88 $class->{$product->classification_id}->{'object'} ||=
89 new Bugzilla::Classification($product->classification_id);
90 # Nice way to group products per classification, without querying
91 # the DB again.
92 push(@{$class->{$product->classification_id}->{'products'}}, $product);
94 @classifications = sort {$a->{'object'}->sortkey <=> $b->{'object'}->sortkey
95 || lc($a->{'object'}->name) cmp lc($b->{'object'}->name)}
96 (values %$class);
98 else {
99 @classifications = ({object => undef, products => \@enterable_products});
103 unless ($classification) {
104 # We know there is at least one classification available,
105 # else we would have stopped earlier.
106 if (scalar(@classifications) > 1) {
107 # We only need classification objects.
108 $vars->{'classifications'} = [map {$_->{'object'}} @classifications];
110 $vars->{'target'} = "enter_bug.cgi";
111 $vars->{'format'} = $cgi->param('format');
112 $vars->{'cloned_bug_id'} = $cgi->param('cloned_bug_id');
114 print $cgi->header();
115 $template->process("global/choose-classification.html.tmpl", $vars)
116 || ThrowTemplateError($template->error());
117 exit;
119 # If we come here, then there is only one classification available.
120 $classification = $classifications[0]->{'object'}->name;
123 # Keep only enterable products which are in the specified classification.
124 if ($classification ne "__all") {
125 my $class = new Bugzilla::Classification({'name' => $classification});
126 # If the classification doesn't exist, then there is no product in it.
127 if ($class) {
128 @enterable_products
129 = grep {$_->classification_id == $class->id} @enterable_products;
130 @classifications = ({object => $class, products => \@enterable_products});
132 else {
133 @enterable_products = ();
137 if (scalar(@enterable_products) == 0) {
138 ThrowUserError('no_products');
140 elsif (scalar(@enterable_products) > 1) {
141 $vars->{'classifications'} = \@classifications;
142 $vars->{'target'} = "enter_bug.cgi";
143 $vars->{'format'} = $cgi->param('format');
144 $vars->{'cloned_bug_id'} = $cgi->param('cloned_bug_id');
146 print $cgi->header();
147 $template->process("global/choose-product.html.tmpl", $vars)
148 || ThrowTemplateError($template->error());
149 exit;
150 } else {
151 # Only one product exists.
152 $product = $enterable_products[0];
155 else {
156 # Do not use Bugzilla::Product::check_product() here, else the user
157 # could know whether the product doesn't exist or is not accessible.
158 $product = new Bugzilla::Product({'name' => $product_name});
161 # We need to check and make sure that the user has permission
162 # to enter a bug against this product.
163 $user->can_enter_product($product ? $product->name : $product_name, THROW_ERROR);
165 ##############################################################################
166 # Useful Subroutines
167 ##############################################################################
168 sub formvalue {
169 my ($name, $default) = (@_);
170 return Bugzilla->cgi->param($name) || $default || "";
173 # Takes the name of a field and a list of possible values for that
174 # field. Returns the first value in the list that is actually a
175 # valid value for that field.
176 # The field should be named after its DB table.
177 # Returns undef if none of the platforms match.
178 sub pick_valid_field_value (@) {
179 my ($field, @values) = @_;
180 my $dbh = Bugzilla->dbh;
182 foreach my $value (@values) {
183 return $value if $dbh->selectrow_array(
184 "SELECT 1 FROM $field WHERE value = ?", undef, $value);
186 return undef;
189 sub pickplatform {
190 return formvalue("rep_platform") if formvalue("rep_platform");
192 my @platform;
194 if (Bugzilla->params->{'defaultplatform'}) {
195 @platform = Bugzilla->params->{'defaultplatform'};
196 } else {
197 # If @platform is a list, this function will return the first
198 # item in the list that is a valid platform choice. If
199 # no choice is valid, we return "Other".
200 for ($ENV{'HTTP_USER_AGENT'}) {
201 #PowerPC
202 /\(.*PowerPC.*\)/i && do {@platform = "Macintosh"; last;};
203 /\(.*PPC.*\)/ && do {@platform = "Macintosh"; last;};
204 /\(.*AIX.*\)/ && do {@platform = "Macintosh"; last;};
205 #Intel x86
206 /\(.*Intel.*\)/ && do {@platform = "PC"; last;};
207 /\(.*[ix0-9]86.*\)/ && do {@platform = "PC"; last;};
208 #Versions of Windows that only run on Intel x86
209 /\(.*Win(?:dows |)[39M].*\)/ && do {@platform = "PC"; last};
210 /\(.*Win(?:dows |)16.*\)/ && do {@platform = "PC"; last;};
211 #Sparc
212 /\(.*sparc.*\)/ && do {@platform = "Sun"; last;};
213 /\(.*sun4.*\)/ && do {@platform = "Sun"; last;};
214 #Alpha
215 /\(.*AXP.*\)/i && do {@platform = "DEC"; last;};
216 /\(.*[ _]Alpha.\D/i && do {@platform = "DEC"; last;};
217 /\(.*[ _]Alpha\)/i && do {@platform = "DEC"; last;};
218 #MIPS
219 /\(.*IRIX.*\)/i && do {@platform = "SGI"; last;};
220 /\(.*MIPS.*\)/i && do {@platform = "SGI"; last;};
221 #68k
222 /\(.*68K.*\)/ && do {@platform = "Macintosh"; last;};
223 /\(.*680[x0]0.*\)/ && do {@platform = "Macintosh"; last;};
225 /\(.*9000.*\)/ && do {@platform = "HP"; last;};
226 #ARM
227 # /\(.*ARM.*\) && do {$platform = "ARM";};
228 #Stereotypical and broken
229 /\(.*Macintosh.*\)/ && do {@platform = "Macintosh"; last;};
230 /\(.*Mac OS [89].*\)/ && do {@platform = "Macintosh"; last;};
231 /\(Win.*\)/ && do {@platform = "PC"; last;};
232 /\(.*Win(?:dows[ -])NT.*\)/ && do {@platform = "PC"; last;};
233 /\(.*OSF.*\)/ && do {@platform = "DEC"; last;};
234 /\(.*HP-?UX.*\)/i && do {@platform = "HP"; last;};
235 /\(.*IRIX.*\)/i && do {@platform = "SGI"; last;};
236 /\(.*(SunOS|Solaris).*\)/ && do {@platform = "Sun"; last;};
237 #Braindead old browsers who didn't follow convention:
238 /Amiga/ && do {@platform = "Macintosh"; last;};
239 /WinMosaic/ && do {@platform = "PC"; last;};
243 return pick_valid_field_value('rep_platform', @platform) || "Other";
246 sub pickos {
247 if (formvalue('op_sys') ne "") {
248 return formvalue('op_sys');
251 my @os = ();
253 if (Bugzilla->params->{'defaultopsys'}) {
254 @os = Bugzilla->params->{'defaultopsys'};
255 } else {
256 # This function will return the first
257 # item in @os that is a valid platform choice. If
258 # no choice is valid, we return "Other".
259 for ($ENV{'HTTP_USER_AGENT'}) {
260 /\(.*IRIX.*\)/ && do {push @os, "IRIX"; };
261 /\(.*OSF.*\)/ && do {push @os, "OSF/1";};
262 /\(.*Linux.*\)/ && do {push @os, "Linux";};
263 /\(.*Solaris.*\)/ && do {push @os, "Solaris";};
264 /\(.*SunOS.*\)/ && do {
265 /\(.*SunOS 5.11.*\)/ && do {push @os, ("OpenSolaris", "Opensolaris", "Solaris 11");};
266 /\(.*SunOS 5.10.*\)/ && do {push @os, "Solaris 10";};
267 /\(.*SunOS 5.9.*\)/ && do {push @os, "Solaris 9";};
268 /\(.*SunOS 5.8.*\)/ && do {push @os, "Solaris 8";};
269 /\(.*SunOS 5.7.*\)/ && do {push @os, "Solaris 7";};
270 /\(.*SunOS 5.6.*\)/ && do {push @os, "Solaris 6";};
271 /\(.*SunOS 5.5.*\)/ && do {push @os, "Solaris 5";};
272 /\(.*SunOS 5.*\)/ && do {push @os, "Solaris";};
273 /\(.*SunOS.*sun4u.*\)/ && do {push @os, "Solaris";};
274 /\(.*SunOS.*i86pc.*\)/ && do {push @os, "Solaris";};
275 /\(.*SunOS.*\)/ && do {push @os, "SunOS";};
277 /\(.*HP-?UX.*\)/ && do {push @os, "HP-UX";};
278 /\(.*BSD.*\)/ && do {
279 /\(.*BSD\/(?:OS|386).*\)/ && do {push @os, "BSDI";};
280 /\(.*FreeBSD.*\)/ && do {push @os, "FreeBSD";};
281 /\(.*OpenBSD.*\)/ && do {push @os, "OpenBSD";};
282 /\(.*NetBSD.*\)/ && do {push @os, "NetBSD";};
284 /\(.*BeOS.*\)/ && do {push @os, "BeOS";};
285 /\(.*AIX.*\)/ && do {push @os, "AIX";};
286 /\(.*OS\/2.*\)/ && do {push @os, "OS/2";};
287 /\(.*QNX.*\)/ && do {push @os, "Neutrino";};
288 /\(.*VMS.*\)/ && do {push @os, "OpenVMS";};
289 /\(.*Win.*\)/ && do {
290 /\(.*Windows XP.*\)/ && do {push @os, "Windows XP";};
291 /\(.*Windows NT 6\.0.*\)/ && do {push @os, "Windows Vista";};
292 /\(.*Windows NT 5\.2.*\)/ && do {push @os, "Windows Server 2003";};
293 /\(.*Windows NT 5\.1.*\)/ && do {push @os, "Windows XP";};
294 /\(.*Windows 2000.*\)/ && do {push @os, "Windows 2000";};
295 /\(.*Windows NT 5.*\)/ && do {push @os, "Windows 2000";};
296 /\(.*Win.*9[8x].*4\.9.*\)/ && do {push @os, "Windows ME";};
297 /\(.*Win(?:dows |)M[Ee].*\)/ && do {push @os, "Windows ME";};
298 /\(.*Win(?:dows |)98.*\)/ && do {push @os, "Windows 98";};
299 /\(.*Win(?:dows |)95.*\)/ && do {push @os, "Windows 95";};
300 /\(.*Win(?:dows |)16.*\)/ && do {push @os, "Windows 3.1";};
301 /\(.*Win(?:dows[ -]|)NT.*\)/ && do {push @os, "Windows NT";};
302 /\(.*Windows.*NT.*\)/ && do {push @os, "Windows NT";};
304 /\(.*Mac OS X.*\)/ && do {
305 /\(.*Intel.*Mac OS X 10.5.*\)/ && do {push @os, "Mac OS X 10.5";};
306 /\(.*Intel.*Mac OS X.*\)/ && do {push @os, "Mac OS X 10.4";};
307 /\(.*Mac OS X.*\)/ && do {push @os, ("Mac OS X 10.3", "Mac OS X 10.0", "Mac OS X");};
309 /\(.*32bit.*\)/ && do {push @os, "Windows 95";};
310 /\(.*16bit.*\)/ && do {push @os, "Windows 3.1";};
311 /\(.*Mac OS \d.*\)/ && do {
312 /\(.*Mac OS 9.*\)/ && do {push @os, ("Mac System 9.x", "Mac System 9.0");};
313 /\(.*Mac OS 8\.6.*\)/ && do {push @os, ("Mac System 8.6", "Mac System 8.5");};
314 /\(.*Mac OS 8\.5.*\)/ && do {push @os, "Mac System 8.5";};
315 /\(.*Mac OS 8\.1.*\)/ && do {push @os, ("Mac System 8.1", "Mac System 8.0");};
316 /\(.*Mac OS 8\.0.*\)/ && do {push @os, "Mac System 8.0";};
317 /\(.*Mac OS 8[^.].*\)/ && do {push @os, "Mac System 8.0";};
318 /\(.*Mac OS 8.*\)/ && do {push @os, "Mac System 8.6";};
320 /\(.*Darwin.*\)/ && do {push @os, ("Mac OS X 10.0", "Mac OS X");};
321 # Silly
322 /\(.*Mac.*\)/ && do {
323 /\(.*Mac.*PowerPC.*\)/ && do {push @os, "Mac System 9.x";};
324 /\(.*Mac.*PPC.*\)/ && do {push @os, "Mac System 9.x";};
325 /\(.*Mac.*68k.*\)/ && do {push @os, "Mac System 8.0";};
327 # Evil
328 /Amiga/i && do {push @os, "Other";};
329 /WinMosaic/ && do {push @os, "Windows 95";};
330 /\(.*PowerPC.*\)/ && do {push @os, "Mac System 9.x";};
331 /\(.*PPC.*\)/ && do {push @os, "Mac System 9.x";};
332 /\(.*68K.*\)/ && do {push @os, "Mac System 8.0";};
336 push(@os, "Windows") if grep(/^Windows /, @os);
337 push(@os, "Mac OS") if grep(/^Mac /, @os);
339 return pick_valid_field_value('op_sys', @os) || "Other";
341 ##############################################################################
342 # End of subroutines
343 ##############################################################################
345 my $has_editbugs = $user->in_group('editbugs', $product->id);
346 my $has_canconfirm = $user->in_group('canconfirm', $product->id);
348 # If a user is trying to clone a bug
349 # Check that the user has authorization to view the parent bug
350 # Create an instance of Bug that holds the info from the parent
351 $cloned_bug_id = $cgi->param('cloned_bug_id');
353 if ($cloned_bug_id) {
354 ValidateBugID($cloned_bug_id);
355 $cloned_bug = new Bugzilla::Bug($cloned_bug_id);
358 if (scalar(@{$product->components}) == 1) {
359 # Only one component; just pick it.
360 $cgi->param('component', $product->components->[0]->name);
363 my %default;
365 $vars->{'product'} = $product;
367 $vars->{'priority'} = get_legal_field_values('priority');
368 $vars->{'bug_severity'} = get_legal_field_values('bug_severity');
369 $vars->{'rep_platform'} = get_legal_field_values('rep_platform');
370 $vars->{'op_sys'} = get_legal_field_values('op_sys');
372 $vars->{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
374 $vars->{'assigned_to'} = formvalue('assigned_to');
375 $vars->{'assigned_to_disabled'} = !$has_editbugs;
376 $vars->{'cc_disabled'} = 0;
378 $vars->{'qa_contact'} = formvalue('qa_contact');
379 $vars->{'qa_contact_disabled'} = !$has_editbugs;
381 $vars->{'cloned_bug_id'} = $cloned_bug_id;
383 $vars->{'token'} = issue_session_token('createbug:');
386 my @enter_bug_fields = grep { $_->enter_bug } Bugzilla->active_custom_fields;
387 foreach my $field (@enter_bug_fields) {
388 $vars->{$field->name} = formvalue($field->name);
391 if ($cloned_bug_id) {
393 $default{'component_'} = $cloned_bug->component;
394 $default{'priority'} = $cloned_bug->priority;
395 $default{'bug_severity'} = $cloned_bug->bug_severity;
396 $default{'rep_platform'} = $cloned_bug->rep_platform;
397 $default{'op_sys'} = $cloned_bug->op_sys;
399 $vars->{'short_desc'} = $cloned_bug->short_desc;
400 $vars->{'bug_file_loc'} = $cloned_bug->bug_file_loc;
401 $vars->{'keywords'} = $cloned_bug->keywords;
402 $vars->{'dependson'} = $cloned_bug_id;
403 $vars->{'blocked'} = "";
404 $vars->{'deadline'} = $cloned_bug->deadline;
406 if (defined $cloned_bug->cc) {
407 $vars->{'cc'} = join (", ", @{$cloned_bug->cc});
408 } else {
409 $vars->{'cc'} = formvalue('cc');
412 foreach my $field (@enter_bug_fields) {
413 my $field_name = $field->name;
414 $vars->{$field_name} = $cloned_bug->$field_name;
417 # We need to ensure that we respect the 'insider' status of
418 # the first comment, if it has one. Either way, make a note
419 # that this bug was cloned from another bug.
420 # We cannot use $cloned_bug->longdescs because this method
421 # depends on the "comment_sort_order" user pref, and we
422 # really want the first comment of the bug.
423 my $bug_desc = Bugzilla::Bug::GetComments($cloned_bug_id, 'oldest_to_newest');
424 my $isprivate = $bug_desc->[0]->{'isprivate'};
426 $vars->{'comment'} = "";
427 $vars->{'commentprivacy'} = 0;
429 if (!$isprivate || Bugzilla->user->is_insider) {
430 $vars->{'comment'} = $bug_desc->[0]->{'body'};
431 $vars->{'commentprivacy'} = $isprivate;
434 } # end of cloned bug entry form
436 else {
438 $default{'component_'} = formvalue('component');
439 $default{'priority'} = formvalue('priority', Bugzilla->params->{'defaultpriority'});
440 $default{'bug_severity'} = formvalue('bug_severity', Bugzilla->params->{'defaultseverity'});
441 $default{'rep_platform'} = pickplatform();
442 $default{'op_sys'} = pickos();
444 $vars->{'short_desc'} = formvalue('short_desc');
445 $vars->{'bug_file_loc'} = formvalue('bug_file_loc', "http://");
446 $vars->{'keywords'} = formvalue('keywords');
447 $vars->{'dependson'} = formvalue('dependson');
448 $vars->{'blocked'} = formvalue('blocked');
449 $vars->{'deadline'} = formvalue('deadline');
451 $vars->{'cc'} = join(', ', $cgi->param('cc'));
453 $vars->{'comment'} = formvalue('comment');
454 $vars->{'commentprivacy'} = formvalue('commentprivacy');
456 } # end of normal/bookmarked entry form
459 # IF this is a cloned bug,
460 # AND the clone's product is the same as the parent's
461 # THEN use the version from the parent bug
462 # ELSE IF a version is supplied in the URL
463 # THEN use it
464 # ELSE IF there is a version in the cookie
465 # THEN use it (Posting a bug sets a cookie for the current version.)
466 # ELSE
467 # The default version is the last one in the list (which, it is
468 # hoped, will be the most recent one).
470 # Eventually maybe each product should have a "current version"
471 # parameter.
472 $vars->{'version'} = [map($_->name, @{$product->versions})];
474 if ( ($cloned_bug_id) &&
475 ($product->name eq $cloned_bug->product ) ) {
476 $default{'version'} = $cloned_bug->version;
477 } elsif (formvalue('version')) {
478 $default{'version'} = formvalue('version');
479 } elsif (defined $cgi->cookie("VERSION-" . $product->name) &&
480 lsearch($vars->{'version'}, $cgi->cookie("VERSION-" . $product->name)) != -1) {
481 $default{'version'} = $cgi->cookie("VERSION-" . $product->name);
482 } else {
483 $default{'version'} = $vars->{'version'}->[$#{$vars->{'version'}}];
486 # Get list of milestones.
487 if ( Bugzilla->params->{'usetargetmilestone'} ) {
488 $vars->{'target_milestone'} = [map($_->name, @{$product->milestones})];
489 if (formvalue('target_milestone')) {
490 $default{'target_milestone'} = formvalue('target_milestone');
491 } else {
492 $default{'target_milestone'} = $product->default_milestone;
496 # Construct the list of allowable statuses.
497 my $initial_statuses = Bugzilla::Status->can_change_to();
498 # Exclude closed states from the UI, even if the workflow allows them.
499 # The back-end code will still accept them, though.
500 @$initial_statuses = grep { $_->is_open } @$initial_statuses;
502 my @status = map { $_->name } @$initial_statuses;
503 # UNCONFIRMED is illegal if votes_to_confirm = 0.
504 @status = grep {$_ ne 'UNCONFIRMED'} @status unless $product->votes_to_confirm;
505 scalar(@status) || ThrowUserError('no_initial_bug_status');
507 # If the user has no privs...
508 unless ($has_editbugs || $has_canconfirm) {
509 # ... use UNCONFIRMED if available, else use the first status of the list.
510 my $bug_status = (grep {$_ eq 'UNCONFIRMED'} @status) ? 'UNCONFIRMED' : $status[0];
511 @status = ($bug_status);
514 $vars->{'bug_status'} = \@status;
516 # Get the default from a template value if it is legitimate.
517 # Otherwise, and only if the user has privs, set the default
518 # to the first confirmed bug status on the list, if available.
520 if (formvalue('bug_status') && (lsearch(\@status, formvalue('bug_status')) >= 0)) {
521 $default{'bug_status'} = formvalue('bug_status');
522 } elsif (scalar @status == 1) {
523 $default{'bug_status'} = $status[0];
525 else {
526 $default{'bug_status'} = ($status[0] ne 'UNCONFIRMED') ? $status[0] : $status[1];
529 my $grouplist = $dbh->selectall_arrayref(
530 q{SELECT DISTINCT groups.id, groups.name, groups.description,
531 membercontrol, othercontrol
532 FROM groups
533 LEFT JOIN group_control_map
534 ON group_id = id AND product_id = ?
535 WHERE isbuggroup != 0 AND isactive != 0
536 ORDER BY description}, undef, $product->id);
538 my @groups;
540 foreach my $row (@$grouplist) {
541 my ($id, $groupname, $description, $membercontrol, $othercontrol) = @$row;
542 # Only include groups if the entering user will have an option.
543 next if ((!$membercontrol)
544 || ($membercontrol == CONTROLMAPNA)
545 || ($membercontrol == CONTROLMAPMANDATORY)
546 || (($othercontrol != CONTROLMAPSHOWN)
547 && ($othercontrol != CONTROLMAPDEFAULT)
548 && (!Bugzilla->user->in_group($groupname)))
550 my $check;
552 # If this is a cloned bug,
553 # AND the product for this bug is the same as for the original
554 # THEN set a group's checkbox if the original also had it on
555 # ELSE IF this is a bookmarked template
556 # THEN set a group's checkbox if was set in the bookmark
557 # ELSE
558 # set a groups's checkbox based on the group control map
560 if ( ($cloned_bug_id) &&
561 ($product->name eq $cloned_bug->product ) ) {
562 foreach my $i (0..(@{$cloned_bug->groups} - 1) ) {
563 if ($cloned_bug->groups->[$i]->{'bit'} == $id) {
564 $check = $cloned_bug->groups->[$i]->{'ison'};
568 elsif(formvalue("maketemplate") ne "") {
569 $check = formvalue("bit-$id", 0);
571 else {
572 # Checkbox is checked by default if $control is a default state.
573 $check = (($membercontrol == CONTROLMAPDEFAULT)
574 || (($othercontrol == CONTROLMAPDEFAULT)
575 && (!Bugzilla->user->in_group($groupname))));
578 my $group =
580 'bit' => $id ,
581 'checked' => $check ,
582 'description' => $description
585 push @groups, $group;
588 $vars->{'group'} = \@groups;
590 Bugzilla::Hook::process("enter_bug-entrydefaultvars", { vars => $vars });
592 $vars->{'default'} = \%default;
594 my $format = $template->get_format("bug/create/create",
595 scalar $cgi->param('format'),
596 scalar $cgi->param('ctype'));
598 print $cgi->header($format->{'ctype'});
599 $template->process($format->{'template'}, $vars)
600 || ThrowTemplateError($template->error());