#!/usr/bonsaitools/bin/perl -w # -*- Mode: perl; indent-tabs-mode: nil -*- # # 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. # # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is Holger # Schurig. Portions created by Holger Schurig are # Copyright (C) 1999 Holger Schurig. All # Rights Reserved. # # Contributor(s): Holger Schurig # Terry Weissman # # Direct any questions on this source code to # # Holger Schurig use diagnostics; use strict; use lib "."; require "CGI.pl"; require "globals.pl"; # Shut up misguided -w warnings about "used only once". For some reason, # "use vars" chokes on me when I try it here. sub sillyness { my $zz; $zz = $::buffer; } my $dobugcounts = (defined $::FORM{'dobugcounts'}); # TestProduct: just returns if the specified product does exists # CheckProduct: same check, optionally emit an error text # TestComponent: just returns if the specified product/component combination exists # CheckComponent: same check, optionally emit an error text sub TestProduct ($) { my $prod = shift; # does the product exist? SendSQL("SELECT product FROM products WHERE product=" . SqlQuote($prod)); return FetchOneColumn(); } sub CheckProduct ($) { my $prod = shift; # do we have a product? unless ($prod) { print "Sorry, you haven't specified a product."; PutTrailer(); exit; } unless (TestProduct $prod) { print "Sorry, product '$prod' does not exist."; PutTrailer(); exit; } } sub TestComponent ($$) { my ($prod,$comp) = @_; # does the product exist? SendSQL("SELECT program,value FROM components WHERE program=" . SqlQuote($prod) . " and value=" . SqlQuote($comp)); return FetchOneColumn(); } sub CheckComponent ($$) { my ($prod,$comp) = @_; # do we have the component? unless ($comp) { print "Sorry, you haven't specified a component."; PutTrailer(); exit; } CheckProduct($prod); unless (TestComponent $prod,$comp) { print "Sorry, component '$comp' for product '$prod' does not exist."; PutTrailer(); exit; } } # # Displays the form to edit component parameters # sub EmitFormElements ($$$$$) { my ($product, $component, $initialownerid, $initialqacontactid, $description) = @_; my ($initialowner, $initialqacontact) = ($initialownerid ? DBID_to_name ($initialownerid) : '', $initialqacontactid ? DBID_to_name ($initialqacontactid) : ''); print " Component:\n"; print " \n"; print " \n"; print "\n"; print " Description:\n"; print " \n"; print "\n"; print " Initial owner:\n"; print " \n"; if (Param('useqacontact')) { print "\n"; print " Initial QA contact:\n"; print " \n"; } } # # Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d." # sub PutTrailer (@) { my (@links) = ("Back to the query page", @_); my $count = $#links; my $num = 0; print "

\n"; if (!$dobugcounts) { print qq{}; print qq{Redisplay table with bug counts (slower)

\n}; } foreach (@links) { print $_; if ($num == $count) { print ".\n"; } elsif ($num == $count-1) { print " or "; } else { print ", "; } $num++; } PutFooter(); } # # Preliminary checks: # ConnectToDatabase(); confirm_login(); print "Content-type: text/html\n\n"; unless (UserInGroup("editcomponents")) { PutHeader("Not allowed"); print "Sorry, you aren't a member of the 'editcomponents' group.\n"; print "And so, you aren't allowed to add, modify or delete components.\n"; PutTrailer(); exit; } # # often used variables # my $product = trim($::FORM{product} || ''); my $component = trim($::FORM{component} || ''); my $action = trim($::FORM{action} || ''); my $localtrailer; if ($product) { $localtrailer = "edit more components"; } else { $localtrailer = "edit more components"; } # # product = '' -> Show nice list of products # unless ($product) { PutHeader("Select product"); if ($dobugcounts){ SendSQL("SELECT products.product,products.description,COUNT(bug_id) FROM products LEFT JOIN bugs ON products.product=bugs.product GROUP BY products.product ORDER BY products.product"); } else { SendSQL("SELECT products.product,products.description FROM products ORDER BY products.product"); } print "\n"; print " \n"; print " \n"; if ($dobugcounts) { print " \n"; } #print " \n"; print ""; while ( MoreSQLData() ) { my ($product, $description, $bugs) = FetchSQLData(); $description ||= "missing"; print "\n"; print " \n"; print " \n"; if ($dobugcounts) { $bugs ||= "none"; print " \n"; } #print " \n"; } print "
Edit components of ...DescriptionBugsEdit
$product$description$bugsEdit
\n"; PutTrailer(); exit; } # # action='' -> Show nice list of components # unless ($action) { PutHeader("Select component of $product"); CheckProduct($product); if ($dobugcounts) { SendSQL("SELECT value,description,initialowner,initialqacontact,COUNT(bug_id) FROM components LEFT JOIN bugs ON components.program=bugs.product AND components.value=bugs.component WHERE program=" . SqlQuote($product) . " GROUP BY value"); } else { SendSQL("SELECT value,description,initialowner,initialqacontact FROM components WHERE program=" . SqlQuote($product) . " GROUP BY value"); } print "\n"; print " \n"; print " \n"; print " \n"; print " \n" if Param('useqacontact'); print " \n" if $dobugcounts; print " \n"; print ""; my @data; while (MoreSQLData()) { push @data, [FetchSQLData()]; } foreach (@data) { my ($component,$desc,$initialownerid,$initialqacontactid, $bugs) = @$_; $desc ||= "missing"; my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "missing"; my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "missing"; print "\n"; print " \n"; print " \n"; print " \n"; print " \n" if Param('useqacontact'); if ($dobugcounts) { $bugs ||= 'none'; print " \n"; } print " \n"; print ""; } print "\n"; my $span = 3; $span++ if Param('useqacontact'); $span++ if $dobugcounts; print " \n"; print " \n"; print "
Edit component ...DescriptionInitial ownerInitial QA contactBugsDelete
$component$desc$initialowner$initialqacontact$bugsDelete
Add a new componentAdd
\n"; PutTrailer(); exit; } $dobugcounts = 1; # Stupid hack to force further PutTrailer() # calls to not offer a "bug count" option. # # action='add' -> present form for parameters for new component # # (next action will be 'new') # if ($action eq 'add') { PutHeader("Add component of $product"); CheckProduct($product); #print "This page lets you add a new product to bugzilla.\n"; print "

