Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ivan Ivlev
bugzilla
Commits
c293c6f4
Commit
c293c6f4
authored
Nov 19, 2001
by
gerv%gerv.net
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 98707. Query.cgi rewrite. Patch by me, layout by mpt and others, r=justdave, mattyt. Wahey!
parent
63c7d007
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
240 additions
and
878 deletions
+240
-878
CGI.pl
CGI.pl
+2
-0
query.cgi
query.cgi
+238
-878
No files found.
CGI.pl
View file @
c293c6f4
...
...
@@ -29,6 +29,8 @@
use
diagnostics
;
use
strict
;
use
lib
"."
;
# use Carp; # for confess
# commented out the following snippet of code. this tosses errors into the
...
...
query.cgi
View file @
c293c6f4
#!/usr/bonsaitools/bin/perl -w
#!/usr/bonsaitools/bin/perl -w
T
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
...
...
@@ -21,39 +21,82 @@
# Contributor(s): Terry Weissman <terry@mozilla.org>
# David Gardiner <david.gardiner@unisa.edu.au>
# Matthias Radestock <matthias@sorted.org>
# Chris Lahey <clahey@ximian.com> [javascript fixes]
# Christian Reis <kiko@async.com.br> [javascript rewrite]
# Gervase Markham <gerv@gerv.net>
use
diagnostics
;
use
strict
;
use
lib
"."
;
require
"CGI.pl"
;
$::CheckOptionValues
=
0
;
# It's OK if we have some bogus things in the
# pop-up lists here, from a remembered query
# that is no longer quite valid. We don't
# want to crap out in the query page.
# Shut up misguided -w warnings about "used only once":
# Prevents &make_options in CGI.pl from throwing an error if we give it
# an invalid list of selections (from a remembered query containing values
# that no longer exist). We don't want to die in the query page even if
# strict value checks are turned on.
$::CheckOptionValues
=
0
;
use
vars
@::CheckOptionValues
,
@::legal_resolution
,
@::legal_bug_status
,
@::legal_components
,
@::legal_keywords
,
@::legal_opsys
,
@::legal_platform
,
@::legal_priority
,
@::legal_product
,
@::legal_severity
,
@::legal_target_milestone
,
@::legal_versions
,
@::log_columns
,
%::
versions
,
%::
components
,
%::
FORM
;
@::CheckOptionValues
,
@::legal_resolution
,
@::legal_bug_status
,
@::legal_components
,
@::legal_keywords
,
@::legal_opsys
,
@::legal_platform
,
@::legal_priority
,
@::legal_product
,
@::legal_severity
,
@::legal_target_milestone
,
@::legal_versions
,
@::log_columns
,
%::
versions
,
%::
components
,
%::
FORM
;
# Use the template toolkit (http://www.template-toolkit.org/) to generate
# the user interface (HTML pages and mail messages) using templates in the
# "template/" subdirectory.
use
Template
;
# Create the global template object that processes templates and specify
# configuration parameters that apply to all templates processed in this script.
my
$template
=
Template
->
new
(
{
# Colon-separated list of directories containing templates.
INCLUDE_PATH
=>
"template/custom:template/default"
,
# Allow templates to be specified with relative paths.
RELATIVE
=>
1
,
PRE_CHOMP
=>
1
,
FILTERS
=>
{
# Returns the text with backslashes, single/double quotes,
# and newlines/carriage returns escaped for use in JS strings.
'js'
=>
sub
{
my
(
$var
)
=
@_
;
$var
=~
s/([\\\'\"])/\\$1/g
;
$var
=~
s/\n/\\n/g
;
$var
=~
s/\r/\\r/g
;
return
$var
;
}
},
});
# Define the global variables and functions that will be passed to the UI
# template. Individual functions add their own values to this hash before
# sending them to the templates they process.
my
$vars
=
{
# Function for retrieving global parameters.
'Param'
=>
\&
Param
,
# Function for processing global parameters that contain references
# to other global parameters.
'PerformSubsts'
=>
\&
PerformSubsts
,
# Function to search an array for a value
'lsearch'
=>
\&
lsearch
,
};
if
(
defined
$::FORM
{
"GoAheadAndLogIn"
})
{
# We got here from a login page, probably from relogin.cgi. We better
...
...
@@ -62,15 +105,11 @@ if (defined $::FORM{"GoAheadAndLogIn"}) {
}
else
{
quietly_check_login
();
}
my
$userid
=
0
;
if
(
defined
$::COOKIE
{
"Bugzilla_login"
})
{
$userid
=
DBNameToIdAndCheck
(
$::COOKIE
{
"Bugzilla_login"
});
}
# Backwards compat
a
bility hack -- if there are any of the old QUERY_*
# Backwards compat
i
bility hack -- if there are any of the old QUERY_*
# cookies around, and we are logged in, then move them into the database
# and nuke the cookie.
if
(
$userid
)
{
# and nuke the cookie.
This is required for Bugzilla 2.8 and earlier.
if
(
$
::
userid
)
{
my
@oldquerycookies
;
foreach
my
$i
(
keys
%::
COOKIE
)
{
if
(
$i
=~
/^QUERY_(.*)$/
)
{
...
...
@@ -87,65 +126,68 @@ if ($userid) {
if
(
$value
)
{
my
$qname
=
SqlQuote
(
$name
);
SendSQL
(
"SELECT query FROM namedqueries "
.
"WHERE userid = $userid AND name = $qname"
);
"WHERE userid = $
::
userid AND name = $qname"
);
my
$query
=
FetchOneColumn
();
if
(
!
$query
)
{
SendSQL
(
"REPLACE INTO namedqueries "
.
"(userid, name, query) VALUES "
.
"($userid, $qname, "
.
SqlQuote
(
$value
)
.
")"
);
"($
::
userid, $qname, "
.
SqlQuote
(
$value
)
.
")"
);
}
}
print
"Set-Cookie: $cookiename= ; path="
.
Param
(
"cookiepath"
)
.
"; expires=Sun, 30-Jun-1980 00:00:00 GMT\n"
;
print
"Set-Cookie: $cookiename= ; path="
.
Param
(
"cookiepath"
)
.
"; expires=Sun, 30-Jun-1980 00:00:00 GMT\n"
;
}
}
}
if
(
$::FORM
{
'nukedefaultquery'
})
{
if
(
$userid
)
{
if
(
$
::
userid
)
{
SendSQL
(
"DELETE FROM namedqueries "
.
"WHERE userid = $userid AND name = '$::defaultqueryname'"
);
"WHERE userid = $
::
userid AND name = '$::defaultqueryname'"
);
}
$::buffer
=
""
;
}
my
$userdefaultquery
;
if
(
$userid
)
{
if
(
$
::
userid
)
{
SendSQL
(
"SELECT query FROM namedqueries "
.
"WHERE userid = $userid AND name = '$::defaultqueryname'"
);
"WHERE userid = $
::
userid AND name = '$::defaultqueryname'"
);
$userdefaultquery
=
FetchOneColumn
();
}
my
%
default
;
my
%
type
;
sub
ProcessFormStuff
{
# We pass the defaults as a hash of references to arrays. For those
# Items which are single-valued, the template should only reference [0]
# and ignore any multiple values.
sub
PrefillForm
{
my
(
$buf
)
=
(
@_
);
my
$foundone
=
0
;
# Nothing must be undef, otherwise the template complains.
foreach
my
$name
(
"bug_status"
,
"resolution"
,
"assigned_to"
,
"rep_platform"
,
"priority"
,
"bug_severity"
,
"product"
,
"reporter"
,
"op_sys"
,
"component"
,
"version"
,
"chfield"
,
"chfieldfrom"
,
"chfieldto"
,
"chfieldvalue"
,
"target_milestone"
,
"email1"
,
"emailtype1"
,
"emailreporter1"
,
"emailassigned_to1"
,
"emailcc1"
,
"emailqa_contact1"
,
"emaillongdesc1"
,
"email2"
,
"emailtype2"
,
"emailreporter2"
,
"emailassigned_to2"
,
"emailcc2"
,
"emailqa_contact2"
,
"emaillongdesc2"
,
"email"
,
"emailtype"
,
"emailreporter"
,
"emailassigned_to"
,
"emailcc"
,
"emailqa_contact"
,
"emaillongdesc"
,
"changedin"
,
"votes"
,
"short_desc"
,
"short_desc_type"
,
"long_desc"
,
"long_desc_type"
,
"bug_file_loc"
,
"bug_file_loc_type"
,
"status_whiteboard"
,
"status_whiteboard_type"
,
"bug_id"
,
"bugidtype"
,
"keywords"
,
"keywords_type"
)
{
$default
{
$name
}
=
""
;
$type
{
$name
}
=
0
;
# This is a bit of a hack. The default, empty list has
# three entries to accommodate the needs of the email fields -
# we use each position to denote the relevant field. Array
# position 0 is unused for email fields because the form
# parameters historically started at 1.
$default
{
$name
}
=
[
""
,
""
,
""
];
}
# Iterate over the URL parameters
foreach
my
$item
(
split
(
/\&/
,
$buf
))
{
my
@el
=
split
(
/=/
,
$item
);
my
$name
=
$el
[
0
];
...
...
@@ -155,870 +197,216 @@ sub ProcessFormStuff {
}
else
{
$value
=
""
;
}
if
(
defined
$default
{
$name
})
{
# If the name ends in a number (which it does for the fields which
# are part of the email searching), we use the array
# positions to show the defaults for that number field.
if
(
$name
=~
m/^(.+)(\d)$/
&&
defined
(
$default
{
$1
}))
{
$foundone
=
1
;
if
(
$default
{
$name
}
ne
""
)
{
$default
{
$name
}
.=
"|$value"
;
$type
{
$name
}
=
1
;
}
else
{
$default
{
$name
}
=
$value
;
}
$default
{
$1
}
->
[
$2
]
=
$value
;
}
}
# If there's no default yet, we replace the blank string.
elsif
(
defined
(
$default
{
$name
})
&&
$default
{
$name
}
->
[
0
]
eq
""
)
{
$foundone
=
1
;
$default
{
$name
}
=
[
$value
];
}
# If there's already a default, we push on the new value.
elsif
(
defined
(
$default
{
$name
}))
{
push
(
@
{
$default
{
$name
}},
$value
);
}
}
return
$foundone
;
}
if
(
!
Pr
ocessFormStuff
(
$::buffer
))
{
if
(
!
Pr
efillForm
(
$::buffer
))
{
# Ah-hah, there was no form stuff specified. Do it again with the
# default query.
if
(
$userdefaultquery
)
{
Pr
ocessFormStuff
(
$userdefaultquery
);
Pr
efillForm
(
$userdefaultquery
);
}
else
{
Pr
ocessFormStuff
(
Param
(
"defaultquery"
));
Pr
efillForm
(
Param
(
"defaultquery"
));
}
}
if
(
$default
{
'chfieldto'
}
eq
""
)
{
$default
{
'chfieldto'
}
=
"Now"
;
if
(
$default
{
'chfieldto'
}
->
[
0
]
eq
""
)
{
$default
{
'chfieldto'
}
=
[
"Now"
];
}
print
"Set-Cookie: BUGLIST=
Content-type: text/html\n\n"
;
GetVersionTable
();
sub
GenerateEmailInput
{
my
(
$id
)
=
(
@_
);
my
$defstr
=
value_quote
(
$default
{
"email$id"
});
my
$deftype
=
$default
{
"emailtype$id"
};
if
(
$deftype
eq
""
)
{
$deftype
=
"substring"
;
}
my
$assignedto
=
(
$default
{
"emailassigned_to$id"
}
eq
"1"
)
?
"checked"
:
""
;
my
$reporter
=
(
$default
{
"emailreporter$id"
}
eq
"1"
)
?
"checked"
:
""
;
my
$cc
=
(
$default
{
"emailcc$id"
}
eq
"1"
)
?
"checked"
:
""
;
my
$longdesc
=
(
$default
{
"emaillongdesc$id"
}
eq
"1"
)
?
"checked"
:
""
;
my
$qapart
=
""
;
my
$qacontact
=
""
;
if
(
Param
(
"useqacontact"
))
{
$qacontact
=
(
$default
{
"emailqa_contact$id"
}
eq
"1"
)
?
"checked"
:
""
;
$qapart
=
qq|
<tr>
<td></td>
<td>
<input type="checkbox" name="emailqa_contact$id" value=1 $qacontact>QA Contact
</td>
</tr>
|
;
}
if
(
$assignedto
eq
""
&&
$reporter
eq
""
&&
$cc
eq
""
&&
$qacontact
eq
""
)
{
if
(
$id
eq
"1"
)
{
$assignedto
=
"checked"
;
}
else
{
$reporter
=
"checked"
;
}
}
$default
{
"emailtype$id"
}
||=
"substring"
;
return
qq{
<table border=1 cellspacing=0 cellpadding=0>
<tr><td>
<table cellspacing=0 cellpadding=0>
<tr>
<td rowspan=2 valign=top><a href="queryhelp.cgi#peopleinvolved">Email:</a>
<input name="email$id" size="30" value="$defstr"> matching as
}
.
BuildPulldown
(
"emailtype$id"
,
[[
"regexp"
,
"regexp"
],
[
"notregexp"
,
"not regexp"
],
[
"substring"
,
"substring"
],
[
"exact"
,
"exact"
]],
$default
{
"emailtype$id"
})
.
qq{
</td>
<td>
<input type="checkbox" name="emailassigned_to$id" value=1 $assignedto>Assigned To
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="emailreporter$id" value=1 $reporter>Reporter
</td>
</tr>$qapart
<tr>
<td align=right>(Will match any of the selected fields)</td>
<td>
<input type="checkbox" name="emailcc$id" value=1 $cc>CC
</td>
</tr>
<tr>
<td></td>
<td>
<input type="checkbox" name="emaillongdesc$id" value=1 $longdesc>Added comment
</td>
</tr>
</table>
</table>
}
;
}
my
$emailinput1
=
GenerateEmailInput
(
1
);
my
$emailinput2
=
GenerateEmailInput
(
2
);
# if using usebuggroups, then we don't want people to see products they don't
# have access to.
r
emove them from the list.
# have access to.
R
emove them from the list.
@::product_list
=
();
my
@products
=
();
my
%
component_set
;
my
%
version_set
;
my
%
milestone_set
;
foreach
my
$p
(
@::legal_product
)
{
if
(
Param
(
"usebuggroups"
)
&&
GroupExists
(
$p
)
&&
!
UserInGroup
(
$p
))
{
# If we're using bug groups to restrict entry on products, and
# this product has a bug group, and the user is not in that
# group, we don't want to include that product in this list.
next
;
}
push
@::product_list
,
$p
;
if
(
$::components
{
$p
})
{
foreach
my
$c
(
@
{
$::components
{
$p
}})
{
$component_set
{
$c
}
=
1
;
}
}
foreach
my
$v
(
@
{
$::versions
{
$p
}})
{
$version_set
{
$v
}
=
1
;
}
foreach
my
$m
(
@
{
$::target_milestone
{
$p
}})
{
$milestone_set
{
$m
}
=
1
;
}
}
@::component_list
=
();
@::version_list
=
();
@::milestone_list
=
();
foreach
my
$c
(
@::legal_components
)
{
if
(
$component_set
{
$c
})
{
push
@::component_list
,
$c
;
}
}
foreach
my
$v
(
@::legal_versions
)
{
if
(
$version_set
{
$v
})
{
push
@::version_list
,
$v
;
}
}
foreach
my
$m
(
@::legal_target_milestone
)
{
if
(
$milestone_set
{
$m
})
{
push
@::milestone_list
,
$m
;
}
}
# SELECT box javascript handling. This is done to make the component,
# versions and milestone SELECTs repaint automatically when a product is
# selected. Refactored for bug 96534.
# make_js_array: iterates through the product array creating a
# javascript array keyed by product with an alphabetically ordered array
# for the corresponding elements in the components array passed in.
# return a string with javascript definitions for the product in a nice
# arrays which can be linearly appended later on.
# make_js_array ( \@products, \%[components/versions/milestones], $array )
sub
make_js_array
{
my
@prods
=
@
{
$_
[
0
]};
my
%
data
=
%
{
$_
[
1
]};
my
$arr
=
$_
[
2
];
my
$ret
=
"\nvar $arr = new Array();\n"
;
foreach
my
$p
(
@prods
)
{
# join each element with a "," case-insensitively alpha sorted
if
(
$data
{
$p
}
)
{
$ret
.=
$arr
.
"["
.
SqlQuote
(
$p
)
.
"] = ["
;
# the SqlQuote() protects our 's.
my
@tmp
=
map
(
SqlQuote
(
$_
),
@
{
$data
{
$p
}
}
);
# do the join on a sorted, quoted list
@tmp
=
sort
{
lc
(
$a
)
cmp
lc
(
$b
)
}
@tmp
;
$ret
.=
join
(
", "
,
@tmp
);
$ret
.=
"];\n"
;
next
if
(
Param
(
"usebuggroups"
)
&&
GroupExists
(
$p
)
&&
!
UserInGroup
(
$p
));
# We build up boolean hashes in the "-set" hashes for each of these things
# before making a list because there may be duplicates names across products.
push
@products
,
$p
;
if
(
$::components
{
$p
})
{
foreach
my
$c
(
@
{
$::components
{
$p
}})
{
$component_set
{
$c
}
=
1
;
}
}
return
$ret
;
}
my
$jscript
=
'<script language="JavaScript" type="text/javascript">'
;
$jscript
.=
"\n<!--\n\n"
;
# Add the javascript code for the arrays of components and versions
# This is used in our javascript functions
$jscript
.=
"var usetms = 0; // do we have target milestone?\n"
;
$jscript
.=
"var first_load = 1; // is this the first time we load the page?\n"
;
$jscript
.=
"var last_sel = []; // caches last selection\n"
;
$jscript
.=
make_js_array
(
\
@::product_list
,
\%::
components
,
"cpts"
);
$jscript
.=
make_js_array
(
\
@::product_list
,
\%::
versions
,
"vers"
);
if
(
Param
(
"usetargetmilestone"
)
)
{
$jscript
.=
make_js_array
(
\
@::product_list
,
\%::
target_milestone
,
"tms"
);
$jscript
.=
"\nusetms = 1; // hooray, we use target milestones\n"
;
}
$jscript
.=
<<
'ENDSCRIPT'
;
//
Adds
to
the
target
select
object
all
elements
in
array
that
//
correspond
to
the
elements
selected
in
source
.
//
-
array
should
be
a
array
of
arrays
,
indexed
by
product
name
.
the
//
array
should
contain
the
elements
that
correspont
to
that
//
product
.
Example:
//
var
array
=
Array
();
//
array
[
'ProductOne'
]
=
[
'ComponentA'
,
'ComponentB'
];
//
updateSelect
(
array
,
source
,
target
);
//
-
sel
is
a
list
of
selected
items
,
either
whole
or
a
diff
//
depending
on
sel_is_diff
.
//
-
sel_is_diff
determines
if
we
are
sending
in
just
a
diff
or
the
//
whole
selection
.
a
diff
is
used
to
optimize
adding
selections
.
//
-
target
should
be
the
target
select
object
.
//
-
single
specifies
if
we
selected
a
single
item
.
if
we
did
,
no
//
need
to
merge
.
function
updateSelect
(
array
,
sel
,
target
,
sel_is_diff
,
single
)
{
var
i
,
comp
;
//
if
single
,
even
if
it
's a diff (happens when you have nothing
// selected and select one item alone), skip this.
if ( ! single ) {
// array merging/sorting in the case of multiple selections
if ( sel_is_diff ) {
// merge in the current options with the first selection
comp = merge_arrays( array[sel[0]], target.options, 1 );
// merge the rest of the selection with the results
for ( i = 1 ; i < sel.length ; i++ ) {
comp = merge_arrays( array[sel[i]], comp, 0 );
}
} else {
// here we micro-optimize for two arrays to avoid merging with a
// null array
comp = merge_arrays( array[sel[0]],array[sel[1]], 0 );
// merge the arrays. not very good for multiple selections.
for ( i = 2; i < sel.length; i++ ) {
comp = merge_arrays( comp, array[sel[i]], 0 );
}
}
} else {
// single item in selection, just get me the list
comp = array[sel[0]];
foreach
my
$v
(
@
{
$::versions
{
$p
}})
{
$version_set
{
$v
}
=
1
;
}
// clear select
target.options.length = 0;
// load elements of list into select
for ( i = 0; i < comp.length; i++ ) {
target.options[i] = new Option( comp[i], comp[i] );
foreach
my
$m
(
@
{
$::target_milestone
{
$p
}})
{
$milestone_set
{
$m
}
=
1
;
}
}
// Returns elements in a that are not in b.
// NOT A REAL DIFF: does not check the reverse.
// - a,b: arrays of values to be compare.
function fake_diff_array( a, b ) {
var newsel = new Array();
# @products is now all the products we are ever concerned with, as a list
# %x_set is now a unique "list" of the relevant components/versions/tms
@products
=
sort
{
lc
(
$a
)
cmp
lc
(
$b
)
}
@products
;
// do a boring array diff to see who'
s
new
for
(
var
ia
in
a
)
{
var
found
=
0
;
for
(
var
ib
in
b
)
{
if
(
a
[
ia
]
==
b
[
ib
]
)
{
found
=
1
;
}
}
if
(
!
found
)
{
newsel
[
newsel
.
length
]
=
a
[
ia
];
}
found
=
0
;
# Create the component, version and milestone lists.
my
@components
=
();
my
@versions
=
();
my
@milestones
=
();
foreach
my
$c
(
@::legal_components
)
{
if
(
$component_set
{
$c
})
{
push
@components
,
$c
;
}
return
newsel
;
}
//
takes
two
arrays
and
sorts
them
by
string
,
returning
a
new
,
sorted
//
array
.
the
merge
removes
dupes
,
too
.
//
-
a
,
b:
arrays
to
be
merge
.
//
-
b_is_select:
if
true
,
then
b
is
actually
an
optionitem
and
as
//
such
we
need
to
use
item
.
value
on
it
.
function
merge_arrays
(
a
,
b
,
b_is_select
)
{
var
pos_a
=
0
;
var
pos_b
=
0
;
var
ret
=
new
Array
();
var
bitem
,
aitem
;
//
iterate
through
both
arrays
and
add
the
larger
item
to
the
return
//
list
.
remove
dupes
,
too
.
Use
toLowerCase
to
provide
//
case
-
insensitivity
.
while
(
(
pos_a
<
a
.
length
)
&&
(
pos_b
<
b
.
length
)
)
{
if
(
b_is_select
)
{
bitem
=
b
[
pos_b
]
.
value
;
}
else
{
bitem
=
b
[
pos_b
];
}
aitem
=
a
[
pos_a
];
//
smaller
item
in
list
a
if
(
aitem
.
toLowerCase
()
<
bitem
.
toLowerCase
()
)
{
ret
[
ret
.
length
]
=
aitem
;
pos_a
++
;
}
else
{
//
smaller
item
in
list
b
if
(
aitem
.
toLowerCase
()
>
bitem
.
toLowerCase
()
)
{
ret
[
ret
.
length
]
=
bitem
;
pos_b
++
;
}
else
{
//
list
contents
are
equal
,
inc
both
counters
.
ret
[
ret
.
length
]
=
aitem
;
pos_a
++
;
pos_b
++
;
}
}
}
//
catch
leftovers
here
.
these
sections
are
ugly
code
-
copying
.
if
(
pos_a
<
a
.
length
)
{
for
(
;
pos_a
<
a
.
length
;
pos_a
++
)
{
ret
[
ret
.
length
]
=
a
[
pos_a
];
}
}
if
(
pos_b
<
b
.
length
)
{
for
(
;
pos_b
<
b
.
length
;
pos_b
++
)
{
if
(
b_is_select
)
{
bitem
=
b
[
pos_b
]
.
value
;
}
else
{
bitem
=
b
[
pos_b
];
}
ret
[
ret
.
length
]
=
bitem
;
}
foreach
my
$v
(
@::legal_versions
)
{
if
(
$version_set
{
$v
})
{
push
@versions
,
$v
;
}
return
ret
;
}
//
selectProduct
reads
the
selection
from
f
.
product
and
updates
//
f
.
version
,
component
and
target_milestone
accordingly
.
//
-
f:
a
form
containing
product
,
component
,
varsion
and
//
target_milestone
select
boxes
.
//
globals
(
3
vil
!
):
//
-
cpts
,
vers
,
tms:
array
of
arrays
,
indexed
by
product
name
.
the
//
subarrays
contain
a
list
of
names
to
be
fed
to
the
respective
//
selectboxes
.
For
bugzilla
,
these
are
generated
with
perl
code
//
at
page
start
.
//
-
usetms:
this
is
a
global
boolean
that
is
defined
if
the
//
bugzilla
installation
has
it
turned
on
.
generated
in
perl
too
.
//
-
first_load:
boolean
,
specifying
if
it
's the first time we load
// the query page.
// - last_sel: saves our last selection list so we know what has
// changed, and optimize for additions.
function selectProduct( f ) {
// this is to avoid handling events that occur before the form
// itself is ready, which happens in buggy browsers.
if ( ( !f ) || ( ! f.product ) ) {
return;
}
// if this is the first load and nothing is selected, no need to
// merge and sort all components; perl gives it to us sorted.
if ( ( first_load ) && ( f.product.selectedIndex == -1 ) ) {
first_load = 0;
return;
}
// turn first_load off. this is tricky, since it seems to be
// redundant with the above clause. It'
s
not
:
if
when
we
first
load
//
the
page
there
is
_one_
element
selected
,
it
won
't fall into that
// clause, and first_load will remain 1. Then, if we unselect that
// item, selectProduct will be called but the clause will be valid
// (since selectedIndex == -1), and we will return - incorrectly -
// without merge/sorting.
first_load = 0;
// - sel keeps the array of products we are selected.
// - is_diff says if it'
s
a
full
list
or
just
a
list
of
products
that
//
were
added
to
the
current
selection
.
//
-
single
indicates
if
a
single
item
was
selected
var
sel
=
Array
();
var
is_diff
=
0
;
var
single
;
//
if
nothing
selected
,
pick
all
if
(
f
.
product
.
selectedIndex
==
-
1
)
{
for
(
var
i
=
0
;
i
<
f
.
product
.
length
;
i
++
)
{
sel
[
sel
.
length
]
=
f
.
product
.
options
[
i
]
.
value
;
}
single
=
0
;
}
else
{
for
(
i
=
0
;
i
<
f
.
product
.
length
;
i
++
)
{
if
(
f
.
product
.
options
[
i
]
.
selected
)
{
sel
[
sel
.
length
]
=
f
.
product
.
options
[
i
]
.
value
;
}
}
single
=
(
sel
.
length
==
1
);
//
save
last_sel
before
we
kill
it
var
tmp
=
last_sel
;
last_sel
=
sel
;
//
this
is
an
optimization:
if
we
've added components, no need
// to remerge them; just merge the new ones with the existing
// options.
if ( ( tmp ) && ( tmp.length < sel.length ) ) {
sel = fake_diff_array(sel, tmp);
is_diff = 1;
}
}
// do the actual fill/update
updateSelect( cpts, sel, f.component, is_diff, single );
updateSelect( vers, sel, f.version, is_diff, single );
if ( usetms ) {
updateSelect( tms, sel, f.target_milestone, is_diff, single );
foreach
my
$m
(
@::legal_target_milestone
)
{
if
(
$milestone_set
{
$m
})
{
push
@milestones
,
$m
;
}
}
// -->
</script>
ENDSCRIPT
#
# End the fearsome Javascript section.
#
# Muck the "legal product" list so that the default one is always first (and
# is therefore visibly selected.
# Commented out, until we actually have enough products for this to matter.
# set w [lsearch $legal_product $default{"product"}]
# if {$w >= 0} {
# set legal_product [concat $default{"product"} [lreplace $legal_product $w $w]]
# }
PutHeader("Bugzilla Query Page", "Query",
"This page lets you search the database for recorded bugs.",
q{onLoad="selectProduct(document.forms['
queryform
']);"}, $jscript);
push @::legal_resolution, "---"; # Oy, what a hack.
my @logfields = ("[Bug creation]", @::log_columns);
print"<P>Give me a <A HREF=\"queryhelp.cgi\">clue</A> about how to use this form.<P>";
print qq{
<FORM METHOD=GET ACTION="buglist.cgi" NAME="queryform">
<table>
<tr>
<th align=left><A HREF="queryhelp.cgi#status">Status</a>:</th>
<th align=left><A HREF="queryhelp.cgi#resolution">Resolution</a>:</th>
<th align=left><A HREF="queryhelp.cgi#platform">Platform</a>:</th>
<th align=left><A HREF="queryhelp.cgi#opsys">OpSys</a>:</th>
<th align=left><A HREF="queryhelp.cgi#priority">Priority</a>:</th>
<th align=left><A HREF="queryhelp.cgi#severity">Severity</a>:</th>
};
print "
</tr>
<tr>
<td align=left valign=top>
@{[make_selection_widget(\"bug_status\",\@::legal_bug_status,$default{'
bug_status
'}, $type{'
bug_status
'}, 1)]}
</td>
<td align=left valign=top>
@{[make_selection_widget(\"resolution\",\@::legal_resolution,$default{'
resolution
'}, $type{'
resolution
'}, 1)]}
</td>
<td align=left valign=top>
@{[make_selection_widget(\"rep_platform\",\@::legal_platform,$default{'
platform
'}, $type{'
platform
'}, 1)]}
</td>
<td align=left valign=top>
@{[make_selection_widget(\"op_sys\",\@::legal_opsys,$default{'
op_sys
'}, $type{'
op_sys
'}, 1)]}
</td>
<td align=left valign=top>
@{[make_selection_widget(\"priority\",\@::legal_priority,$default{'
priority
'}, $type{'
priority
'}, 1)]}
</td>
<td align=left valign=top>
@{[make_selection_widget(\"bug_severity\",\@::legal_severity,$default{'
bug_severity
'}, $type{'
bug_severity
'}, 1)]}
</tr>
</table>
<p>
<table>
<tr><td colspan=2>
$emailinput1<p>
</td></tr><tr><td colspan=2>
$emailinput2<p>
</td></tr>";
my $inclselected = "SELECTED";
my $exclselected = "";
if ($default{'
bugidtype
'} eq "exclude") {
$inclselected = "";
$exclselected = "SELECTED";
}
my $bug_id = value_quote($default{'
bug_id
'});
print qq{
<TR>
<TD COLSPAN="3">
<SELECT NAME="bugidtype">
<OPTION VALUE="include" $inclselected>Only
<OPTION VALUE="exclude" $exclselected>Exclude
</SELECT>
bugs numbered:
<INPUT TYPE="text" NAME="bug_id" VALUE="$bug_id" SIZE=30>
</TD>
</TR>
};
print "
<tr>
<td>
Changed in the <NOBR>last <INPUT NAME=changedin SIZE=2 VALUE=\"$default{'
changedin
'}\"> days.</NOBR>
</td>
<td align=right>
At <NOBR>least <INPUT NAME=votes SIZE=3 VALUE=\"$default{'
votes
'}\"> votes.</NOBR>
</tr>
</table>
<table>
<tr>
<td rowspan=2 align=right>Where the field(s)
</td><td rowspan=2>
<SELECT NAME=\"chfield\" MULTIPLE SIZE=4>
@{[make_options(\@logfields, $default{'
chfield
'}, $type{'
chfield
'})]}
</SELECT>
</td><td rowspan=2>
changed.
</td><td>
<nobr>dates <INPUT NAME=chfieldfrom SIZE=10 VALUE=\"$default{'
chfieldfrom
'}\"></nobr>
<nobr>to <INPUT NAME=chfieldto SIZE=10 VALUE=\"$default{'
chfieldto
'}\"></nobr>
</td>
</tr>
<tr>
<td>changed to value <nobr><INPUT NAME=chfieldvalue SIZE=10> (optional)</nobr>
</td>
</table>
<P>
<table>
<tr>
<TH ALIGN=LEFT VALIGN=BOTTOM>Program:</th>
<TH ALIGN=LEFT VALIGN=BOTTOM>Version:</th>
<TH ALIGN=LEFT VALIGN=BOTTOM><A HREF=describecomponents.cgi>Component:</a></th>
";
if (Param("usetargetmilestone")) {
print "<TH ALIGN=LEFT VALIGN=BOTTOM>Target Milestone:</th>";
}
print "
</tr>
<tr>
<td align=left valign=top>
<SELECT NAME=\"product\" MULTIPLE SIZE=5 onChange=\"selectProduct(this.form);\">
@{[make_options(\@::product_list, $default{'
product
'}, $type{'
product
'})]}
</SELECT>
</td>
# Sort the component list...
my
$comps
=
\%::
components
;
foreach
my
$p
(
@products
)
{
my
@tmp
=
sort
{
lc
(
$a
)
cmp
lc
(
$b
)
}
@
{
$comps
->
{
$p
}};
$comps
->
{
$p
}
=
\
@tmp
;
}
<td align=left valign=top>
<SELECT NAME=\"version\" MULTIPLE SIZE=5>
@{[make_options(\@::version_list, $default{'
version
'}, $type{'
version
'})]}
</SELECT>
</td>
# and the version list...
my
$vers
=
\%::
versions
;
foreach
my
$p
(
@products
)
{
my
@tmp
=
sort
{
lc
(
$a
)
cmp
lc
(
$b
)
}
@
{
$vers
->
{
$p
}};
$vers
->
{
$p
}
=
\
@tmp
;
}
<td align=left valign=top>
<SELECT NAME=\"component\" MULTIPLE SIZE=5>
@{[make_options(\@::component_list, $default{'
component
'}, $type{'
component
'})]}
</SELECT>
</td>";
if (Param("usetargetmilestone")) {
print "
<td align=left valign=top>
<SELECT NAME=\"target_milestone\" MULTIPLE SIZE=5>
@{[make_options(\@::milestone_list, $default{'
target_milestone
'}, $type{'
target_milestone
'})]}
</SELECT>
</td>";
# and the milestone list.
my
$mstones
;
if
(
Param
(
'usetargetmilestone'
))
{
$mstones
=
\%::
target_milestone
;
foreach
my
$p
(
@products
)
{
my
@tmp
=
sort
{
lc
(
$a
)
cmp
lc
(
$b
)
}
@
{
$mstones
->
{
$p
}};
$mstones
->
{
$p
}
=
\
@tmp
;
}
}
# "foo" or "foos" is a list of all the possible (or legal) products,
# components, versions or target milestones.
# "foobyproduct" is a hash, keyed by product, of sorted lists
# of the same data.
sub StringSearch {
my ($desc, $name) = (@_);
my $type = $name . "_type";
my $def = value_quote($default{$name});
print qq{<tr>
<td align=right>$desc:</td>
<td><input name=$name size=30 value="$def"></td>
<td><SELECT NAME=$type>
};
if ($default{$type} eq "") {
$default{$type} = "allwordssubstr";
}
foreach my $i (["substring", "case-insensitive substring"],
["casesubstring", "case-sensitive substring"],
["allwordssubstr", "all words as substrings"],
["anywordssubstr", "any words as substrings"],
["allwords", "all words"],
["anywords", "any words"],
["regexp", "regular expression"],
["notregexp", "not ( regular expression )"]) {
my ($n, $d) = (@$i);
my $sel = "";
if ($default{$type} eq $n) {
$sel = " SELECTED";
}
print qq{<OPTION VALUE="$n"$sel>$d\n};
}
print "</SELECT></TD>
</tr>
";
}
$vars
->
{
'product'
}
=
\
@products
;
print "
</tr>
</table>
# We use 'component_' because 'component' is a Template Toolkit reserved word.
$vars
->
{
'componentsbyproduct'
}
=
$comps
;
$vars
->
{
'component_'
}
=
\
@components
;
<table border=0>
";
StringSearch("Summary", "short_desc");
StringSearch("A description entry", "long_desc");
StringSearch("URL", "bug_file_loc");
if (Param("usestatuswhiteboard")) {
StringSearch("Status whiteboard", "status_whiteboard");
}
$vars
->
{
'versionsbyproduct'
}
=
$vers
;
$vars
->
{
'version'
}
=
\
@versions
;
if (@::legal_keywords) {
my $def = value_quote($default{'
keywords
'});
print qq{
<TR>
<TD ALIGN="right"><A HREF="describekeywords.cgi">Keywords</A>:</TD>
<TD><INPUT NAME="keywords" SIZE=30 VALUE="$def"></TD>
<TD>
};
my $type = $default{"keywords_type"};
if ($type eq "or") { # Backward compatability hack.
$type = "anywords";
}
print BuildPulldown("keywords_type",
[["anywords", "Any of the listed keywords set"],
["allwords", "All of the listed keywords set"],
["nowords", "None of the listed keywords set"]],
$type);
print qq{</TD></TR>};
if
(
Param
(
'usetargetmilestone'
))
{
$vars
->
{
'milestonesbyproduct'
}
=
$mstones
;
$vars
->
{
'target_milestone'
}
=
\
@milestones
;
}
print "
</table>
<p>
";
$vars
->
{
'have_keywords'
}
=
scalar
(
%::
legal_keywords
);
push
@::legal_resolution
,
"---"
;
# Oy, what a hack.
shift
@::legal_resolution
;
# Another hack - this array contains "" for some reason. See bug 106589.
$vars
->
{
'resolution'
}
=
\
@::legal_resolution
;
$vars
->
{
'chfield'
}
=
[
"[Bug creation]"
,
@::log_columns
];
$vars
->
{
'bug_status'
}
=
\
@::legal_bug_status
;
$vars
->
{
'rep_platform'
}
=
\
@::legal_platform
;
$vars
->
{
'op_sys'
}
=
\
@::legal_opsys
;
$vars
->
{
'priority'
}
=
\
@::legal_priority
;
$vars
->
{
'bug_severity'
}
=
\
@::legal_severity
;
$vars
->
{
'userid'
}
=
$::userid
;
# Boolean charts
my
@fields
;
push(@fields,
["noop", "---"]
);
push
(
@fields
,
{
name
=>
"noop"
,
description
=>
"---"
}
);
ConnectToDatabase
();
SendSQL
(
"SELECT name, description FROM fielddefs ORDER BY sortkey"
);
while
(
MoreSQLData
())
{
my ($name, $description) =
(FetchSQLData()
);
push(@fields,
[$name, $description]
);
my
(
$name
,
$description
)
=
FetchSQLData
(
);
push
(
@fields
,
{
name
=>
$name
,
description
=>
$description
}
);
}
my @types = (
["noop", "---"],
["equals", "equal to"],
["notequals", "not equal to"],
["casesubstring", "contains (case-sensitive) substring"],
["substring", "contains (case-insensitive) substring"],
["notsubstring", "does not contain (case-insensitive) substring"],
["allwordssubstr", "all words as (case-insensitive) substrings"],
["anywordssubstr", "any words as (case-insensitive) substrings"],
["regexp", "contains regexp"],
["notregexp", "does not contain regexp"],
["lessthan", "less than"],
["greaterthan", "greater than"],
["anywords", "any words"],
["allwords", "all words"],
["nowords", "none of the words"],
["changedbefore", "changed before"],
["changedafter", "changed after"],
["changedfrom", "changed from"],
["changedto", "changed to"],
["changedby", "changed by"],
);
print qq{<A NAME="chart"> </A>\n};
$vars
->
{
'fields'
}
=
\
@fields
;
# Creating new charts - if the cmd-add value is there, we define the field
# value so the code sees it and creates the chart. It will attempt to select
# "xyzzy" as the default, and fail. This is the correct behaviour.
foreach
my
$cmd
(
grep
(
/^cmd-/
,
keys
(
%::
FORM
)))
{
if
(
$cmd
=~
/^cmd-add(\d+)-(\d+)-(\d+)$/
)
{
$::FORM
{
"field$1-$2-$3"
}
=
"xyzzy"
;
}
}
# foreach my $i (sort(keys(%::FORM))) {
# print "$i : " . value_quote($::FORM{$i}) . "<BR>\n";
# }
if
(
!
exists
$::FORM
{
'field0-0-0'
})
{
$::FORM
{
'field0-0-0'
}
=
"xyzzy"
;
}
my $jsmagic = qq{ONCLICK="document.forms[0].action='
query
.
cgi
#chart' ; document.forms[0].method='POST' ; return 1;"};
my
$chart
;
for
(
$chart
=
0
;
exists
$::FORM
{
"field$chart-0-0"
}
;
$chart
++
)
{
# Create data structure of boolean chart info. It's an array of arrays of
# arrays - with the inner arrays having three members - field, type and
# value.
my
@charts
;
for
(
my
$chart
=
0
;
$::FORM
{
"field$chart-0-0"
};
$chart
++
)
{
my
@rows
;
my
$row
;
for
(
$row
=
0
;
exists
$::FORM
{
"field$chart-$row-0"
}
;
$row
++
)
{
for
(
my
$row
=
0
;
$::FORM
{
"field$chart-$row-0"
};
$row
++
)
{
my
@cols
;
my
$col
;
for
(
$col
=
0
;
exists
$::FORM
{
"field$chart-$row-$col"
}
;
$col
++
)
{
my
$key
=
"$chart-$row-$col"
;
my
$deffield
=
$::FORM
{
"field$key"
}
||
""
;
my
$deftype
=
$::FORM
{
"type$key"
}
||
""
;
my
$defvalue
=
value_quote
(
$::FORM
{
"value$key"
}
||
""
);
my
$line
=
""
;
$line
.=
"<TD>"
;
$line
.=
BuildPulldown
(
"field$key"
,
\
@fields
,
$deffield
);
$line
.=
BuildPulldown
(
"type$key"
,
\
@types
,
$deftype
);
$line
.=
qq{<INPUT NAME="value$key" VALUE="$defvalue">}
;
$line
.=
"</TD>\n"
;
push
(
@cols
,
$line
);
for
(
my
$col
=
0
;
$::FORM
{
"field$chart-$row-$col"
};
$col
++
)
{
push
(
@cols
,
{
field
=>
$::FORM
{
"field$chart-$row-$col"
},
type
=>
$::FORM
{
"type$chart-$row-$col"
},
value
=>
$::FORM
{
"value$chart-$row-$col"
}
});
}
push
(
@rows
,
"<TR>"
.
join
(
qq{<TD ALIGN="center"> or </TD>\n}
,
@cols
)
.
qq{<TD><INPUT TYPE="submit" VALUE="Or" NAME="cmd-add$chart-$row-$col" $jsmagic></TD></TR>}
);
}
print
qq{
<HR>
<TABLE>
}
;
print
join
(
'<TR><TD>And</TD></TR>'
,
@rows
);
print
qq{
<TR><TD><INPUT TYPE="submit" VALUE="And" NAME="cmd-add$chart-$row-0" $jsmagic>
}
;
my
$n
=
$chart
+
1
;
if
(
!
exists
$::FORM
{
"field$n-0-0"
})
{
print
qq{
<INPUT TYPE="submit" VALUE="Add another boolean chart" NAME="cmd-add$n-0-0" $jsmagic>
<NOBR><A HREF="queryhelp.cgi#advancedquerying">What is this stuff?</A></NOBR>
}
;
push
(
@rows
,
\
@cols
);
}
print
qq{
</TD>
</TR>
</TABLE>
}
;
push
(
@charts
,
\
@rows
);
}
print
qq{<HR>}
;
$default
{
'charts'
}
=
\
@charts
;
if
(
!
$userid
)
{
print
qq{<INPUT TYPE="hidden" NAME="cmdtype" VALUE="doit">}
;
}
else
{
print
"
<BR>
<INPUT TYPE=radio NAME=cmdtype VALUE=doit CHECKED> Run this query
<BR>
"
;
# Named queries
if
(
$::userid
)
{
my
@namedqueries
;
if
(
$userid
)
{
SendSQL
(
"SELECT name FROM namedqueries "
.
"WHERE userid = $userid AND name != '$::defaultqueryname' "
.
"ORDER BY name"
);
while
(
MoreSQLData
())
{
push
(
@namedqueries
,
FetchOneColumn
());
}
SendSQL
(
"SELECT name FROM namedqueries "
.
"WHERE userid = $::userid AND name != '$::defaultqueryname' "
.
"ORDER BY name"
);
while
(
MoreSQLData
())
{
push
(
@namedqueries
,
FetchOneColumn
());
}
if
(
@namedqueries
)
{
my
$namelist
=
make_options
(
\
@namedqueries
);
print
qq{
<table cellspacing=0 cellpadding=0><tr>
<td><INPUT TYPE=radio NAME=cmdtype VALUE=editnamed> Load the remembered query:</td>
<td rowspan=3><select name=namedcmd>$namelist</select>
</tr><tr>
<td><INPUT TYPE=radio NAME=cmdtype VALUE=runnamed> Run the remembered query:</td>
</tr><tr>
<td><INPUT TYPE=radio NAME=cmdtype VALUE=forgetnamed> Forget the remembered query:</td>
</tr></table>}
;
}
print
qq{
<INPUT TYPE=radio NAME=cmdtype VALUE=asdefault> Remember this as the default query
<BR>
<INPUT TYPE=radio NAME=cmdtype VALUE=asnamed> Remember this query, and name it:
<INPUT TYPE=text NAME=newqueryname>
<br> <INPUT TYPE="checkbox" NAME="tofooter" VALUE="1">
and put it in my page footer.
<BR>
}
;
$vars
->
{
'namedqueries'
}
=
\
@namedqueries
;
}
print
qq{
<NOBR><B>Sort By:</B>
<SELECT NAME=\"order\">
}
;
my
$deforder
=
"'Importance'"
;
my
@orders
=
(
'Bug Number'
,
$deforder
,
'Assignee'
,
'Last Changed'
);
# Sort order
my
$deforder
;
my
@orders
=
(
'Bug Number'
,
'Importance'
,
'Assignee'
,
'Last Changed'
);
if
(
$::COOKIE
{
'LASTORDER'
})
{
$deforder
=
"Reuse same sort as last time"
;
...
...
@@ -1027,43 +415,15 @@ if ($::COOKIE{'LASTORDER'}) {
if
(
$::FORM
{
'order'
})
{
$deforder
=
$::FORM
{
'order'
}
}
my
$defquerytype
=
$userdefaultquery
?
"my"
:
"the"
;
print
make_options
(
\
@orders
,
$deforder
);
print
"</SELECT></NOBR>
<INPUT TYPE=\"submit\" VALUE=\"Submit query\">
<INPUT TYPE=\"reset\" VALUE=\"Reset back to $defquerytype default query\">
"
;
if
(
$userdefaultquery
)
{
print
qq{<BR><A HREF="query.cgi?nukedefaultquery=1">Set my default query back to the system default</A>}
;
}
print
"
</FORM>
"
;
###
### I really hate this redudancy, but if somebody for some inexplicable reason doesn't like using
### the footer for these links, they can uncomment this section.
###
# if (UserInGroup("tweakparams")) {
# print "<a href=editparams.cgi>Edit Bugzilla operating parameters</a><br>\n";
# }
# if (UserInGroup("editcomponents")) {
# print "<a href=editproducts.cgi>Edit Bugzilla products and components</a><br>\n";
# }
# if (UserInGroup("editkeywords")) {
# print "<a href=editkeywords.cgi>Edit Bugzilla keywords</a><br>\n";
# }
# if ($userid) {
# print "<a href=relogin.cgi>Log in as someone besides <b>$::COOKIE{'Bugzilla_login'}</b></a><br>\n";
# }
# print "<a href=userprefs.cgi>Change your password or preferences.</a><br>\n";
# print "<a href=\"enter_bug.cgi\">Report a new bug.</a><br>\n";
# print "<a href=\"createaccount.cgi\">Open a new Bugzilla account</a><br>\n";
# print "<a href=\"reports.cgi\">Bug reports</a><br>\n";
$vars
->
{
'userdefaultquery'
}
=
$userdefaultquery
;
$vars
->
{
'orders'
}
=
\
@orders
;
$default
{
'querytype'
}
=
$deforder
||
'Importance'
;
# Add in the defaults.
$vars
->
{
'default'
}
=
\%
default
;
PutFooter
();
# Generate and return the UI (HTML page) from the appropriate template.
print
"Content-type: text/html\n\n"
;
$template
->
process
(
"query/query.atml"
,
$vars
)
||
DisplayError
(
"Template process failed: "
.
$template
->
error
())
&&
exit
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment