2010-08-30 Alejandro G. Castro <alex@igalia.com>
[WebKit-https.git] / BugsSite / post_bug.cgi
1 #!/usr/bin/env perl -wT
2 # -*- Mode: perl; indent-tabs-mode: nil -*-
3 #
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/
8 #
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.
13 #
14 # The Original Code is the Bugzilla Bug Tracking System.
15 #
16 # The Initial Developer of the Original Code is Netscape Communications
17 # Corporation. Portions created by Netscape are
18 # Copyright (C) 1998 Netscape Communications Corporation. All
19 # Rights Reserved.
20 #
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>
25 #                 Marc Schumann <wurblzap@gmail.com>
26
27 use strict;
28 use lib qw(. lib);
29
30 use Bugzilla;
31 use Bugzilla::Attachment;
32 use Bugzilla::BugMail;
33 use Bugzilla::Constants;
34 use Bugzilla::Util;
35 use Bugzilla::Error;
36 use Bugzilla::Bug;
37 use Bugzilla::User;
38 use Bugzilla::Field;
39 use Bugzilla::Hook;
40 use Bugzilla::Product;
41 use Bugzilla::Component;
42 use Bugzilla::Keyword;
43 use Bugzilla::Token;
44 use Bugzilla::Flag;
45
46 my $user = Bugzilla->login(LOGIN_REQUIRED);
47
48 my $cgi = Bugzilla->cgi;
49 my $dbh = Bugzilla->dbh;
50 my $template = Bugzilla->template;
51 my $vars = {};
52
53 ######################################################################
54 # Main Script
55 ######################################################################
56
57 # redirect to enter_bug if no field is passed.
58 print $cgi->redirect(correct_urlbase() . 'enter_bug.cgi') unless $cgi->param();
59
60 # Detect if the user already used the same form to submit a bug
61 my $token = trim($cgi->param('token'));
62 if ($token) {
63     my ($creator_id, $date, $old_bug_id) = Bugzilla::Token::GetTokenData($token);
64     unless ($creator_id
65               && ($creator_id == $user->id)
66               && ($old_bug_id =~ "^createbug:"))
67     {
68         # The token is invalid.
69         ThrowUserError('token_does_not_exist');
70     }
71
72     $old_bug_id =~ s/^createbug://;
73
74     if ($old_bug_id && (!$cgi->param('ignore_token')
75                         || ($cgi->param('ignore_token') != $old_bug_id)))
76     {
77         $vars->{'bugid'} = $old_bug_id;
78         $vars->{'allow_override'} = defined $cgi->param('ignore_token') ? 0 : 1;
79
80         print $cgi->header();
81         $template->process("bug/create/confirm-create-dupe.html.tmpl", $vars)
82            || ThrowTemplateError($template->error());
83         exit;
84     }
85 }    
86
87 # do a match on the fields if applicable
88
89 &Bugzilla::User::match_field ($cgi, {
90     'cc'            => { 'type' => 'multi'  },
91     'assigned_to'   => { 'type' => 'single' },
92     'qa_contact'    => { 'type' => 'single' },
93     '^requestee_type-(\d+)$' => { 'type' => 'multi' },
94 });
95
96 if (defined $cgi->param('maketemplate')) {
97     $vars->{'url'} = $cgi->canonicalise_query('token');
98     $vars->{'short_desc'} = $cgi->param('short_desc');
99     
100     print $cgi->header();
101     $template->process("bug/create/make-template.html.tmpl", $vars)
102       || ThrowTemplateError($template->error());
103     exit;
104 }
105
106 umask 0;
107
108 # get current time
109 my $timestamp = $dbh->selectrow_array(q{SELECT NOW()});
110
111 # Group Validation
112 my @selected_groups;
113 foreach my $group (grep(/^bit-\d+$/, $cgi->param())) {
114     $group =~ /^bit-(\d+)$/;
115     push(@selected_groups, $1);
116 }
117
118 # The format of the initial comment can be structured by adding fields to the
119 # enter_bug template and then referencing them in the comment template.
120 my $comment;
121 my $format = $template->get_format("bug/create/comment",
122                                    scalar($cgi->param('format')), "txt");
123 $template->process($format->{'template'}, $vars, \$comment)
124     || ThrowTemplateError($template->error());
125
126 # Include custom fields editable on bug creation.
127 my @custom_bug_fields = grep {$_->type != FIELD_TYPE_MULTI_SELECT && $_->enter_bug}
128                              Bugzilla->active_custom_fields;
129
130 # Undefined custom fields are ignored to ensure they will get their default
131 # value (e.g. "---" for custom single select fields).
132 my @bug_fields = grep { defined $cgi->param($_->name) } @custom_bug_fields;
133 @bug_fields = map { $_->name } @bug_fields;
134
135 push(@bug_fields, qw(
136     product
137     component
138
139     assigned_to
140     qa_contact
141
142     alias
143     blocked
144     commentprivacy
145     bug_file_loc
146     bug_severity
147     bug_status
148     dependson
149     keywords
150     short_desc
151     op_sys
152     priority
153     rep_platform
154     version
155     target_milestone
156     status_whiteboard
157
158     estimated_time
159     deadline
160 ));
161 my %bug_params;
162 foreach my $field (@bug_fields) {
163     $bug_params{$field} = $cgi->param($field);
164 }
165 $bug_params{'creation_ts'} = $timestamp;
166 $bug_params{'cc'}          = [$cgi->param('cc')];
167 $bug_params{'groups'}      = \@selected_groups;
168 $bug_params{'comment'}     = $comment;
169
170 my @multi_selects = grep {$_->type == FIELD_TYPE_MULTI_SELECT && $_->enter_bug}
171                          Bugzilla->active_custom_fields;
172
173 foreach my $field (@multi_selects) {
174     $bug_params{$field->name} = [$cgi->param($field->name)];
175 }
176
177 my $bug = Bugzilla::Bug->create(\%bug_params);
178
179 # Get the bug ID back.
180 my $id = $bug->bug_id;
181
182 # Set Version cookie, but only if the user actually selected
183 # a version on the page.
184 if (defined $cgi->param('version')) {
185     $cgi->send_cookie(-name => "VERSION-" . $bug->product,
186                       -value => $bug->version,
187                       -expires => "Fri, 01-Jan-2038 00:00:00 GMT");
188 }
189
190 # We don't have to check if the user can see the bug, because a user filing
191 # a bug can always see it. You can't change reporter_accessible until
192 # after the bug is filed.
193
194 # Add an attachment if requested.
195 if (defined($cgi->upload('data')) || $cgi->param('attachurl')) {
196     $cgi->param('isprivate', $cgi->param('commentprivacy'));
197     my $attachment = Bugzilla::Attachment->insert_attachment_for_bug(!THROW_ERROR,
198                                                   $bug, $user, $timestamp, $vars);
199
200     if ($attachment) {
201         # Update the comment to include the new attachment ID.
202         # This string is hardcoded here because Template::quoteUrls()
203         # expects to find this exact string.
204         my $new_comment = "Created an attachment (id=" . $attachment->id . ")\n" .
205                           $attachment->description . "\n";
206         # We can use $bug->longdescs here because we are sure that the bug
207         # description is of type CMT_NORMAL. No need to include it if it's
208         # empty, though.
209         if ($bug->longdescs->[0]->{'body'} !~ /^\s+$/) {
210             $new_comment .= "\n" . $bug->longdescs->[0]->{'body'};
211         }
212         $bug->update_comment($bug->longdescs->[0]->{'id'}, $new_comment);
213     }
214     else {
215         $vars->{'message'} = 'attachment_creation_failed';
216     }
217
218     # Determine if Patch Viewer is installed, for Diff link
219     eval {
220         require PatchReader;
221         $vars->{'patchviewerinstalled'} = 1;
222     };
223 }
224
225 # Add flags, if any. To avoid dying if something goes wrong
226 # while processing flags, we will eval() flag validation.
227 # This requires errors to die().
228 # XXX: this can go away as soon as flag validation is able to
229 #      fail without dying.
230 my $error_mode_cache = Bugzilla->error_mode;
231 Bugzilla->error_mode(ERROR_MODE_DIE);
232 eval {
233     Bugzilla::Flag::validate($id, undef, SKIP_REQUESTEE_ON_ERROR);
234     Bugzilla::Flag->process($bug, undef, $timestamp, $vars);
235 };
236 Bugzilla->error_mode($error_mode_cache);
237 if ($@) {
238     $vars->{'message'} = 'flag_creation_failed';
239     $vars->{'flag_creation_error'} = $@;
240 }
241
242 # Email everyone the details of the new bug 
243 $vars->{'mailrecipients'} = {'changer' => $user->login};
244
245 $vars->{'id'} = $id;
246 $vars->{'bug'} = $bug;
247
248 Bugzilla::Hook::process("post_bug-after_creation", { vars => $vars });
249
250 ThrowCodeError("bug_error", { bug => $bug }) if $bug->error;
251
252 $vars->{'sentmail'} = [];
253
254 push (@{$vars->{'sentmail'}}, { type => 'created',
255                                 id => $id,
256                               });
257
258 foreach my $i (@{$bug->dependson || []}, @{$bug->blocked || []}) {
259     push (@{$vars->{'sentmail'}}, { type => 'dep', id => $i, });
260 }
261
262 my @bug_list;
263 if ($cgi->cookie("BUGLIST")) {
264     @bug_list = split(/:/, $cgi->cookie("BUGLIST"));
265 }
266 $vars->{'bug_list'} = \@bug_list;
267 $vars->{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
268
269 if ($token) {
270     trick_taint($token);
271     $dbh->do('UPDATE tokens SET eventdata = ? WHERE token = ?', undef, 
272              ("createbug:$id", $token));
273 }
274
275 if (Bugzilla->usage_mode == USAGE_MODE_EMAIL) {
276     Bugzilla::BugMail::Send($id, $vars->{'mailrecipients'});
277 }
278 else {
279     print $cgi->header();
280     $template->process("bug/create/created.html.tmpl", $vars)
281         || ThrowTemplateError($template->error());
282 }
283
284 1;