~ubuntu-branches/ubuntu/oneiric/bugzilla/oneiric

« back to all changes in this revision

Viewing changes to editcomponents.cgi

  • Committer: Bazaar Package Importer
  • Author(s): Raphael Bossek
  • Date: 2008-06-27 22:34:34 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080627223434-0ib57vstn43bb4a3
Tags: 3.0.4.1-1
* Update of French, Russian and German translations. (closes: #488251)
* Added Bulgarian and Belarusian translations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/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 mozilla.org code.
15
 
#
16
 
# The Initial Developer of the Original Code is Holger
17
 
# Schurig. Portions created by Holger Schurig are
18
 
# Copyright (C) 1999 Holger Schurig. All
19
 
# Rights Reserved.
20
 
#
21
 
# Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
22
 
#                 Terry Weissman <terry@mozilla.org>
23
 
#                 Frédéric Buclin <LpSolit@gmail.com>
24
 
#                 Akamai Technologies <bugzilla-dev@akamai.com>
25
 
#
26
 
# Direct any questions on this source code to
27
 
#
28
 
# Holger Schurig <holgerschurig@nikocity.de>
29
 
 
30
 
use strict;
31
 
use lib ".";
32
 
 
33
 
use Bugzilla;
34
 
use Bugzilla::Constants;
35
 
use Bugzilla::Series;
36
 
use Bugzilla::Util;
37
 
use Bugzilla::Error;
38
 
use Bugzilla::User;
39
 
use Bugzilla::Component;
40
 
use Bugzilla::Bug;
41
 
use Bugzilla::Token;
42
 
 
43
 
###############
44
 
# Subroutines #
45
 
###############
46
 
 
47
 
# Takes an arrayref of login names and returns an arrayref of user ids.
48
 
sub check_initial_cc {
49
 
    my ($user_names) = @_;
50
 
 
51
 
    my %cc_ids;
52
 
    foreach my $cc (@$user_names) {
53
 
        my $id = login_to_id($cc, THROW_ERROR);
54
 
        $cc_ids{$id} = 1;
55
 
    }
56
 
    return [keys %cc_ids];
57
 
}
58
 
 
59
 
###############
60
 
# Main Script #
61
 
###############
62
 
 
63
 
my $cgi = Bugzilla->cgi;
64
 
my $dbh = Bugzilla->dbh;
65
 
my $template = Bugzilla->template;
66
 
my $vars = {};
67
 
 
68
 
#
69
 
# Preliminary checks:
70
 
#
71
 
 
72
 
my $user = Bugzilla->login(LOGIN_REQUIRED);
73
 
my $whoid = $user->id;
74
 
 
75
 
print $cgi->header();
76
 
 
77
 
$user->in_group('editcomponents')
78
 
  || scalar(@{$user->get_products_by_permission('editcomponents')})
79
 
  || ThrowUserError("auth_failure", {group  => "editcomponents",
80
 
                                     action => "edit",
81
 
                                     object => "components"});
82
 
 
83
 
#
84
 
# often used variables
85
 
#
86
 
my $product_name  = trim($cgi->param('product')     || '');
87
 
my $comp_name     = trim($cgi->param('component')   || '');
88
 
my $action        = trim($cgi->param('action')      || '');
89
 
my $showbugcounts = (defined $cgi->param('showbugcounts'));
90
 
my $token         = $cgi->param('token');
91
 
 
92
 
#
93
 
# product = '' -> Show nice list of products
94
 
#
95
 
 
96
 
unless ($product_name) {
97
 
    my $selectable_products = $user->get_selectable_products;
98
 
    # If the user has editcomponents privs for some products only,
99
 
    # we have to restrict the list of products to display.
100
 
    unless ($user->in_group('editcomponents')) {
101
 
        $selectable_products = $user->get_products_by_permission('editcomponents');
102
 
    }
103
 
    $vars->{'products'} = $selectable_products;
104
 
    $vars->{'showbugcounts'} = $showbugcounts;
105
 
 
106
 
    $template->process("admin/components/select-product.html.tmpl", $vars)
107
 
      || ThrowTemplateError($template->error());
108
 
    exit;
109
 
}
110
 
 
111
 
my $product = $user->check_can_admin_product($product_name);
112
 
 
113
 
#
114
 
# action='' -> Show nice list of components
115
 
#
116
 
 
117
 
unless ($action) {
118
 
 
119
 
    $vars->{'showbugcounts'} = $showbugcounts;
120
 
    $vars->{'product'} = $product;
121
 
    $template->process("admin/components/list.html.tmpl", $vars)
122
 
        || ThrowTemplateError($template->error());
123
 
 
124
 
    exit;
125
 
}
126
 
 
127
 
 
128
 
#
129
 
# action='add' -> present form for parameters for new component
130
 
#
131
 
# (next action will be 'new')
132
 
#
133
 
 
134
 
if ($action eq 'add') {
135
 
    $vars->{'token'} = issue_session_token('add_component');
136
 
    $vars->{'product'} = $product;
137
 
    $template->process("admin/components/create.html.tmpl", $vars)
138
 
        || ThrowTemplateError($template->error());
139
 
 
140
 
    exit;
141
 
}
142
 
 
143
 
 
144
 
 
145
 
#
146
 
# action='new' -> add component entered in the 'action=add' screen
147
 
#
148
 
 
149
 
if ($action eq 'new') {
150
 
    check_token_data($token, 'add_component');
151
 
    # Do the user matching
152
 
    Bugzilla::User::match_field ($cgi, {
153
 
        'initialowner'     => { 'type' => 'single' },
154
 
        'initialqacontact' => { 'type' => 'single' },
155
 
        'initialcc'        => { 'type' => 'multi'  },
156
 
    });
157
 
 
158
 
    my $default_assignee   = trim($cgi->param('initialowner')     || '');
159
 
    my $default_qa_contact = trim($cgi->param('initialqacontact') || '');
160
 
    my $description        = trim($cgi->param('description')      || '');
161
 
    my @initial_cc         = $cgi->param('initialcc');
162
 
 
163
 
    $comp_name || ThrowUserError('component_blank_name');
164
 
 
165
 
    if (length($comp_name) > 64) {
166
 
        ThrowUserError('component_name_too_long',
167
 
                       {'name' => $comp_name});
168
 
    }
169
 
 
170
 
    my $component =
171
 
        new Bugzilla::Component({product => $product,
172
 
                                 name => $comp_name});
173
 
 
174
 
    if ($component) {
175
 
        ThrowUserError('component_already_exists',
176
 
                       {'name' => $component->name});
177
 
    }
178
 
 
179
 
    $description || ThrowUserError('component_blank_description',
180
 
                                   {name => $comp_name});
181
 
 
182
 
    $default_assignee || ThrowUserError('component_need_initialowner',
183
 
                                        {name => $comp_name});
184
 
 
185
 
    my $default_assignee_id   = login_to_id($default_assignee);
186
 
    my $default_qa_contact_id = Bugzilla->params->{'useqacontact'} ?
187
 
        (login_to_id($default_qa_contact) || undef) : undef;
188
 
 
189
 
    my $initial_cc_ids = check_initial_cc(\@initial_cc);
190
 
 
191
 
    trick_taint($comp_name);
192
 
    trick_taint($description);
193
 
 
194
 
    $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE');
195
 
 
196
 
    $dbh->do("INSERT INTO components
197
 
                (product_id, name, description, initialowner,
198
 
                 initialqacontact)
199
 
              VALUES (?, ?, ?, ?, ?)", undef,
200
 
             ($product->id, $comp_name, $description,
201
 
              $default_assignee_id, $default_qa_contact_id));
202
 
 
203
 
    $component = new Bugzilla::Component({ product => $product,
204
 
                                           name => $comp_name });
205
 
 
206
 
    my $sth = $dbh->prepare("INSERT INTO component_cc 
207
 
                             (user_id, component_id) VALUES (?, ?)");
208
 
    foreach my $user_id (@$initial_cc_ids) {
209
 
        $sth->execute($user_id, $component->id);
210
 
    }
211
 
 
212
 
    $dbh->bz_unlock_tables;
213
 
 
214
 
    # Insert default charting queries for this product.
215
 
    # If they aren't using charting, this won't do any harm.
216
 
    my @series;
217
 
 
218
 
    my $prodcomp = "&product="   . url_quote($product->name) .
219
 
                   "&component=" . url_quote($comp_name);
220
 
 
221
 
    # For localization reasons, we get the title of the queries from the
222
 
    # submitted form.
223
 
    my $open_name = $cgi->param('open_name');
224
 
    my $nonopen_name = $cgi->param('nonopen_name');
225
 
    my $open_query = "field0-0-0=resolution&type0-0-0=notregexp&value0-0-0=." .
226
 
                     $prodcomp;
227
 
    my $nonopen_query = "field0-0-0=resolution&type0-0-0=regexp&value0-0-0=." .
228
 
                        $prodcomp;
229
 
 
230
 
    # trick_taint is ok here, as these variables aren't used as a command
231
 
    # or in SQL unquoted
232
 
    trick_taint($open_name);
233
 
    trick_taint($nonopen_name);
234
 
    trick_taint($open_query);
235
 
    trick_taint($nonopen_query);
236
 
 
237
 
    push(@series, [$open_name, $open_query]);
238
 
    push(@series, [$nonopen_name, $nonopen_query]);
239
 
 
240
 
    foreach my $sdata (@series) {
241
 
        my $series = new Bugzilla::Series(undef, $product->name,
242
 
                                          $comp_name, $sdata->[0],
243
 
                                          $whoid, 1, $sdata->[1], 1);
244
 
        $series->writeToDatabase();
245
 
    }
246
 
 
247
 
    $vars->{'comp'} = $component;
248
 
    $vars->{'product'} = $product;
249
 
    delete_token($token);
250
 
 
251
 
    $template->process("admin/components/created.html.tmpl",
252
 
                       $vars)
253
 
      || ThrowTemplateError($template->error());
254
 
 
255
 
    exit;
256
 
}
257
 
 
258
 
 
259
 
 
260
 
#
261
 
# action='del' -> ask if user really wants to delete
262
 
#
263
 
# (next action would be 'delete')
264
 
#
265
 
 
266
 
if ($action eq 'del') {
267
 
    $vars->{'token'} = issue_session_token('delete_component');
268
 
    $vars->{'comp'} =
269
 
        Bugzilla::Component::check_component($product, $comp_name);
270
 
 
271
 
    $vars->{'product'} = $product;
272
 
 
273
 
    $template->process("admin/components/confirm-delete.html.tmpl", $vars)
274
 
        || ThrowTemplateError($template->error());
275
 
 
276
 
    exit;
277
 
}
278
 
 
279
 
 
280
 
 
281
 
#
282
 
# action='delete' -> really delete the component
283
 
#
284
 
 
285
 
if ($action eq 'delete') {
286
 
    check_token_data($token, 'delete_component');
287
 
    my $component =
288
 
        Bugzilla::Component::check_component($product, $comp_name);
289
 
 
290
 
    if ($component->bug_count) {
291
 
        if (Bugzilla->params->{"allowbugdeletion"}) {
292
 
            foreach my $bug_id (@{$component->bug_ids}) {
293
 
                # Note: We allow admins to delete bugs even if they can't
294
 
                # see them, as long as they can see the product.
295
 
                my $bug = new Bugzilla::Bug($bug_id);
296
 
                $bug->remove_from_db();
297
 
            }
298
 
        } else {
299
 
            ThrowUserError("component_has_bugs",
300
 
                           {nb => $component->bug_count });
301
 
        }
302
 
    }
303
 
    
304
 
    $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE',
305
 
                         'flaginclusions WRITE', 'flagexclusions WRITE');
306
 
 
307
 
    $dbh->do("DELETE FROM flaginclusions WHERE component_id = ?",
308
 
             undef, $component->id);
309
 
    $dbh->do("DELETE FROM flagexclusions WHERE component_id = ?",
310
 
             undef, $component->id);
311
 
    $dbh->do("DELETE FROM component_cc WHERE component_id = ?",
312
 
             undef, $component->id);
313
 
    $dbh->do("DELETE FROM components WHERE id = ?",
314
 
             undef, $component->id);
315
 
 
316
 
    $dbh->bz_unlock_tables();
317
 
 
318
 
    $vars->{'comp'} = $component;
319
 
    $vars->{'product'} = $product;
320
 
    delete_token($token);
321
 
 
322
 
    $template->process("admin/components/deleted.html.tmpl", $vars)
323
 
      || ThrowTemplateError($template->error());
324
 
    exit;
325
 
}
326
 
 
327
 
 
328
 
 
329
 
#
330
 
# action='edit' -> present the edit component form
331
 
#
332
 
# (next action would be 'update')
333
 
#
334
 
 
335
 
if ($action eq 'edit') {
336
 
    $vars->{'token'} = issue_session_token('edit_component');
337
 
    my $component =
338
 
        Bugzilla::Component::check_component($product, $comp_name);
339
 
    $vars->{'comp'} = $component;
340
 
 
341
 
    $vars->{'initial_cc_names'} = 
342
 
        join(', ', map($_->login, @{$component->initial_cc}));
343
 
 
344
 
    $vars->{'product'} = $product;
345
 
 
346
 
    $template->process("admin/components/edit.html.tmpl",
347
 
                       $vars)
348
 
      || ThrowTemplateError($template->error());
349
 
 
350
 
    exit;
351
 
}
352
 
 
353
 
 
354
 
 
355
 
#
356
 
# action='update' -> update the component
357
 
#
358
 
 
359
 
if ($action eq 'update') {
360
 
    check_token_data($token, 'edit_component');
361
 
    # Do the user matching
362
 
    Bugzilla::User::match_field ($cgi, {
363
 
        'initialowner'     => { 'type' => 'single' },
364
 
        'initialqacontact' => { 'type' => 'single' },
365
 
        'initialcc'        => { 'type' => 'multi'  },
366
 
    });
367
 
 
368
 
    my $comp_old_name         = trim($cgi->param('componentold')     || '');
369
 
    my $default_assignee      = trim($cgi->param('initialowner')     || '');
370
 
    my $default_qa_contact    = trim($cgi->param('initialqacontact') || '');
371
 
    my $description           = trim($cgi->param('description')      || '');
372
 
    my @initial_cc            = $cgi->param('initialcc');
373
 
 
374
 
    my $component_old =
375
 
        Bugzilla::Component::check_component($product, $comp_old_name);
376
 
 
377
 
    $comp_name || ThrowUserError('component_blank_name');
378
 
 
379
 
    if (length($comp_name) > 64) {
380
 
        ThrowUserError('component_name_too_long',
381
 
                       {'name' => $comp_name});
382
 
    }
383
 
 
384
 
    if ($comp_name ne $component_old->name) {
385
 
        my $component =
386
 
            new Bugzilla::Component({product => $product,
387
 
                                     name => $comp_name});
388
 
        if ($component) {
389
 
            ThrowUserError('component_already_exists',
390
 
                           {'name' => $component->name});
391
 
        }
392
 
    }
393
 
 
394
 
    $description || ThrowUserError('component_blank_description',
395
 
                                   {'name' => $component_old->name});
396
 
 
397
 
    $default_assignee || ThrowUserError('component_need_initialowner',
398
 
                                        {name => $comp_name});
399
 
 
400
 
    my $default_assignee_id   = login_to_id($default_assignee);
401
 
    my $default_qa_contact_id = login_to_id($default_qa_contact) || undef;
402
 
 
403
 
    my $initial_cc_ids = check_initial_cc(\@initial_cc);
404
 
 
405
 
    $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE', 
406
 
                         'profiles READ');
407
 
 
408
 
    if ($comp_name ne $component_old->name) {
409
 
 
410
 
        trick_taint($comp_name);
411
 
        $dbh->do("UPDATE components SET name = ? WHERE id = ?",
412
 
                 undef, ($comp_name, $component_old->id));
413
 
 
414
 
        $vars->{'updated_name'} = 1;
415
 
 
416
 
    }
417
 
 
418
 
    if ($description ne $component_old->description) {
419
 
    
420
 
        trick_taint($description);
421
 
        $dbh->do("UPDATE components SET description = ? WHERE id = ?",
422
 
                 undef, ($description, $component_old->id));
423
 
 
424
 
        $vars->{'updated_description'} = 1;
425
 
    }
426
 
 
427
 
    if ($default_assignee ne $component_old->default_assignee->login) {
428
 
 
429
 
        $dbh->do("UPDATE components SET initialowner = ? WHERE id = ?",
430
 
                 undef, ($default_assignee_id, $component_old->id));
431
 
 
432
 
        $vars->{'updated_initialowner'} = 1;
433
 
    }
434
 
 
435
 
    if (Bugzilla->params->{'useqacontact'}
436
 
        && $default_qa_contact ne $component_old->default_qa_contact->login) {
437
 
        $dbh->do("UPDATE components SET initialqacontact = ?
438
 
                  WHERE id = ?", undef,
439
 
                 ($default_qa_contact_id, $component_old->id));
440
 
 
441
 
        $vars->{'updated_initialqacontact'} = 1;
442
 
    }
443
 
 
444
 
    my @initial_cc_old = map($_->id, @{$component_old->initial_cc});
445
 
    my ($removed, $added) = diff_arrays(\@initial_cc_old, $initial_cc_ids);
446
 
 
447
 
    foreach my $user_id (@$removed) {
448
 
        $dbh->do('DELETE FROM component_cc 
449
 
                   WHERE component_id = ? AND user_id = ?', undef,
450
 
                 $component_old->id, $user_id);
451
 
        $vars->{'updated_initialcc'} = 1;
452
 
    }
453
 
 
454
 
    foreach my $user_id (@$added) {
455
 
        $dbh->do("INSERT INTO component_cc (user_id, component_id) 
456
 
                       VALUES (?, ?)", undef, $user_id, $component_old->id);
457
 
        $vars->{'updated_initialcc'} = 1;
458
 
    }
459
 
 
460
 
    $dbh->bz_unlock_tables();
461
 
 
462
 
    my $component = new Bugzilla::Component($component_old->id);
463
 
    
464
 
    $vars->{'comp'} = $component;
465
 
    $vars->{'initial_cc_names'} = 
466
 
        join(', ', map($_->login, @{$component->initial_cc}));
467
 
    $vars->{'product'} = $product;
468
 
    delete_token($token);
469
 
 
470
 
    $template->process("admin/components/updated.html.tmpl",
471
 
                       $vars)
472
 
      || ThrowTemplateError($template->error());
473
 
 
474
 
    exit;
475
 
}
476
 
 
477
 
#
478
 
# No valid action found
479
 
#
480
 
ThrowUserError('no_valid_action', {'field' => "component"});