\n"; print "\n"; EmitFormElements($product, '', 0, 0, ''); print "
\n
\n"; print "\n"; print "\n"; print "
"; my $other = $localtrailer; $other =~ s/more/other/; PutTrailer($other); exit; } # # action='new' -> add component entered in the 'action=add' screen # if ($action eq 'new') { PutHeader("Adding new component of $product"); CheckProduct($product); # Cleanups and valididy checks unless ($component) { print "You must enter a name for the new component. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } if (TestComponent($product,$component)) { print "The component '$component' already exists. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } if (length($component) > 50) { print "Sorry, the name of a component is limited to 50 characters."; PutTrailer($localtrailer); exit; } my $description = trim($::FORM{description} || ''); if ($description eq '') { print "You must enter a description for the component '$component'. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } my $initialowner = trim($::FORM{initialowner} || ''); if ($initialowner eq '') { print "You must enter an initial owner for the component '$component'. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } my $initialownerid = DBname_to_id ($initialowner); if (!$initialownerid) { print "You must use an existing Bugzilla account as initial owner for the component '$component'. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } my $initialqacontact = trim($::FORM{initialqacontact} || ''); my $initialqacontactid = DBname_to_id ($initialqacontact); if (Param('useqacontact')) { if (!$initialqacontactid && $initialqacontact ne '') { print "You must use an existing Bugzilla account as initial QA contact for the component '$component'. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } } # Add the new component SendSQL("INSERT INTO components ( " . "program, value, description, initialowner, initialqacontact " . " ) VALUES ( " . SqlQuote($product) . "," . SqlQuote($component) . "," . SqlQuote($description) . "," . SqlQuote($initialownerid) . "," . SqlQuote($initialqacontactid) . ")"); # Make versioncache flush unlink "data/versioncache"; print "OK, done.

\n"; if ($product) { PutTrailer("edit more components or Add another component"); } else { PutTrailer("edit more components or Add another component"); } exit; } # # action='del' -> ask if user really wants to delete # # (next action would be 'delete') # if ($action eq 'del') { PutHeader("Delete component of $product"); CheckComponent($product, $component); # display some data about the component SendSQL("SELECT products.product,products.description, products.milestoneurl,products.disallownew, components.program,components.value,components.initialowner, components.initialqacontact,components.description FROM products LEFT JOIN components on product=program WHERE product=" . SqlQuote($product) . " AND value=" . SqlQuote($component) ); my ($product,$pdesc,$milestoneurl,$disallownew, $dummy,$component,$initialownerid,$initialqacontactid,$cdesc) = FetchSQLData(); my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : "missing"; my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : "missing"; my $milestonelink = $milestoneurl ? "$milestoneurl" : "missing"; $pdesc ||= "missing"; $disallownew = $disallownew ? 'closed' : 'open'; $cdesc ||= "missing"; print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " "; print "\n"; print " \n"; print " "; print "\n"; print " \n"; print " "; if (Param('useqacontact')) { print "\n"; print " \n"; print " "; } SendSQL("SELECT count(bug_id) FROM bugs WHERE product=" . SqlQuote($product) . " AND component=" . SqlQuote($component)); print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " \n"; if (Param('usetargetmilestone')) { print "\n"; print " \n"; print " \n"; } print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " \n
PartValue
Component:$component
Component description:$cdesc
Initial owner:$initialowner
Initial QA contact:$initialqacontact
Component of product:$product
Description:$pdesc
Milestone URL:$milestonelink
Closed for bugs:$disallownew
Bugs"; my $bugs = FetchOneColumn(); print $bugs || 'none'; print "
"; print "

Confirmation

\n"; if ($bugs) { if (!Param("allowbugdeletion")) { print "Sorry, there are $bugs bugs outstanding for this component. You must reassign those bugs to another component before you can delete this one."; PutTrailer($localtrailer); exit; } print "
\n", "There are bugs entered for this component! When you delete this ", "component, all stored bugs will be deleted, too. ", "You could not even see the bug history for this component anymore!\n", "
\n"; } print "

Do you really want to delete this component?

\n"; print "

\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
"; PutTrailer($localtrailer); exit; } # # action='delete' -> really delete the component # if ($action eq 'delete') { PutHeader("Deleting component of $product"); CheckComponent($product,$component); # lock the tables before we start to change everything: SendSQL("LOCK TABLES attachments WRITE, bugs WRITE, bugs_activity WRITE, components WRITE, dependencies WRITE"); # According to MySQL doc I cannot do a DELETE x.* FROM x JOIN Y, # so I have to iterate over bugs and delete all the indivial entries # in bugs_activies and attachments. if (Param("allowbugdeletion")) { SendSQL("SELECT bug_id FROM bugs WHERE product=" . SqlQuote($product) . " AND component=" . SqlQuote($component)); while (MoreSQLData()) { my $bugid = FetchOneColumn(); PushGlobalSQLState(); SendSQL("DELETE FROM attachments WHERE bug_id=$bugid"); SendSQL("DELETE FROM bugs_activity WHERE bug_id=$bugid"); SendSQL("DELETE FROM dependencies WHERE blocked=$bugid"); PopGlobalSQLState(); } print "Attachments, bug activity and dependencies deleted.
\n"; # Deleting the rest is easier: SendSQL("DELETE FROM bugs WHERE product=" . SqlQuote($product) . " AND component=" . SqlQuote($component)); print "Bugs deleted.
\n"; } SendSQL("DELETE FROM components WHERE program=" . SqlQuote($product) . " AND value=" . SqlQuote($component)); print "Components deleted.

\n"; SendSQL("UNLOCK TABLES"); unlink "data/versioncache"; PutTrailer($localtrailer); exit; } # # action='edit' -> present the edit component form # # (next action would be 'update') # if ($action eq 'edit') { PutHeader("Edit component of $product"); CheckComponent($product,$component); # get data of component SendSQL("SELECT products.product,products.description, products.milestoneurl,products.disallownew, components.program,components.value,components.initialowner, components.initialqacontact,components.description FROM products LEFT JOIN components on product=program WHERE product=" . SqlQuote($product) . " AND value=" . SqlQuote($component) ); my ($product,$pdesc,$milestoneurl,$disallownew, $dummy,$component,$initialownerid,$initialqacontactid,$cdesc) = FetchSQLData(); my $initialowner = $initialownerid ? DBID_to_name ($initialownerid) : ''; my $initialqacontact = $initialqacontactid ? DBID_to_name ($initialqacontactid) : ''; print "

\n"; print "\n"; #+++ display product/product description EmitFormElements($product, $component, $initialownerid, $initialqacontactid, $cdesc); print "\n"; print " \n"; print " \n
Bugs:"; SendSQL("SELECT count(*) FROM bugs WHERE product=" . SqlQuote($product) . " and component=" . SqlQuote($component)); my $bugs = ''; $bugs = FetchOneColumn() if MoreSQLData(); print $bugs || 'none'; print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
"; my $other = $localtrailer; $other =~ s/more/other/; PutTrailer($other); exit; } # # action='update' -> update the component # if ($action eq 'update') { PutHeader("Update component of $product"); my $componentold = trim($::FORM{componentold} || ''); my $description = trim($::FORM{description} || ''); my $descriptionold = trim($::FORM{descriptionold} || ''); my $initialowner = trim($::FORM{initialowner} || ''); my $initialownerold = trim($::FORM{initialownerold} || ''); my $initialqacontact = trim($::FORM{initialqacontact} || ''); my $initialqacontactold = trim($::FORM{initialqacontactold} || ''); CheckComponent($product,$componentold); if (length($component) > 50) { print "Sorry, the name of a component is limited to 50 characters."; PutTrailer($localtrailer); exit; } # Note that the order of this tests is important. If you change # them, be sure to test for WHERE='$component' or WHERE='$componentold' SendSQL("LOCK TABLES bugs WRITE, components WRITE, profiles READ"); if ($description ne $descriptionold) { unless ($description) { print "Sorry, I can't delete the description."; PutTrailer($localtrailer); SendSQL("UNLOCK TABLES"); exit; } SendSQL("UPDATE components SET description=" . SqlQuote($description) . " WHERE program=" . SqlQuote($product) . " AND value=" . SqlQuote($componentold)); print "Updated description.
\n"; } if ($initialowner ne $initialownerold) { unless ($initialowner) { print "Sorry, I can't delete the initial owner."; SendSQL("UNLOCK TABLES"); PutTrailer($localtrailer); exit; } my $initialownerid = DBname_to_id($initialowner); unless ($initialownerid) { print "Sorry, you must use an existing Bugzilla account as initial owner."; SendSQL("UNLOCK TABLES"); PutTrailer($localtrailer); exit; } SendSQL("UPDATE components SET initialowner=" . SqlQuote($initialownerid) . " WHERE program=" . SqlQuote($product) . " AND value=" . SqlQuote($componentold)); print "Updated initial owner.
\n"; } if (Param('useqacontact') && $initialqacontact ne $initialqacontactold) { my $initialqacontactid = DBname_to_id($initialqacontact); if (!$initialqacontactid && $initialqacontact ne '') { print "Sorry, you must use an existing Bugzilla account as initial QA contact."; SendSQL("UNLOCK TABLES"); PutTrailer($localtrailer); exit; } SendSQL("UPDATE components SET initialqacontact=" . SqlQuote($initialqacontactid) . " WHERE program=" . SqlQuote($product) . " AND value=" . SqlQuote($componentold)); print "Updated initial QA contact.
\n"; } if ($component ne $componentold) { unless ($component) { print "Sorry, I can't delete the product name."; PutTrailer($localtrailer); SendSQL("UNLOCK TABLES"); exit; } if (TestComponent($product,$component)) { print "Sorry, component name '$component' is already in use."; PutTrailer($localtrailer); SendSQL("UNLOCK TABLES"); exit; } SendSQL("UPDATE bugs SET component=" . SqlQuote($component) . ", delta_ts = delta_ts WHERE component=" . SqlQuote($componentold) . " AND product=" . SqlQuote($product)); SendSQL("UPDATE components SET value=" . SqlQuote($component) . " WHERE value=" . SqlQuote($componentold) . " AND program=" . SqlQuote($product)); unlink "data/versioncache"; print "Updated product name.
\n"; } SendSQL("UNLOCK TABLES"); PutTrailer($localtrailer); exit; } # # No valid action found # PutHeader("Error"); print "I don't have a clue what you want.
\n"; foreach ( sort keys %::FORM) { print "$_: $::FORM{$_}
\n"; }