Compare commits
38 Commits
Bugzilla_P
...
Bugzilla_P
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c591d53e2 | ||
|
|
c1aa983fd5 | ||
|
|
3551227412 | ||
|
|
d0cc91f285 | ||
|
|
65ff7d56b3 | ||
|
|
800eccde9a | ||
|
|
5360e5b008 | ||
|
|
da759055dd | ||
|
|
1f960bb1bd | ||
|
|
e0f4b89db1 | ||
|
|
025b6e8e46 | ||
|
|
704f46aa53 | ||
|
|
f26338df7e | ||
|
|
58548c3f0d | ||
|
|
9a6b4393ad | ||
|
|
4316819604 | ||
|
|
9d93dfabb8 | ||
|
|
d2ddb07675 | ||
|
|
66d426dc97 | ||
|
|
b7e91cb3b6 | ||
|
|
5ac0899827 | ||
|
|
4f49e57a3b | ||
|
|
38c27be28f | ||
|
|
d60d3d6121 | ||
|
|
db0b87fb6c | ||
|
|
6e2791a4b7 | ||
|
|
14542c62c7 | ||
|
|
38ebcba576 | ||
|
|
a5502157a9 | ||
|
|
ba69b37618 | ||
|
|
22b863a5e9 | ||
|
|
3e54979994 | ||
|
|
d73ca44c76 | ||
|
|
a4fc52b12e | ||
|
|
353baca797 | ||
|
|
4618ab6c36 | ||
|
|
faaed9c15f | ||
|
|
675f64d0ae |
@@ -43,7 +43,7 @@ sub query
|
||||
# "attachments" variable.
|
||||
my ($bugid) = @_;
|
||||
|
||||
my $in_editbugs = &::UserInGroup($::userid, "editbugs");
|
||||
my $in_editbugs = &::UserInGroup("editbugs");
|
||||
|
||||
# Retrieve a list of attachments for this bug and write them into an array
|
||||
# of hashes in which each hash represents a single attachment.
|
||||
|
||||
@@ -36,8 +36,8 @@ my %ok_field;
|
||||
for my $key (qw (bug_id product version rep_platform op_sys bug_status
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts
|
||||
delta_ts votes whoid comment query error) ){
|
||||
qa_contact status_whiteboard creation_ts groupset
|
||||
delta_ts votes whoid usergroupset comment query error) ){
|
||||
$ok_field{$key}++;
|
||||
}
|
||||
|
||||
@@ -101,17 +101,16 @@ sub initBug {
|
||||
|
||||
|
||||
$self->{'whoid'} = $user_id;
|
||||
&::SendSQL("SELECT groupset FROM profiles WHERE userid=$self->{'whoid'}");
|
||||
my $usergroupset = &::FetchOneColumn();
|
||||
if (!$usergroupset) { $usergroupset = '0' }
|
||||
$self->{'usergroupset'} = $usergroupset;
|
||||
|
||||
# First check that we can see it
|
||||
if (!&::CanSeeBug($bug_id, $user_id)) {
|
||||
# is it not there, or are we just forbidden to see it?
|
||||
&::SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $bug_id");
|
||||
if (&::FetchSQLData()) {
|
||||
$self->{'error'} = "NotPermitted";
|
||||
} else {
|
||||
$self->{'error'} = "NotFound";
|
||||
}
|
||||
$self->{'bug_id'} = $bug_id;
|
||||
# Check to see if we can see this bug
|
||||
if (!&::CanSeeBug($bug_id, $user_id, $usergroupset)) {
|
||||
# Permission denied to see bug
|
||||
$self->{'bug_id'} = $old_bug_id;
|
||||
$self->{'error'} = "PermissionDenied";
|
||||
return $self;
|
||||
}
|
||||
|
||||
@@ -123,7 +122,7 @@ sub initBug {
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact,
|
||||
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
|
||||
delta_ts, sum(votes.count)
|
||||
groupset, delta_ts, sum(votes.count)
|
||||
from bugs left join votes using(bug_id)
|
||||
where bugs.bug_id = $bug_id
|
||||
group by bugs.bug_id";
|
||||
@@ -134,32 +133,45 @@ sub initBug {
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact,
|
||||
status_whiteboard, creation_ts,
|
||||
delta_ts, sum(votes.count)
|
||||
groupset, delta_ts, sum(votes.count)
|
||||
from bugs left join votes using(bug_id)
|
||||
where bugs.bug_id = $bug_id
|
||||
and (bugs.groupset & int8($usergroupset)) = bugs.groupset
|
||||
group by bugs.bug_id, product, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact, status_whiteboard,
|
||||
creation_ts, delta_ts";
|
||||
creation_ts, groupset, delta_ts";
|
||||
}
|
||||
|
||||
&::SendSQL($query);
|
||||
my @row;
|
||||
|
||||
@row = &::FetchSQLData();
|
||||
my $count = 0;
|
||||
my %fields;
|
||||
foreach my $field ("bug_id", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes") {
|
||||
$fields{$field} = shift @row;
|
||||
if ($fields{$field}) {
|
||||
$self->{$field} = $fields{$field};
|
||||
}
|
||||
$count++;
|
||||
if (@row = &::FetchSQLData()) {
|
||||
my $count = 0;
|
||||
my %fields;
|
||||
foreach my $field ("bug_id", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"groupset", "delta_ts", "votes") {
|
||||
$fields{$field} = shift @row;
|
||||
if ($fields{$field}) {
|
||||
$self->{$field} = $fields{$field};
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
} else {
|
||||
&::SendSQL("select groupset from bugs where bug_id = $bug_id");
|
||||
if (@row = &::FetchSQLData()) {
|
||||
$self->{'bug_id'} = $bug_id;
|
||||
$self->{'error'} = "NotPermitted";
|
||||
return $self;
|
||||
} else {
|
||||
$self->{'bug_id'} = $bug_id;
|
||||
$self->{'error'} = "NotFound";
|
||||
return $self;
|
||||
}
|
||||
}
|
||||
|
||||
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
|
||||
@@ -363,14 +375,24 @@ sub XML_Footer {
|
||||
sub UserInGroup {
|
||||
my $self = shift();
|
||||
my ($groupname) = (@_);
|
||||
return &::UserInGroup($self->{'whoid'}, $groupname);
|
||||
if ($self->{'usergroupset'} eq "0") {
|
||||
return 0;
|
||||
}
|
||||
&::ConnectToDatabase();
|
||||
&::SendSQL("select (group_bit & int8($self->{'usergroupset'})) != 0 from groups where name = "
|
||||
. &::SqlQuote($groupname));
|
||||
my $bit = &::FetchOneColumn();
|
||||
if ($bit) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub CanChangeField {
|
||||
my $self = shift();
|
||||
my ($f, $oldvalue, $newvalue) = (@_);
|
||||
my $UserInEditGroup = -1;
|
||||
my $UserInCanConfirmGroup = -1;
|
||||
my $UserInEditGroupSet = -1;
|
||||
my $UserInCanConfirmGroupSet = -1;
|
||||
my $ownerid;
|
||||
my $reporterid;
|
||||
my $qacontactid;
|
||||
@@ -393,10 +415,10 @@ sub CanChangeField {
|
||||
if ($f =~ /^longdesc/) {
|
||||
return 1;
|
||||
}
|
||||
if ($UserInEditGroup < 0) {
|
||||
$UserInEditGroup = UserInGroup($self, "editbugs");
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup($self, "editbugs");
|
||||
}
|
||||
if ($UserInEditGroup) {
|
||||
if ($UserInEditGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
|
||||
@@ -417,10 +439,10 @@ sub CanChangeField {
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($UserInCanConfirmGroup < 0) {
|
||||
$UserInCanConfirmGroup = &::UserInGroup($self->{'whoid'},"canconfirm");
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = &::UserInGroup("canconfirm");
|
||||
}
|
||||
if ($UserInCanConfirmGroup) {
|
||||
if ($UserInCanConfirmGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $self->{'bug_id'}");
|
||||
|
||||
@@ -254,27 +254,20 @@ sub ValidateBugID {
|
||||
# database, and that the user is authorized to access that bug.
|
||||
# We detaint the number here, too
|
||||
|
||||
# Make sure the bug number is a positive integer.
|
||||
# Whitespace can be ignored because the SQL server will ignore it.
|
||||
$_[0] = trim($_[0]); # Allow whitespace arround the number
|
||||
detaint_natural($_[0])
|
||||
|| DisplayError("The bug number is invalid. If you are trying to use " .
|
||||
|| DisplayError("The bug number is invalid. If you are trying to use " .
|
||||
"QuickSearch, you need to enable JavaScript in your " .
|
||||
"browser. To help us fix this limitation, look " .
|
||||
"<a href=\"http://bugzilla.mozilla.org/show_bug.cgi?id=70907\">here</a>.")
|
||||
&& exit;
|
||||
|
||||
# Only assign vars here, because we ahve to detaint the reference so that
|
||||
# it passses taint checks in the caller
|
||||
my ($id, $userid) = @_;
|
||||
my ($id) = @_;
|
||||
|
||||
# Users are authorized to access bugs if they are a member of one of
|
||||
# groups to which the bug is restricted.
|
||||
# A user is also authorized to access a bug if she is the reporter,
|
||||
# assignee, QA contact, or member of the cc: list of the bug and the bug
|
||||
# allows users in those roles to see the bug. The boolean fields
|
||||
# reporter_accessible, assignee_accessible, qacontact_accessible, and
|
||||
# cclist_accessible identify whether or not those roles can see the bug.
|
||||
# Get the values of the usergroupset and userid global variables
|
||||
# and write them to local variables for use within this function,
|
||||
# setting those local variables to the default value of zero if
|
||||
# the global variables are undefined.
|
||||
|
||||
# First check that the bug exists
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $id");
|
||||
@@ -283,13 +276,14 @@ sub ValidateBugID {
|
||||
|| DisplayError("Bug #$id does not exist.")
|
||||
&& exit;
|
||||
|
||||
return if CanSeeBug($id, $userid);
|
||||
my $canseeref = CanSeeBug($id, $::userid, $::usergroupset);
|
||||
return if $canseeref->{$id};
|
||||
|
||||
# The user did not pass any of the authorization tests, which means they
|
||||
# are not authorized to see the bug. Display an error and stop execution.
|
||||
# The error the user sees depends on whether or not they are logged in
|
||||
# (i.e. $::userid contains the user's positive integer ID).
|
||||
if ($userid) {
|
||||
if ($::userid) {
|
||||
DisplayError("You are not authorized to access bug #$id.");
|
||||
} else {
|
||||
DisplayError(
|
||||
@@ -299,6 +293,7 @@ sub ValidateBugID {
|
||||
);
|
||||
}
|
||||
exit;
|
||||
|
||||
}
|
||||
|
||||
sub ValidateComment {
|
||||
@@ -441,14 +436,15 @@ sub PasswordForLogin {
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub quietly_check_login {
|
||||
my ($userid, $loginname, $ok, $disabledtext);
|
||||
$userid = 0;
|
||||
sub quietly_check_login() {
|
||||
$::usergroupset = '0';
|
||||
my $loginok = 0;
|
||||
$::disabledreason = '';
|
||||
$::userid = 0;
|
||||
if (defined $::COOKIE{"Bugzilla_login"} &&
|
||||
defined $::COOKIE{"Bugzilla_logincookie"}) {
|
||||
ConnectToDatabase();
|
||||
SendSQL("SELECT profiles.userid, " .
|
||||
SendSQL("SELECT profiles.userid, profiles.groupset, " .
|
||||
"profiles.login_name, " .
|
||||
"profiles.login_name = " .
|
||||
SqlQuote($::COOKIE{"Bugzilla_login"}) .
|
||||
@@ -460,21 +456,21 @@ sub quietly_check_login {
|
||||
" AND profiles.userid = logincookies.userid");
|
||||
my @row;
|
||||
if (@row = FetchSQLData()) {
|
||||
($userid, $loginname, $ok, $disabledtext) = (@row);
|
||||
my ($userid, $groupset, $loginname, $ok, $disabledtext) = (@row);
|
||||
if ($ok) {
|
||||
if ($disabledtext eq '') {
|
||||
$loginok = 1;
|
||||
$::userid = $userid;
|
||||
$::usergroupset = $groupset;
|
||||
$::COOKIE{"Bugzilla_login"} = $loginname; # Makes sure case
|
||||
# is in
|
||||
# canonical form.
|
||||
# We've just verified that this is ok
|
||||
detaint_natural($::COOKIE{"Bugzilla_logincookie"});
|
||||
} else {
|
||||
$userid = 0;
|
||||
$::disabledreason = $disabledtext;
|
||||
}
|
||||
} else {
|
||||
$userid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# if 'who' is passed in, verify that it's a good value
|
||||
@@ -482,12 +478,13 @@ sub quietly_check_login {
|
||||
my $whoid = DBname_to_id($::FORM{'who'});
|
||||
delete $::FORM{'who'} unless $whoid;
|
||||
}
|
||||
if (!$userid) {
|
||||
if (!$loginok) {
|
||||
delete $::COOKIE{"Bugzilla_login"};
|
||||
}
|
||||
|
||||
$vars->{'user'} = GetUserInfo($userid);
|
||||
return $userid;
|
||||
|
||||
$vars->{'user'} = GetUserInfo($::userid);
|
||||
|
||||
return $loginok;
|
||||
}
|
||||
|
||||
# Populate a hash with information about this user.
|
||||
@@ -503,9 +500,9 @@ sub GetUserInfo {
|
||||
$user{'login'} = $::COOKIE{"Bugzilla_login"};
|
||||
$user{'userid'} = $userid;
|
||||
|
||||
SendSQL("SELECT mybugslink, realname FROM profiles " .
|
||||
SendSQL("SELECT mybugslink, realname, groupset FROM profiles " .
|
||||
"WHERE userid = $userid");
|
||||
($user{'showmybugslink'}, $user{'realname'}) =
|
||||
($user{'showmybugslink'}, $user{'realname'}, $user{'groupset'}) =
|
||||
FetchSQLData();
|
||||
|
||||
SendSQL("SELECT name, query, linkinfooter FROM namedqueries " .
|
||||
@@ -519,12 +516,14 @@ sub GetUserInfo {
|
||||
|
||||
$user{'queries'} = \@queries;
|
||||
|
||||
SendSQL("SELECT groups.name FROM groups, user_group_map " .
|
||||
"WHERE groups.group_id = user_group_map.group_id " .
|
||||
"AND user_group_map.user_id = $userid");
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select name, (bit & $user{'groupset'}) != 0 from groups");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select name, (group_bit & int8($user{'groupset'})) != 0 from groups");
|
||||
}
|
||||
while (MoreSQLData()) {
|
||||
my ($name) = FetchSQLData();
|
||||
$groups{$name} = 1;
|
||||
my ($name, $bit) = FetchSQLData();
|
||||
$groups{$name} = $bit;
|
||||
}
|
||||
|
||||
$user{'groups'} = \%groups;
|
||||
@@ -774,9 +773,9 @@ sub confirm_login {
|
||||
print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
}
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
my $loginok = quietly_check_login();
|
||||
|
||||
if (!$userid) {
|
||||
if ($loginok != 1) {
|
||||
if ($::disabledreason) {
|
||||
my $cookiepath = Param("cookiepath");
|
||||
print "Set-Cookie: Bugzilla_login= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
@@ -898,7 +897,7 @@ Content-type: text/html
|
||||
SendSQL("UPDATE logincookies SET lastused = NULL " .
|
||||
"WHERE cookie = $::COOKIE{'Bugzilla_logincookie'}");
|
||||
}
|
||||
return $userid;
|
||||
return $::userid;
|
||||
}
|
||||
|
||||
sub PutHeader {
|
||||
@@ -930,8 +929,6 @@ sub DisplayError {
|
||||
$template->process("global/user-error.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
RollBack();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -948,9 +945,7 @@ sub ThrowCodeError {
|
||||
print "Content-type: text/html\n\n" if !$vars->{'header_done'};
|
||||
$template->process("global/code-error.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
RollBack();
|
||||
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -1053,27 +1048,17 @@ sub GetBugActivity {
|
||||
if ($::driver eq 'mysql') {
|
||||
$query = "
|
||||
SELECT
|
||||
IFNULL(fielddefs.name, bugs_activity.fieldid),
|
||||
bugs_activity.attach_id,
|
||||
bugs_activity.bug_when, ";
|
||||
|
||||
IFNULL(fielddefs.name, bugs_activity.fieldid), ";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
# $query = "
|
||||
# SELECT
|
||||
# COALESCE(fielddefs.name, chr(bugs_activity.fieldid)),
|
||||
# bugs_activity.attach_id,
|
||||
# TO_CHAR(bugs_activity.bug_when, 'YYYY-MM-DD'), ";
|
||||
$query = "
|
||||
SELECT
|
||||
bugs_activity.fieldid,
|
||||
bugs_activity.attach_id,
|
||||
TO_CHAR(bugs_activity.bug_when, 'YYYY-MM-DD'), ";
|
||||
|
||||
COALESCE(fielddefs.name, chr(bugs_activity.fieldid)), ";
|
||||
}
|
||||
|
||||
$query .= "
|
||||
bugs_activity.removed,
|
||||
bugs_activity.added,
|
||||
bugs_activity.attach_id,
|
||||
bugs_activity.bug_when,
|
||||
bugs_activity.removed, bugs_activity.added,
|
||||
profiles.login_name
|
||||
FROM
|
||||
bugs_activity LEFT JOIN fielddefs ON
|
||||
|
||||
@@ -42,8 +42,9 @@ require "CGI.pl";
|
||||
# Establish a connection to the database backend.
|
||||
ConnectToDatabase();
|
||||
|
||||
# Check whether or not the user is logged in and, if so, set the $userid
|
||||
my $userid = quietly_check_login();
|
||||
# Check whether or not the user is logged in and, if so, set the $::userid
|
||||
# and $::usergroupset variables.
|
||||
quietly_check_login();
|
||||
|
||||
################################################################################
|
||||
# Main Body Execution
|
||||
@@ -63,19 +64,19 @@ if ($action eq "view")
|
||||
}
|
||||
elsif ($action eq "viewall")
|
||||
{
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
ValidateBugID($::FORM{'bugid'});
|
||||
viewall();
|
||||
}
|
||||
elsif ($action eq "enter")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'});
|
||||
enter();
|
||||
}
|
||||
elsif ($action eq "insert")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'});
|
||||
ValidateComment($::FORM{'comment'});
|
||||
validateFilename();
|
||||
validateData();
|
||||
@@ -94,10 +95,7 @@ elsif ($action eq "edit")
|
||||
}
|
||||
elsif ($action eq "update")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
UserInGroup($userid, "editbugs")
|
||||
|| DisplayError("You are not authorized to edit attachments.")
|
||||
&& exit;
|
||||
confirm_login();
|
||||
ValidateComment($::FORM{'comment'});
|
||||
validateID();
|
||||
validateCanEdit($::FORM{'id'});
|
||||
@@ -136,7 +134,7 @@ sub validateID
|
||||
|
||||
# Make sure the user is authorized to access this attachment's bug.
|
||||
my ($bugid) = FetchSQLData();
|
||||
ValidateBugID($bugid, $userid);
|
||||
ValidateBugID($bugid);
|
||||
}
|
||||
|
||||
sub validateCanEdit
|
||||
@@ -147,14 +145,14 @@ sub validateCanEdit
|
||||
# the edit scrren to be displayed to people who aren't logged in.
|
||||
# People not logged in can't actually commit changes, because that code
|
||||
# calls confirm_login, not quietly_check_login, before calling this sub
|
||||
return if $userid == 0;
|
||||
return if $::userid == 0;
|
||||
|
||||
# People in editbugs can edit all attachments
|
||||
return if UserInGroup($userid, "editbugs");
|
||||
return if UserInGroup("editbugs");
|
||||
|
||||
# Bug 97729 - the submitter can edit their attachments
|
||||
SendSQL("SELECT attach_id FROM attachments WHERE " .
|
||||
"attach_id = $attach_id AND submitter_id = $userid");
|
||||
"attach_id = $attach_id AND submitter_id = $::userid");
|
||||
|
||||
FetchSQLData()
|
||||
|| DisplayError("You are not authorised to edit attachment #$attach_id")
|
||||
@@ -430,8 +428,8 @@ sub enter
|
||||
# Retrieve the attachments the user can edit from the database and write
|
||||
# them into an array of hashes where each hash represents one attachment.
|
||||
my $canEdit = "";
|
||||
if (!UserInGroup($userid, "editbugs")) {
|
||||
$canEdit = "AND submitter_id = $userid";
|
||||
if (!UserInGroup("editbugs")) {
|
||||
$canEdit = "AND submitter_id = $::userid";
|
||||
}
|
||||
SendSQL("SELECT attach_id, description
|
||||
FROM attachments
|
||||
@@ -477,10 +475,11 @@ sub insert
|
||||
|
||||
# Insert the attachment into the database.
|
||||
SendSQL("INSERT INTO attachments (bug_id, filename, description, mimetype, ispatch, submitter_id, thedata)
|
||||
VALUES ($::FORM{'bugid'}, $filename, $description, $contenttype, $::FORM{'ispatch'}, $userid, $thedata)");
|
||||
VALUES ($::FORM{'bugid'}, $filename, $description, $contenttype, $::FORM{'ispatch'}, $::userid, $thedata)");
|
||||
|
||||
# Retrieve the ID of the newly created attachment record.
|
||||
my $attachid = CurrId('attachments_attach_id_seq');
|
||||
SendSQL("SELECT LAST_INSERT_ID()");
|
||||
my $attachid = FetchOneColumn();
|
||||
|
||||
# Insert a comment about the new attachment into the database.
|
||||
my $comment = "Created an attachment (id=$attachid)\n$::FORM{'description'}\n";
|
||||
@@ -500,14 +499,14 @@ sub insert
|
||||
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
|
||||
SendSQL("UPDATE attachments SET isobsolete = 1 WHERE attach_id = $attachid");
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($::FORM{'bugid'}, $attachid, $userid, NOW(), $fieldid, '0', '1')");
|
||||
VALUES ($::FORM{'bugid'}, $attachid, $::userid, NOW(), $fieldid, '0', '1')");
|
||||
}
|
||||
|
||||
# Send mail to let people know the attachment has been created. Uses a
|
||||
# special syntax of the "open" and "exec" commands to capture the output of
|
||||
# "processmail", which "system" doesn't allow, without running the command
|
||||
# through a shell, which backticks (``) do.
|
||||
#system ("./processmail", $bugid , $userid);
|
||||
#system ("./processmail", $bugid , $::userid);
|
||||
#my $mailresults = `./processmail $bugid $::userid`;
|
||||
my $mailresults = '';
|
||||
open(PMAIL, "-|") or exec('./processmail', $::FORM{'bugid'}, $::COOKIE{'Bugzilla_login'});
|
||||
@@ -528,7 +527,6 @@ sub insert
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/created.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
|
||||
}
|
||||
|
||||
|
||||
@@ -554,7 +552,7 @@ sub edit
|
||||
# Retrieve a list of status flags that have been set on the attachment.
|
||||
my %statuses;
|
||||
SendSQL("SELECT id, name
|
||||
FROM attachstatuses, attachstatusdefs
|
||||
FROM attachstatuses JOIN attachstatusdefs
|
||||
WHERE attachstatuses.statusid = attachstatusdefs.id
|
||||
AND attach_id = $::FORM{'id'}");
|
||||
while ( my ($id, $name) = FetchSQLData() )
|
||||
@@ -684,23 +682,23 @@ sub update
|
||||
my $quotedolddescription = SqlQuote($olddescription);
|
||||
my $fieldid = GetFieldID('attachments.description');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedolddescription, $quoteddescription)");
|
||||
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedolddescription, $quoteddescription)");
|
||||
}
|
||||
if ($oldcontenttype ne $::FORM{'contenttype'}) {
|
||||
my $quotedoldcontenttype = SqlQuote($oldcontenttype);
|
||||
my $fieldid = GetFieldID('attachments.mimetype');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedoldcontenttype, $quotedcontenttype)");
|
||||
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedoldcontenttype, $quotedcontenttype)");
|
||||
}
|
||||
if ($oldispatch ne $::FORM{'ispatch'}) {
|
||||
my $fieldid = GetFieldID('attachments.ispatch');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $oldispatch, $::FORM{'ispatch'})");
|
||||
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldispatch, $::FORM{'ispatch'})");
|
||||
}
|
||||
if ($oldisobsolete ne $::FORM{'isobsolete'}) {
|
||||
my $fieldid = GetFieldID('attachments.isobsolete');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $oldisobsolete, $::FORM{'isobsolete'})");
|
||||
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldisobsolete, $::FORM{'isobsolete'})");
|
||||
}
|
||||
if ($oldstatuslist ne $newstatuslist) {
|
||||
my ($removed, $added) = DiffStrings($oldstatuslist, $newstatuslist);
|
||||
@@ -708,7 +706,7 @@ sub update
|
||||
my $quotedadded = SqlQuote($added);
|
||||
my $fieldid = GetFieldID('attachstatusdefs.name');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedremoved, $quotedadded)");
|
||||
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $quotedremoved, $quotedadded)");
|
||||
}
|
||||
|
||||
# Unlock all database tables now that we are finished updating the database.
|
||||
@@ -760,7 +758,9 @@ sub update
|
||||
}
|
||||
|
||||
# Get the user's login name since the AppendComment function needs it.
|
||||
my $who = DBID_to_name($userid);
|
||||
my $who = DBID_to_name($::userid);
|
||||
# Mention $::userid again so Perl doesn't give me a warning about it.
|
||||
my $neverused = $::userid;
|
||||
|
||||
# Append the comment to the list of comments in the database.
|
||||
AppendComment($bugid, $who, $wrappedcomment);
|
||||
@@ -771,10 +771,10 @@ sub update
|
||||
# of the "open" and "exec" commands to capture the output of "processmail",
|
||||
# which "system" doesn't allow, without running the command through a shell,
|
||||
# which backticks (``) do.
|
||||
#system ("./processmail", $bugid , $userid);
|
||||
#my $mailresults = `./processmail $bugid $userid`;
|
||||
#system ("./processmail", $bugid , $::userid);
|
||||
#my $mailresults = `./processmail $bugid $::userid`;
|
||||
my $mailresults = '';
|
||||
open(PMAIL, "-|") or exec('./processmail', $bugid, DBID_to_name($userid));
|
||||
open(PMAIL, "-|") or exec('./processmail', $bugid, DBID_to_name($::userid));
|
||||
$mailresults .= $_ while <PMAIL>;
|
||||
close(PMAIL);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ sub show_bug {
|
||||
$vars->{'lsearch'} = \&lsearch,
|
||||
$vars->{'header_done'} = (@_),
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
|
||||
@@ -99,10 +99,12 @@ SELECT
|
||||
if ($::driver eq 'mysql') {
|
||||
$query .= "
|
||||
date_format(creation_ts, '%Y-%m-%d %H:%i'),
|
||||
groupset,
|
||||
delta_ts, ";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$query .= "
|
||||
TO_CHAR(creation_ts, 'YYYY-MM-DD HH24:MI:SS'),
|
||||
groupset,
|
||||
TO_CHAR(delta_ts, 'YYYYMMDDHH24MISS'), ";
|
||||
}
|
||||
|
||||
@@ -131,6 +133,7 @@ GROUP BY
|
||||
qa_contact,
|
||||
status_whiteboard,
|
||||
creation_ts,
|
||||
groupset,
|
||||
delta_ts ";
|
||||
|
||||
SendSQL($query);
|
||||
@@ -142,7 +145,7 @@ GROUP BY
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes")
|
||||
"groupset", "delta_ts", "votes")
|
||||
{
|
||||
$value = shift(@row);
|
||||
$bug{$field} = defined($value) ? $value : "";
|
||||
@@ -165,7 +168,15 @@ GROUP BY
|
||||
next;
|
||||
}
|
||||
|
||||
next if !CanSeeProduct($userid, $product);
|
||||
if (Param("usebuggroupsentry")
|
||||
&& GroupExists($product)
|
||||
&& !UserInGroup($product))
|
||||
{
|
||||
# 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(@prodlist, $product);
|
||||
}
|
||||
@@ -239,49 +250,50 @@ GROUP BY
|
||||
|
||||
# Groups
|
||||
my @groups;
|
||||
my (%buggroups, %usergroups);
|
||||
|
||||
# Find out if this bug is private to any group
|
||||
SendSQL("SELECT group_id FROM bug_group_map WHERE bug_id = $id");
|
||||
while (my $group_id = FetchOneColumn()) {
|
||||
$buggroups{$group_id} = 1;
|
||||
}
|
||||
|
||||
# Get a list of active groups the user is in, subject to the above conditions
|
||||
if ($userid) {
|
||||
# NB - the number of groups is likely to be small - should we just select
|
||||
# everything, and weed manually? OTOH, the number of products is likely
|
||||
# to be small, too. This buggroup stuff needs to be rethought
|
||||
SendSQL("SELECT groups.group_id, groups.isactive " .
|
||||
"FROM user_group_map, " .
|
||||
"groups LEFT JOIN products ON groups.name = products.product " .
|
||||
"WHERE groups.group_id = user_group_map.group_id AND " .
|
||||
"user_group_map.user_id = $userid AND groups.isbuggroup != 0 AND " .
|
||||
"(groups.name = " . SqlQuote($bug{'product'}) . " OR " .
|
||||
"products.product IS NULL)");
|
||||
while (my $group_id = FetchOneColumn()) {
|
||||
$usergroups{$group_id} = 1;
|
||||
if ($::usergroupset ne '0' || $bug{'groupset'} ne '0') {
|
||||
my $bug_groupset = $bug{'groupset'};
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select bit, name, description, (bit & $bug{'groupset'} != 0), " .
|
||||
"(bit & $::usergroupset != 0) from groups where isbuggroup != 0 " .
|
||||
# Include active groups as well as inactive groups to which
|
||||
# the bug already belongs. This way the bug can be removed
|
||||
# from an inactive group but can only be added to active ones.
|
||||
"and ((isactive = 1 or (bit & $bug{'groupset'} != 0)) or " .
|
||||
"(bit & $bug{'groupset'} != 0)) " .
|
||||
"order by description");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select group_bit, name, description, (group_bit & int8($bug{'groupset'}) != 0), " .
|
||||
"(group_bit & int8($::usergroupset) != 0) from groups where isbuggroup != 0 " .
|
||||
# Include active groups as well as inactive groups to which
|
||||
# the bug already belongs. This way the bug can be removed
|
||||
# from an inactive group but can only be added to active ones.
|
||||
"and ((isactive = 1 or (group_bit & int8($bug{'groupset'}) != 0)) or " .
|
||||
"(group_bit & int8($bug{'groupset'}) != 0)) " .
|
||||
"order by description");
|
||||
}
|
||||
|
||||
# Now get information about each group
|
||||
SendSQL("SELECT group_id, name, description " .
|
||||
"FROM groups " .
|
||||
# "WHERE group_id IN (" . join(',', @groups) . ") " .
|
||||
"ORDER BY description");
|
||||
$user{'inallgroups'} = 1;
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($group_id, $name, $description) = FetchSQLData();
|
||||
my ($ison, $ingroup);
|
||||
|
||||
if ($buggroups{$group_id} ||
|
||||
($usergroups{$group_id} && (($name eq $bug{'product'}) ||
|
||||
(!defined $::proddesc{$name}))))
|
||||
my ($bit, $name, $description, $ison, $ingroup) = FetchSQLData();
|
||||
# For product groups, we only want to display the checkbox if either
|
||||
# (1) The bit is already set, or
|
||||
# (2) The user is in the group, but either:
|
||||
# (a) The group is a product group for the current product, or
|
||||
# (b) The group name isn't a product name
|
||||
# This means that all product groups will be skipped, but
|
||||
# non-product bug groups will still be displayed.
|
||||
if($ison ||
|
||||
($ingroup && (($name eq $bug{'product'}) ||
|
||||
(!defined $::proddesc{$name}))))
|
||||
{
|
||||
$user{'inallgroups'} &= $ingroup;
|
||||
|
||||
push (@groups, { "bit" => $group_id,
|
||||
"ison" => $buggroups{$group_id},
|
||||
"ingroup" => $usergroups{$group_id},
|
||||
"description" => $description });
|
||||
push (@groups, { "bit" => $bit,
|
||||
"ison" => $ison,
|
||||
"ingroup" => $ingroup,
|
||||
"description" => $description });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +301,7 @@ GROUP BY
|
||||
# the user to set whether or not the reporter
|
||||
# and cc list can see the bug even if they are not members of all
|
||||
# groups to which the bug is restricted.
|
||||
if (%buggroups) {
|
||||
if ($bug{'groupset'} != 0) {
|
||||
$bug{'inagroup'} = 1;
|
||||
|
||||
# Determine whether or not the bug is always accessible by the
|
||||
@@ -321,8 +333,8 @@ GROUP BY
|
||||
|| $::userid == $bug{'reporter'}
|
||||
|| $::userid == $bug{'qa_contact'}
|
||||
|| $::userid == $bug{'assigned_to'}
|
||||
|| UserInGroup($userid, "editbugs");
|
||||
$user{'canconfirm'} = ($::userid == 0) || UserInGroup($userid, "canconfirm");
|
||||
|| UserInGroup("editbugs");
|
||||
$user{'canconfirm'} = ($::userid == 0) || UserInGroup("canconfirm");
|
||||
|
||||
# Bug states
|
||||
$bug{'isunconfirmed'} = ($bug{'bug_status'} eq $::unconfirmedstate);
|
||||
|
||||
@@ -56,6 +56,7 @@ sub sillyness {
|
||||
$zz = @::settable_resolution;
|
||||
$zz = @::target_milestone;
|
||||
$zz = $::unconfirmedstate;
|
||||
$zz = $::userid;
|
||||
$zz = @::versions;
|
||||
};
|
||||
|
||||
@@ -136,10 +137,9 @@ if ($::FORM{'cmdtype'} eq 'runnamed') {
|
||||
$filename =~ s/\s//;
|
||||
}
|
||||
|
||||
my $userid = 0;
|
||||
if ($dotweak) {
|
||||
$userid = confirm_login();
|
||||
if (!UserInGroup($userid, "editbugs")) {
|
||||
confirm_login();
|
||||
if (!UserInGroup("editbugs")) {
|
||||
DisplayError("Sorry, you do not have sufficient privileges to edit
|
||||
multiple bugs.");
|
||||
exit;
|
||||
@@ -147,7 +147,7 @@ if ($dotweak) {
|
||||
GetVersionTable();
|
||||
}
|
||||
else {
|
||||
$userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
}
|
||||
|
||||
|
||||
@@ -251,17 +251,25 @@ sub GetQuip {
|
||||
}
|
||||
|
||||
sub GetGroupsByGroupSet {
|
||||
my ($userid) = @_;
|
||||
my ($groupset) = @_;
|
||||
|
||||
return if !$userid;
|
||||
return if !$groupset;
|
||||
|
||||
SendSQL("
|
||||
SELECT groups.group_id, groups.name, groups.description, groups.isactive
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("
|
||||
SELECT bit, name, description, isactive
|
||||
FROM groups
|
||||
LEFT JOIN user_group_map ON groups.group_id = user_group_map.group_id
|
||||
WHERE groups.isbuggroup != 0
|
||||
AND user_group_map.user_id = $userid
|
||||
ORDER BY description ");
|
||||
WHERE (bit & $groupset) != 0
|
||||
AND isbuggroup != 0
|
||||
ORDER BY description ");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("
|
||||
SELECT group_bit, name, description, isactive
|
||||
FROM groups
|
||||
WHERE (group_bit & int8($groupset)) != 0
|
||||
AND isbuggroup != 0
|
||||
ORDER BY description ");
|
||||
}
|
||||
|
||||
my @groups;
|
||||
|
||||
@@ -296,8 +304,6 @@ sub GenerateSQL {
|
||||
my @specialchart;
|
||||
my @andlist;
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
|
||||
# First, deal with all the old hard-coded non-chart-based poop.
|
||||
|
||||
# unshift(@supptables,
|
||||
@@ -348,7 +354,7 @@ sub GenerateSQL {
|
||||
my @legal_fields = ("product", "version", "rep_platform", "op_sys",
|
||||
"bug_status", "resolution", "priority", "bug_severity",
|
||||
"assigned_to", "reporter", "component",
|
||||
"target_milestone");
|
||||
"target_milestone", "groupset");
|
||||
|
||||
foreach my $field (keys %F) {
|
||||
if (lsearch(\@legal_fields, $field) != -1) {
|
||||
@@ -642,11 +648,7 @@ sub GenerateSQL {
|
||||
}
|
||||
},
|
||||
"^changedin," => sub {
|
||||
if ($::driver eq 'mysql') {
|
||||
$f = "(to_days(now()) - to_days(bugs.delta_ts))";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$f = "(now() - bugs.delta_ts)";
|
||||
}
|
||||
$f = "(to_days(now()) - to_days(bugs.delta_ts))";
|
||||
},
|
||||
|
||||
"^keywords," => sub {
|
||||
@@ -1207,6 +1209,7 @@ sub DefineColumn {
|
||||
|
||||
# Column: ID Name Title
|
||||
DefineColumn("id" , "bugs.bug_id" , "ID" );
|
||||
DefineColumn("groupset" , "bugs.groupset" , "Groupset" );
|
||||
if ($::driver eq 'mysql') {
|
||||
DefineColumn("opendate", "unix_timestamp(bugs.creation_ts)", "Opened",
|
||||
"bugs.creation_ts");
|
||||
@@ -1273,6 +1276,9 @@ else {
|
||||
# and are hard-coded into the display templates.
|
||||
@displaycolumns = grep($_ ne 'id', @displaycolumns);
|
||||
|
||||
# IMPORTANT! Never allow the groupset column to be displayed!
|
||||
@displaycolumns = grep($_ ne 'groupset', @displaycolumns);
|
||||
|
||||
# Add the votes column to the list of columns to be displayed
|
||||
# in the bug list if the user is searching for bugs with a certain
|
||||
# number of votes and the votes column is not already on the list.
|
||||
@@ -1294,10 +1300,11 @@ if (trim($::FORM{'votes'}) && !grep($_ eq 'votes', @displaycolumns)) {
|
||||
|
||||
# Generate the list of columns that will be selected in the SQL query.
|
||||
|
||||
# The bug ID is always selected because bug IDs are always
|
||||
# displayed
|
||||
my @selectcolumns = ("id");
|
||||
my @groupbylist = ("id");
|
||||
# The bug ID and groupset are always selected because bug IDs are always
|
||||
# displayed and we need the groupset to determine whether or not the bug
|
||||
# is visible to the user.
|
||||
my @selectcolumns = ("id", "groupset");
|
||||
my @groupbylist = ("id", "groupset");
|
||||
|
||||
# Display columns are selected because otherwise we could not display them.
|
||||
push (@selectcolumns, @displaycolumns);
|
||||
@@ -1325,6 +1332,7 @@ my @groupbynames = map($columns->{$_}->{'name'}, @groupbylist);
|
||||
# Generate the basic SQL query that will be used to generate the bug list.
|
||||
my $query = GenerateSQL(\@selectnames, $::buffer, \@groupbynames);
|
||||
|
||||
|
||||
################################################################################
|
||||
# Sort Order Determination
|
||||
################################################################################
|
||||
@@ -1439,6 +1447,7 @@ $::SIG{PIPE} = 'DEFAULT';
|
||||
# Execute the query.
|
||||
SendSQL($query);
|
||||
|
||||
|
||||
################################################################################
|
||||
# Results Retrieval
|
||||
################################################################################
|
||||
@@ -1449,8 +1458,6 @@ SendSQL($query);
|
||||
my $bugowners = {};
|
||||
my $bugproducts = {};
|
||||
my $bugstatuses = {};
|
||||
my @buglist = ();
|
||||
my @canseebugs = ();
|
||||
|
||||
my @bugs; # the list of records
|
||||
|
||||
@@ -1475,18 +1482,20 @@ while (my @row = FetchSQLData()) {
|
||||
$bugproducts->{$bug->{'product'}} = 1 if $bug->{'product'};
|
||||
$bugstatuses->{$bug->{'status'}} = 1 if $bug->{'status'};
|
||||
|
||||
# Keep list of bugs so we can check them later for permission
|
||||
push(@buglist, $bug->{id});
|
||||
|
||||
# Add the record to the list.
|
||||
push(@bugs, $bug);
|
||||
}
|
||||
|
||||
# Check to see which bugs we have permission to see
|
||||
my $canseeref = CanSeeBug(\@buglist, $userid);
|
||||
# Fix the list of bugs depending on which ones we are allowed to see
|
||||
my @buglist = ();
|
||||
my @canseebugs = ();
|
||||
foreach my $bug (@bugs) {
|
||||
# next if !$canseeref->{$bug->{id}};
|
||||
push(@canseebugs, $bug);
|
||||
push(@buglist, $bug->{id});
|
||||
}
|
||||
my $canseeref = CanSeeBug(\@buglist, $::userid, $::usergroupset);
|
||||
foreach my $bug (@bugs) {
|
||||
next if !$canseeref->{$bug->{id}};
|
||||
push (@canseebugs, $bug);
|
||||
}
|
||||
|
||||
# Switch back from the shadow database to the regular database so PutFooter()
|
||||
@@ -1500,8 +1509,8 @@ SendSQL("USE $::db_name") if $::driver eq 'mysql';
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
|
||||
$vars->{'bugs'} = \@bugs;
|
||||
$vars->{'buglist'} = join(',', map($_->{id}, @bugs));
|
||||
$vars->{'bugs'} = \@canseebugs;
|
||||
$vars->{'buglist'} = join(',', map($_->{id}, @canseebugs));
|
||||
$vars->{'columns'} = $columns;
|
||||
$vars->{'displaycolumns'} = \@displaycolumns;
|
||||
|
||||
@@ -1523,7 +1532,8 @@ $vars->{'order'} = $order;
|
||||
# The user's login account name (i.e. email address).
|
||||
my $login = $::COOKIE{'Bugzilla_login'};
|
||||
|
||||
$vars->{'caneditbugs'} = UserInGroup($userid, 'editbugs');
|
||||
$vars->{'caneditbugs'} = UserInGroup('editbugs');
|
||||
$vars->{'usebuggroups'} = Param('usebuggroups');
|
||||
|
||||
# Whether or not this user is authorized to move bugs to another installation.
|
||||
$vars->{'ismover'} = 1
|
||||
@@ -1532,7 +1542,7 @@ $vars->{'ismover'} = 1
|
||||
&& Param('movers') =~ /^(\Q$login\E[,\s])|([,\s]\Q$login\E[,\s]+)/;
|
||||
|
||||
my @bugowners = keys %$bugowners;
|
||||
if (scalar(@bugowners) > 1 && UserInGroup($userid, 'editbugs')) {
|
||||
if (scalar(@bugowners) > 1 && UserInGroup('editbugs')) {
|
||||
my $suffix = Param('emailsuffix');
|
||||
map(s/$/$suffix/, @bugowners) if $suffix;
|
||||
my $bugowners = join(",", @bugowners);
|
||||
@@ -1570,7 +1580,7 @@ if ($dotweak) {
|
||||
$vars->{'bugstatuses'} = [ keys %$bugstatuses ];
|
||||
|
||||
# The groups to which the user belongs.
|
||||
$vars->{'groups'} = GetGroupsByGroupSet($userid) if $userid ne '0';
|
||||
$vars->{'groups'} = GetGroupsByGroupSet($::usergroupset) if $::usergroupset ne '0';
|
||||
|
||||
# If all bugs being changed are in the same product, the user can change
|
||||
# their version and component, so generate a list of products, a list of
|
||||
@@ -1584,6 +1594,11 @@ if ($dotweak) {
|
||||
$vars->{'targetmilestones'} = $::target_milestone{$product} if Param('usetargetmilestone');
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "Content-Type: $format->{'contenttype'}\n";
|
||||
}
|
||||
|
||||
print "\n"; # end HTTP headers
|
||||
|
||||
################################################################################
|
||||
# HTTP Header Generation
|
||||
@@ -1607,7 +1622,7 @@ if ($format->{'extension'} eq "html") {
|
||||
my $qorder = url_quote($order);
|
||||
print "Set-Cookie: LASTORDER=$qorder ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
}
|
||||
my $bugids = join(":", map( $_->{'id'}, @bugs));
|
||||
my $bugids = join(":", map( $_->{'id'}, @canseebugs));
|
||||
# See also Bug 111999
|
||||
if (length($bugids) < 4000) {
|
||||
print "Set-Cookie: BUGLIST=$bugids ; path=$cookiepath; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
@@ -1638,4 +1653,3 @@ $template->process("list/$format->{'template'}", $vars)
|
||||
################################################################################
|
||||
|
||||
print "\n--thisrandomstring--\n" if $serverpush;
|
||||
|
||||
|
||||
@@ -174,50 +174,20 @@ sub have_vers {
|
||||
}
|
||||
|
||||
# Check versions of dependencies. 0 for version = any version acceptible
|
||||
my $modules = [
|
||||
{
|
||||
name => 'AppConfig',
|
||||
version => '1.52'
|
||||
},
|
||||
{
|
||||
name => 'CGI::Carp',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'Data::Dumper',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'Date::Parse',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'DBI',
|
||||
version => '1.13'
|
||||
},
|
||||
{
|
||||
name => 'DBD::mysql',
|
||||
version => '1.2209'
|
||||
},
|
||||
{
|
||||
name => 'File::Spec',
|
||||
version => '0.82'
|
||||
},
|
||||
{
|
||||
name => 'Template',
|
||||
version => '2.07'
|
||||
},
|
||||
{
|
||||
name => 'Text::Wrap',
|
||||
version => '2001.0131'
|
||||
}
|
||||
];
|
||||
my %modules = (
|
||||
"DBI" => "1.13",
|
||||
"Data::Dumper" => "0",
|
||||
"DBD::mysql" => "1.2209",
|
||||
"Date::Parse" => "0",
|
||||
"AppConfig" => "1.52",
|
||||
"Template" => "2.07",
|
||||
"Text::Wrap" => "2001.0131",
|
||||
"File::Spec" => "0.82"
|
||||
);
|
||||
|
||||
my %missing = ();
|
||||
foreach my $module (@{$modules}) {
|
||||
unless (have_vers($module->{name}, $module->{version})) {
|
||||
$missing{$module->{name}} = $module->{version};
|
||||
}
|
||||
foreach my $module (keys %modules) {
|
||||
unless (have_vers($module, $modules{$module})) { $missing{$module} = $modules{$module} }
|
||||
}
|
||||
|
||||
# If CGI::Carp was loaded successfully for version checking, it changes the
|
||||
@@ -398,11 +368,12 @@ LocalVar('webservergroup', '
|
||||
$webservergroup = "nobody";
|
||||
');
|
||||
|
||||
|
||||
|
||||
LocalVar('db_host', '
|
||||
#
|
||||
# How to access the SQL database:
|
||||
#
|
||||
$db_driver = "mysql"; # Which database we are using
|
||||
$db_host = "localhost"; # where is the database?
|
||||
$db_port = 3306; # which port to use
|
||||
$db_name = "bugs"; # name of the MySQL database
|
||||
@@ -1291,6 +1262,7 @@ $table{attachstatusdefs} =
|
||||
#
|
||||
$table{bugs} =
|
||||
'bug_id mediumint not null auto_increment primary key,
|
||||
groupset bigint not null,
|
||||
assigned_to mediumint not null, # This is a comment.
|
||||
bug_file_loc text,
|
||||
bug_severity enum($my_severities) not null,
|
||||
@@ -1377,6 +1349,13 @@ $table{dependencies} =
|
||||
index(dependson)';
|
||||
|
||||
|
||||
# Group bits must be a power of two. Groups are identified by a bit; sets of
|
||||
# groups are indicated by or-ing these values together.
|
||||
#
|
||||
# isbuggroup is nonzero if this is a group that controls access to a set
|
||||
# of bugs. In otherword, the groupset field in the bugs table should only
|
||||
# have this group's bit set if isbuggroup is nonzero.
|
||||
#
|
||||
# User regexp is which email addresses are initially put into this group.
|
||||
# This is only used when an email account is created; otherwise, profiles
|
||||
# may be individually tweaked to add them in and out of groups.
|
||||
@@ -1389,14 +1368,14 @@ $table{dependencies} =
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=75482
|
||||
|
||||
$table{groups} =
|
||||
'group_id mediumint not null auto_increment primary key,
|
||||
'bit bigint not null,
|
||||
name varchar(255) not null,
|
||||
description text not null,
|
||||
isbuggroup tinyint not null,
|
||||
userregexp tinytext not null,
|
||||
isactive tinyint not null default 1,
|
||||
|
||||
unique(group_id),
|
||||
unique(bit),
|
||||
unique(name)';
|
||||
|
||||
$table{logincookies} =
|
||||
@@ -1409,8 +1388,7 @@ $table{logincookies} =
|
||||
|
||||
|
||||
$table{products} =
|
||||
'product_id mediumint primary key auto_increment not null,
|
||||
product varchar(64),
|
||||
'product varchar(64),
|
||||
description mediumtext,
|
||||
milestoneurl tinytext not null,
|
||||
disallownew tinyint not null,
|
||||
@@ -1426,10 +1404,12 @@ $table{profiles} =
|
||||
login_name varchar(255) not null,
|
||||
cryptpassword varchar(34),
|
||||
realname varchar(255),
|
||||
groupset bigint not null,
|
||||
disabledtext mediumtext not null,
|
||||
mybugslink tinyint not null default 1,
|
||||
blessgroupset bigint not null default 0,
|
||||
emailflags mediumtext,
|
||||
admin tinyint not null default 0,
|
||||
|
||||
|
||||
unique(login_name)';
|
||||
|
||||
@@ -1535,39 +1515,7 @@ $table{tokens} =
|
||||
|
||||
index(userid)';
|
||||
|
||||
# 2001-09-18, dkl@redhat.com
|
||||
# Group tables for tracking group memberships, admin memberships,
|
||||
# product permissions, and bug permissions.
|
||||
#
|
||||
# This table determines the groups that a user belongs to
|
||||
# and the level that they can bless others to.
|
||||
# canbless:
|
||||
# 0 = Cannot bless others into the group
|
||||
# 1 = Can bless others into the group
|
||||
# 2 = Can give others permission to bless people into the group
|
||||
$table{user_group_map} =
|
||||
'user_id mediumint not null,
|
||||
group_id mediumint not null,
|
||||
canbless smallint default 0,
|
||||
|
||||
unique(user_id, group_id),
|
||||
index(group_id)';
|
||||
|
||||
# This table determines which groups have permission to see a bug
|
||||
$table{bug_group_map} =
|
||||
'bug_id mediumint not null,
|
||||
group_id mediumint not null,
|
||||
|
||||
unique(bug_id, group_id),
|
||||
index(group_id)';
|
||||
|
||||
# This table determines which groups may report bugs against a product
|
||||
$table{product_group_map} =
|
||||
'product_id mediumint not null,
|
||||
group_id mediumint not null,
|
||||
|
||||
unique(product_id, group_id),
|
||||
index(group_id)';
|
||||
|
||||
###########################################################################
|
||||
# Create tables
|
||||
@@ -1609,24 +1557,6 @@ while (my ($tabname, $fielddef) = each %table) {
|
||||
# Populate groups table
|
||||
###########################################################################
|
||||
|
||||
# We need to add a couple of columns first if this is our first time
|
||||
# using the new group schema and populate the group ids
|
||||
# 2002/01/23 dkl@redhat.com
|
||||
if (&GetFieldDef('groups', 'bit')) {
|
||||
&AddField('groups', 'group_id', 'mediumint primary key auto_increment not null');
|
||||
&AddField('profiles', 'admin', 'smallint default 0');
|
||||
my $currentgroupid = 1;
|
||||
my $query = "select bit from groups order by bit";
|
||||
my $sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
while (my ($bit) = $sth->fetchrow_array()) {
|
||||
my $query = "update groups set group_id = $currentgroupid where bit = $bit";
|
||||
my $sth2 = $dbh->prepare($query);
|
||||
$sth2->execute();
|
||||
$currentgroupid++;
|
||||
}
|
||||
}
|
||||
|
||||
sub GroupDoesExist ($)
|
||||
{
|
||||
my ($name) = @_;
|
||||
@@ -1641,7 +1571,7 @@ sub GroupDoesExist ($)
|
||||
|
||||
#
|
||||
# This subroutine checks if a group exist. If not, it will be automatically
|
||||
# created with the next available groupid
|
||||
# created with the next available bit set
|
||||
#
|
||||
|
||||
sub AddGroup {
|
||||
@@ -1650,17 +1580,26 @@ sub AddGroup {
|
||||
|
||||
return if GroupDoesExist($name);
|
||||
|
||||
# get highest bit number
|
||||
my $sth = $dbh->prepare("SELECT bit FROM groups ORDER BY bit DESC");
|
||||
$sth->execute;
|
||||
my @row = $sth->fetchrow_array;
|
||||
|
||||
# normalize bits
|
||||
my $bit;
|
||||
if (defined $row[0]) {
|
||||
$bit = $row[0] << 1;
|
||||
} else {
|
||||
$bit = 1;
|
||||
}
|
||||
|
||||
|
||||
print "Adding group $name ...\n";
|
||||
my $sth = $dbh->prepare('INSERT INTO groups
|
||||
(name, description, userregexp, isbuggroup)
|
||||
VALUES (?, ?, ?, ?)');
|
||||
$sth->execute($name, $desc, $userregexp, 0);
|
||||
|
||||
$sth = $dbh->prepare("select last_insert_id()");
|
||||
$sth->execute();
|
||||
my ($last) = $sth->fetchrow_array();
|
||||
|
||||
return $last;
|
||||
$sth = $dbh->prepare('INSERT INTO groups
|
||||
(bit, name, description, userregexp, isbuggroup)
|
||||
VALUES (?, ?, ?, ?, ?)');
|
||||
$sth->execute($bit, $name, $desc, $userregexp, 0);
|
||||
return $bit;
|
||||
}
|
||||
|
||||
|
||||
@@ -1674,27 +1613,24 @@ AddGroup 'creategroups', 'Can create and destroy groups.';
|
||||
AddGroup 'editcomponents', 'Can create, destroy, and edit components.';
|
||||
AddGroup 'editkeywords', 'Can create, destroy, and edit keywords.';
|
||||
|
||||
# Add the groupset field here because this code is run before the
|
||||
# code that updates the database structure.
|
||||
&AddField('profiles', 'groupset', 'bigint not null');
|
||||
|
||||
if (!GroupDoesExist("editbugs")) {
|
||||
my $id = AddGroup('editbugs', 'Can edit all aspects of any bug.', ".*");
|
||||
my $sth = $dbh->prepare("SELECT userid FROM profiles ORDER BY userid");
|
||||
$sth->execute();
|
||||
while ( my ($userid) = $sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $id)");
|
||||
}
|
||||
$dbh->do("UPDATE profiles SET groupset = groupset | $id");
|
||||
}
|
||||
|
||||
if (!GroupDoesExist("canconfirm")) {
|
||||
my $id = AddGroup('canconfirm', 'Can confirm a bug.', ".*");
|
||||
my $sth = $dbh->prepare("SELECT userid FROM profiles ORDER BY userid");
|
||||
$sth->execute();
|
||||
while ( my ($userid) = $sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $id)");
|
||||
}
|
||||
$dbh->do("UPDATE profiles SET groupset = groupset | $id");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Populate the list of fields.
|
||||
###########################################################################
|
||||
@@ -1877,25 +1813,17 @@ CheckEnumField('bugs', 'rep_platform', @my_platforms);
|
||||
# Prompt the user for the email address and name of an administrator. Create
|
||||
# that login, if it doesn't exist already, and make it a member of all groups.
|
||||
|
||||
my @groups = ();
|
||||
my $sth = $dbh->prepare("select group_id from groups");
|
||||
$sth->execute();
|
||||
while ( my @row = $sth->fetchrow_array() ) {
|
||||
push (@groups, $row[0]);
|
||||
}
|
||||
|
||||
sub bailout { # this is just in case we get interrupted while getting passwd
|
||||
system("stty","echo"); # re-enable input echoing
|
||||
exit 1;
|
||||
}
|
||||
|
||||
$sth = $dbh->prepare(<<_End_Of_SQL_);
|
||||
SELECT login_name
|
||||
my $sth = $dbh->prepare(<<_End_Of_SQL_);
|
||||
SELECT login_name
|
||||
FROM profiles
|
||||
WHERE admin = 1
|
||||
WHERE groupset=9223372036854775807
|
||||
_End_Of_SQL_
|
||||
$sth->execute;
|
||||
|
||||
# when we have no admin users, prompt for admin email address and password ...
|
||||
if ($sth->rows == 0) {
|
||||
my $login = "";
|
||||
@@ -2028,52 +1956,15 @@ _End_Of_SQL_
|
||||
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
INSERT INTO profiles
|
||||
(login_name, realname, cryptpassword, admin)
|
||||
VALUES ($login, $realname, $cryptedpassword, 1)
|
||||
(login_name, realname, cryptpassword, groupset)
|
||||
VALUES ($login, $realname, $cryptedpassword, 0x7fffffffffffffff)
|
||||
_End_Of_SQL_
|
||||
|
||||
# Put the admin in each group if not already
|
||||
my $query = "select userid from profiles where login_name = $login";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
my ($userid) = $sth->fetchrow_array();
|
||||
|
||||
foreach my $group ( @groups ) {
|
||||
my $query = "SELECT user_id FROM user_group_map WHERE group_id = $group AND user_id = $userid";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
if ( !$sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $group, 1)");
|
||||
} else {
|
||||
$dbh->do("UPDATE user_group_map SET canbless = 1 WHERE user_id = $userid AND group_id = $group");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
UPDATE profiles
|
||||
SET admin=1
|
||||
SET groupset=0x7fffffffffffffff
|
||||
WHERE login_name=$login
|
||||
_End_Of_SQL_
|
||||
|
||||
# Put the admin in each group if not already
|
||||
my $query = "SELECT userid FROM profiles WHERE login_name = $login";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
my ($userid) = $sth->fetchrow_array();
|
||||
|
||||
foreach my $group ( @groups ) {
|
||||
my $query = "SELECT user_id FROM user_group_map WHERE group_id = $group AND user_id = $userid";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
if ( !$sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $group, 1)");
|
||||
} else {
|
||||
$dbh->do("UPDATE user_group_map SET canbless = 1 WHERE user_id = $userid AND group_id = $group");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n$login is now set up as the administrator account.\n";
|
||||
}
|
||||
@@ -2088,7 +1979,7 @@ _End_Of_SQL_
|
||||
$sth = $dbh->prepare(<<_End_Of_SQL_);
|
||||
SELECT userid
|
||||
FROM profiles
|
||||
WHERE admin=1
|
||||
WHERE groupset=9223372036854775807
|
||||
_End_Of_SQL_
|
||||
$sth->execute;
|
||||
my ($adminuid) = $sth->fetchrow_array;
|
||||
@@ -2215,6 +2106,7 @@ sub TableExists ($)
|
||||
# but aren't in very old bugzilla's (like 2.1)
|
||||
# Steve Stock (sstock@iconnect-inc.com)
|
||||
AddField('bugs', 'target_milestone', 'varchar(20) not null default "---"');
|
||||
AddField('bugs', 'groupset', 'bigint not null');
|
||||
AddField('bugs', 'qa_contact', 'mediumint not null');
|
||||
AddField('bugs', 'status_whiteboard', 'mediumtext not null');
|
||||
AddField('products', 'disallownew', 'tinyint not null');
|
||||
@@ -2512,7 +2404,7 @@ if (!GetFieldDef('bugs', 'lastdiffed')) {
|
||||
# in my database. This code detects that, cleans up the duplicates, and
|
||||
# then tweaks the table to declare the field to be unique. What a pain.
|
||||
|
||||
if (GetIndexDef('profiles', 'login_name')) {
|
||||
if (GetIndexDef('profiles', 'login_name')->[1]) {
|
||||
print "Searching for duplicate entries in the profiles table ...\n";
|
||||
while (1) {
|
||||
# This code is weird in that it loops around and keeps doing this
|
||||
@@ -2645,6 +2537,7 @@ if (!GetFieldDef('bugs', 'everconfirmed')) {
|
||||
}
|
||||
AddField('products', 'maxvotesperbug', 'smallint not null default 10000');
|
||||
AddField('products', 'votestoconfirm', 'smallint not null');
|
||||
AddField('profiles', 'blessgroupset', 'bigint not null');
|
||||
|
||||
# 2000-03-21 Adding a table for target milestones to
|
||||
# database - matthew@zeroknowledge.com
|
||||
@@ -2972,116 +2865,7 @@ AddField("bugs", "cclist_accessible", "tinyint not null default 1");
|
||||
# using the attachment manager can record changes to attachments.
|
||||
AddField("bugs_activity", "attach_id", "mediumint null");
|
||||
|
||||
# 2002-01-20 dkl@redhat.com 68022
|
||||
# Drop bit, groupset, blessgroupset fields from certain tables after converting
|
||||
# all users and bugs to new group schema
|
||||
if (GetFieldDef('groups', 'bit')) {
|
||||
print "Converting bug database to new group schema format...\n";
|
||||
my $superusergroupset = '9223372036854775807';
|
||||
my %bit_groups = ();
|
||||
my $sth;
|
||||
my $sth2;
|
||||
my $sth3;
|
||||
|
||||
$sth = $dbh->prepare("select bit, group_id from groups order by bit");
|
||||
$sth->execute();
|
||||
while (my ($bit, $groupid) = $sth->fetchrow_array()) {
|
||||
$bit_groups{$bit} = $groupid;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
print "Populating user_group_map and bless_group_map table from users in profiles...\n";
|
||||
foreach my $bit (sort keys %bit_groups) {
|
||||
# Fix profiles table first
|
||||
$sth = $dbh->prepare("select userid from profiles where (groupset & $bit) != 0 order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select user_id from user_group_map where " .
|
||||
"user_id = $userid and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth2->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2 = $dbh->prepare("insert into user_group_map values ($userid, $bit_groups{$bit}, 0)");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
# Next fix bless group privileges
|
||||
$sth = $dbh->prepare("select userid from profiles where blessgroupset & $bit != 0 order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select user_id from user_group_map " .
|
||||
"where user_id = $userid and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2->prepare("update user_group_map set canbless = 1 where user_id = $userid " .
|
||||
"and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
} else {
|
||||
$sth2 = $dbh->prepare("insert into user_group_map values ($userid, $bit_groups{$bit}, 1)");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
# Fix super users by adding 1 to admin column
|
||||
# We shouldn't need to add them to any groups since that would have been done earlier.
|
||||
print "Populating profile's admin column for super users...\n";
|
||||
$sth = $dbh->prepare("select userid from profiles where groupset = $superusergroupset order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
my $sth2 = $dbh->prepare("update profiles set admin = 1 where userid = $userid");
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
# Fix bug groupsets
|
||||
print "Populating bug_group_map table with bugs that are marked private...\n";
|
||||
foreach my $bit (sort keys %bit_groups) {
|
||||
$sth = $dbh->prepare("select bug_id from bugs where (groupset & $bit) != 0 order by bug_id");
|
||||
$sth->execute();
|
||||
while (my ($id) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select bug_id from bug_group_map " .
|
||||
"where bug_id = $id and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2 = $dbh->prepare("insert into bug_group_map values ($id, $bit_groups{$bit})");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
DropField('bugs', 'groupset');
|
||||
DropField('profiles', 'groupset');
|
||||
DropField('profiles', 'blessgroupset');
|
||||
DropField('groups', 'bit');
|
||||
}
|
||||
|
||||
# Added product_group_map table for product privacy
|
||||
# Adding product_id column to products table to allow this to work
|
||||
# 2002/01/24 dkl@redhat.com
|
||||
if (!GetFieldDef('products', 'product_id')) {
|
||||
AddField('products', 'product_id', 'mediumint primary key auto_increment not null');
|
||||
my $sth = $dbh->prepare('select product from products');
|
||||
$sth->execute();
|
||||
my $currproductid = 1;
|
||||
while (my ($name) = $sth->fetchrow_array()) {
|
||||
my $sth2 = $dbh->prepare("update products set product_id = $currproductid where product = " .
|
||||
$dbh->quote($name));
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
# 2001-01-17 bbaetz@student.usyd.edu.au bug 95732
|
||||
# 2002-02-04 bbaetz@student.usyd.edu.au bug 95732
|
||||
# Remove logincookies.cryptpassword, and delete entries which become
|
||||
# invalid
|
||||
if (GetFieldDef("logincookies", "cryptpassword")) {
|
||||
|
||||
@@ -34,38 +34,6 @@ use vars qw(
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# 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,
|
||||
});
|
||||
|
||||
# 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,
|
||||
};
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
|
||||
# The master list not only says what fields are possible, but what order
|
||||
|
||||
@@ -34,9 +34,9 @@ require "globals.pl";
|
||||
|
||||
# Shut up misguided -w warnings about "used only once":
|
||||
use vars qw(
|
||||
%FORM
|
||||
$template
|
||||
$vars
|
||||
%FORM
|
||||
$template
|
||||
$vars
|
||||
);
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
@@ -126,7 +126,7 @@ DefParam("maintainer",
|
||||
'THE MAINTAINER HAS NOT YET BEEN SET');
|
||||
|
||||
DefParam("urlbase",
|
||||
"The URL that is the common initial leading part of all Bugzilla URLs. Must end with a / character.",
|
||||
"The URL that is the common initial leading part of all Bugzilla URLs.",
|
||||
"t",
|
||||
"http://cvs-mirror.mozilla.org/webtools/bugzilla/",
|
||||
\&check_urlbase);
|
||||
@@ -149,11 +149,17 @@ DefParam("usequip",
|
||||
"b",
|
||||
1);
|
||||
|
||||
# Added parameter - dkl, 5/28/02
|
||||
DefParam("usetransactions",
|
||||
"If this is on, Bugzilla will enable transaction support (currently PostgreSQL only).",
|
||||
# Added parameter - JMR, 2/16/00
|
||||
DefParam("usebuggroups",
|
||||
"If this is on, Bugzilla will associate a bug group with each product in the database, and use it for querying bugs.",
|
||||
"b",
|
||||
0);
|
||||
0);
|
||||
|
||||
# Added parameter - JMR, 2/16/00
|
||||
DefParam("usebuggroupsentry",
|
||||
"If this is on, Bugzilla will use product bug groups to restrict who can enter bugs. Requires usebuggroups to be on as well.",
|
||||
"b",
|
||||
0);
|
||||
|
||||
DefParam("shadowdb",
|
||||
"If non-empty, then this is the name of another database in which Bugzilla will keep a shadow read-only copy of everything. This is done so that long slow read-only operations can be used against this db, and not lock up things for everyone else. Turning on this parameter will create the given database; be careful not to use the name of an existing database with useful data in it!",
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
use vars qw(
|
||||
%FORM
|
||||
%proddesc
|
||||
$userid
|
||||
);
|
||||
|
||||
@@ -37,15 +36,21 @@ require "CGI.pl";
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
|
||||
if (!defined $::FORM{'product'}) {
|
||||
# Reference to a subset of %::proddesc, which the user is allowed to see
|
||||
my %products;
|
||||
|
||||
foreach my $p (@::legal_product) {
|
||||
next if !CanSeeProduct($userid, $p);
|
||||
$products{$p} = $::proddesc{$p};
|
||||
if (Param("usebuggroups")) {
|
||||
# OK, now only add products the user can see
|
||||
confirm_login();
|
||||
foreach my $p (@::legal_product) {
|
||||
if (!GroupExists($p) || UserInGroup($p)) {
|
||||
$products{$p} = $::proddesc{$p};
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
%products = %::proddesc;
|
||||
}
|
||||
|
||||
my $prodsize = scalar(keys %products);
|
||||
@@ -67,7 +72,7 @@ if (!defined $::FORM{'product'}) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$::FORM{'product'} = (keys %products)[0];
|
||||
$::FORM{'product'} = (keys %::proddesc)[0];
|
||||
}
|
||||
|
||||
my $product = $::FORM{'product'};
|
||||
@@ -83,9 +88,12 @@ grep($product eq $_ , @::legal_product)
|
||||
&& exit;
|
||||
|
||||
# Make sure the user is authorized to access this product.
|
||||
!CanSeeProduct($userid, $product)
|
||||
&& DisplayError("You are not authorized to access that product.")
|
||||
&& exit;
|
||||
if (Param("usebuggroups") && GroupExists($product) && !$::userid) {
|
||||
confirm_login();
|
||||
UserInGroup($product)
|
||||
|| DisplayError("You are not authorized to access that product.")
|
||||
&& exit;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# End Data/Security Validation
|
||||
|
||||
@@ -32,7 +32,7 @@ use vars qw($vars $template);
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
SendSQL("SELECT keyworddefs.name, keyworddefs.description,
|
||||
COUNT(keywords.bug_id)
|
||||
@@ -51,7 +51,7 @@ while (MoreSQLData()) {
|
||||
}
|
||||
|
||||
$vars->{'keywords'} = \@keywords;
|
||||
$vars->{'caneditkeywords'} = UserInGroup($userid, "editkeywords");
|
||||
$vars->{'caneditkeywords'} = UserInGroup("editkeywords");
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
$template->process("reports/keywords.html.tmpl", $vars)
|
||||
|
||||
306
mozilla/webtools/bugzilla/docs/html/cust-templates.html
Normal file
306
mozilla/webtools/bugzilla/docs/html/cust-templates.html
Normal file
@@ -0,0 +1,306 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Template Customisation</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Administering Bugzilla"
|
||||
HREF="administration.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Bugzilla Security"
|
||||
HREF="security.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Integrating Bugzilla with Third-Party Tools"
|
||||
HREF="integration.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="security.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 5. Administering Bugzilla</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="integration.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="cust-templates">5.7. Template Customisation</H1
|
||||
><P
|
||||
> One of the large changes for 2.16 was the templatisation of the
|
||||
entire user-facing UI, using the
|
||||
<A
|
||||
HREF="http://www.template-toolkit.org"
|
||||
TARGET="_top"
|
||||
>Template Toolkit</A
|
||||
>.
|
||||
Administrators can now configure the look and feel of Bugzilla without
|
||||
having to edit Perl files or face the nightmare of massive merge
|
||||
conflicts when they upgrade to a newer version in the future.
|
||||
</P
|
||||
><P
|
||||
> Templatisation also makes localised versions of Bugzilla possible,
|
||||
for the first time. In the future, a Bugzilla installation may
|
||||
have templates installed for multiple localisations, and select
|
||||
which ones to use based on the user's browser language setting.
|
||||
</P
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN1611">5.7.1. What to Edit</H2
|
||||
><P
|
||||
> There are several ways to take advantage of Bugzilla's templates,
|
||||
and which you use depends on what you want to do. The Bugzilla
|
||||
template directory structure is that there's a top level directory,
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>template</TT
|
||||
>, which contains a directory for
|
||||
each installed localisation. The default English templates are
|
||||
therefore in <TT
|
||||
CLASS="filename"
|
||||
>en</TT
|
||||
>. Underneath that, there
|
||||
are two directories - <TT
|
||||
CLASS="filename"
|
||||
>default</TT
|
||||
> and
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>custom</TT
|
||||
>. The <TT
|
||||
CLASS="filename"
|
||||
>default</TT
|
||||
>
|
||||
directory contains all the templates shipped with Bugzilla.
|
||||
</P
|
||||
><P
|
||||
> One method of making customisations is to directly edit the templates
|
||||
in <TT
|
||||
CLASS="filename"
|
||||
>template/en/default</TT
|
||||
>. This is probably the
|
||||
best method for small changes, because if you then execute a
|
||||
<B
|
||||
CLASS="command"
|
||||
>cvs update</B
|
||||
>, any template fixes will get
|
||||
automagically merged into your modified versions.
|
||||
</P
|
||||
><P
|
||||
> The other method is to copy the templates into
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>template/en/custom</TT
|
||||
>. This method is better if
|
||||
you are going to make major changes, because it is guaranteed that
|
||||
the contents of this directory will not be touched during an upgrade,
|
||||
and you can then decide whether to continue using your own templates,
|
||||
or make the effort to merge your changes into the new versions by
|
||||
hand.
|
||||
</P
|
||||
><P
|
||||
> The syntax of the Template Toolkit language is beyond the scope of
|
||||
this guide. It's reasonably easy to pick up by looking at the current
|
||||
templates; or, you can read the manual, available on the
|
||||
<A
|
||||
HREF="http://www.template-toolkit.org"
|
||||
TARGET="_top"
|
||||
>Template Toolkit home
|
||||
page </A
|
||||
>.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN1626">5.7.2. Particular Templates</H2
|
||||
><P
|
||||
> There are a few templates you may be particularly interested in
|
||||
customising for your installation.
|
||||
</P
|
||||
><P
|
||||
> <B
|
||||
CLASS="command"
|
||||
>global/header.html.tmpl</B
|
||||
> and
|
||||
<B
|
||||
CLASS="command"
|
||||
>global/footer.html.tmpl</B
|
||||
>:
|
||||
These define the header and footer that go on all Bugzilla pages.
|
||||
Editing these is a way to quickly get a distinctive look and
|
||||
feel for your Bugzilla installation.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN1632">5.7.3. Template Formats</H2
|
||||
><P
|
||||
> Some CGIs have the ability to use more than one template. For
|
||||
example, buglist.cgi can output bug lists as RDF or two
|
||||
different forms of HTML (complex and simple). (Try this out
|
||||
by appending <TT
|
||||
CLASS="filename"
|
||||
>&format=simple</TT
|
||||
> to a buglist.cgi
|
||||
URL on your Bugzilla installation.) This
|
||||
mechanism, called template 'formats', is extensible.
|
||||
</P
|
||||
><P
|
||||
> To see if a CGI supports multiple output formats, grep the
|
||||
CGI for "ValidateOutputFormat". If it's not present, adding
|
||||
multiple format support isn't too hard - see how it's done in
|
||||
other CGIs.
|
||||
</P
|
||||
><P
|
||||
> To make a new format template for a CGI which supports this,
|
||||
open a current template for
|
||||
that CGI and take note of the INTERFACE comment (if present.) This
|
||||
comment defines what variables are passed into this template. If
|
||||
there isn't one, I'm afraid you'll have to read the template and
|
||||
the code to find out what information you get.
|
||||
</P
|
||||
><P
|
||||
> Write your template in whatever markup or text style is appropriate.
|
||||
</P
|
||||
><P
|
||||
> You now need to decide what content type you want your template
|
||||
served as. Open up the localconfig file and find the $contenttypes
|
||||
variable. If your content type is not there, add it. Remember
|
||||
the three- or four-letter tag assigned to you content type.
|
||||
This tag will be part of the template filename.
|
||||
</P
|
||||
><P
|
||||
> Save the template as <TT
|
||||
CLASS="filename"
|
||||
><stubname>-<formatname>.<contenttypetag>.tmpl</TT
|
||||
>.
|
||||
Try out the template by calling the CGI as
|
||||
<TT
|
||||
CLASS="filename"
|
||||
><cginame>.cgi?format=<formatname></TT
|
||||
> .
|
||||
</P
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="security.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="integration.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Bugzilla Security</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="administration.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Integrating Bugzilla with Third-Party Tools</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
390
mozilla/webtools/bugzilla/docs/html/extraconfig.html
Normal file
390
mozilla/webtools/bugzilla/docs/html/extraconfig.html
Normal file
@@ -0,0 +1,390 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Optional Additional Configuration</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Installation"
|
||||
HREF="installation.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Step-by-step Install"
|
||||
HREF="stepbystep.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Win32 Installation Notes"
|
||||
HREF="win32.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="stepbystep.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 4. Installation</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="win32.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="extraconfig">4.2. Optional Additional Configuration</H1
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN836">4.2.1. Dependency Charts</H2
|
||||
><P
|
||||
>As well as the text-based dependency graphs, Bugzilla also
|
||||
supports dependency graphing, using a package called 'dot'.
|
||||
Exactly how this works is controlled by the 'webdotbase' parameter.
|
||||
</P
|
||||
><P
|
||||
>(To be written...</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN840">4.2.2. Bug Graphs</H2
|
||||
><P
|
||||
>As long as you installed the GD and Graph::Base Perl modules you
|
||||
might as well turn on the nifty Bugzilla bug reporting graphs.</P
|
||||
><P
|
||||
>Add a cron entry like this to run
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>collectstats.pl</TT
|
||||
>
|
||||
daily at 5 after midnight:
|
||||
<P
|
||||
></P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
><TBODY
|
||||
><TR
|
||||
><TD
|
||||
> <TT
|
||||
CLASS="computeroutput"
|
||||
> <TT
|
||||
CLASS="prompt"
|
||||
>bash#</TT
|
||||
>
|
||||
|
||||
<B
|
||||
CLASS="command"
|
||||
>crontab -e</B
|
||||
>
|
||||
</TT
|
||||
>
|
||||
</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
> <TT
|
||||
CLASS="computeroutput"
|
||||
>5 0 * * * cd <your-bugzilla-directory> ;
|
||||
./collectstats.pl</TT
|
||||
>
|
||||
</TD
|
||||
></TR
|
||||
></TBODY
|
||||
></TABLE
|
||||
><P
|
||||
></P
|
||||
>
|
||||
</P
|
||||
><P
|
||||
>After two days have passed you'll be able to view bug graphs from
|
||||
the Bug Reports page.</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN853">4.2.3. The Whining Cron</H2
|
||||
><P
|
||||
>By now you have a fully functional Bugzilla, but what good are
|
||||
bugs if they're not annoying? To help make those bugs more annoying you
|
||||
can set up Bugzilla's automatic whining system to complain at engineers
|
||||
which leave their bugs in the NEW state without triaging them.
|
||||
</P
|
||||
><P
|
||||
> This can be done by
|
||||
adding the following command as a daily crontab entry (for help on that
|
||||
see that crontab man page):
|
||||
<P
|
||||
></P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
><TBODY
|
||||
><TR
|
||||
><TD
|
||||
> <TT
|
||||
CLASS="computeroutput"
|
||||
> <B
|
||||
CLASS="command"
|
||||
>cd <your-bugzilla-directory> ;
|
||||
./whineatnews.pl</B
|
||||
>
|
||||
</TT
|
||||
>
|
||||
</TD
|
||||
></TR
|
||||
></TBODY
|
||||
></TABLE
|
||||
><P
|
||||
></P
|
||||
>
|
||||
</P
|
||||
><DIV
|
||||
CLASS="tip"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="tip"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/tip.gif"
|
||||
HSPACE="5"
|
||||
ALT="Tip"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>Depending on your system, crontab may have several manpages.
|
||||
The following command should lead you to the most useful page for
|
||||
this purpose:
|
||||
<TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><FONT
|
||||
COLOR="#000000"
|
||||
><PRE
|
||||
CLASS="programlisting"
|
||||
>man 5 crontab</PRE
|
||||
></FONT
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
>
|
||||
</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="bzldap">4.2.4. LDAP Authentication</H2
|
||||
><P
|
||||
> <DIV
|
||||
CLASS="warning"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="warning"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/warning.gif"
|
||||
HSPACE="5"
|
||||
ALT="Warning"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>This information on using the LDAP
|
||||
authentication options with Bugzilla is old, and the authors do
|
||||
not know of anyone who has tested it. Approach with caution.
|
||||
</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
>
|
||||
</P
|
||||
><P
|
||||
> The existing authentication
|
||||
scheme for Bugzilla uses email addresses as the primary user ID, and a
|
||||
password to authenticate that user. All places within Bugzilla where
|
||||
you need to deal with user ID (e.g assigning a bug) use the email
|
||||
address. The LDAP authentication builds on top of this scheme, rather
|
||||
than replacing it. The initial log in is done with a username and
|
||||
password for the LDAP directory. This then fetches the email address
|
||||
from LDAP and authenticates seamlessly in the standard Bugzilla
|
||||
authentication scheme using this email address. If an account for this
|
||||
address already exists in your Bugzilla system, it will log in to that
|
||||
account. If no account for that email address exists, one is created at
|
||||
the time of login. (In this case, Bugzilla will attempt to use the
|
||||
"displayName" or "cn" attribute to determine the user's full name.)
|
||||
After authentication, all other user-related tasks are still handled by
|
||||
email address, not LDAP username. You still assign bugs by email
|
||||
address, query on users by email address, etc.
|
||||
</P
|
||||
><P
|
||||
>Using LDAP for Bugzilla authentication requires the
|
||||
Mozilla::LDAP (aka PerLDAP) Perl module. The
|
||||
Mozilla::LDAP module in turn requires Netscape's Directory SDK for C.
|
||||
After you have installed the SDK, then install the PerLDAP module.
|
||||
Mozilla::LDAP and the Directory SDK for C are both
|
||||
<A
|
||||
HREF="http://www.mozilla.org/directory/"
|
||||
TARGET="_top"
|
||||
>available for
|
||||
download</A
|
||||
> from mozilla.org.
|
||||
</P
|
||||
><P
|
||||
> Set the Param 'useLDAP' to "On" **only** if you will be using an LDAP
|
||||
directory for
|
||||
authentication. Be very careful when setting up this parameter; if you
|
||||
set LDAP authentication, but do not have a valid LDAP directory set up,
|
||||
you will not be able to log back in to Bugzilla once you log out. (If
|
||||
this happens, you can get back in by manually editing the data/params
|
||||
file, and setting useLDAP back to 0.)
|
||||
</P
|
||||
><P
|
||||
>If using LDAP, you must set the
|
||||
three additional parameters: Set LDAPserver to the name (and optionally
|
||||
port) of your LDAP server. If no port is specified, it defaults to the
|
||||
default port of 389. (e.g "ldap.mycompany.com" or
|
||||
"ldap.mycompany.com:1234") Set LDAPBaseDN to the base DN for searching
|
||||
for users in your LDAP directory. (e.g. "ou=People,o=MyCompany") uids
|
||||
must be unique under the DN specified here. Set LDAPmailattribute to
|
||||
the name of the attribute in your LDAP directory which contains the
|
||||
primary email address. On most directory servers available, this is
|
||||
"mail", but you may need to change this.
|
||||
</P
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="stepbystep.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="win32.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Step-by-step Install</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="installation.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Win32 Installation Notes</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
431
mozilla/webtools/bugzilla/docs/html/groups.html
Normal file
431
mozilla/webtools/bugzilla/docs/html/groups.html
Normal file
@@ -0,0 +1,431 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Groups and Group Security</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Administering Bugzilla"
|
||||
HREF="administration.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Voting"
|
||||
HREF="voting.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Bugzilla Security"
|
||||
HREF="security.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="voting.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 5. Administering Bugzilla</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="security.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="groups">5.5. Groups and Group Security</H1
|
||||
><P
|
||||
>Groups can be very useful in bugzilla, because they allow users
|
||||
to isolate bugs or products that should only be seen by certain people.
|
||||
Groups can also be a complicated minefield of interdependencies and
|
||||
weirdness if mismanaged.
|
||||
<DIV
|
||||
CLASS="example"
|
||||
><A
|
||||
NAME="AEN1521"><P
|
||||
><B
|
||||
>Example 5-5. When to Use Group Security</B
|
||||
></P
|
||||
><DIV
|
||||
CLASS="informalexample"
|
||||
><A
|
||||
NAME="AEN1523"><P
|
||||
></P
|
||||
><P
|
||||
>Many Bugzilla sites isolate "Security-related" bugs from all
|
||||
other bugs. This way, they can have a fix ready before the security
|
||||
vulnerability is announced to the world. You can create a
|
||||
"Security" product which, by default, has no members, and only add
|
||||
members to the group (in their individual User page, as described
|
||||
under User Administration) who should have priveleged access to
|
||||
"Security" bugs. Alternately, you may create a Group independently
|
||||
of any Product, and change the Group mask on individual bugs to
|
||||
restrict access to members only of certain Groups.</P
|
||||
><P
|
||||
></P
|
||||
></DIV
|
||||
></DIV
|
||||
>
|
||||
|
||||
Groups only work if you enable the "usebuggroups" paramater. In
|
||||
addition, if the "usebuggroupsentry" parameter is "On", one can
|
||||
restrict access to products by groups, so that only members of a
|
||||
product group are able to view bugs within that product. Group security
|
||||
in Bugzilla can be divided into two categories: Generic and
|
||||
Product-Based.</P
|
||||
><DIV
|
||||
CLASS="note"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="note"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/note.gif"
|
||||
HSPACE="5"
|
||||
ALT="Note"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>Groups in Bugzilla are a complicated beast that evolved out of
|
||||
very simple user permission bitmasks, apparently itself derived from
|
||||
common concepts in UNIX access controls. A "bitmask" is a
|
||||
fixed-length number whose value can describe one, and only one, set
|
||||
of states. For instance, UNIX file permissions are assigned bitmask
|
||||
values: "execute" has a value of 1, "write" has a value of 2, and
|
||||
"read" has a value of 4. Add them together, and a file can be read,
|
||||
written to, and executed if it has a bitmask of "7". (This is a
|
||||
simplified example -- anybody who knows UNIX security knows there is
|
||||
much more to it than this. Please bear with me for the purpose of
|
||||
this note.) The only way a bitmask scheme can work is by doubling the
|
||||
bit count for each value. Thus if UNIX wanted to offer another file
|
||||
permission, the next would have to be a value of 8, then the next 16,
|
||||
the next 32, etc.</P
|
||||
><P
|
||||
>Similarly, Bugzilla offers a bitmask to define group
|
||||
permissions, with an internal limit of 64. Several are already
|
||||
occupied by built-in permissions. The way around this limitation is
|
||||
to avoid assigning groups to products if you have many products,
|
||||
avoid bloating of group lists, and religiously prune irrelevant
|
||||
groups. In reality, most installations of Bugzilla support far fewer
|
||||
than 64 groups, so this limitation has not hit for most sites, but it
|
||||
is on the table to be revised for Bugzilla 3.0 because it interferes
|
||||
with the security schemes of some administrators.</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
><P
|
||||
>To enable Generic Group Security ("usebuggroups"):</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
>Turn "On" "usebuggroups" in the "Edit Parameters"
|
||||
screen.</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>You will generally have no groups set up. Select the "groups"
|
||||
link in the footer.</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Take a moment to understand the instructions on the "Edit
|
||||
Groups" screen. Once you feel confident you understand what is
|
||||
expected of you, select the "Add Group" link.</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Fill out the "New Name" (remember, no spaces!), "New
|
||||
Description", and "New User RegExp" fields. "New User RegExp"
|
||||
allows you to automatically place all users who fulfill the Regular
|
||||
Expression into the new group.
|
||||
<DIV
|
||||
CLASS="example"
|
||||
><A
|
||||
NAME="AEN1538"><P
|
||||
><B
|
||||
>Example 5-6. Creating a New Group</B
|
||||
></P
|
||||
><DIV
|
||||
CLASS="informalexample"
|
||||
><A
|
||||
NAME="AEN1540"><P
|
||||
></P
|
||||
><P
|
||||
>I created a group called DefaultGroup with a description
|
||||
of
|
||||
<SPAN
|
||||
CLASS="QUOTE"
|
||||
>"This is simply a group to play with"</SPAN
|
||||
>
|
||||
|
||||
, and a New User RegExp of
|
||||
<SPAN
|
||||
CLASS="QUOTE"
|
||||
>".*@mydomain.tld"</SPAN
|
||||
>
|
||||
|
||||
. This new group automatically includes all Bugzilla users with
|
||||
"@mydomain.tld" at the end of their user id. When I finished,
|
||||
my new group was assigned bit #128.</P
|
||||
><P
|
||||
></P
|
||||
></DIV
|
||||
></DIV
|
||||
>
|
||||
|
||||
When you have finished, select the Add button.</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
>To enable Product-Based Group Security
|
||||
(usebuggroupsentry):</P
|
||||
><DIV
|
||||
CLASS="warning"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="warning"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/warning.gif"
|
||||
HSPACE="5"
|
||||
ALT="Warning"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>Don't forget that you only have 64 groups masks available,
|
||||
total, for your installation of Bugzilla! If you plan on having more
|
||||
than 50 products in your individual Bugzilla installation, and
|
||||
require group security for your products, you should consider either
|
||||
running multiple Bugzillas or using Generic Group Security instead of
|
||||
Product-Based ("usebuggroupsentry") Group Security.</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
>Turn "On" "usebuggroups" and "usebuggroupsentry" in the "Edit
|
||||
Parameters" screen.</P
|
||||
><DIV
|
||||
CLASS="warning"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="warning"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/warning.gif"
|
||||
HSPACE="5"
|
||||
ALT="Warning"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>"usebuggroupsentry" has the capacity to prevent the
|
||||
administrative user from directly altering bugs because of
|
||||
conflicting group permissions. If you plan on using
|
||||
"usebuggroupsentry", you should plan on restricting
|
||||
administrative account usage to administrative duties only. In
|
||||
other words, manage bugs with an unpriveleged user account, and
|
||||
manage users, groups, Products, etc. with the administrative
|
||||
account.</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>You will generally have no Groups set up, unless you enabled
|
||||
"usebuggroupsentry" prior to creating any Products. To create
|
||||
"Generic Group Security" groups, follow the instructions given
|
||||
above. To create Product-Based Group security, simply follow the
|
||||
instructions for creating a new Product. If you need to add users
|
||||
to these new groups as you create them, you will find the option to
|
||||
add them to the group available under the "Edit User"
|
||||
screens.</P
|
||||
></LI
|
||||
></OL
|
||||
><P
|
||||
>You may find this example illustrative for how bug groups work.
|
||||
<DIV
|
||||
CLASS="example"
|
||||
><A
|
||||
NAME="AEN1555"><P
|
||||
><B
|
||||
>Example 5-7. Bugzilla Groups</B
|
||||
></P
|
||||
><P
|
||||
CLASS="literallayout"
|
||||
>Bugzilla Groups example ----------------------- For<br>
|
||||
this example, let us suppose we have four groups, call them Group1,<br>
|
||||
Group2, Group3, and Group4. We have 5 users, User1, User2, User3,<br>
|
||||
User4, User5. We have 8 bugs, Bug1, ..., Bug8. Group membership is<br>
|
||||
defined by this chart: (X denotes that user is in that group.) (I<br>
|
||||
apologize for the nasty formatting of this table. Try viewing it in a<br>
|
||||
text-based browser or something for now. -MPB) G G G G r r r r o o o<br>
|
||||
o u u u u p p p p 1 2 3 4 +-+-+-+-+ User1|X| | | | +-+-+-+-+ User2|<br>
|
||||
|X| | | +-+-+-+-+ User3|X| |X| | +-+-+-+-+ User4|X|X|X| | +-+-+-+-+<br>
|
||||
User5| | | | | +-+-+-+-+ Bug restrictions are defined by this chart:<br>
|
||||
(X denotes that bug is restricted to that group.) G G G G r r r r o o<br>
|
||||
o o u u u u p p p p 1 2 3 4 +-+-+-+-+ Bug1| | | | | +-+-+-+-+ Bug2|<br>
|
||||
|X| | | +-+-+-+-+ Bug3| | |X| | +-+-+-+-+ Bug4| | | |X| +-+-+-+-+<br>
|
||||
Bug5|X|X| | | +-+-+-+-+ Bug6|X| |X| | +-+-+-+-+ Bug7|X|X|X| |<br>
|
||||
+-+-+-+-+ Bug8|X|X|X|X| +-+-+-+-+ Who can see each bug? Bug1 has no<br>
|
||||
group restrictions. Therefore, Bug1 can be seen by any user, whatever<br>
|
||||
their group membership. This is going to be the only bug that User5<br>
|
||||
can see, because User5 isn't in any groups. Bug2 can be seen by<br>
|
||||
anyone in Group2, that is User2 and User4. Bug3 can be seen by anyone<br>
|
||||
in Group3, that is User3 and User4. Bug4 can be seen by anyone in<br>
|
||||
Group4. Nobody is in Group4, so none of these users can see Bug4.<br>
|
||||
Bug5 can be seen by anyone who is in _both_ Group1 and Group2. This<br>
|
||||
is only User4. User1 cannot see it because he is not in Group2, and<br>
|
||||
User2 cannot see it because she is not in Group1. Bug6 can be seen by<br>
|
||||
anyone who is in both Group1 and Group3. This would include User3 and<br>
|
||||
User4. Similar to Bug5, User1 cannot see Bug6 because he is not in<br>
|
||||
Group3. Bug7 can be seen by anyone who is in Group1, Group2, and<br>
|
||||
Group3. This is only User4. All of the others are missing at least<br>
|
||||
one of those group privileges, and thus cannot see the bug. Bug8 can<br>
|
||||
be seen by anyone who is in Group1, Group2, Group3, and Group4. There<br>
|
||||
is nobody in all four of these groups, so nobody can see Bug8. It<br>
|
||||
doesn't matter that User4 is in Group1, Group2, and Group3, since he<br>
|
||||
isn't in Group4.</P
|
||||
></DIV
|
||||
>
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="voting.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="security.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Voting</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="administration.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Bugzilla Security</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
296
mozilla/webtools/bugzilla/docs/html/hintsandtips.html
Normal file
296
mozilla/webtools/bugzilla/docs/html/hintsandtips.html
Normal file
@@ -0,0 +1,296 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Hints and Tips</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Using Bugzilla"
|
||||
HREF="using.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="How do I use Bugzilla?"
|
||||
HREF="how.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="User Preferences"
|
||||
HREF="userpreferences.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="how.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 3. Using Bugzilla</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="userpreferences.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="hintsandtips">3.2. Hints and Tips</H1
|
||||
><P
|
||||
>This section distills some Bugzilla tips and best practices
|
||||
that have been developed.</P
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN434">3.2.1. Autolinkification</H2
|
||||
><P
|
||||
>Bugzilla comments are plain text - so posting HTML will result
|
||||
in literal HTML tags rather than being interpreted by a browser.
|
||||
However, Bugzilla will automatically make hyperlinks out of certain
|
||||
sorts of text in comments. For example, the text
|
||||
http://www.bugzilla.org will be turned into
|
||||
<A
|
||||
HREF="http://www.bugzilla.org"
|
||||
TARGET="_top"
|
||||
>http://www.bugzilla.org</A
|
||||
>.
|
||||
Other strings which get linkified in the obvious manner are:
|
||||
<P
|
||||
></P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
><TBODY
|
||||
><TR
|
||||
><TD
|
||||
>bug 12345</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
>bug 23456, comment 53</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
>attachment 4321</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
>mailto:george@example.com</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
>ftp://ftp.mozilla.org</TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
>Most other sorts of URL</TD
|
||||
></TR
|
||||
></TBODY
|
||||
></TABLE
|
||||
><P
|
||||
></P
|
||||
>
|
||||
</P
|
||||
><P
|
||||
>A corollary here is that if you type a bug number in a comment,
|
||||
you should put the word "bug" before it, so it gets autolinkified
|
||||
for the convenience of others.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="quicksearch">3.2.2. Quicksearch</H2
|
||||
><P
|
||||
>Quicksearch is a single-text-box query tool which uses
|
||||
metacharacters to indicate what is to be searched. For example, typing
|
||||
"foo|bar" into Quicksearch would search for "foo" or "bar" in the
|
||||
summary and status whiteboard of a bug; adding ":BazProduct" would
|
||||
search only in that product.
|
||||
</P
|
||||
><P
|
||||
>You'll find the Quicksearch box on Bugzilla's
|
||||
front page, along with a
|
||||
<A
|
||||
HREF="../../quicksearch.html"
|
||||
TARGET="_top"
|
||||
>Help</A
|
||||
>
|
||||
link which details how to use it.</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="commenting">3.2.3. Comments</H2
|
||||
><P
|
||||
>If you are changing the fields on a bug, only comment if
|
||||
either you have something pertinent to say, or Bugzilla requires it.
|
||||
Otherwise, you may spam people unnecessarily with bug mail.
|
||||
To take an example: a user sets up their account to filter out messages
|
||||
where someone just adds themselves to the CC field of a bug
|
||||
(which happens a lot.) If you come along, add yourself to the CC field,
|
||||
and add a comment saying "Adding self to CC", then that person
|
||||
gets a pointless piece of mail they would otherwise have avoided.
|
||||
</P
|
||||
><P
|
||||
> Don't use sigs in comments. Signing your name ("Bill") is acceptable,
|
||||
particularly if you do it out of habit, but full mail/news-style
|
||||
four line ASCII art creations are not.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="attachments">3.2.4. Attachments</H2
|
||||
><P
|
||||
> Use attachments, rather than comments, for large chunks of ASCII data,
|
||||
such as trace, debugging output files, or log files. That way, it doesn't
|
||||
bloat the bug for everyone who wants to read it, and cause people to
|
||||
receive fat, useless mails.
|
||||
</P
|
||||
><P
|
||||
>Trim screenshots. There's no need to show the whole screen if
|
||||
you are pointing out a single-pixel problem.
|
||||
</P
|
||||
><P
|
||||
>Don't attach simple test cases (e.g. one html file and one
|
||||
css file and one image) as a ZIP file. Instead, upload them in
|
||||
reverse order and edit the referring file so that they point to the
|
||||
attached files. This way, the test case works immediately
|
||||
out of the bug.
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN460">3.2.5. Filing Bugs</H2
|
||||
><P
|
||||
>Try to make sure that everything said in the summary is also
|
||||
said in the first comment. Summaries are often updated and this will
|
||||
ensure your original information is easily accessible.
|
||||
</P
|
||||
><P
|
||||
> You do not need to put "any" or similar strings in the URL field.
|
||||
If there is no specific URL associated with the bug, leave this
|
||||
field blank.
|
||||
</P
|
||||
><P
|
||||
>If you feel a bug you filed was incorrectly marked as a
|
||||
DUPLICATE of another, please question it in your bug, not
|
||||
the bug it was duped to. Feel free to CC the person who duped it
|
||||
if they are not already CCed.
|
||||
</P
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="how.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="userpreferences.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>How do I use Bugzilla?</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="using.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>User Preferences</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
153
mozilla/webtools/bugzilla/docs/html/introduction.html
Normal file
153
mozilla/webtools/bugzilla/docs/html/introduction.html
Normal file
@@ -0,0 +1,153 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Introduction</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Document Conventions"
|
||||
HREF="conventions.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="What is Bugzilla?"
|
||||
HREF="whatis.html"></HEAD
|
||||
><BODY
|
||||
CLASS="chapter"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="conventions.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="whatis.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="chapter"
|
||||
><H1
|
||||
><A
|
||||
NAME="introduction">Chapter 2. Introduction</H1
|
||||
><DIV
|
||||
CLASS="TOC"
|
||||
><DL
|
||||
><DT
|
||||
><B
|
||||
>Table of Contents</B
|
||||
></DT
|
||||
><DT
|
||||
>2.1. <A
|
||||
HREF="whatis.html"
|
||||
>What is Bugzilla?</A
|
||||
></DT
|
||||
><DT
|
||||
>2.2. <A
|
||||
HREF="why.html"
|
||||
>Why Should We Use Bugzilla?</A
|
||||
></DT
|
||||
></DL
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="conventions.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="whatis.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Document Conventions</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
> </TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>What is Bugzilla?</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
282
mozilla/webtools/bugzilla/docs/html/troubleshooting.html
Normal file
282
mozilla/webtools/bugzilla/docs/html/troubleshooting.html
Normal file
@@ -0,0 +1,282 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Troubleshooting</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Installation"
|
||||
HREF="installation.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="General Installation Notes"
|
||||
HREF="geninstall.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Administering Bugzilla"
|
||||
HREF="administration.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="geninstall.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 4. Installation</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="administration.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="troubleshooting">4.6. Troubleshooting</H1
|
||||
><P
|
||||
>This section gives solutions to common Bugzilla installation
|
||||
problems.
|
||||
</P
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="AEN1208">4.6.1. DBD::Sponge::db prepare failed</H2
|
||||
><P
|
||||
> The following error message may appear due to a bug in DBD::mysql
|
||||
(over which the Bugzilla team have no control):
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><FONT
|
||||
COLOR="#000000"
|
||||
><PRE
|
||||
CLASS="programlisting"
|
||||
> "DBD::Sponge::db prepare failed: Cannot determine NUM_OF_FIELDS at D:/Perl/site/lib/DBD/mysql.pm line 248.
|
||||
SV = NULL(0x0) at 0x20fc444
|
||||
REFCNT = 1
|
||||
FLAGS = (PADBUSY,PADMY)"
|
||||
</PRE
|
||||
></FONT
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> To fix this, go to <path-to-perl>/lib/DBD/sponge.pm in your Perl
|
||||
installation and replace
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><FONT
|
||||
COLOR="#000000"
|
||||
><PRE
|
||||
CLASS="programlisting"
|
||||
> my $numFields;
|
||||
if ($attribs->{'NUM_OF_FIELDS'}) {
|
||||
$numFields = $attribs->{'NUM_OF_FIELDS'};
|
||||
} elsif ($attribs->{'NAME'}) {
|
||||
$numFields = @{$attribs->{NAME}};
|
||||
</PRE
|
||||
></FONT
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> by
|
||||
</P
|
||||
><TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><FONT
|
||||
COLOR="#000000"
|
||||
><PRE
|
||||
CLASS="programlisting"
|
||||
> my $numFields;
|
||||
if ($attribs->{'NUM_OF_FIELDS'}) {
|
||||
$numFields = $attribs->{'NUM_OF_FIELDS'};
|
||||
} elsif ($attribs->{'NAMES'}) {
|
||||
$numFields = @{$attribs->{NAMES}};
|
||||
</PRE
|
||||
></FONT
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><P
|
||||
> (note the S added to NAME.)
|
||||
</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="paranoid-security">4.6.2. cannot chdir(/var/spool/mqueue)</H2
|
||||
><P
|
||||
>If you are installing Bugzilla on SuSE Linux, or some other
|
||||
distributions with
|
||||
<SPAN
|
||||
CLASS="QUOTE"
|
||||
>"paranoid"</SPAN
|
||||
>
|
||||
security options, it is possible that the checksetup.pl script may fail
|
||||
with the error:
|
||||
<TABLE
|
||||
BORDER="0"
|
||||
BGCOLOR="#E0E0E0"
|
||||
WIDTH="100%"
|
||||
><TR
|
||||
><TD
|
||||
><FONT
|
||||
COLOR="#000000"
|
||||
><PRE
|
||||
CLASS="programlisting"
|
||||
>cannot chdir(/var/spool/mqueue): Permission denied
|
||||
</PRE
|
||||
></FONT
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
>
|
||||
</P
|
||||
><P
|
||||
> This is because your
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>/var/spool/mqueue</TT
|
||||
>
|
||||
directory has a mode of
|
||||
<SPAN
|
||||
CLASS="QUOTE"
|
||||
>"drwx------"</SPAN
|
||||
>. Type
|
||||
<B
|
||||
CLASS="command"
|
||||
>chmod 755
|
||||
<TT
|
||||
CLASS="filename"
|
||||
>/var/spool/mqueue</TT
|
||||
>
|
||||
</B
|
||||
>
|
||||
as root to fix this problem.
|
||||
</P
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="geninstall.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="administration.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>General Installation Notes</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="installation.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Administering Bugzilla</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
241
mozilla/webtools/bugzilla/docs/html/userpreferences.html
Normal file
241
mozilla/webtools/bugzilla/docs/html/userpreferences.html
Normal file
@@ -0,0 +1,241 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>User Preferences</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Using Bugzilla"
|
||||
HREF="using.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Hints and Tips"
|
||||
HREF="hintsandtips.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Installation"
|
||||
HREF="installation.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="hintsandtips.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 3. Using Bugzilla</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="installation.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="userpreferences">3.3. User Preferences</H1
|
||||
><P
|
||||
>Once you have logged in, you can customise various aspects of
|
||||
Bugzilla via the "Edit prefs" link in the page footer.
|
||||
The preferences are split into four tabs:</P
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="accountsettings">3.3.1. Account Settings</H2
|
||||
><P
|
||||
>On this tab, you can change your basic account information,
|
||||
including your password, email address and real name. For security
|
||||
reasons, in order to change anything on this page you must type your
|
||||
<EM
|
||||
>current</EM
|
||||
>
|
||||
password into the
|
||||
<SPAN
|
||||
CLASS="QUOTE"
|
||||
>"Password"</SPAN
|
||||
>
|
||||
field at the top of the page.
|
||||
If you attempt to change your email address, a confirmation
|
||||
email is sent to both the old and new addresses, with a link to use to
|
||||
confirm the change. This helps to prevent account hijacking.</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="emailsettings">3.3.2. Email Settings</H2
|
||||
><P
|
||||
>On this tab you can reduce or increase the amount of email sent
|
||||
you from Bugzilla, opting in our out depending on your relationship to
|
||||
the bug and the change that was made to it. (Note that you can also do
|
||||
client-side filtering using the X-Bugzilla-Reason header which Bugzilla
|
||||
adds to all bugmail.)</P
|
||||
><P
|
||||
>By entering user email names, delineated by commas, into the
|
||||
"Users to watch" text entry box you can receive a copy of all the
|
||||
bugmail of other users (security settings permitting.) This powerful
|
||||
functionality enables seamless transitions as developers change
|
||||
projects, managers wish to get in touch with the issues faced by their
|
||||
direct reports, or users go on vacation.</P
|
||||
><DIV
|
||||
CLASS="note"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="note"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/note.gif"
|
||||
HSPACE="5"
|
||||
ALT="Note"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>The ability to watch other users may not be available in all
|
||||
Bugzilla installations. If you can't see it, ask your
|
||||
administrator.</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="footersettings">3.3.3. Page Footer</H2
|
||||
><P
|
||||
>On the Search page, you can store queries in Bugzilla, so if you
|
||||
regularly run a particular query it is just a drop-down menu away.
|
||||
Once you have a stored query, you can come
|
||||
here to request that it also be displayed in your page footer.</P
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H2
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="permissionsettings">3.3.4. Permissions</H2
|
||||
><P
|
||||
>This is a purely informative page which outlines your current
|
||||
permissions on this installation of Bugzilla - what product groups you
|
||||
are in, and whether you can edit bugs or perform various administration
|
||||
functions.</P
|
||||
></DIV
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="hintsandtips.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="installation.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Hints and Tips</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="using.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Installation</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
235
mozilla/webtools/bugzilla/docs/html/voting.html
Normal file
235
mozilla/webtools/bugzilla/docs/html/voting.html
Normal file
@@ -0,0 +1,235 @@
|
||||
<HTML
|
||||
><HEAD
|
||||
><TITLE
|
||||
>Voting</TITLE
|
||||
><META
|
||||
NAME="GENERATOR"
|
||||
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
|
||||
"><LINK
|
||||
REL="HOME"
|
||||
TITLE="The Bugzilla Guide"
|
||||
HREF="index.html"><LINK
|
||||
REL="UP"
|
||||
TITLE="Administering Bugzilla"
|
||||
HREF="administration.html"><LINK
|
||||
REL="PREVIOUS"
|
||||
TITLE="Product, Component, Milestone, and Version Administration"
|
||||
HREF="programadmin.html"><LINK
|
||||
REL="NEXT"
|
||||
TITLE="Groups and Group Security"
|
||||
HREF="groups.html"></HEAD
|
||||
><BODY
|
||||
CLASS="section"
|
||||
BGCOLOR="#FFFFFF"
|
||||
TEXT="#000000"
|
||||
LINK="#0000FF"
|
||||
VLINK="#840084"
|
||||
ALINK="#0000FF"
|
||||
><DIV
|
||||
CLASS="NAVHEADER"
|
||||
><TABLE
|
||||
SUMMARY="Header navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TH
|
||||
COLSPAN="3"
|
||||
ALIGN="center"
|
||||
>The Bugzilla Guide</TH
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="left"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="programadmin.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="80%"
|
||||
ALIGN="center"
|
||||
VALIGN="bottom"
|
||||
>Chapter 5. Administering Bugzilla</TD
|
||||
><TD
|
||||
WIDTH="10%"
|
||||
ALIGN="right"
|
||||
VALIGN="bottom"
|
||||
><A
|
||||
HREF="groups.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"></DIV
|
||||
><DIV
|
||||
CLASS="section"
|
||||
><H1
|
||||
CLASS="section"
|
||||
><A
|
||||
NAME="voting">5.4. Voting</H1
|
||||
><P
|
||||
>The concept of "voting" is a poorly understood, yet powerful
|
||||
feature for the management of open-source projects. Each user is
|
||||
assigned so many Votes per product, which they can freely reassign (or
|
||||
assign multiple votes to a single bug). This allows developers to gauge
|
||||
user need for a particular enhancement or bugfix. By allowing bugs with
|
||||
a certain number of votes to automatically move from "UNCONFIRMED" to
|
||||
"NEW", users of the bug system can help high-priority bugs garner
|
||||
attention so they don't sit for a long time awaiting triage.</P
|
||||
><P
|
||||
>The daunting challenge of Votes is deciding where you draw the
|
||||
line for a "vocal majority". If you only have a user base of 100 users,
|
||||
setting a low threshold for bugs to move from UNCONFIRMED to NEW makes
|
||||
sense. As the Bugzilla user base expands, however, these thresholds
|
||||
must be re-evaluated. You should gauge whether this feature is worth
|
||||
the time and close monitoring involved, and perhaps forego
|
||||
implementation until you have a critical mass of users who demand
|
||||
it.</P
|
||||
><P
|
||||
>To modify Voting settings:</P
|
||||
><P
|
||||
></P
|
||||
><OL
|
||||
TYPE="1"
|
||||
><LI
|
||||
><P
|
||||
>Navigate to the "Edit product" screen for the Product you
|
||||
wish to modify</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Set "Maximum Votes per person" to your calculated value.
|
||||
Setting this field to "0" disables voting.</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Set "Maximum Votes a person can put on a single bug" to your
|
||||
calculated value. It should probably be some number lower than the
|
||||
"Maximum votes per person". Setting this field to "0" disables
|
||||
voting, but leaves the voting options open to the user. This is
|
||||
confusing.</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Set "Number of votes a bug in this product needs to
|
||||
automatically get out of the UNCONFIRMED state" to your calculated
|
||||
number. Setting this field to "0" disables the automatic move of
|
||||
bugs from UNCONFIRMED to NEW. Some people advocate leaving this at
|
||||
"0", but of what use are Votes if your Bugzilla user base is unable
|
||||
to affect which bugs appear on Development radar?
|
||||
<DIV
|
||||
CLASS="tip"
|
||||
><P
|
||||
></P
|
||||
><TABLE
|
||||
CLASS="tip"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="25"
|
||||
ALIGN="CENTER"
|
||||
VALIGN="TOP"
|
||||
><IMG
|
||||
SRC="../images/tip.gif"
|
||||
HSPACE="5"
|
||||
ALT="Tip"></TD
|
||||
><TD
|
||||
ALIGN="LEFT"
|
||||
VALIGN="TOP"
|
||||
><P
|
||||
>You should probably set this number to higher than a small
|
||||
coalition of Bugzilla users can influence it. Most sites use this
|
||||
as a "referendum" mechanism -- if users are able to vote a bug
|
||||
out of UNCONFIRMED, it is a
|
||||
<EM
|
||||
>really</EM
|
||||
>
|
||||
|
||||
bad bug!</P
|
||||
></TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
>
|
||||
</P
|
||||
></LI
|
||||
><LI
|
||||
><P
|
||||
>Once you have adjusted the values to your preference, select
|
||||
the "Update" button.</P
|
||||
></LI
|
||||
></OL
|
||||
></DIV
|
||||
><DIV
|
||||
CLASS="NAVFOOTER"
|
||||
><HR
|
||||
ALIGN="LEFT"
|
||||
WIDTH="100%"><TABLE
|
||||
SUMMARY="Footer navigation table"
|
||||
WIDTH="100%"
|
||||
BORDER="0"
|
||||
CELLPADDING="0"
|
||||
CELLSPACING="0"
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="programadmin.html"
|
||||
ACCESSKEY="P"
|
||||
>Prev</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="index.html"
|
||||
ACCESSKEY="H"
|
||||
>Home</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="groups.html"
|
||||
ACCESSKEY="N"
|
||||
>Next</A
|
||||
></TD
|
||||
></TR
|
||||
><TR
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="left"
|
||||
VALIGN="top"
|
||||
>Product, Component, Milestone, and Version Administration</TD
|
||||
><TD
|
||||
WIDTH="34%"
|
||||
ALIGN="center"
|
||||
VALIGN="top"
|
||||
><A
|
||||
HREF="administration.html"
|
||||
ACCESSKEY="U"
|
||||
>Up</A
|
||||
></TD
|
||||
><TD
|
||||
WIDTH="33%"
|
||||
ALIGN="right"
|
||||
VALIGN="top"
|
||||
>Groups and Group Security</TD
|
||||
></TR
|
||||
></TABLE
|
||||
></DIV
|
||||
></BODY
|
||||
></HTML
|
||||
>
|
||||
22
mozilla/webtools/bugzilla/docs/sgml/gd-makefile.patch
Normal file
22
mozilla/webtools/bugzilla/docs/sgml/gd-makefile.patch
Normal file
@@ -0,0 +1,22 @@
|
||||
--- GD-1.33/Makefile.PL Fri Aug 4 16:59:22 2000
|
||||
+++ GD-1.33-darwin/Makefile.PL Tue Jun 26 01:29:32 2001
|
||||
@@ -3,8 +3,8 @@
|
||||
warn "NOTICE: This module requires libgd 1.8.3 or higher (shared library version 4.X).\n";
|
||||
|
||||
# =====> PATHS: CHECK AND ADJUST <=====
|
||||
-my @INC = qw(-I/usr/local/include -I/usr/local/include/gd);
|
||||
-my @LIBPATH = qw(-L/usr/lib/X11 -L/usr/X11R6/lib -L/usr/X11/lib -L/usr/local/lib );
|
||||
+my @INC = qw(-I/sw/include -I/sw/include/gd -I/usr/local/include -I/usr/local/include/gd);
|
||||
+my @LIBPATH = qw(-L/usr/lib/X11 -L/usr/X11R6/lib -L/usr/X11/lib -L/sw/lib -L/usr/local/lib);
|
||||
my @LIBS = qw(-lgd -lpng -lz);
|
||||
|
||||
# FEATURE FLAGS
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
push @LIBS,'-lttf' if $TTF;
|
||||
push @LIBS,'-ljpeg' if $JPEG;
|
||||
-push @LIBS, '-lm' unless $^O eq 'MSWin32';
|
||||
+push @LIBS, '-lm' unless ($^O =~ /^MSWin32|darwin$/);
|
||||
|
||||
# FreeBSD 3.3 with libgd built from ports croaks if -lXpm is specified
|
||||
if ($^O ne 'freebsd' && $^O ne 'MSWin32') {
|
||||
146
mozilla/webtools/bugzilla/docs/sgml/introduction.sgml
Normal file
146
mozilla/webtools/bugzilla/docs/sgml/introduction.sgml
Normal file
@@ -0,0 +1,146 @@
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<section id="whatis">
|
||||
<title>What is Bugzilla?</title>
|
||||
|
||||
<para>
|
||||
Bugzilla is a bug- or issue-tracking system. Bug-tracking
|
||||
systems allow individual or groups of developers effectively to keep track
|
||||
of outstanding problems with their product.
|
||||
Bugzilla was originally
|
||||
written by Terry Weissman in a programming language called TCL, to
|
||||
replace a rudimentary bug-tracking database used internally by Netscape
|
||||
Communications. Terry later ported Bugzilla to Perl from TCL, and in Perl
|
||||
it remains to this day. Most commercial defect-tracking software vendors
|
||||
at the time charged enormous licensing fees, and Bugzilla quickly became
|
||||
a favorite of the open-source crowd (with its genesis in the open-source
|
||||
browser project, Mozilla). It is now the de-facto standard
|
||||
defect-tracking system against which all others are measured.
|
||||
</para>
|
||||
|
||||
<para>Bugzilla boasts many advanced features. These include:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Powerful searching</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>User-configurable email notifications of bug changes</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Full change history</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Inter-bug dependency tracking and graphing</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Excellent attachment management</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Integrated, product-based, granular security schema</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Fully security-audited, and runs under Perl's taint mode</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A robust, stable RDBMS back-end</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Web, XML, email and console interfaces</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Completely customisable and/or localisable web user
|
||||
interface</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Extensive configurability</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Smooth upgrade pathway between versions</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why">
|
||||
<title>Why Should We Use Bugzilla?</title>
|
||||
|
||||
<para>For many years, defect-tracking software has remained principally
|
||||
the domain of large software development houses. Even then, most shops
|
||||
never bothered with bug-tracking software, and instead simply relied on
|
||||
shared lists and email to monitor the status of defects. This procedure
|
||||
is error-prone and tends to cause those bugs judged least significant by
|
||||
developers to be dropped or ignored.</para>
|
||||
|
||||
<para>These days, many companies are finding that integrated
|
||||
defect-tracking systems reduce downtime, increase productivity, and raise
|
||||
customer satisfaction with their systems. Along with full disclosure, an
|
||||
open bug-tracker allows manufacturers to keep in touch with their clients
|
||||
and resellers, to communicate about problems effectively throughout the
|
||||
data management chain. Many corporations have also discovered that
|
||||
defect-tracking helps reduce costs by providing IT support
|
||||
accountability, telephone support knowledge bases, and a common,
|
||||
well-understood system for accounting for unusual system or software
|
||||
issues.</para>
|
||||
|
||||
<para>But why should
|
||||
<emphasis>you</emphasis>
|
||||
|
||||
use Bugzilla?</para>
|
||||
|
||||
<para>Bugzilla is very adaptable to various situations. Known uses
|
||||
currently include IT support queues, Systems Administration deployment
|
||||
management, chip design and development problem tracking (both
|
||||
pre-and-post fabrication), and software and hardware bug tracking for
|
||||
luminaries such as Redhat, NASA, Linux-Mandrake, and VA Systems.
|
||||
Combined with systems such as CVS, Bonsai, or Perforce SCM, Bugzilla
|
||||
provides a powerful, easy-to-use solution to configuration management and
|
||||
replication problems.</para>
|
||||
|
||||
<para>Bugzilla can dramatically increase the productivity and
|
||||
accountability of individual employees by providing a documented workflow
|
||||
and positive feedback for good performance. How many times do you wake up
|
||||
in the morning, remembering that you were supposed to do
|
||||
<emphasis>something</emphasis>
|
||||
today, but you just can't quite remember? Put it in Bugzilla, and you
|
||||
have a record of it from which you can extrapolate milestones, predict
|
||||
product versions for integration, and follow the discussion trail
|
||||
that led to critical decisions.</para>
|
||||
|
||||
<para>Ultimately, Bugzilla puts the power in your hands to improve your
|
||||
value to your employer or business while providing a usable framework for
|
||||
your natural attention to detail and knowledge store to flourish.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.sgml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
@@ -34,11 +34,11 @@ use vars %::param,
|
||||
@::param_list;
|
||||
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup($userid, "tweakparams")) {
|
||||
if (!UserInGroup("tweakparams")) {
|
||||
print "<H1>Sorry, you aren't a member of the 'tweakparams' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the parameters.\n";
|
||||
PutFooter();
|
||||
|
||||
@@ -39,9 +39,9 @@ use vars qw($template $vars);
|
||||
ConnectToDatabase(1);
|
||||
GetVersionTable();
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
use vars qw (%FORM $userid @legal_product);
|
||||
use vars qw (%FORM $userid $usergroupset @legal_product);
|
||||
|
||||
my %dbmcount;
|
||||
my %count;
|
||||
@@ -152,7 +152,7 @@ my @bug_ids;
|
||||
my $loop = 0;
|
||||
|
||||
my @canseebugs = keys %count;
|
||||
my $canseeref = CanSeeBug(\@canseebugs, $userid);
|
||||
my $canseeref = CanSeeBug(\@canseebugs, $userid, $usergroupset);
|
||||
|
||||
foreach my $id (keys(%count)) {
|
||||
# Maximum row count is dealt with in the template.
|
||||
|
||||
@@ -44,9 +44,8 @@ ConnectToDatabase();
|
||||
# Make sure the user is logged in and is allowed to edit products
|
||||
# (i.e. the user has "editcomponents" privileges), since attachment
|
||||
# statuses are product-specific.
|
||||
my $userid = confirm_login();
|
||||
|
||||
UserInGroup($userid, "editcomponents")
|
||||
confirm_login();
|
||||
UserInGroup("editcomponents")
|
||||
|| DisplayError("You are not authorized to administer attachment statuses.")
|
||||
&& exit;
|
||||
|
||||
|
||||
@@ -188,11 +188,11 @@ sub PutTrailer (@)
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup($userid, "editcomponents")) {
|
||||
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";
|
||||
|
||||
@@ -29,11 +29,11 @@ use lib ".";
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup($userid, "creategroups")) {
|
||||
if (!UserInGroup("creategroups")) {
|
||||
PutHeader("Not Authorized","Edit Groups","","Not Authorized for this function!");
|
||||
print "<H1>Sorry, you aren't a member of the 'creategroups' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the groups.\n";
|
||||
@@ -102,7 +102,7 @@ unless ($action) {
|
||||
print "<form method=post action=editgroups.cgi>\n";
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>ID</th>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "<th>User RegExp</th>";
|
||||
@@ -110,24 +110,24 @@ unless ($action) {
|
||||
print "<th>Action</th>";
|
||||
print "</tr>\n";
|
||||
|
||||
SendSQL("SELECT group_id,name,description,userregexp,isactive " .
|
||||
SendSQL("SELECT group_bit,name,description,userregexp,isactive " .
|
||||
"FROM groups " .
|
||||
"WHERE isbuggroup != 0 " .
|
||||
"ORDER BY group_id");
|
||||
"ORDER BY group_bit");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $name, $desc, $regexp, $isactive) = FetchSQLData();
|
||||
my ($bit, $name, $desc, $regexp, $isactive) = FetchSQLData();
|
||||
print "<tr>\n";
|
||||
print "<td valign=middle>$id</td>\n";
|
||||
print "<td><input size=20 name=\"name-$id\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"oldname-$id\" value=\"$name\"></td>\n";
|
||||
print "<td><input size=40 name=\"desc-$id\" value=\"$desc\">\n";
|
||||
print "<input type=hidden name=\"olddesc-$id\" value=\"$desc\"></td>\n";
|
||||
print "<td><input size=30 name=\"regexp-$id\" value=\"$regexp\">\n";
|
||||
print "<input type=hidden name=\"oldregexp-$id\" value=\"$regexp\"></td>\n";
|
||||
print "<td><input type=\"checkbox\" name=\"isactive-$id\" value=\"1\"" . ($isactive ? " checked" : "") . ">\n";
|
||||
print "<input type=hidden name=\"oldisactive-$id\" value=\"$isactive\"></td>\n";
|
||||
print "<td align=center valign=middle><a href=\"editgroups.cgi?action=del&group=$id\">Delete</a></td>\n";
|
||||
print "<td valign=middle>$bit</td>\n";
|
||||
print "<td><input size=20 name=\"name-$bit\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"oldname-$bit\" value=\"$name\"></td>\n";
|
||||
print "<td><input size=40 name=\"desc-$bit\" value=\"$desc\">\n";
|
||||
print "<input type=hidden name=\"olddesc-$bit\" value=\"$desc\"></td>\n";
|
||||
print "<td><input size=30 name=\"regexp-$bit\" value=\"$regexp\">\n";
|
||||
print "<input type=hidden name=\"oldregexp-$bit\" value=\"$regexp\"></td>\n";
|
||||
print "<td><input type=\"checkbox\" name=\"isactive-$bit\" value=\"1\"" . ($isactive ? " checked" : "") . ">\n";
|
||||
print "<input type=hidden name=\"oldisactive-$bit\" value=\"$isactive\"></td>\n";
|
||||
print "<td align=center valign=middle><a href=\"editgroups.cgi?action=del&group=$bit\">Delete</a></td>\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
@@ -163,27 +163,27 @@ sake of convience.<p>";
|
||||
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>ID</th>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "<th>User RegExp</th>";
|
||||
print "</tr>\n";
|
||||
|
||||
SendSQL("SELECT group_id,name,description,userregexp " .
|
||||
SendSQL("SELECT group_bit,name,description,userregexp " .
|
||||
"FROM groups " .
|
||||
"WHERE isbuggroup = 0 " .
|
||||
"ORDER BY group_id");
|
||||
|
||||
"ORDER BY group_bit");
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $name, $desc, $regexp) = FetchSQLData();
|
||||
my ($bit, $name, $desc, $regexp) = FetchSQLData();
|
||||
print "<tr>\n";
|
||||
print "<td>$id</td>\n";
|
||||
print "<td>$bit</td>\n";
|
||||
print "<td>$name</td>\n";
|
||||
print "<input type=hidden name=\"name-$id\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"oldname-$id\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"name-$bit\" value=\"$name\">\n";
|
||||
print "<input type=hidden name=\"oldname-$bit\" value=\"$name\">\n";
|
||||
print "<td>$desc</td>\n";
|
||||
print "<td><input type=text size=30 name=\"regexp-$id\" value=\"$regexp\"></td>\n";
|
||||
print "<input type=hidden name=\"oldregexp-$id\" value=\"$regexp\">\n";
|
||||
print "<td><input type=text size=30 name=\"regexp-$bit\" value=\"$regexp\"></td>\n";
|
||||
print "<input type=hidden name=\"oldregexp-$bit\" value=\"$regexp\">\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
@@ -287,10 +287,54 @@ if ($action eq 'new') {
|
||||
exit;
|
||||
}
|
||||
|
||||
# Major hack for bit values... perl can't handle 64-bit ints, so I can't
|
||||
# just do the math to get the next available bit number, gotta handle
|
||||
# them as strings... also, we're actually only going to allow 63 bits
|
||||
# because that's all that opblessgroupset masks for (the high bit is off
|
||||
# to avoid signing issues).
|
||||
|
||||
my @bitvals = ('1','2','4','8','16','32','64','128','256','512','1024',
|
||||
'2048','4096','8192','16384','32768',
|
||||
|
||||
'65536','131072','262144','524288','1048576','2097152',
|
||||
'4194304','8388608','16777216','33554432','67108864',
|
||||
'134217728','268435456','536870912','1073741824',
|
||||
'2147483648',
|
||||
|
||||
'4294967296','8589934592','17179869184','34359738368',
|
||||
'68719476736','137438953472','274877906944',
|
||||
'549755813888','1099511627776','2199023255552',
|
||||
'4398046511104','8796093022208','17592186044416',
|
||||
'35184372088832','70368744177664','140737488355328',
|
||||
|
||||
'281474976710656','562949953421312','1125899906842624',
|
||||
'2251799813685248','4503599627370496','9007199254740992',
|
||||
'18014398509481984','36028797018963968','72057594037927936',
|
||||
'144115188075855872','288230376151711744',
|
||||
'576460752303423488','1152921504606846976',
|
||||
'2305843009213693952','4611686018427387904');
|
||||
|
||||
# First the next available bit
|
||||
my $bit = "";
|
||||
foreach (@bitvals) {
|
||||
if ($bit eq "") {
|
||||
SendSQL("SELECT group_bit FROM groups WHERE group_bit=" . SqlQuote($_));
|
||||
if (!FetchOneColumn()) { $bit = $_; }
|
||||
}
|
||||
}
|
||||
if ($bit eq "") {
|
||||
ShowError("Sorry, you already have the maximum number of groups " .
|
||||
"defined.<BR><BR>You must delete a group first before you " .
|
||||
"can add any more.</B>");
|
||||
PutTrailer("<a href=editgroups.cgi>Back to the group list</a>");
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new group
|
||||
SendSQL("INSERT INTO groups ( " .
|
||||
"name, description, isbuggroup, userregexp, isactive" .
|
||||
" ) VALUES ( " .
|
||||
"group_bit, name, description, isbuggroup, userregexp, isactive" .
|
||||
" ) VALUES (" .
|
||||
$bit . "," .
|
||||
SqlQuote($name) . "," .
|
||||
SqlQuote($desc) . "," .
|
||||
"1," .
|
||||
@@ -298,30 +342,7 @@ if ($action eq 'new') {
|
||||
$isactive . ")" );
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
SendSQL("SELECT group_id FROM groups where name = " . SqlQuote($name));
|
||||
my $id = FetchOneColumn();
|
||||
print "Your new group was assigned id # $id.<p>";
|
||||
|
||||
# Add each user designated as an Admin to the new group
|
||||
my @adminlist = ();
|
||||
SendSQL("SELECT userid FROM profiles WHERE admin = 1");
|
||||
while (my @row = FetchSQLData()) {
|
||||
push(@adminlist, $row[0]);
|
||||
}
|
||||
foreach my $userid (@adminlist) {
|
||||
SendSQL("INSERT INTO user_group_map (user_id, group_id, canbless) VALUES ($userid, $id, 1)");
|
||||
}
|
||||
|
||||
# Add people who match regular expression to this group.
|
||||
my $count = 0;
|
||||
SendSQL("SELECT userid FROM profiles WHERE admin != 1 ORDER BY userid");
|
||||
while (my ($userid) = FetchSQLData()) {
|
||||
if ($userid =~ /$regexp/) {
|
||||
PushGlobalSQLState();
|
||||
SendSQL("INSERT INTO user_group_map (user_id, group_id, canbless) VALUES ($userid, $id, 0)");
|
||||
PopGlobalSQLState();
|
||||
}
|
||||
}
|
||||
print "Your new group was assigned bit #$bit.<p>";
|
||||
PutTrailer("<a href=\"editgroups.cgi?action=add\">Add another group</a>",
|
||||
"<a href=\"editgroups.cgi\">Back to the group list</a>");
|
||||
exit;
|
||||
@@ -335,15 +356,15 @@ if ($action eq 'new') {
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete group");
|
||||
my $id = trim($::FORM{group} || '');
|
||||
unless ($id) {
|
||||
my $bit = trim($::FORM{group} || '');
|
||||
unless ($bit) {
|
||||
ShowError("No group specified.<BR>" .
|
||||
"Click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
exit;
|
||||
}
|
||||
SendSQL("SELECT group_id FROM groups WHERE group_id = " . SqlQuote($id));
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("SELECT group_bit FROM groups WHERE group_bit=" . SqlQuote($bit));
|
||||
if (!FetchOneColumn()) {
|
||||
ShowError("That group doesn't exist.<BR>" .
|
||||
"Click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
@@ -351,17 +372,17 @@ if ($action eq 'del') {
|
||||
}
|
||||
SendSQL("SELECT name,description " .
|
||||
"FROM groups " .
|
||||
"WHERE group_id = " . SqlQuote($id));
|
||||
"WHERE group_bit = " . SqlQuote($bit));
|
||||
|
||||
my ($name, $desc) = FetchSQLData();
|
||||
print "<table border=1>\n";
|
||||
print "<tr>";
|
||||
print "<th>ID</th>";
|
||||
print "<th>Bit</th>";
|
||||
print "<th>Name</th>";
|
||||
print "<th>Description</th>";
|
||||
print "</tr>\n";
|
||||
print "<tr>\n";
|
||||
print "<td>$id</td>\n";
|
||||
print "<td>$bit</td>\n";
|
||||
print "<td>$name</td>\n";
|
||||
print "<td>$desc</td>\n";
|
||||
print "</tr>\n";
|
||||
@@ -369,19 +390,38 @@ if ($action eq 'del') {
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editgroups.cgi>\n";
|
||||
my $cantdelete = 0;
|
||||
SendSQL("SELECT COUNT(user_id) FROM user_group_map WHERE group_id = $id");
|
||||
my $usergroupcount = FetchOneColumn();
|
||||
if ($usergroupcount) {
|
||||
$cantdelete = 1;
|
||||
print "
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT login_name FROM profiles WHERE " .
|
||||
"(groupset & $bit) OR (blessgroupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT login_name FROM profiles WHERE " .
|
||||
"(groupset & int8($bit)) != 0 OR (blessgroupset & int8($bit)) != 0");
|
||||
}
|
||||
if (!FetchOneColumn()) {} else {
|
||||
$cantdelete = 1;
|
||||
if ($::driver eq 'mysql') {
|
||||
print "
|
||||
<B>One or more users belong to this group. You cannot delete this group while
|
||||
there are users in it.</B><BR>
|
||||
<A HREF=\"editusers.cgi?action=list&group=$id\">
|
||||
Show me which users.</A> - <INPUT TYPE=CHECKBOX NAME=\"removeusers\">Remove all users from
|
||||
<A HREF=\"editusers.cgi?action=list&query=" .
|
||||
url_quote("(groupset & $bit) OR (blessgroupset & $bit)") . "\">Show me which users.</A> - <INPUT TYPE=CHECKBOX NAME=\"removeusers\">Remove all users from
|
||||
this group for me<P>
|
||||
";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
print "
|
||||
<B>One or more users belong to this group. You cannot delete this group while
|
||||
there are users in it.</B><BR>
|
||||
<A HREF=\"editusers.cgi?action=list&query=" .
|
||||
url_quote("(groupset & int8($bit)) != 0 OR (blessgroupset & int8($bit)) != 0") . "\">Show me which users.</A> - <INPUT TYPE=CHECKBOX NAME=\"removeusers\">Remove all users from
|
||||
this group for me<P>
|
||||
";
|
||||
}
|
||||
}
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & int8($bit)) != 0");
|
||||
}
|
||||
SendSQL("SELECT bug_id FROM bug_group_map WHERE group_id = $id ORDER BY bug_id");
|
||||
if (MoreSQLData()) {
|
||||
$cantdelete = 1;
|
||||
my $buglist = "0";
|
||||
@@ -398,9 +438,8 @@ restriction for me<BR>
|
||||
<B>NOTE:</B> It's quite possible to make confidential bugs public by checking
|
||||
this box. It is <B>strongly</B> suggested that you review the bugs in this
|
||||
group before checking the box.<P>
|
||||
";
|
||||
";
|
||||
}
|
||||
|
||||
SendSQL("SELECT product FROM products WHERE product=" . SqlQuote($name));
|
||||
if (MoreSQLData()) {
|
||||
$cantdelete = 1;
|
||||
@@ -420,7 +459,7 @@ You cannot delete this group while it is tied to a product.</B><BR>
|
||||
}
|
||||
print "<P><INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"group\" VALUE=\"$id\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"group\" VALUE=\"$bit\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>No, go back to the group list</a>");
|
||||
@@ -433,8 +472,8 @@ You cannot delete this group while it is tied to a product.</B><BR>
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting group");
|
||||
my $groupid = trim($::FORM{group} || '');
|
||||
unless ($groupid) {
|
||||
my $bit = trim($::FORM{group} || '');
|
||||
unless ($bit) {
|
||||
ShowError("No group specified.<BR>" .
|
||||
"Click the <b>Back</b> button and try again.");
|
||||
PutFooter();
|
||||
@@ -442,24 +481,49 @@ if ($action eq 'delete') {
|
||||
}
|
||||
SendSQL("SELECT name " .
|
||||
"FROM groups " .
|
||||
"WHERE group_id = " . SqlQuote($groupid));
|
||||
"WHERE group_bit = " . SqlQuote($bit));
|
||||
my ($name) = FetchSQLData();
|
||||
|
||||
my $cantdelete = 0;
|
||||
|
||||
SendSQL("SELECT COUNT(user_id) FROM user_group_map WHERE group_id = $groupid");
|
||||
my $opblessgroupset = '9223372036854775807';
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT userid FROM profiles " .
|
||||
"WHERE (groupset & $opblessgroupset) = $opblessgroupset");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT userid FROM profiles " .
|
||||
"WHERE (groupset & int8($opblessgroupset)) = $opblessgroupset");
|
||||
}
|
||||
my @opusers = ();
|
||||
while (MoreSQLData()) {
|
||||
my ($userid) = FetchSQLData();
|
||||
push @opusers, $userid; # cache a list of the users with admin powers
|
||||
}
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT login_name FROM profiles WHERE " .
|
||||
"(groupset & $bit) = $bit OR (blessgroupset & $bit) = $bit");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT login_name FROM profiles WHERE " .
|
||||
"(groupset & int8($bit)) = $bit OR (blessgroupset & int8($bit)) = $bit");
|
||||
}
|
||||
if (FetchOneColumn()) {
|
||||
if (!defined $::FORM{'removeusers'}) {
|
||||
$cantdelete = 1;
|
||||
}
|
||||
}
|
||||
SendSQL("SELECT COUNT(bug_id) FROM bug_group_map WHERE group_id = $groupid");
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & $bit) = $bit");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & int8($bit)) = $bit");
|
||||
}
|
||||
if (FetchOneColumn()) {
|
||||
if (!defined $::FORM{'removebugs'}) {
|
||||
$cantdelete = 1;
|
||||
}
|
||||
}
|
||||
SendSQL("SELECT product FROM products WHERE product = " . SqlQuote($name));
|
||||
SendSQL("SELECT product FROM products WHERE product=" . SqlQuote($name));
|
||||
if (FetchOneColumn()) {
|
||||
if (!defined $::FORM{'unbind'}) {
|
||||
$cantdelete = 1;
|
||||
@@ -471,27 +535,68 @@ if ($action eq 'delete') {
|
||||
"records in the database which refer to it. All child records " .
|
||||
"must be removed or altered to remove the reference to this " .
|
||||
"group before the group can be deleted.");
|
||||
print "<A HREF=\"editgroups.cgi?action=del&group=$groupid\">" .
|
||||
print "<A HREF=\"editgroups.cgi?action=del&group=$bit\">" .
|
||||
"View the list of which records are affected</A><BR>";
|
||||
PutTrailer("<a href=editgroups.cgi>Back to group list</a>");
|
||||
exit;
|
||||
}
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT login_name, groupset, blessgroupset FROM profiles WHERE " .
|
||||
"(groupset & $bit) OR (blessgroupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT login_name, groupset, blessgroupset FROM profiles WHERE " .
|
||||
"(groupset & int8($bit)) != 0 OR (blessgroupset & int8($bit)) != 0 ");
|
||||
}
|
||||
if (FetchOneColumn()) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles SET groupset = (groupset - $bit) " .
|
||||
"WHERE (groupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles SET groupset = (groupset - int8($bit)) " .
|
||||
"WHERE (groupset & int8($bit)) != 0");
|
||||
}
|
||||
print "All users have been removed from group $bit.<BR>";
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles SET blessgroupset = (blessgroupset - $bit) " .
|
||||
"WHERE (blessgroupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles SET blessgroupset = (blessgroupset - int8($bit)) " .
|
||||
"WHERE (blessgroupset & int8($bit)) != 0");
|
||||
}
|
||||
print "All users with authority to add users to group $bit have " .
|
||||
"had that authority removed.<BR>";
|
||||
}
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE (groupset & int8($bit)) != 0");
|
||||
}
|
||||
if (FetchOneColumn()) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE bugs SET groupset = (groupset - $bit), delta_ts=delta_ts" .
|
||||
"WHERE (groupset & $bit)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE bugs SET groupset = (groupset - int8($bit)), delta_ts=now() " .
|
||||
"WHERE (groupset & int8($bit)) != 0");
|
||||
}
|
||||
print "All bugs have had group bit $bit cleared. Any of these " .
|
||||
"bugs that were not also in another group are now " .
|
||||
"publicly visible.<BR>";
|
||||
}
|
||||
SendSQL("DELETE FROM groups WHERE group_bit = $bit");
|
||||
print "<B>Group $bit has been deleted.</B><BR>";
|
||||
|
||||
SendSQL("SELECT COUNT(user_id) FROM user_group_map " .
|
||||
"WHERE group_id = $groupid");
|
||||
if (FetchOneColumn()) {
|
||||
SendSQL("DELETE FROM user_group_map WHERE group_id = $groupid");
|
||||
print "All users have been removed from group $groupid.<BR>";
|
||||
foreach my $userid (@opusers) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles SET groupset = $opblessgroupset " .
|
||||
"WHERE userid = $userid");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles SET groupset = int8($opblessgroupset) " .
|
||||
"WHERE userid = $userid");
|
||||
}
|
||||
print "Group bits restored for " . DBID_to_name($userid) .
|
||||
" (maintainer)<BR>\n";
|
||||
}
|
||||
SendSQL("SELECT COUNT(bug_id) FROM bug_group_map WHERE group_id = $groupid");
|
||||
if (FetchOneColumn()) {
|
||||
SendSQL("DELETE FROM bug_group_map WHERE group_id = $groupid");
|
||||
print "All bugs have had group bit $groupid cleared. Any of these " .
|
||||
"bugs that were not also in another group are now " .
|
||||
"publicly visible.<BR>";
|
||||
}
|
||||
SendSQL("DELETE FROM groups WHERE group_id = $groupid");
|
||||
print "<B>Group $groupid has been deleted.</B><BR>";
|
||||
|
||||
PutTrailer("<a href=editgroups.cgi>Back to group list</a>");
|
||||
exit;
|
||||
@@ -517,16 +622,19 @@ if ($action eq 'update') {
|
||||
|
||||
if ($::FORM{"oldname-$v"} ne $::FORM{"name-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("SELECT name FROM groups WHERE name = " . SqlQuote($::FORM{"name-$v"}));
|
||||
SendSQL("SELECT name FROM groups WHERE name=" .
|
||||
SqlQuote($::FORM{"name-$v"}));
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("SELECT name FROM groups WHERE name = " . SqlQuote($::FORM{"oldname-$v"}) .
|
||||
" AND isbuggroup = 0");
|
||||
SendSQL("SELECT name FROM groups WHERE name=" .
|
||||
SqlQuote($::FORM{"oldname-$v"}) .
|
||||
" && isbuggroup = 0");
|
||||
if (FetchOneColumn()) {
|
||||
ShowError("You cannot update the name of a " .
|
||||
"system group. Skipping $v");
|
||||
} else {
|
||||
SendSQL("UPDATE groups SET name = " . SqlQuote($::FORM{"name-$v"}) .
|
||||
" WHERE group_id = " . SqlQuote($v));
|
||||
SendSQL("UPDATE groups SET name = " .
|
||||
SqlQuote($::FORM{"name-$v"}) .
|
||||
" WHERE group_bit = " . SqlQuote($v));
|
||||
print "Group $v name updated.<br>\n";
|
||||
}
|
||||
} else {
|
||||
@@ -537,10 +645,11 @@ if ($action eq 'update') {
|
||||
}
|
||||
if ($::FORM{"olddesc-$v"} ne $::FORM{"desc-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("SELECT description FROM groups WHERE description = " . SqlQuote($::FORM{"desc-$v"}));
|
||||
SendSQL("SELECT description FROM groups WHERE description=" .
|
||||
SqlQuote($::FORM{"desc-$v"}));
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("UPDATE groups SET description = " . SqlQuote($::FORM{"desc-$v"}) .
|
||||
" WHERE group_id = " . SqlQuote($v));
|
||||
SendSQL("UPDATE groups SET description=" .
|
||||
" WHERE group_bit=" . SqlQuote($v));
|
||||
print "Group $v description updated.<br>\n";
|
||||
} else {
|
||||
ShowError("Duplicate description '" . $::FORM{"desc-$v"} .
|
||||
@@ -550,9 +659,9 @@ if ($action eq 'update') {
|
||||
}
|
||||
if ($::FORM{"oldregexp-$v"} ne $::FORM{"regexp-$v"}) {
|
||||
$chgs = 1;
|
||||
SendSQL("UPDATE groups SET userregexp = " .
|
||||
SendSQL("UPDATE groups SET userregexp=" .
|
||||
SqlQuote($::FORM{"regexp-$v"}) .
|
||||
" WHERE group_id = " . SqlQuote($v));
|
||||
" WHERE group_bit=" . SqlQuote($v));
|
||||
print "Group $v user regexp updated.<br>\n";
|
||||
}
|
||||
# convert an undefined value in the inactive field to zero
|
||||
@@ -562,8 +671,8 @@ if ($action eq 'update') {
|
||||
if ($::FORM{"oldisactive-$v"} != $isactive) {
|
||||
$chgs = 1;
|
||||
if ($isactive == 0 || $isactive == 1) {
|
||||
SendSQL("UPDATE groups SET isactive = $isactive " .
|
||||
"WHERE group_id = " . SqlQuote($v));
|
||||
SendSQL("UPDATE groups SET isactive=$isactive" .
|
||||
" WHERE group_bit=" . SqlQuote($v));
|
||||
print "Group $v active flag updated.<br>\n";
|
||||
} else {
|
||||
ShowError("The value '" . $isactive .
|
||||
|
||||
@@ -108,11 +108,11 @@ sub Validate ($$) {
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup($userid, "editkeywords")) {
|
||||
unless (UserInGroup("editkeywords")) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editkeywords' group.\n";
|
||||
print "And so, you aren't allowed to add, modify or delete keywords.\n";
|
||||
|
||||
@@ -146,11 +146,11 @@ sub PutTrailer (@)
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup($userid, "editcomponents")) {
|
||||
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 milestones.\n";
|
||||
|
||||
@@ -32,11 +32,11 @@ require "defparams.pl";
|
||||
use vars @::param_desc,
|
||||
@::param_list;
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
if (!UserInGroup($userid, "tweakparams")) {
|
||||
if (!UserInGroup("tweakparams")) {
|
||||
print "<H1>Sorry, you aren't a member of the 'tweakparams' group.</H1>\n";
|
||||
print "And so, you aren't allowed to edit the parameters.\n";
|
||||
PutFooter();
|
||||
|
||||
@@ -42,7 +42,6 @@ sub sillyness {
|
||||
$zz = $::unconfirmedstate;
|
||||
}
|
||||
|
||||
my $userid = 0;
|
||||
|
||||
# TestProduct: just returns if the specified product does exists
|
||||
# CheckProduct: same check, optionally emit an error text
|
||||
@@ -112,16 +111,13 @@ sub EmitFormElements ($$$$$$$$$)
|
||||
print qq{<INPUT TYPE=HIDDEN NAME="defaultmilestone" VALUE="$defaultmilestone">\n};
|
||||
}
|
||||
|
||||
print "</tr><tr>\n";
|
||||
print " <TH ALIGN=\"right\">Create Product Specific Group:</TH>\n";
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($product));
|
||||
my $checked = FetchOneColumn() ? "CHECKED" : "";
|
||||
print " <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"productgroup\" $checked></TD>\n";
|
||||
|
||||
$userregexp = value_quote($userregexp);
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">User Regexp for Product Group:</TH>\n";
|
||||
print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"userregexp\" VALUE=\"$userregexp\"></TD>\n";
|
||||
# Added -JMR, 2/16/00
|
||||
if (Param("usebuggroups")) {
|
||||
$userregexp = value_quote($userregexp);
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">User Regexp for Bug Group:</TH>\n";
|
||||
print " <TD><INPUT TYPE=TEXT SIZE=64 MAXLENGTH=255 NAME=\"userregexp\" VALUE=\"$userregexp\"></TD>\n";
|
||||
}
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Closed for bug entry:</TH>\n";
|
||||
@@ -139,46 +135,6 @@ sub EmitFormElements ($$$$$$$$$)
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Number of votes a bug in this product needs to automatically get out of the <A HREF=\"bug_status.html#status\">UNCONFIRMED</A> state:</TH>\n";
|
||||
print " <TD><INPUT SIZE=5 MAXLENGTH=5 NAME=\"votestoconfirm\" VALUE=\"$votestoconfirm\"></TD>\n";
|
||||
|
||||
# Find list of groups that this product can be marked private to
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"right\">Other Group Access:</TH>\n";
|
||||
print " <TD><TABLE>\n";
|
||||
my $productid = 0;
|
||||
my %productbelongs = ();
|
||||
if ($product) {
|
||||
SendSQL("select product_id from products where product = " . SqlQuote($product));
|
||||
$productid = FetchOneColumn();
|
||||
SendSQL("select groups.group_id from groups, product_group_map " .
|
||||
"where groups.group_id = product_group_map.group_id ".
|
||||
"and product_group_map.product_id = $productid");
|
||||
while (my ($groupid) = FetchSQLData()) {
|
||||
$productbelongs{$groupid} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my %groupsbelong = ();
|
||||
my %groupsbelongname = ();
|
||||
my %groupsbelongdesc = ();
|
||||
SendSQL("select groups.group_id, groups.name, groups.description " .
|
||||
"from groups, user_group_map " .
|
||||
"where groups.group_id = user_group_map.group_id " .
|
||||
"and groups.isbuggroup = 1 " .
|
||||
"and user_group_map.user_id = $userid");
|
||||
while (my ($groupid, $name, $desc) = FetchSQLData()) {
|
||||
$groupsbelong{$groupid} = 1;
|
||||
$groupsbelongname{$groupid} = $name;
|
||||
$groupsbelongdesc{$groupid} = $desc;
|
||||
}
|
||||
|
||||
foreach my $groupid (keys %groupsbelong) {
|
||||
my $checked = defined ($productbelongs{$groupid}) ? "CHECKED" : "";
|
||||
print "<TR>\n<TD><INPUT TYPE=\"checkbox\" NAME=\"group_$groupid\" VALUE=\"$groupid\" $checked></TD>\n";
|
||||
print "<TD><B>" . ucfirst($groupsbelongname{$groupid}) . ":</B> ";
|
||||
print "$groupsbelongdesc{$groupid}</TD>\n</TR>\n";
|
||||
}
|
||||
print "</TABLE>\n</TD>\n";
|
||||
print "<INPUT TYPE=\"hidden\" NAME=\"productid\" VALUE=\"$productid\">\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -219,11 +175,11 @@ sub PutTrailer (@)
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
$userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup($userid, "editcomponents")) {
|
||||
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 products.\n";
|
||||
@@ -249,16 +205,10 @@ my $localtrailer = "<A HREF=\"editproducts.cgi\">edit</A> more products";
|
||||
unless ($action) {
|
||||
PutHeader("Select product");
|
||||
|
||||
# SendSQL("SELECT products.product,description,disallownew,
|
||||
# votesperuser,maxvotesperbug,votestoconfirm,COUNT(bug_id)
|
||||
# FROM products LEFT JOIN bugs
|
||||
# ON products.product=bugs.product
|
||||
# GROUP BY products.product,description,disallownew,
|
||||
# votesperuser,maxvotesperbug,votestoconfirm
|
||||
# ORDER BY products.product");
|
||||
SendSQL("SELECT products.product,description,disallownew,
|
||||
votesperuser,maxvotesperbug,votestoconfirm
|
||||
FROM products
|
||||
votesperuser,maxvotesperbug,votestoconfirm,COUNT(bug_id)
|
||||
FROM products LEFT JOIN bugs
|
||||
ON products.product=bugs.product
|
||||
GROUP BY products.product,description,disallownew,
|
||||
votesperuser,maxvotesperbug,votestoconfirm
|
||||
ORDER BY products.product");
|
||||
@@ -269,13 +219,12 @@ unless ($action) {
|
||||
print " <TH ALIGN=\"left\">Votes<br>per<br>user</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Max<br>Votes<br>per<br>bug</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Votes<br>to<br>confirm</TH>\n";
|
||||
# print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Bugs</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Action</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($product, $description, $disallownew, $votesperuser,
|
||||
$maxvotesperbug, $votestoconfirm, $bugs) = FetchSQLData();
|
||||
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
$disallownew = $disallownew ? 'closed' : 'open';
|
||||
$bugs ||= 'none';
|
||||
@@ -286,13 +235,12 @@ unless ($action) {
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$votesperuser</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$maxvotesperbug</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$votestoconfirm</TD>\n";
|
||||
# print " <TD VALIGN=\"top\" ALIGN=\"right\">$bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"right\">$bugs</TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"editproducts.cgi?action=del&product=", url_quote($product), "\">Delete</A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\" COLSPAN=6>Add a new product</TD>\n";
|
||||
# print " <TD VALIGN=\"top\" COLSPAN=7>Add a new product</TD>\n";
|
||||
print " <TD VALIGN=\"top\" COLSPAN=7>Add a new product</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><FONT SIZE =-1><A HREF=\"editproducts.cgi?action=add\">Add</A></FONT></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
@@ -379,7 +327,6 @@ if ($action eq 'new') {
|
||||
my $votestoconfirm = $::FORM{votestoconfirm};
|
||||
$votestoconfirm ||= 0;
|
||||
my $defaultmilestone = $::FORM{defaultmilestone} || "---";
|
||||
my $productgroup = $::FORM{'productgroup'} || "";
|
||||
|
||||
# Add the new product.
|
||||
SendSQL("INSERT INTO products ( " .
|
||||
@@ -392,9 +339,6 @@ if ($action eq 'new') {
|
||||
$disallownew . "," .
|
||||
"$votesperuser, $maxvotesperbug, $votestoconfirm, " .
|
||||
SqlQuote($defaultmilestone) . ")");
|
||||
|
||||
my $productid = CurrId('products_product_id_seq');
|
||||
|
||||
SendSQL("INSERT INTO versions ( " .
|
||||
"value, program" .
|
||||
" ) VALUES ( " .
|
||||
@@ -402,29 +346,32 @@ if ($action eq 'new') {
|
||||
SqlQuote($product) . ")" );
|
||||
|
||||
SendSQL("INSERT INTO milestones (product, value, sortkey) VALUES (" .
|
||||
SqlQuote($product) . ", " . SqlQuote($defaultmilestone) . ", 0)");
|
||||
SqlQuote($product) . ", " . SqlQuote($defaultmilestone) . ", 1)");
|
||||
|
||||
if ($productgroup) {
|
||||
# Check for a group already by this name
|
||||
SendSQL("SELECT name FROM groups WHERE name = " . SqlQuote($product));
|
||||
my $name = FetchOneColumn();
|
||||
if ($name) {
|
||||
DisplayError("There is already a group by that name.")
|
||||
&& exit;
|
||||
# If we're using bug groups, then we need to create a group for this
|
||||
# product as well. -JMR, 2/16/00
|
||||
if(Param("usebuggroups")) {
|
||||
# First we need to figure out the bit for this group. We'll simply
|
||||
# use the next highest bit available. We'll use a minimum bit of 256,
|
||||
# to leave room for a few more Bugzilla operation groups at the bottom.
|
||||
SendSQL("SELECT MAX(group_bit) FROM groups");
|
||||
my $bit = FetchOneColumn();
|
||||
if($bit < 256) {
|
||||
$bit = 256;
|
||||
} else {
|
||||
# Next we insert into the groups table
|
||||
SendSQL("INSERT INTO groups " .
|
||||
"(name, description, isbuggroup, userregexp) " .
|
||||
"VALUES (" .
|
||||
SqlQuote($product) . ", " .
|
||||
SqlQuote($product . " Bugs Access") . ", " .
|
||||
"1, " .
|
||||
SqlQuote($userregexp) . ")");
|
||||
$bit = $bit * 2;
|
||||
}
|
||||
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($product));
|
||||
my $groupid = FetchOneColumn();
|
||||
|
||||
|
||||
# Next we insert into the groups table
|
||||
SendSQL("INSERT INTO groups " .
|
||||
"(group_bit, name, description, isbuggroup, userregexp) " .
|
||||
"VALUES (" .
|
||||
$bit . ", " .
|
||||
SqlQuote($product) . ", " .
|
||||
SqlQuote($product . " Bugs Access") . ", " .
|
||||
"1, " .
|
||||
SqlQuote($userregexp) . ")");
|
||||
|
||||
# And last, we need to add any existing users that match the regexp
|
||||
# to the group.
|
||||
# There may be a better way to do this in MySql, but I need to compare
|
||||
@@ -442,44 +389,15 @@ if ($action eq 'new') {
|
||||
# find matching users with a much simpler statement that lets the
|
||||
# mySQL database do the work.
|
||||
unless($userregexp eq "") {
|
||||
SendSQL("SELECT DISTINCT userid FROM profiles " .
|
||||
"WHERE admin = 1 OR " . SqlRegEx('login_name', "$userregexp"));
|
||||
my @winners = ();
|
||||
while (my ($userid) = FetchSQLData()) {
|
||||
push (@winners, $userid);
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles ".
|
||||
"SET groupset = groupset | " . $bit . " " .
|
||||
"WHERE " . SqlRegEx("login_name", SqlQuote($userregexp)));
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles ".
|
||||
"SET groupset = groupset | int8(" . $bit . ") " .
|
||||
"WHERE " . SqlRegEx("login_name", SqlQuote($userregexp)));
|
||||
}
|
||||
|
||||
foreach my $userid (@winners) {
|
||||
SendSQL("SELECT user_id FROM user_group_map " .
|
||||
"WHERE user_id = $userid AND group_id = $groupid");
|
||||
my $result = FetchOneColumn();
|
||||
if (!$result) {
|
||||
SendSQL("INSERT INTO user_group_map VALUES ($userid, $groupid, 0)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Update group permissions for this product
|
||||
my %newgroups = ();
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^group_/;
|
||||
detaint_natural($::FORM{$_});
|
||||
$newgroups{$::FORM{$_}} = 1;
|
||||
}
|
||||
|
||||
my %groupsbelong = ();
|
||||
SendSQL("select groups.group_id from groups, user_group_map " .
|
||||
"where groups.group_id = user_group_map.group_id " .
|
||||
"and groups.isbuggroup = 1 " .
|
||||
"and user_group_map.user_id = $userid");
|
||||
while (my ($groupid) = FetchSQLData()) {
|
||||
$groupsbelong{$groupid} = 1;
|
||||
}
|
||||
|
||||
foreach my $groupid (keys %groupsbelong) {
|
||||
if ($newgroups{$groupid}) {
|
||||
SendSQL("INSERT INTO product_group_map (product_id, group_id) VALUES ($productid, $groupid)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +450,23 @@ if ($action eq 'del') {
|
||||
print " <TD VALIGN=\"top\">$milestonelink</TD>\n";
|
||||
}
|
||||
|
||||
# Added -JMR, 2/16/00
|
||||
if(Param('usebuggroups')) {
|
||||
# Get the regexp for this product.
|
||||
SendSQL("SELECT userregexp
|
||||
FROM groups
|
||||
WHERE name=" . SqlQuote($product));
|
||||
my $userregexp = FetchOneColumn();
|
||||
if(!defined $userregexp) {
|
||||
$userregexp = "<FONT COLOR=\"red\">undefined</FONT>";
|
||||
} elsif ($userregexp eq "") {
|
||||
$userregexp = "<FONT COLOR=\"blue\">blank</FONT>";
|
||||
}
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">User Regexp for Bug Group:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$userregexp</TD>\n";
|
||||
}
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Closed for bugs:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">$disallownew</TD>\n";
|
||||
@@ -649,7 +584,7 @@ one.";
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting product");
|
||||
CheckProduct($product);
|
||||
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
@@ -661,14 +596,9 @@ if ($action eq 'delete') {
|
||||
products WRITE,
|
||||
groups WRITE,
|
||||
profiles WRITE,
|
||||
milestones WRITE,
|
||||
user_group_map WRITE,
|
||||
product_group_map WRITE");
|
||||
milestones WRITE");
|
||||
}
|
||||
|
||||
SendSQL("SELECT product_id FROM products WHERE product = " . SqlQuote($product));
|
||||
my $productid = FetchOneColumn();
|
||||
|
||||
# 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.
|
||||
@@ -709,25 +639,45 @@ if ($action eq 'delete') {
|
||||
WHERE product=" . SqlQuote($product));
|
||||
print "Milestones deleted.<BR>\n";
|
||||
|
||||
# Deleting any users from product group and delete group
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($product));
|
||||
my $groupid = FetchOneColumn();
|
||||
if ($groupid) {
|
||||
SendSQL("DELETE FROM user_group_map WHERE group_id = $groupid");
|
||||
SendSQL("DELETE FROM groups WHERE group_id = $groupid");
|
||||
print "Users removed from product group and group removed.<br>\n";
|
||||
}
|
||||
|
||||
# Deleting any product groups
|
||||
SendSQL("DELETE FROM product_group_map WHERE product_id = $productid");
|
||||
print "Other product groups deleted.<BR>\n";
|
||||
|
||||
SendSQL("DELETE FROM products
|
||||
WHERE product=" . SqlQuote($product));
|
||||
print "Product '$product' deleted.<BR>\n";
|
||||
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
# Added -JMR, 2/16/00
|
||||
if (Param("usebuggroups")) {
|
||||
# We need to get the bit of the group from the table, then update the
|
||||
# groupsets of members of that group and remove the group.
|
||||
SendSQL("SELECT group_bit, description FROM groups " .
|
||||
"WHERE name = " . SqlQuote($product));
|
||||
my ($bit, $group_desc) = FetchSQLData();
|
||||
|
||||
# Make sure there is a group before we try to do any deleting...
|
||||
if($bit) {
|
||||
# I'm kludging a bit so that I don't break superuser access;
|
||||
# I'm merely checking to make sure that the groupset is not
|
||||
# the superuser groupset in doing this update...
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles " .
|
||||
"SET groupset = groupset - $bit " .
|
||||
"WHERE (groupset & $bit) " .
|
||||
"AND (groupset != 9223372036854710271)");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles " .
|
||||
"SET groupset = groupset - $bit " .
|
||||
"WHERE (groupset & int8($bit)) " .
|
||||
"AND (groupset != int8(9223372036854710271))");
|
||||
}
|
||||
print "Users dropped from group '$group_desc'.<BR>\n";
|
||||
|
||||
SendSQL("DELETE FROM groups " .
|
||||
"WHERE group_bit = $bit");
|
||||
print "Group '$group_desc' deleted.<BR>\n";
|
||||
}
|
||||
}
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UNLOCK TABLES");
|
||||
}
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
@@ -755,10 +705,12 @@ if ($action eq 'edit') {
|
||||
FetchSQLData();
|
||||
|
||||
my $userregexp = '';
|
||||
SendSQL("SELECT userregexp
|
||||
FROM groups
|
||||
WHERE name=" . SqlQuote($product));
|
||||
$userregexp = FetchOneColumn() || "";
|
||||
if(Param("usebuggroups")) {
|
||||
SendSQL("SELECT userregexp
|
||||
FROM groups
|
||||
WHERE name=" . SqlQuote($product));
|
||||
$userregexp = FetchOneColumn() || "";
|
||||
}
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editproducts.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
@@ -849,8 +801,10 @@ if ($action eq 'edit') {
|
||||
value_quote($description) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"milestoneurlold\" VALUE=\"" .
|
||||
value_quote($milestoneurl) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"userregexpold\" VALUE=\"" .
|
||||
value_quote($userregexp) . "\">\n";
|
||||
if(Param("usebuggroups")) {
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"userregexpold\" VALUE=\"" .
|
||||
value_quote($userregexp) . "\">\n";
|
||||
}
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"disallownewold\" VALUE=\"$disallownew\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"votesperuserold\" VALUE=\"$votesperuser\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"maxvotesperbugold\" VALUE=\"$maxvotesperbug\">\n";
|
||||
@@ -876,8 +830,7 @@ if ($action eq 'edit') {
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update product");
|
||||
|
||||
my $productid = trim($::FORM{productid} || 0);
|
||||
|
||||
my $productold = trim($::FORM{productold} || '');
|
||||
my $description = trim($::FORM{description} || '');
|
||||
my $descriptionold = trim($::FORM{descriptionold} || '');
|
||||
@@ -895,8 +848,7 @@ if ($action eq 'update') {
|
||||
my $votestoconfirmold = trim($::FORM{votestoconfirmold} || 0);
|
||||
my $defaultmilestone = trim($::FORM{defaultmilestone} || '---');
|
||||
my $defaultmilestoneold = trim($::FORM{defaultmilestoneold} || '---');
|
||||
my $productgroup = trim($::FORM{productgroup} || 0);
|
||||
my $productgroupold = trim($::FORM{productgroupold} || 0);
|
||||
|
||||
my $checkvotes = 0;
|
||||
|
||||
CheckProduct($productold);
|
||||
@@ -911,14 +863,12 @@ if ($action eq 'update') {
|
||||
# them, be sure to test for WHERE='$product' or WHERE='$productold'
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("LOCK TABLES bugs WRITE,
|
||||
components WRITE,
|
||||
products WRITE,
|
||||
versions WRITE,
|
||||
groups WRITE,
|
||||
profiles WRITE,
|
||||
milestones WRITE,
|
||||
user_group_map WRITE,
|
||||
product_group_map WRITE");
|
||||
components WRITE,
|
||||
products WRITE,
|
||||
versions WRITE,
|
||||
groups WRITE,
|
||||
profiles WRITE,
|
||||
milestones WRITE");
|
||||
}
|
||||
|
||||
if ($disallownew ne $disallownewold) {
|
||||
@@ -951,89 +901,75 @@ if ($action eq 'update') {
|
||||
print "Updated mile stone URL.<BR>\n";
|
||||
}
|
||||
|
||||
if ($userregexp ne $userregexpold && $productgroup) {
|
||||
# Added -JMR, 2/16/00
|
||||
if (Param("usebuggroups") && $userregexp ne $userregexpold) {
|
||||
# This will take a little bit of work here, since there may not be
|
||||
# an existing bug group for this product, and we will also have to
|
||||
# update users groupsets.
|
||||
# First we find out if there's an existing group for this product, and
|
||||
# get its bit if there is.
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($productold));
|
||||
my $groupid = FetchOneColumn();
|
||||
if($groupid) {
|
||||
SendSQL("SELECT group_bit " .
|
||||
"FROM groups " .
|
||||
"WHERE name = " . SqlQuote($productold));
|
||||
my $bit = FetchOneColumn();
|
||||
if($bit) {
|
||||
# Group exists, so we do an update statement.
|
||||
SendSQL("UPDATE groups " .
|
||||
"SET userregexp = " . SqlQuote($userregexp) . " " .
|
||||
"WHERE name = " . SqlQuote($productold));
|
||||
print "Updated user regexp for bug group.<BR>\n";
|
||||
} else {
|
||||
# Next we insert into the groups table
|
||||
# Group doesn't exist. Let's make it, the same way as we make a
|
||||
# group for a new product above.
|
||||
SendSQL("SELECT MAX(group_bit) FROM groups");
|
||||
my $tmp_bit = FetchOneColumn();
|
||||
if($tmp_bit < 256) {
|
||||
$bit = 256;
|
||||
} else {
|
||||
$bit = $tmp_bit * 2;
|
||||
}
|
||||
SendSQL("INSERT INTO groups " .
|
||||
"(name, description, isbuggroup, userregexp) " .
|
||||
"VALUES (" .
|
||||
SqlQuote($product) . ", " .
|
||||
SqlQuote($product . " Bugs Access") . ", " .
|
||||
"(group_bit, name, description, isbuggroup, userregexp) " .
|
||||
"values (" . $bit . ", " .
|
||||
SqlQuote($productold) . ", " .
|
||||
SqlQuote($productold . " Bugs Access") . ", " .
|
||||
"1, " .
|
||||
SqlQuote($userregexp) . ")");
|
||||
print "Created bug group.<br>\n";
|
||||
print "Created bug group.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($productold));
|
||||
$groupid = FetchOneColumn();
|
||||
|
||||
# And last, we need to add any existing users that match the regexp
|
||||
# to the group. This does not remove pre-existing users that used to match.
|
||||
unless($userregexp eq "") {
|
||||
SendSQL("SELECT DISTINCT userid FROM profiles " .
|
||||
"WHERE admin = 1 OR " . SqlRegEx('login_name', $userregexp));
|
||||
my @winners = ();
|
||||
while (my ($userid) = FetchSQLData()) {
|
||||
push (@winners, $userid);
|
||||
}
|
||||
|
||||
foreach my $userid (@winners) {
|
||||
SendSQL("SELECT user_id FROM user_group_map " .
|
||||
"WHERE user_id = $userid AND group_id = $groupid");
|
||||
my $result = FetchOneColumn();
|
||||
if (!$result) {
|
||||
SendSQL("INSERT INTO user_group_map VALUES ($userid, $groupid, 0)");
|
||||
|
||||
# And now we have to update the profiles again to add any users who
|
||||
# match the new regexp to the group. I'll do this the same way as
|
||||
# when I create a new group above. Note that I'm not taking out
|
||||
# users who matched the old regexp and not the new one; that would
|
||||
# be insanely messy. Use the group administration page for that
|
||||
# instead.
|
||||
SendSQL("SELECT login_name FROM profiles");
|
||||
my @login_list = ();
|
||||
my $this_login;
|
||||
while($this_login = FetchOneColumn()) {
|
||||
push @login_list, $this_login;
|
||||
}
|
||||
my $updated_profiles = 0;
|
||||
foreach $this_login (@login_list) {
|
||||
if($this_login =~ /$userregexp/) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles " .
|
||||
"SET groupset = groupset | " . $bit . " " .
|
||||
"WHERE login_name = " . SqlQuote($this_login));
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles " .
|
||||
"SET groupset = groupset | int8(" . $bit . ") " .
|
||||
"WHERE login_name = " . SqlQuote($this_login));
|
||||
}
|
||||
$updated_profiles = 1;
|
||||
}
|
||||
}
|
||||
if($updated_profiles) {
|
||||
print "Added users matching regexp to group.<BR>\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Update group permissions for this product
|
||||
my %newgroups = ();
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^group_/;
|
||||
detaint_natural($::FORM{$_});
|
||||
$newgroups{$::FORM{$_}} = 1;
|
||||
}
|
||||
|
||||
my %groupsbelong = ();
|
||||
SendSQL("select groups.group_id from groups, user_group_map " .
|
||||
"where groups.group_id = user_group_map.group_id " .
|
||||
"and groups.isbuggroup = 1 " .
|
||||
"and user_group_map.user_id = $userid");
|
||||
while (my ($groupid) = FetchSQLData()) {
|
||||
$groupsbelong{$groupid} = 1;
|
||||
}
|
||||
|
||||
foreach my $groupid (keys %groupsbelong) {
|
||||
if ($newgroups{$groupid}) {
|
||||
SendSQL("SELECT group_id FROM product_group_map " .
|
||||
"WHERE product_id = $productid AND group_id = $groupid");
|
||||
if (!FetchOneColumn()) {
|
||||
SendSQL("INSERT INTO product_group_map (product_id, group_id) VALUES ($productid, $groupid)");
|
||||
}
|
||||
} else {
|
||||
SendSQL("DELETE FROM product_group_map " .
|
||||
"WHERE product_id = $productid AND group_id = $groupid");
|
||||
}
|
||||
}
|
||||
print "Groups updated.<br>\n";
|
||||
|
||||
|
||||
if ($votesperuser ne $votesperuserold) {
|
||||
SendSQL("UPDATE products
|
||||
SET votesperuser=$votesperuser
|
||||
@@ -1105,10 +1041,17 @@ if ($action eq 'update') {
|
||||
SendSQL("UPDATE products SET product=$qp WHERE product=$qpold");
|
||||
SendSQL("UPDATE versions SET program=$qp WHERE program=$qpold");
|
||||
SendSQL("UPDATE milestones SET product=$qp WHERE product=$qpold");
|
||||
# Need to do an update to groups as well. If there is a corresponding
|
||||
# bug group, whether usebuggroups is currently set or not, we want to
|
||||
# update it so it will match in the future. If there is no group, this
|
||||
# update statement will do nothing, so no harm done. -JMR, 3/8/00
|
||||
SendSQL("UPDATE groups " .
|
||||
"SET name=$qp, " .
|
||||
"description=".SqlQuote($product." Bugs Access")." ".
|
||||
"WHERE name=$qpold");
|
||||
|
||||
print "Updated product name.<BR>\n";
|
||||
}
|
||||
|
||||
unlink "data/versioncache";
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UNLOCK TABLES");
|
||||
|
||||
@@ -1,534 +0,0 @@
|
||||
#!/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
|
||||
#
|
||||
# This code was based on editversions.cgi code by Holger Schurig
|
||||
# <holgerschurig@nikocity.de>
|
||||
#
|
||||
# The Initial Developer of the Original code is Alex
|
||||
# Schuilenburg. Portions created by Alex Schuilenburg are
|
||||
# Copyright (C) 2002 Alex Schuilenburg. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Alex Schuilenburg <alex@schuilenburg.org>
|
||||
#
|
||||
#
|
||||
# Direct any questions on this source code to
|
||||
#
|
||||
# Alex Schuilenburg <alex@schuilenburg.org>
|
||||
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use lib ".";
|
||||
|
||||
require "CGI.pl";
|
||||
require "globals.pl";
|
||||
|
||||
|
||||
# This could be moved to localparams or globals.pl
|
||||
my %TableMap = (
|
||||
'bug_status' => 'States in which a bug can be in during its lifecycle',
|
||||
'bug_severity' => 'Impact the bug has on the application',
|
||||
'priority' => 'Subjective priority placed on a bug',
|
||||
'op_sys' => 'Host operating systems',
|
||||
'rep_platform' => 'Target platforms',
|
||||
'resolution' => 'State in which the bug was resolved'
|
||||
);
|
||||
|
||||
|
||||
# CheckTable: same check, optionally emit an error text
|
||||
# TestValue: just returns if the specified table/value combination exists
|
||||
# CheckValue: same check, optionally emit an error text
|
||||
|
||||
|
||||
sub CheckTable ($)
|
||||
{
|
||||
my $table = shift;
|
||||
my $ret;
|
||||
|
||||
# do we have a table?
|
||||
unless ($table) {
|
||||
print "Sorry, you haven't specified a table.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
$ret = $TableMap{$table};
|
||||
|
||||
unless ($ret) {
|
||||
print "Sorry, table '$table' does not exist or is not editable.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub TestValue ($$)
|
||||
{
|
||||
my ($table,$value) = @_;
|
||||
|
||||
# does the value exist?
|
||||
SendSQL("SELECT value
|
||||
FROM $table
|
||||
WHERE value=" . SqlQuote($value));
|
||||
return FetchOneColumn();
|
||||
}
|
||||
|
||||
sub CheckValue ($$)
|
||||
{
|
||||
my ($table,$value) = @_;
|
||||
# do we have the value?
|
||||
unless ($value) {
|
||||
print "Sorry, you haven't specified a value.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
my $desc = CheckTable($table);
|
||||
|
||||
unless (TestValue($table,$value)) {
|
||||
print "Sorry, value '$value' for table '$table' does not exist.";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Displays the form to edit a value
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$)
|
||||
{
|
||||
my ($table, $value) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Value:</TH>\n";
|
||||
print " <TD><INPUT SIZE=64 MAXLENGTH=64 NAME=\"value\" VALUE=\"" .
|
||||
value_quote($value) . "\">\n";
|
||||
print " <INPUT TYPE=HIDDEN NAME=\"table\" VALUE=\"" .
|
||||
value_quote($table) . "\"></TD>\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 <A HREF=\"query.cgi\">query page</A>", @_);
|
||||
|
||||
my $count = $#links;
|
||||
my $num = 0;
|
||||
print "<P>\n";
|
||||
foreach (@links) {
|
||||
print $_;
|
||||
if ($num == $count) {
|
||||
print ".\n";
|
||||
}
|
||||
elsif ($num == $count-1) {
|
||||
print " or ";
|
||||
}
|
||||
else {
|
||||
print ", ";
|
||||
}
|
||||
$num++;
|
||||
}
|
||||
PutFooter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
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 table values.\n";
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# often used variables
|
||||
#
|
||||
my $table = trim($::FORM{table} || '');
|
||||
my $value = trim($::FORM{value} || '');
|
||||
my $action = trim($::FORM{action} || '');
|
||||
my $localtrailer;
|
||||
if ($value) {
|
||||
$localtrailer = "<A HREF=\"edittable.cgi?table=" . url_quote($table) . "\">edit</A> more values";
|
||||
} else {
|
||||
$localtrailer = "<A HREF=\"edittable.cgi\">edit</A> more values";
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# table = '' -> Show nice list of values
|
||||
#
|
||||
|
||||
unless ($table) {
|
||||
PutHeader("Select table");
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit values of ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Description</TH>\n";
|
||||
print "</TR>";
|
||||
foreach $table ( keys %TableMap ) {
|
||||
my $description = $TableMap{$table};
|
||||
$description ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"edittable.cgi?table=", url_quote($table), "\"><B>$table</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\">$description</TD>\n";
|
||||
#print " <TD VALIGN=\"top\"><A HREF=\"edittable.cgi?action=edit&table=", url_quote($table), "\">Edit</A></TD>\n";
|
||||
}
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='' -> Show nice list of values
|
||||
#
|
||||
|
||||
unless ($action) {
|
||||
PutHeader("Select value of $table ($TableMap{$table})");
|
||||
CheckTable($table);
|
||||
|
||||
SendSQL("SELECT value
|
||||
FROM $table
|
||||
ORDER BY value");
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0><TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH ALIGN=\"left\">Edit value ...</TH>\n";
|
||||
print " <TH ALIGN=\"left\">Action</TH>\n";
|
||||
print "</TR>";
|
||||
while ( MoreSQLData() ) {
|
||||
my ($value) = FetchSQLData();
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"edittable.cgi?table=", url_quote($table), "&value=", url_quote($value), "&action=edit\"><B>$value</B></A></TD>\n";
|
||||
print " <TD VALIGN=\"top\"><A HREF=\"edittable.cgi?table=", url_quote($table), "&value=", url_quote($value), "&action=del\"><B>Delete</B></A></TD>\n";
|
||||
print "</TR>";
|
||||
}
|
||||
print "<TR>\n";
|
||||
print " <TD VALIGN=\"top\">Add a new value</TD>\n";
|
||||
print " <TD VALIGN=\"top\" ALIGN=\"middle\"><A HREF=\"edittable.cgi?table=", url_quote($table) . "&action=add\">Add</A></TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
PutTrailer();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='add' -> present form for parameters for new value
|
||||
#
|
||||
# (next action will be 'new')
|
||||
#
|
||||
|
||||
if ($action eq 'add') {
|
||||
PutHeader("Add value to $table ($TableMap{$table})");
|
||||
CheckTable($table);
|
||||
|
||||
#print "This page lets you add a new value to a table in bugzilla.\n";
|
||||
|
||||
print "<FORM METHOD=POST ACTION=edittable.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($table, $value);
|
||||
|
||||
print "</TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"new\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='new' -> add value entered in the 'action=add' screen
|
||||
#
|
||||
|
||||
if ($action eq 'new') {
|
||||
PutHeader("Adding new value to $table ($TableMap{$table})");
|
||||
CheckTable($table);
|
||||
|
||||
# Cleanups and valididy checks
|
||||
|
||||
unless ($value) {
|
||||
print "You must enter text for the new value. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestValue($table,$value)) {
|
||||
print "The value '$value' already exists. Please press\n";
|
||||
print "<b>Back</b> and try again.\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
# Add the new value
|
||||
SendSQL("INSERT INTO $table ( " .
|
||||
"value" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($value) . ")");
|
||||
|
||||
# Make versioncache flush
|
||||
unlink "data/versioncache";
|
||||
|
||||
print "OK, done.<p>\n";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='del' -> ask if user really wants to delete
|
||||
#
|
||||
# (next action would be 'delete')
|
||||
#
|
||||
|
||||
if ($action eq 'del') {
|
||||
PutHeader("Delete $value from $table ($TableMap{$table})");
|
||||
CheckValue($table, $value);
|
||||
|
||||
SendSQL("SELECT count(bug_id),$table
|
||||
FROM bugs
|
||||
GROUP BY $table
|
||||
HAVING $table
|
||||
=" . SqlQuote($value));
|
||||
my $bugs = FetchOneColumn();
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
print "<TR BGCOLOR=\"#6666FF\">\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Part</TH>\n";
|
||||
print " <TH VALIGN=\"top\" ALIGN=\"left\">Value</TH>\n";
|
||||
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Table:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">" . url_quote($table) . "</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Value:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">" . url_quote($value) . "</TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print " <TH ALIGN=\"left\" VALIGN=\"top\">Bugs:</TH>\n";
|
||||
print " <TD VALIGN=\"top\">", $bugs || 'none' , "</TD>\n";
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<H2>Confirmation</H2>\n";
|
||||
|
||||
if ($bugs) {
|
||||
if (!Param("allowbugdeletion")) {
|
||||
print "Sorry, there are $bugs bugs outstanding with this value.
|
||||
You must reassign those bugs to another value before you can delete this
|
||||
one.";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
print "<TABLE BORDER=0 CELLPADDING=20 WIDTH=\"70%\" BGCOLOR=\"red\"><TR><TD>\n",
|
||||
"There are bugs entered for this value! When you delete this ",
|
||||
"value, <B><BLINK>all</BLINK></B> stored bugs will be deleted, too. ",
|
||||
"You could not even see the bug history for this value anymore!\n",
|
||||
"</TD></TR></TABLE>\n";
|
||||
}
|
||||
|
||||
print "<P>Do you really want to delete this value?<P>\n";
|
||||
print "<FORM METHOD=POST ACTION=edittable.cgi>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Yes, delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"delete\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"table\" VALUE=\"" .
|
||||
value_quote($table) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"value\" VALUE=\"" .
|
||||
value_quote($value) . "\">\n";
|
||||
print "</FORM>";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='delete' -> really delete the value
|
||||
#
|
||||
|
||||
if ($action eq 'delete') {
|
||||
PutHeader("Deleting $value from $table ($TableMap{$table})");
|
||||
CheckValue($table,$value);
|
||||
|
||||
# lock the tables before we start to change everything:
|
||||
|
||||
SendSQL("LOCK TABLES attachments WRITE,
|
||||
bugs WRITE,
|
||||
bugs_activity WRITE,
|
||||
$table WRITE,
|
||||
dependencies WRITE") if $::driver eq 'mysql';
|
||||
|
||||
# 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 $table=" . SqlQuote($value));
|
||||
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.<BR>\n";
|
||||
|
||||
|
||||
# Deleting the rest is easier:
|
||||
|
||||
SendSQL("DELETE FROM bugs
|
||||
WHERE $table=" . SqlQuote($value));
|
||||
print "Bugs deleted.<BR>\n";
|
||||
}
|
||||
|
||||
SendSQL("DELETE FROM $table
|
||||
WHERE value=" . SqlQuote($value));
|
||||
print "Value deleted.<P>\n";
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
|
||||
unlink "data/versioncache";
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='edit' -> present the edit value form
|
||||
#
|
||||
# (next action would be 'update')
|
||||
#
|
||||
|
||||
if ($action eq 'edit') {
|
||||
PutHeader("Edit value of $table ($TableMap{$table})");
|
||||
CheckValue($table,$value);
|
||||
|
||||
print "<FORM METHOD=POST ACTION=edittable.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($table, $value);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"valueold\" VALUE=\"" .
|
||||
value_quote($value) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Update\">\n";
|
||||
|
||||
print "</FORM>";
|
||||
|
||||
my $other = $localtrailer;
|
||||
$other =~ s/more/other/;
|
||||
PutTrailer($other);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# action='update' -> update the value
|
||||
#
|
||||
|
||||
if ($action eq 'update') {
|
||||
PutHeader("Update value of $table ($TableMap{$table})");
|
||||
|
||||
my $valueold = trim($::FORM{valueold} || '');
|
||||
|
||||
CheckValue($table,$valueold);
|
||||
|
||||
# Note that the order of this tests is important. If you change
|
||||
# them, be sure to test for WHERE='$value' or WHERE='$valueold'
|
||||
|
||||
SendSQL("LOCK TABLES bugs WRITE, $table WRITE") if $::driver eq 'mysql';
|
||||
|
||||
if ($value ne $valueold) {
|
||||
unless ($value) {
|
||||
print "Sorry, I can't delete the value text.";
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
if (TestValue($table,$value)) {
|
||||
print "Sorry, value '$value' is already in use.";
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
SendSQL("UPDATE bugs
|
||||
SET $table=" . SqlQuote($value) . ",
|
||||
delta_ts = delta_ts
|
||||
WHERE $table=" . SqlQuote($valueold));
|
||||
SendSQL("UPDATE $table
|
||||
SET value=" . SqlQuote($value) . "
|
||||
WHERE value=" . SqlQuote($valueold));
|
||||
unlink "data/versioncache";
|
||||
print "Updated value.<BR>\n";
|
||||
}
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# No valid action found
|
||||
#
|
||||
|
||||
PutHeader("Error");
|
||||
print "I don't have a clue what you want.<BR>\n";
|
||||
|
||||
foreach ( sort keys %::FORM) {
|
||||
print "$_: $::FORM{$_}<BR>\n";
|
||||
}
|
||||
|
||||
@@ -37,8 +37,16 @@ require "globals.pl";
|
||||
# Shut up misguided -w warnings about "used only once". "use vars" just
|
||||
# doesn't work for me.
|
||||
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::userid;
|
||||
$zz = $::superusergroupset;
|
||||
}
|
||||
|
||||
my $editall;
|
||||
my %blessgroupset = (); # Groups that this viewer can bless someone into
|
||||
my $opblessgroupset = '72057594037927935'; # This is all 64 bits.
|
||||
|
||||
|
||||
|
||||
# TestUser: just returns if the specified user does exists
|
||||
# CheckUser: same check, optionally emit an error text
|
||||
@@ -90,9 +98,9 @@ sub EmitElement ($$)
|
||||
# Displays the form to edit a user parameters
|
||||
#
|
||||
|
||||
sub EmitFormElements ($$$$$$)
|
||||
sub EmitFormElements ($$$$$)
|
||||
{
|
||||
my ($user, $realname, $disabledtext, $groups_belong, $can_bless, $adminuser) = @_;
|
||||
my ($user, $realname, $groupset, $blessgroupset, $disabledtext) = @_;
|
||||
|
||||
print " <TH ALIGN=\"right\">Login name:</TH>\n";
|
||||
EmitElement("user", $user);
|
||||
@@ -125,87 +133,71 @@ sub EmitFormElements ($$$$$$)
|
||||
}
|
||||
|
||||
|
||||
if ($user ne "") {
|
||||
# Select admin access if user has 'edituser' privileges
|
||||
if ($editall) {
|
||||
my $adminchecked = $adminuser ? "CHECKED" : "";
|
||||
print "</TR><TR><TH VALIGN=TOP ALIGN=RIGHT>Admin User:</TH>\n";
|
||||
print "<TD><INPUT TYPE=\"checkbox\" NAME=\"admin\" VALUE=\"1\" $adminchecked></TD>\n";
|
||||
if($user ne "") {
|
||||
print "</TR><TR><TH VALIGN=TOP ALIGN=RIGHT>Group Access:</TH><TD><TABLE><TR>";
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT group_bit, name, description, (group_bit & $groupset) != 0, " .
|
||||
" (group_bit & $blessgroupset) != 0 " .
|
||||
"FROM groups " .
|
||||
"WHERE (group_bit & $opblessgroupset) != 0 AND isbuggroup != 0 " .
|
||||
"ORDER BY name");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit, name, description, (group_bit & int8($groupset)) != 0, " .
|
||||
" (group_bit & int8($blessgroupset)) != 0 " .
|
||||
"FROM groups " .
|
||||
"WHERE (group_bit & int8($opblessgroupset)) != 0 AND isbuggroup != 0 " .
|
||||
"ORDER BY name");
|
||||
}
|
||||
|
||||
# Edit bug groups
|
||||
print "</TR><TR><TH VALIGN=TOP ALIGN=RIGHT>Group Access:</TH><TD>\n<TABLE><TR>\n";
|
||||
SendSQL("SELECT group_id, name, description FROM groups " .
|
||||
"WHERE isbuggroup = 1 ORDER BY name");
|
||||
|
||||
if (MoreSQLData()) {
|
||||
if ($editall) {
|
||||
print "<TD COLSPAN=3 ALIGN=LEFT><B>Can turn this on for other users</B></TD>\n";
|
||||
print "</TR><TR>\n";
|
||||
print "<TD ALIGN=CENTER><B>|</B></TD>\n";
|
||||
}
|
||||
else {
|
||||
print "<TD COLSPAN=3></TD>\n</TR><TR>\n<TD></TD>\n";
|
||||
print "<TD COLSPAN=3 ALIGN=LEFT><B>Can turn this bit on for other users</B></TD>\n";
|
||||
print "</TR><TR>\n<TD ALIGN=CENTER><B>|</B></TD>\n";
|
||||
}
|
||||
print "<TD COLSPAN=2 ALIGN=LEFT><B>User is a member of these groups</B></TD>\n";
|
||||
}
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($groupid, $name, $description) = FetchSQLData();
|
||||
my ($bless_checked, $group_checked);
|
||||
my $canedit = 0;
|
||||
print "</TR><TR>\n";
|
||||
if ($editall) {
|
||||
$bless_checked = $can_bless->{$groupid} ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"bless_$name\" $bless_checked VALUE=\"$groupid\"></TD>";
|
||||
} else {
|
||||
print "<TD></TD>\n";
|
||||
}
|
||||
if ($editall || $blessgroupset{$groupid}) {
|
||||
$group_checked = $groups_belong->{$groupid} ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"group_$name\" $group_checked VALUE=\"$groupid\"></TD>";
|
||||
$canedit = 1;
|
||||
} else {
|
||||
print "<TD></TD>\n";
|
||||
}
|
||||
if ($canedit) {
|
||||
while (MoreSQLData()) {
|
||||
my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData();
|
||||
print "</TR><TR>\n";
|
||||
if ($editall) {
|
||||
$blchecked = ($blchecked) ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"blbit_$name\" $blchecked VALUE=\"$bit\"></TD>";
|
||||
}
|
||||
$checked = ($checked) ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"bit_$name\" $checked VALUE=\"$bit\"></TD>";
|
||||
print "<TD><B>" . ucfirst($name) . "</B>: $description</TD>\n";
|
||||
}
|
||||
}
|
||||
print "</TR></TABLE></TD>\n";
|
||||
|
||||
# Non non bug groups
|
||||
print "</TR><TR><TH VALIGN=TOP ALIGN=RIGHT>Privileges:</TH><TD>\n<TABLE><TR>\n";
|
||||
SendSQL("SELECT group_id, name, description " .
|
||||
"FROM groups " .
|
||||
"WHERE isbuggroup != 1 " .
|
||||
"ORDER BY name");
|
||||
print "</TR><TR><TH VALIGN=TOP ALIGN=RIGHT>Privileges:</TH><TD><TABLE><TR>";
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT group_bit, name, description, (group_bit & $groupset) != 0, " .
|
||||
" (group_bit & $blessgroupset) != 0 " .
|
||||
"FROM groups " .
|
||||
"WHERE (group_bit & $opblessgroupset) != 0 AND isbuggroup = 0 " .
|
||||
"ORDER BY name");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit, name, description, (group_bit & int8($groupset)) != 0, " .
|
||||
" (group_bit & int8($blessgroupset)) != 0 " .
|
||||
"FROM groups " .
|
||||
"WHERE (group_bit & int8($opblessgroupset)) != 0 AND isbuggroup = 0 " .
|
||||
"ORDER BY name");
|
||||
}
|
||||
if (MoreSQLData()) {
|
||||
if ($editall) {
|
||||
print "<TD COLSPAN=3 ALIGN=LEFT><B>Can turn this on for other users</B></TD>\n";
|
||||
print "<TD COLSPAN=3 ALIGN=LEFT><B>Can turn this bit on for other users</B></TD>\n";
|
||||
print "</TR><TR>\n<TD ALIGN=CENTER><B>|</B></TD>\n";
|
||||
}
|
||||
print "<TD COLSPAN=2 ALIGN=LEFT><B>User has these privileges</B></TD>\n";
|
||||
while (MoreSQLData()) {
|
||||
my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData();
|
||||
print "</TR><TR>\n";
|
||||
print "<TD ALIGN=CENTER><B>|</B></TD>\n";
|
||||
} else {
|
||||
print "<TD COLSPAN=3></TD>\n</TR><TR>\n<TD></TD>\n";
|
||||
}
|
||||
print "<TD COLSPAN=2 ALIGN=LEFT><B>User has these privileges.</B></TD>\n";
|
||||
}
|
||||
while (MoreSQLData()) {
|
||||
my ($groupid, $name, $description) = FetchSQLData();
|
||||
my ($bless_checked, $group_checked);
|
||||
my $canedit = 0;
|
||||
print "</TR><TR>\n";
|
||||
if ($editall) {
|
||||
$bless_checked = $can_bless->{$groupid} ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"bless_$name\" $bless_checked VALUE=\"$groupid\"></TD>";
|
||||
} else {
|
||||
print "<TD></TD>\n";
|
||||
}
|
||||
if ($editall || $blessgroupset{$groupid}) {
|
||||
$group_checked = $groups_belong->{$groupid} ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"group_$name\" $group_checked VALUE=\"$groupid\"></TD>";
|
||||
if ($editall) {
|
||||
$blchecked = ($blchecked) ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"blbit_$name\" $blchecked VALUE=\"$bit\"></TD>";
|
||||
}
|
||||
$checked = ($checked) ? "CHECKED" : "";
|
||||
print "<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX NAME=\"bit_$name\" $checked VALUE=\"$bit\"></TD>";
|
||||
print "<TD><B>" . ucfirst($name) . "</B>: $description</TD>\n";
|
||||
$canedit = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -255,19 +247,16 @@ sub PutTrailer (@)
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
$editall = UserInGroup($userid, "editusers");
|
||||
$editall = UserInGroup("editusers");
|
||||
|
||||
if (!$editall) {
|
||||
SendSQL("SELECT group_id FROM user_group_map WHERE user_id = $userid AND canbless = 1");
|
||||
while (my @row = FetchSQLData()) {
|
||||
$blessgroupset{$row[0]} = 1;
|
||||
}
|
||||
|
||||
unless (%blessgroupset) {
|
||||
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $::userid");
|
||||
$opblessgroupset = FetchOneColumn();
|
||||
if (!$opblessgroupset) {
|
||||
PutHeader("Not allowed");
|
||||
print "Sorry, you aren't a member of the 'editusers' group, and you\n";
|
||||
print "don't have permissions to put people in or out of any group.\n";
|
||||
@@ -336,15 +325,10 @@ if ($action eq 'list') {
|
||||
}
|
||||
$query .= " ORDER BY login_name";
|
||||
} elsif (exists $::FORM{'query'}) {
|
||||
$query = "SELECT login_name,realname,disabledtext " .
|
||||
"FROM profiles WHERE " . $::FORM{'query'} . " ORDER BY login_name";
|
||||
} elsif (exists $::FORM{'group'}) {
|
||||
$query = "SELECT login_name,realname,disabledtext " .
|
||||
"FROM profiles, user_group_map " .
|
||||
"WHERE profiles.userid = user_group_map.user_id " .
|
||||
"AND user_group_map.group_id = " . $::FORM{'group'} . " ORDER BY login_name";
|
||||
$query = "SELECT login_name,realname,disabledtext " .
|
||||
"FROM profiles WHERE " . $::FORM{'query'} . " ORDER BY login_name";
|
||||
} else {
|
||||
die "Missing parameters";
|
||||
die "Missing parameters";
|
||||
}
|
||||
|
||||
SendSQL($query);
|
||||
@@ -423,7 +407,7 @@ if ($action eq 'add') {
|
||||
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements('', '', '', '', '', 0);
|
||||
EmitFormElements('', '', 0, 0, '');
|
||||
|
||||
print "</TR></TABLE>\n<HR>\n";
|
||||
print "<INPUT TYPE=SUBMIT VALUE=\"Add\">\n";
|
||||
@@ -496,40 +480,38 @@ if ($action eq 'new') {
|
||||
# their initial group membership.
|
||||
# We also keep a list of groups the user was added to for display on the
|
||||
# confirmation page.
|
||||
my @groupidlist = ();
|
||||
my @groupnamelist = ();
|
||||
SendSQL("select group_id, name, userregexp from groups where userregexp != ''");
|
||||
my $bits = "0";
|
||||
my @grouplist = ();
|
||||
SendSQL("select group_bit, name, userregexp from groups where userregexp != ''");
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
if ($user =~ m/$row[2]/i) {
|
||||
push(@groupidlist, $row[0]);
|
||||
push(@groupnamelist, $row[1]);
|
||||
$bits .= "+ $row[0]"; # Silly hack to let MySQL do the math,
|
||||
# not Perl, since we're dealing with 64
|
||||
# bit ints here, and I don't *think* Perl
|
||||
# does that.
|
||||
push(@grouplist, $row[1]);
|
||||
}
|
||||
}
|
||||
|
||||
# Add the new user
|
||||
SendSQL("INSERT INTO profiles ( " .
|
||||
"login_name, cryptpassword, realname, disabledtext" .
|
||||
"login_name, cryptpassword, realname, groupset, " .
|
||||
"disabledtext" .
|
||||
" ) VALUES ( " .
|
||||
SqlQuote($user) . "," .
|
||||
SqlQuote(Crypt($password)) . "," .
|
||||
SqlQuote($realname) . "," .
|
||||
$bits . "," .
|
||||
SqlQuote($disabledtext) . ")" );
|
||||
|
||||
#+++ send e-mail away
|
||||
|
||||
# grab userid and place user in each of the groups they need to be
|
||||
SendSQL("select userid from profiles where login_name = " . SqlQuote($user));
|
||||
my $userid = FetchOneColumn();
|
||||
foreach my $groupid ( @groupidlist ) {
|
||||
SendSQL("INSERT INTO user_group_map (user_id, group_id) VALUES ($userid, $groupid)");
|
||||
}
|
||||
|
||||
print "OK, done.<br>\n";
|
||||
if($#groupidlist > -1) {
|
||||
if($#grouplist > -1) {
|
||||
print "New user added to these groups based on group regexps:\n";
|
||||
print "<ul>\n";
|
||||
foreach (@groupnamelist) {
|
||||
foreach (@grouplist) {
|
||||
print "<li>$_</li>\n";
|
||||
}
|
||||
print "</ul>\n";
|
||||
@@ -567,9 +549,10 @@ if ($action eq 'del') {
|
||||
CheckUser($user);
|
||||
|
||||
# display some data about the user
|
||||
SendSQL("SELECT userid, realname FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my ($theuserid, $realname) = FetchSQLData();
|
||||
SendSQL("SELECT realname, groupset FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my ($realname, $groupset) =
|
||||
FetchSQLData();
|
||||
$realname ||= "<FONT COLOR=\"red\">missing</FONT>";
|
||||
|
||||
print "<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>\n";
|
||||
@@ -588,11 +571,17 @@ if ($action eq 'del') {
|
||||
print "</TR><TR>\n";
|
||||
print " <TD VALIGN=\"top\">Group set:</TD>\n";
|
||||
print " <TD VALIGN=\"top\">";
|
||||
SendSQL("SELECT name
|
||||
FROM groups, user_group_map
|
||||
WHERE groups.group_id = user_group_map.group_id
|
||||
AND user_group_map.user_id = $theuserid
|
||||
ORDER BY isbuggroup, name");
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT name
|
||||
FROM groups
|
||||
WHERE bit & $groupset = bit
|
||||
ORDER BY isbuggroup, name");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT name
|
||||
FROM groups
|
||||
WHERE (group_bit & int8($groupset)) = group_bit
|
||||
ORDER BY isbuggroup, name");
|
||||
}
|
||||
my $found = 0;
|
||||
while ( MoreSQLData() ) {
|
||||
my ($name) = FetchSQLData();
|
||||
@@ -705,8 +694,6 @@ if ($action eq 'delete') {
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
SendSQL("DELETE FROM logincookies
|
||||
WHERE userid=" . $userid);
|
||||
SendSQL("DELETE FROM user_group_map
|
||||
WHERE user_id=" . $userid);
|
||||
print "User deleted.<BR>\n";
|
||||
|
||||
PutTrailer($localtrailer);
|
||||
@@ -726,38 +713,23 @@ if ($action eq 'edit') {
|
||||
CheckUser($user);
|
||||
|
||||
# get data of user
|
||||
SendSQL("SELECT userid, realname, disabledtext
|
||||
FROM profiles
|
||||
WHERE login_name = " . SqlQuote($user));
|
||||
my ($userid, $realname, $disabledtext) = FetchSQLData();
|
||||
|
||||
# find out which groups belong to
|
||||
my $groups_belong = {};
|
||||
SendSQL("SELECT group_id FROM user_group_map WHERE user_id = $userid");
|
||||
while ( my @row = FetchSQLData() ) {
|
||||
$groups_belong->{$row[0]} = 1;
|
||||
}
|
||||
|
||||
# find out when groups this person can bless others into
|
||||
my $bless_belong = {};
|
||||
SendSQL("SELECT group_id FROM user_group_map WHERE user_id = $userid AND canbless = 1");
|
||||
while ( my @row = FetchSQLData() ) {
|
||||
$bless_belong->{$row[0]} = 1;
|
||||
}
|
||||
|
||||
# Determine if this user is an administrator or not
|
||||
SendSQL("SELECT admin FROM profiles WHERE userid = $userid");
|
||||
my $adminuser = FetchOneColumn();
|
||||
SendSQL("SELECT realname, groupset, blessgroupset, disabledtext
|
||||
FROM profiles
|
||||
WHERE login_name=" . SqlQuote($user));
|
||||
my ($realname, $groupset, $blessgroupset,
|
||||
$disabledtext) = FetchSQLData();
|
||||
|
||||
print "<FORM METHOD=POST ACTION=editusers.cgi>\n";
|
||||
print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n";
|
||||
|
||||
EmitFormElements($user, $realname, $disabledtext, $groups_belong, $bless_belong, $adminuser);
|
||||
EmitFormElements($user, $realname, $groupset, $blessgroupset, $disabledtext);
|
||||
|
||||
print "</TR></TABLE>\n";
|
||||
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"$user\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"$realname\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"groupsetold\" VALUE=\"$groupset\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"blessgroupsetold\" VALUE=\"$blessgroupset\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"disabledtextold\" VALUE=\"" .
|
||||
value_quote($disabledtext) . "\">\n";
|
||||
print "<INPUT TYPE=HIDDEN NAME=\"action\" VALUE=\"update\">\n";
|
||||
@@ -784,80 +756,75 @@ if ($action eq 'update') {
|
||||
my $password = $::FORM{password} || '';
|
||||
my $disabledtext = trim($::FORM{disabledtext} || '');
|
||||
my $disabledtextold = trim($::FORM{disabledtextold} || '');
|
||||
my $groupsetold = trim($::FORM{groupsetold} || '0');
|
||||
my $blessgroupsetold = trim($::FORM{blessgroupsetold} || '0');
|
||||
|
||||
my %groupset = ();
|
||||
my %blessgroupset = ();
|
||||
|
||||
my $groupset = "0";
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^group_/;
|
||||
next unless /^bit_/;
|
||||
#print "$_=$::FORM{$_}<br>\n";
|
||||
detaint_natural($::FORM{$_}) || die "Groupset field tampered with";
|
||||
$groupset{$::FORM{$_}} = 1;
|
||||
$groupset .= " + $::FORM{$_}";
|
||||
}
|
||||
my $blessgroupset = "0";
|
||||
foreach (keys %::FORM) {
|
||||
next unless /^bless_/;
|
||||
next unless /^blbit_/;
|
||||
#print "$_=$::FORM{$_}<br>\n";
|
||||
detaint_natural($::FORM{$_}) || die "Blessgroupset field tampered with";
|
||||
$blessgroupset{$::FORM{$_}} = 1;
|
||||
$blessgroupset .= " + $::FORM{$_}";
|
||||
}
|
||||
|
||||
CheckUser($userold);
|
||||
|
||||
SendSQL("SELECT userid, admin FROM profiles WHERE login_name = " . SqlQuote($userold));
|
||||
my ($userid, $isadmin) = FetchSQLData();
|
||||
# Note that the order of this tests is important. If you change
|
||||
# them, be sure to test for WHERE='$product' or WHERE='$productold'
|
||||
|
||||
if ($editall) {
|
||||
if (defined $::FORM{'admin'} && $::FORM{'admin'} == 1 && !$isadmin) {
|
||||
SendSQL("UPDATE profiles SET admin = 1 WHERE login_name = " . SqlQuote($userold));
|
||||
print "Added administrator status.<br>\n";
|
||||
} elsif (!defined $::FORM{'admin'} && $::FORM{'admin'} == 0 && $isadmin) {
|
||||
SendSQL("UPDATE profiles SET admin = 0 WHERE login_name = " . SqlQuote($userold));
|
||||
print "Removed administrator status.<br>\n";
|
||||
}
|
||||
if ($groupset ne $groupsetold) {
|
||||
SendSQL("SELECT groupset FROM profiles WHERE login_name=" .
|
||||
SqlQuote($userold));
|
||||
$groupsetold = FetchOneColumn();
|
||||
# Updated, 5/7/00, Joe Robins
|
||||
# We don't want to change the groupset of a superuser.
|
||||
if($groupsetold eq $::superusergroupset) {
|
||||
print "Cannot change permissions of superuser.\n";
|
||||
} else {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE profiles
|
||||
SET groupset =
|
||||
groupset - (groupset & $opblessgroupset) +
|
||||
(($groupset) & $opblessgroupset)
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE profiles
|
||||
SET groupset =
|
||||
groupset - (groupset & int8($opblessgroupset)) +
|
||||
((int8($groupset)) & int8($opblessgroupset))
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
}
|
||||
# I'm paranoid that someone who I give the ability to bless people
|
||||
# will start misusing it. Let's log who blesses who (even though
|
||||
# nothing actually uses this log right now).
|
||||
my $fieldid = GetFieldID("groupset");
|
||||
SendSQL("SELECT userid, groupset FROM profiles WHERE login_name=" .
|
||||
SqlQuote($userold));
|
||||
my $u;
|
||||
($u, $groupset) = (FetchSQLData());
|
||||
if ($groupset ne $groupsetold) {
|
||||
SendSQL("INSERT INTO profiles_activity " .
|
||||
"(userid,who,profiles_when,fieldid,oldvalue,newvalue) " .
|
||||
"VALUES " .
|
||||
"($u, $::userid, now(), $fieldid, " .
|
||||
" '$groupsetold', '$groupset')");
|
||||
}
|
||||
print "Updated permissions.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isadmin || $editall) {
|
||||
my %groups = ();
|
||||
my %oldgroupset = ();
|
||||
my %oldblessgroupset = ();
|
||||
|
||||
SendSQL("SELECT group_id, canbless FROM user_group_map WHERE user_id = $userid");
|
||||
while (my @row = FetchSQLData()) {
|
||||
$oldgroupset{$row[0]} = 1;
|
||||
$oldblessgroupset{$row[0]} = $row[1];
|
||||
}
|
||||
|
||||
SendSQL("SELECT group_id FROM groups");
|
||||
while (my @row = FetchSQLData()) {
|
||||
$groups{$row[0]} = 1;
|
||||
}
|
||||
|
||||
foreach my $groupid (keys %groups) {
|
||||
if ($editall || $blessgroupset{$groupid}) {
|
||||
if (!$oldgroupset{$groupid} && $groupset{$groupid}) {
|
||||
SendSQL("INSERT INTO user_group_map (user_id, group_id, canbless) VALUES ($userid, $groupid, 0)");
|
||||
}
|
||||
if ($oldgroupset{$groupid} && !$groupset{$groupid}) {
|
||||
SendSQL("DELETE FROM user_group_map WHERE user_id = $userid AND group_id = $groupid");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "Updated permissions<br>\n";
|
||||
|
||||
foreach my $groupid (keys %groups) {
|
||||
if ($editall) {
|
||||
if (!$oldblessgroupset{$groupid} && $blessgroupset{$groupid}) {
|
||||
SendSQL("UPDATE user_group_map SET canbless = 1 WHERE user_id = $userid AND group_id = $groupid");
|
||||
}
|
||||
if ($oldblessgroupset{$groupid} && !$blessgroupset{$groupid}) {
|
||||
SendSQL("UPDATE user_group_map SET canbless = 0 WHERE user_id = $userid AND group_id = $groupid");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "Updated ability to tweak permissions of other users.<br>\n";
|
||||
|
||||
} else {
|
||||
print "Cannot change permissions of a superuser.<br>\n";
|
||||
if ($editall && $blessgroupset ne $blessgroupsetold) {
|
||||
SendSQL("UPDATE profiles
|
||||
SET blessgroupset=" . $blessgroupset . "
|
||||
WHERE login_name=" . SqlQuote($userold));
|
||||
print "Updated ability to tweak permissions of other users.\n";
|
||||
}
|
||||
|
||||
# Update the database with the user's new password if they changed it.
|
||||
|
||||
@@ -155,11 +155,11 @@ sub PutTrailer (@)
|
||||
# Preliminary checks:
|
||||
#
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
print "Content-type: text/html\n\n";
|
||||
|
||||
unless (UserInGroup($userid, "editcomponents")) {
|
||||
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 versions.\n";
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
require "CGI.pl";
|
||||
@@ -52,7 +51,6 @@ use vars qw(
|
||||
@legal_severity
|
||||
%MFORM
|
||||
%versions
|
||||
%proddesc
|
||||
);
|
||||
|
||||
# We have to connect to the database, even though we don't use it in this code,
|
||||
@@ -61,23 +59,23 @@ use vars qw(
|
||||
ConnectToDatabase();
|
||||
|
||||
# If we're using bug groups to restrict bug entry, we need to know who the
|
||||
# user is right from the start.
|
||||
my $userid = confirm_login();
|
||||
# user is right from the start.
|
||||
confirm_login() if (Param("usebuggroupsentry"));
|
||||
|
||||
if (!defined $::FORM{'product'}) {
|
||||
GetVersionTable();
|
||||
$userid = quietly_check_login();
|
||||
|
||||
my %products;
|
||||
|
||||
foreach my $p (@enterable_products) {
|
||||
# If we're using bug groups to restrict entry on products, and
|
||||
# this product is private to one or more bug groups and the user is not
|
||||
# in one of those groups group, we don't want to include that product in this list.
|
||||
next if !CanSeeProduct($userid, $p);
|
||||
$products{$p} = $proddesc{$p};
|
||||
if (!(Param("usebuggroupsentry")
|
||||
&& GroupExists($p)
|
||||
&& !UserInGroup($p)))
|
||||
{
|
||||
$products{$p} = $::proddesc{$p};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $prodsize = scalar(keys %products);
|
||||
if ($prodsize == 0) {
|
||||
DisplayError("Either no products have been defined to enter bugs ".
|
||||
@@ -221,11 +219,16 @@ sub pickos {
|
||||
# End of subroutines
|
||||
##############################################################################
|
||||
|
||||
$userid = confirm_login();
|
||||
confirm_login() if (!(Param("usebuggroupsentry")));
|
||||
|
||||
if (!CanSeeProduct($userid, $product)) {
|
||||
# If the usebuggroupsentry parameter is set, we need to check and make sure
|
||||
# that the user has permission to enter a bug against this product.
|
||||
if(Param("usebuggroupsentry")
|
||||
&& GroupExists($product)
|
||||
&& !UserInGroup($product))
|
||||
{
|
||||
DisplayError("Sorry; you do not have the permissions necessary to " .
|
||||
"enter a bug against this product.\n");
|
||||
"enter a bug against this product.\n");
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -239,16 +242,19 @@ if (lsearch(\@::enterable_products, $product) == -1) {
|
||||
if (0 == @{$::components{$product}}) {
|
||||
my $error = "Sorry; there needs to be at least one component for this " .
|
||||
"product in order to create a new bug. ";
|
||||
if (UserInGroup($userid, 'editcomponents')) {
|
||||
if (UserInGroup('editcomponents')) {
|
||||
$error .= "<a href=\"editcomponents.cgi\">" .
|
||||
"Create a new component</a>\n";
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$error .= "Please contact " . Param("maintainer") . ", detailing " .
|
||||
"the product in which you tried to create a new bug.\n";
|
||||
}
|
||||
}
|
||||
|
||||
DisplayError($error);
|
||||
exit;
|
||||
} elsif (1 == @{$::components{$product}}) {
|
||||
}
|
||||
elsif (1 == @{$::components{$product}}) {
|
||||
# Only one component; just pick it.
|
||||
$::FORM{'component'} = $::components{$product}->[0];
|
||||
}
|
||||
@@ -301,65 +307,78 @@ $default{'version'} = $vars->{'version'}->[$#{$vars->{'version'}}];
|
||||
# There must be at least one status in @status.
|
||||
my @status = "NEW";
|
||||
|
||||
if (UserInGroup($userid, "editbugs") || UserInGroup($userid, "canconfirm")) {
|
||||
SendSQL("SELECT votestoconfirm FROM products WHERE product = " . SqlQuote($product));
|
||||
if (UserInGroup("editbugs") || UserInGroup("canconfirm")) {
|
||||
SendSQL("SELECT votestoconfirm FROM products WHERE product = " .
|
||||
SqlQuote($product));
|
||||
push(@status, $unconfirmedstate) if (FetchOneColumn());
|
||||
}
|
||||
|
||||
$vars->{'bug_status'} = \@status;
|
||||
$default{'bug_status'} = $status[0];
|
||||
|
||||
if ($userid) {
|
||||
my %productgroups;
|
||||
SendSQL("SELECT product_group_map.group_id " .
|
||||
"FROM product_group_map, products " .
|
||||
"WHERE product_group_map.product_id = products.product_id " .
|
||||
"AND products.product = " . SqlQuote($product));
|
||||
while (my ($groupid) = FetchSQLData()) {
|
||||
$productgroups{$groupid} = 1;
|
||||
}
|
||||
|
||||
SendSQL("SELECT user_group_map.group_id, groups.name, groups.description " .
|
||||
"FROM user_group_map, groups " .
|
||||
"WHERE user_group_map.group_id = groups.group_id " .
|
||||
"AND user_group_map.user_id = $userid " .
|
||||
"AND groups.isbuggroup != 0 AND groups.isactive = 1 " .
|
||||
"ORDER BY description");
|
||||
# Select whether to restrict this bug to the product's bug group or not,
|
||||
# if the usebuggroups parameter is set, and if this product has a bug group.
|
||||
if ($::usergroupset ne '0') {
|
||||
# First we get the bit and description for the group.
|
||||
my $group_bit = '0';
|
||||
|
||||
if(Param("usebuggroups") && GroupExists($product)) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bit FROM groups ".
|
||||
"WHERE name = " . SqlQuote($product) . " " .
|
||||
"AND isbuggroup != 0");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit FROM groups ".
|
||||
"WHERE name = " . SqlQuote($product) . " " .
|
||||
"AND isbuggroup != 0");
|
||||
}
|
||||
($group_bit) = FetchSQLData();
|
||||
}
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bit, name, description FROM groups " .
|
||||
"WHERE (group_bit & $::usergroupset) != 0 " .
|
||||
" AND isbuggroup != 0 AND isactive = 1 ORDER BY description");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit, name, description FROM groups " .
|
||||
"WHERE (group_bit & int8($::usergroupset)) != 0 " .
|
||||
" AND isbuggroup != 0 AND isactive = 1 ORDER BY description");
|
||||
}
|
||||
|
||||
my @groups;
|
||||
|
||||
while (MoreSQLData()) {
|
||||
my ($id, $name, $description) = FetchSQLData();
|
||||
my ($bit, $prodname, $description) = FetchSQLData();
|
||||
# Don't want to include product groups other than this product.
|
||||
next unless($name eq $product ||
|
||||
!defined($::proddesc{$name}));
|
||||
next unless($prodname eq $product ||
|
||||
!defined($::proddesc{$prodname}));
|
||||
|
||||
my $check;
|
||||
|
||||
# If this is the group for this product, make it checked.
|
||||
if(formvalue("maketemplate") eq
|
||||
"Remember values as bookmarkable template")
|
||||
if(formvalue("maketemplate") eq
|
||||
"Remember values as bookmarkable template")
|
||||
{
|
||||
# If this is a bookmarked template, then we only want to set the
|
||||
# bit for those bits set in the template.
|
||||
$check = formvalue("group-$id", 0);
|
||||
$check = formvalue("bit-$bit", 0);
|
||||
}
|
||||
else {
|
||||
# $group_bit will only have a non-zero value if we're using
|
||||
# bug groups and have one for this product.
|
||||
# If $group_bit is 0, it won't match the current group, so compare
|
||||
# it to the current bit instead of checking for non-zero.
|
||||
$check = $productgroups{$id} ? 1 : 0;
|
||||
$check = ($group_bit == $bit);
|
||||
}
|
||||
|
||||
my $group =
|
||||
my $group =
|
||||
{
|
||||
'bit' => $id ,
|
||||
'checked' => $check ,
|
||||
'description' => $description
|
||||
'bit' => $bit ,
|
||||
'checked' => $check ,
|
||||
'description' => $description
|
||||
};
|
||||
|
||||
push @groups, $group;
|
||||
push @groups, $group;
|
||||
}
|
||||
|
||||
$vars->{'group'} = \@groups;
|
||||
|
||||
@@ -54,8 +54,9 @@ sub globals_pl_sillyness {
|
||||
$zz = @main::milestoneurl;
|
||||
$zz = %main::proddesc;
|
||||
$zz = @main::prodmaxvotes;
|
||||
$zz = $main::superusergroupset;
|
||||
$zz = $main::template;
|
||||
$zz = $main::template;
|
||||
$zz = $main::userid;
|
||||
$zz = $main::vars;
|
||||
}
|
||||
|
||||
@@ -65,10 +66,10 @@ sub globals_pl_sillyness {
|
||||
#
|
||||
|
||||
$::db_host = "localhost";
|
||||
$::db_port = 3306;
|
||||
$::db_port = 5432;
|
||||
$::db_name = "bugs";
|
||||
$::db_user = "bugs";
|
||||
$::db_pass = "n0morehax";
|
||||
$::db_pass = "";
|
||||
|
||||
# Set this your database driver
|
||||
# $::driver = "mysql";
|
||||
@@ -109,6 +110,10 @@ $::defaultqueryname = "(Default query)";
|
||||
$::unconfirmedstate = "UNCONFIRMED";
|
||||
$::dbwritesallowed = 1;
|
||||
|
||||
# Adding a global variable for the value of the superuser groupset.
|
||||
# Joe Robins, 7/5/00
|
||||
$::superusergroupset = "72057594037927935";
|
||||
|
||||
#sub die_with_dignity {
|
||||
# my ($err_msg) = @_;
|
||||
# print $err_msg;
|
||||
@@ -147,25 +152,6 @@ sub ConnectToDatabase {
|
||||
|| die "Bugzilla is currently broken. Please try again later. " .
|
||||
"If the problem persists, please contact " . Param("maintainer") .
|
||||
". The error you should quote is: " . $DBI::errstr;
|
||||
if ($::driver eq 'Pg' && Param('usetransactions')) {
|
||||
$::db->{AutoCommit} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub EndTransaction {
|
||||
if ($::driver eq 'Pg' && Param('usetransactions')) {
|
||||
if ($::db) {
|
||||
$::db->commit || die "Error commiting current transaction: " . $DBI::errstr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub RollBack {
|
||||
if ($::driver eq 'Pg' && Param('usetransactions')) {
|
||||
if ($::db) {
|
||||
$::db->rollback || die "Error rolling back current transaction: " . $DBI::errstr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,9 +355,9 @@ sub SqlRegEx {
|
||||
}
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
if (!$not) {
|
||||
return " LOWER($field) ~ '$pattern' ";
|
||||
return " LOWER($field) ~ $pattern ";
|
||||
} else {
|
||||
return " LOWER($field) !~ '$pattern' ";
|
||||
return " LOWER($field) !~ $pattern ";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -780,39 +766,32 @@ sub InsertNewUser {
|
||||
my $password = GenerateRandomPassword();
|
||||
my $cryptpassword = Crypt($password);
|
||||
|
||||
PushGlobalSQLState();
|
||||
|
||||
# Insert the new user record into the database.
|
||||
$username = SqlQuote($username);
|
||||
$realname = SqlQuote($realname);
|
||||
$cryptpassword = SqlQuote($cryptpassword);
|
||||
SendSQL("INSERT INTO profiles (login_name, realname, cryptpassword)
|
||||
VALUES ($username, $realname, $cryptpassword)");
|
||||
|
||||
# Find the user's new id for adding to groups
|
||||
SendSQL("select LAST_INSERT_ID()");
|
||||
my $userid = FetchOneColumn();
|
||||
|
||||
# Determine what groups the user should be in by default
|
||||
# and add them to those groups.
|
||||
SendSQL("select group_id, userregexp from groups where userregexp != ''");
|
||||
my @groups = ();
|
||||
PushGlobalSQLState();
|
||||
SendSQL("select group_bit, userregexp from groups where userregexp != ''");
|
||||
my $groupset = "0";
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
# Modified -Joe Robins, 2/17/00
|
||||
# Making this case insensitive, since usernames are email addresses,
|
||||
# and could be any case.
|
||||
if ($username =~ m/$row[1]/i) {
|
||||
push(@groups, $row[0]);
|
||||
$groupset .= "+ $row[0]"; # Silly hack to let MySQL do the math,
|
||||
# not Perl, since we're dealing with 64
|
||||
# bit ints here, and I don't *think* Perl
|
||||
# does that.
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $groupid (@groups) {
|
||||
SendSQL("INSERT INTO user_group_map VALUES ($userid, $groupid)");
|
||||
}
|
||||
|
||||
|
||||
# Insert the new user record into the database.
|
||||
$username = SqlQuote($username);
|
||||
$realname = SqlQuote($realname);
|
||||
$cryptpassword = SqlQuote($cryptpassword);
|
||||
SendSQL("INSERT INTO profiles (login_name, realname, cryptpassword, groupset)
|
||||
VALUES ($username, $realname, $cryptpassword, $groupset)");
|
||||
PopGlobalSQLState();
|
||||
|
||||
|
||||
# Return the password to the calling code so it can be included
|
||||
# in an email sent to the user.
|
||||
return $password;
|
||||
@@ -854,13 +833,96 @@ sub GenerateRandomPassword {
|
||||
return $password;
|
||||
}
|
||||
|
||||
sub SelectVisible {
|
||||
my ($query, $userid, $usergroupset) = @_;
|
||||
|
||||
# Run the SQL $query with the additional restriction that
|
||||
# the bugs can be seen by $userid. $usergroupset is provided
|
||||
# as an optimisation when this is already known, eg from CGI.pl
|
||||
# If not present, it will be obtained from the db.
|
||||
# Assumes that 'bugs' is mentioned as a table name. You should
|
||||
# also make sure that bug_id is qualified bugs.bug_id!
|
||||
# Your query must have a WHERE clause. This is unlikely to be a problem.
|
||||
|
||||
# Also, note that mySQL requires aliases for tables to be locked, as well
|
||||
# This means that if you change the name from selectVisible_cc (or add
|
||||
# additional tables), you will need to update anywhere which does a
|
||||
# LOCK TABLE, and then calls routines which call this
|
||||
|
||||
$usergroupset = 0 unless $userid;
|
||||
|
||||
unless (defined($usergroupset)) {
|
||||
PushGlobalSQLState();
|
||||
SendSQL("SELECT groupset FROM profiles WHERE userid = $userid");
|
||||
$usergroupset = FetchOneColumn();
|
||||
PopGlobalSQLState();
|
||||
}
|
||||
|
||||
# Users are authorized to access bugs if they are a member of all
|
||||
# groups to which the bug is restricted. User group membership and
|
||||
# bug restrictions are stored as bits within bitsets, so authorization
|
||||
# can be determined by comparing the intersection of the user's
|
||||
# bitset with the bug's bitset. If the result matches the bug's bitset
|
||||
# the user is a member of all groups to which the bug is restricted
|
||||
# and is authorized to access the bug.
|
||||
|
||||
# A user is also authorized to access a bug if she is the reporter,
|
||||
# or member of the cc: list of the bug and the bug allows users in those
|
||||
# roles to see the bug. The boolean fields reporter_accessible and
|
||||
# cclist_accessible identify whether or not those roles can see the bug.
|
||||
|
||||
# Bit arithmetic is performed by MySQL instead of Perl because bitset
|
||||
# fields in the database are 64 bits wide (BIGINT), and Perl installations
|
||||
# may or may not support integers larger than 32 bits. Using bitsets
|
||||
# and doing bitset arithmetic is probably not cross-database compatible,
|
||||
# however, so these mechanisms are likely to change in the future.
|
||||
|
||||
my $replace = " ";
|
||||
|
||||
if ($userid) {
|
||||
$replace .= ", bugs AS selectVisible_bugs LEFT JOIN cc selectVisible_cc ON
|
||||
selectVisible_bugs.bug_id = selectVisible_cc.bug_id AND
|
||||
selectVisible_cc.who = $userid "
|
||||
}
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
$replace .= "WHERE ((bugs.groupset & $usergroupset) = bugs.groupset ";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$replace .= "WHERE ((bugs.groupset & int8($usergroupset)) = bugs.groupset ";
|
||||
}
|
||||
|
||||
if ($userid) {
|
||||
# There is a mysql bug affecting v3.22 and 3.23 (at least), where this will
|
||||
# cause all rows to be returned! We work arround this by adding an not isnull
|
||||
# test to the JOINed cc table. See http://lists.mysql.com/cgi-ez/ezmlm-cgi?9:mss:11417
|
||||
# Its needed, even though it shouldn't be
|
||||
$replace .= "OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid) ";
|
||||
if ($::driver eq 'mysql') {
|
||||
$replace .= "
|
||||
OR (bugs.cclist_accessible = 1 AND selectVisible_cc.who = $userid AND not isnull(selectVisible_cc.who))";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$replace .= "
|
||||
OR (bugs.cclist_accessible = 1 AND selectVisible_cc.who = $userid AND selectVisible_cc.who IS NOT NULL)";
|
||||
}
|
||||
}
|
||||
|
||||
$replace .= ") AND ";
|
||||
|
||||
$query =~ s/\sWHERE\s/$replace/i;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
sub CanSeeBug {
|
||||
my ($bugs, $userid) = @_;
|
||||
# Note that we pass in the usergroupset, since this is known
|
||||
# in most cases (ie viewing bugs). Maybe make this an optional
|
||||
# parameter?
|
||||
|
||||
my ($bugs, $userid, $usergroupset) = @_;
|
||||
my %cansee;
|
||||
my @buglist;
|
||||
my @groups;
|
||||
|
||||
if(ref($bugs)) {
|
||||
|
||||
if (ref($bugs)) {
|
||||
@buglist = @{$bugs};
|
||||
} else {
|
||||
push(@buglist, $bugs);
|
||||
@@ -869,107 +931,83 @@ sub CanSeeBug {
|
||||
if (@buglist < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Query the database for the bug, retrieving a boolean value that
|
||||
# represents whether or not the user is authorized to access the bug.
|
||||
|
||||
# Users are authorized to access bugs if they are a member of all
|
||||
# groups to which the bug is restricted. User group membership and
|
||||
# bug restrictions are stored as bits within bitsets, so authorization
|
||||
# can be determined by comparing the intersection of the user's
|
||||
# bitset with the bug's bitset. If the result matches the bug's bitset
|
||||
# the user is a member of all groups to which the bug is restricted
|
||||
# and is authorized to access the bug.
|
||||
|
||||
# A user is also authorized to access a bug if she is the reporter,
|
||||
# assignee, QA contact, or member of the cc: list of the bug and the bug
|
||||
# allows users in those roles to see the bug. The boolean fields
|
||||
# reporter_accessible, assignee_accessible, qacontact_accessible, and
|
||||
# cclist_accessible identify whether or not those roles can see the bug.
|
||||
|
||||
# Bit arithmetic is performed by MySQL instead of Perl because bitset
|
||||
# fields in the database are 64 bits wide (BIGINT), and Perl installations
|
||||
# may or may not support integers larger than 32 bits. Using bitsets
|
||||
# and doing bitset arithmetic is probably not cross-database compatible,
|
||||
# however, so these mechanisms are likely to change in the future.
|
||||
|
||||
# Get data from the database about whether or not the user belongs to
|
||||
# all groups the bug is in, and who are the bug's reporter and qa_contact
|
||||
# along with which roles can always access the bug.
|
||||
|
||||
PushGlobalSQLState();
|
||||
|
||||
if ($userid) {
|
||||
SendSQL("SELECT group_id FROM user_group_map WHERE user_id = $userid");
|
||||
while (my @row = FetchSQLData()) {
|
||||
# Processmail requires everything coming out of the db to be detainted
|
||||
detaint_natural($row[0]);
|
||||
push(@groups, $row[0]);
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bug_id, ((groupset & $usergroupset) = groupset),
|
||||
reporter, reporter_accessible , cclist_accessible
|
||||
FROM bugs
|
||||
WHERE bug_id IN (" . join(',', @buglist) . ")");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT bug_id, CASE WHEN ((groupset & int8($usergroupset)) = groupset)
|
||||
THEN 1 ELSE 0 END as isauthorized,
|
||||
reporter, reporter_accessible, cclist_accessible
|
||||
FROM bugs
|
||||
WHERE bug_id IN (" . join(',', @buglist) . ")");
|
||||
}
|
||||
|
||||
while (my @row = FetchSQLData()) {
|
||||
my ($bug_id, $isauthorized, $reporter, $reporter_accessible, $cclist_accessible) = @row;
|
||||
|
||||
# Record bug number and continue if the user is a member of all groups to which the bug belongs.
|
||||
if ($isauthorized) {
|
||||
$cansee{$bug_id} = 1;
|
||||
next;
|
||||
}
|
||||
} else {
|
||||
$userid = 0;
|
||||
}
|
||||
|
||||
my $query = "
|
||||
SELECT
|
||||
bugs.bug_id,
|
||||
COUNT(bug_group_map.group_id)
|
||||
FROM
|
||||
bugs LEFT JOIN bug_group_map ON bugs.bug_id = bug_group_map.bug_id
|
||||
LEFT JOIN cc ON bugs.bug_id = cc.bug_id
|
||||
WHERE
|
||||
bugs.bug_id IN (" . join(',', @buglist) . ")
|
||||
AND ((";
|
||||
if ($#groups >= 0) {
|
||||
$query .= "bug_group_map.group_id IN (" . join(',', @groups) . ") OR ";
|
||||
}
|
||||
$query .= "bug_group_map.group_id IS NULL) ";
|
||||
if ($userid) {
|
||||
$query .= "OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid)
|
||||
OR (bugs.cclist_accessible = 1 AND cc.who = $userid)";
|
||||
}
|
||||
$query .= ") GROUP BY bugs.bug_id";
|
||||
# Record bug number and continue if the user is in a role that has access to the bug.
|
||||
if ($reporter_accessible && $reporter == $userid) {
|
||||
$cansee{$bug_id} = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
SendSQL($query);
|
||||
|
||||
while (my ($id, $count) = FetchSQLData()) {
|
||||
$cansee{$id} = 1 + $count;
|
||||
}
|
||||
# Try to authorize the user one more time by seeing if they are on
|
||||
# the cc: list. If so, finish validation and return.
|
||||
if ($cclist_accessible) {
|
||||
PushGlobalSQLState();
|
||||
detaint_natural($bug_id) || die "CanSeeBug() called with non-integer bug number";
|
||||
detaint_natural($userid) || die "CanSeeBug() called with non-integer bug number";
|
||||
SendSQL("SELECT who FROM cc WHERE bug_id = $bug_id AND who = $userid");
|
||||
my $ccwho = FetchOneColumn();
|
||||
# more efficient to just check the var here instead of
|
||||
# creating a potentially huge array to grep against
|
||||
if ($ccwho) {
|
||||
$cansee{$bug_id} = 1;
|
||||
}
|
||||
PopGlobalSQLState();
|
||||
}
|
||||
}
|
||||
|
||||
PopGlobalSQLState();
|
||||
|
||||
if ((keys %cansee) < 1) {
|
||||
return 0;
|
||||
} else {
|
||||
return \%cansee;
|
||||
}
|
||||
}
|
||||
|
||||
sub CanSeeProduct {
|
||||
my ($userid, $product) = (@_);
|
||||
my @groups = ();
|
||||
|
||||
# If group name same as product and user in that group then return success
|
||||
# Based on the old method of handling product privacy.
|
||||
return 1 if UserInGroup($userid, $product);
|
||||
|
||||
ConnectToDatabase();
|
||||
PushGlobalSQLState();
|
||||
|
||||
# Check first to see if this product is private
|
||||
SendSQL("SELECT count(*) FROM product_group_map, products " .
|
||||
"WHERE products.product_id = product_group_map.product_id " .
|
||||
"AND products.product = " . SqlQuote($product));
|
||||
my $count = FetchOneColumn();
|
||||
|
||||
# Product is not private to any groups so user can see it.
|
||||
if (!$count) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
# User does not have account or is not logged in and product is private so
|
||||
# return 0 value.
|
||||
if (!$userid && $count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SendSQL("SELECT groups.group_id FROM groups " .
|
||||
"LEFT JOIN user_group_map ON groups.group_id = user_group_map.group_id " .
|
||||
"WHERE user_group_map.user_id = $userid");
|
||||
while (MoreSQLData()) {
|
||||
my ($groupid) = FetchSQLData();
|
||||
push (@groups, $groupid);
|
||||
}
|
||||
|
||||
if (@groups < 1) {
|
||||
@groups = (0);
|
||||
}
|
||||
|
||||
SendSQL("
|
||||
SELECT
|
||||
products.product_id
|
||||
FROM
|
||||
products
|
||||
LEFT JOIN product_group_map ON products.product_id = product_group_map.product_id
|
||||
WHERE
|
||||
products.product = " . SqlQuote($product) . "
|
||||
AND product_group_map.group_id IN (" . join(",", @groups) . ")");
|
||||
my $result = FetchOneColumn();
|
||||
PopGlobalSQLState();
|
||||
return 1 if $result;
|
||||
return \%cansee;
|
||||
}
|
||||
|
||||
sub ValidatePassword {
|
||||
@@ -1155,7 +1193,7 @@ sub quoteUrls {
|
||||
my $item = $&;
|
||||
my $bugnum = $2;
|
||||
my $comnum = $4;
|
||||
$item = GetBugLink($bugnum, $item, $::userid);
|
||||
$item = GetBugLink($bugnum, $item);
|
||||
$item =~ s/(id=\d+)/$1#c$comnum/;
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
@@ -1169,7 +1207,7 @@ sub quoteUrls {
|
||||
while ($text =~ s/\bbug(\s|%\#)*(\d+)/"##$count##"/ei) {
|
||||
my $item = $&;
|
||||
my $num = $2;
|
||||
$item = GetBugLink($num, $item, $::userid);
|
||||
$item = GetBugLink($num, $item);
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
while ($text =~ s/\b(Created an )?attachment(\s|%\#)*(\(id=)?(\d+)\)?/"##$count##"/ei) {
|
||||
@@ -1184,7 +1222,7 @@ sub quoteUrls {
|
||||
my $item = $&;
|
||||
my $num = $1;
|
||||
my $bug_link;
|
||||
$bug_link = GetBugLink($num, $num, $::userid);
|
||||
$bug_link = GetBugLink($num, $num);
|
||||
$item =~ s@\d+@$bug_link@;
|
||||
$things[$count++] = $item;
|
||||
}
|
||||
@@ -1204,12 +1242,12 @@ sub quoteUrls {
|
||||
}
|
||||
|
||||
# This is a new subroutine written 12/20/00 for the purpose of processing a
|
||||
# link to a bug. It can be called using "GetBugLink (<BugNumber>, <LinkText>, <userid>);"
|
||||
# link to a bug. It can be called using "GetBugLink (<BugNumber>, <LinkText>);"
|
||||
# Where <BugNumber> is the number of the bug and <LinkText> is what apprears
|
||||
# between '<a>' and '</a>'.
|
||||
|
||||
sub GetBugLink {
|
||||
my ($bug_num, $link_text, $userid) = (@_);
|
||||
my ($bug_num, $link_text) = (@_);
|
||||
detaint_natural($bug_num) || die "GetBugLink() called with non-integer bug number";
|
||||
|
||||
# If we've run GetBugLink() for this bug number before, %::buglink
|
||||
@@ -1220,12 +1258,12 @@ sub GetBugLink {
|
||||
# is saved off rather than overwritten
|
||||
PushGlobalSQLState();
|
||||
|
||||
SendSQL("SELECT bugs.bug_status, resolution, short_desc " .
|
||||
SendSQL("SELECT bugs.bug_status, resolution, short_desc, groupset " .
|
||||
"FROM bugs WHERE bugs.bug_id = $bug_num");
|
||||
|
||||
# If the bug exists, save its data off for use later in the sub
|
||||
if (MoreSQLData()) {
|
||||
my ($bug_state, $bug_res, $bug_desc) = FetchSQLData();
|
||||
my ($bug_state, $bug_res, $bug_desc, $bug_grp) = FetchSQLData();
|
||||
# Initialize these variables to be "" so that we don't get warnings
|
||||
# if we don't change them below (which is highly likely).
|
||||
my ($pre, $title, $post) = ("", "", "");
|
||||
@@ -1240,7 +1278,7 @@ sub GetBugLink {
|
||||
$title .= " $bug_res";
|
||||
$post = "</strike>";
|
||||
}
|
||||
if (CanSeeBug($bug_num, $userid)) {
|
||||
if ($bug_grp == 0 || CanSeeBug($bug_num, $::userid, $::usergroupset)) {
|
||||
$title .= " - $bug_desc";
|
||||
}
|
||||
$::buglink{$bug_num} = [$pre, value_quote($title), $post];
|
||||
@@ -1439,28 +1477,32 @@ sub SqlQuote {
|
||||
|
||||
|
||||
sub UserInGroup {
|
||||
my ($userid, $groupname) = (@_);
|
||||
if (!$userid) {
|
||||
my ($groupname) = (@_);
|
||||
if ($::usergroupset eq "0") {
|
||||
return 0;
|
||||
}
|
||||
ConnectToDatabase();
|
||||
SendSQL("SELECT user_id FROM user_group_map, groups
|
||||
WHERE user_group_map.group_id = groups.group_id
|
||||
AND groups.name = " . SqlQuote($groupname) .
|
||||
" AND user_id = $userid");
|
||||
my $result = FetchOneColumn();
|
||||
return 1 if $result;
|
||||
PushGlobalSQLState();
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select (group_bit & $::usergroupset) != 0 " .
|
||||
"from groups where name = " . SqlQuote($groupname));
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select (group_bit & int8($::usergroupset)) != 0 " .
|
||||
"from groups where name = " . SqlQuote($groupname));
|
||||
}
|
||||
my $bit = FetchOneColumn();
|
||||
PopGlobalSQLState();
|
||||
if ($bit) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub BugInGroup {
|
||||
my ($bugid, $groupname) = (@_);
|
||||
my $groupid = GroupNameToId($groupname);
|
||||
my $groupbit = GroupNameToBit($groupname);
|
||||
PushGlobalSQLState();
|
||||
SendSQL("SELECT bug_id FROM bug_group_map
|
||||
WHERE bug_group_map.group_id = groups.group_id
|
||||
AND groups.name = " . SqlQuote($groupname) .
|
||||
" AND bug_id = $bugid");
|
||||
SendSQL("SELECT (bugs.groupset & $groupbit) != 0 FROM bugs WHERE bugs.bug_id = $bugid");
|
||||
my $bugingroup = FetchOneColumn();
|
||||
PopGlobalSQLState();
|
||||
return $bugingroup;
|
||||
@@ -1477,24 +1519,28 @@ sub GroupExists {
|
||||
# Given the name of an existing group, returns the bit associated with it.
|
||||
# If the group does not exist, returns 0.
|
||||
# !!! Remove this function when the new group system is implemented!
|
||||
sub GroupNameToId {
|
||||
sub GroupNameToBit {
|
||||
my ($groupname) = (@_);
|
||||
ConnectToDatabase();
|
||||
PushGlobalSQLState();
|
||||
SendSQL("SELECT group_id FROM groups WHERE name = " . SqlQuote($groupname));
|
||||
my $id = FetchOneColumn() || 0;
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bit FROM groups WHERE name = " . SqlQuote($groupname));
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit FROM groups WHERE name = " . SqlQuote($groupname));
|
||||
}
|
||||
my $bit = FetchOneColumn() || 0;
|
||||
PopGlobalSQLState();
|
||||
return $id;
|
||||
return $bit;
|
||||
}
|
||||
|
||||
# Determines whether or not a group is active by checking
|
||||
# the "isactive" column for the group in the "groups" table.
|
||||
# Note: This function selects groups by bit rather than by name.
|
||||
sub GroupIsActive {
|
||||
my ($groupid) = (@_);
|
||||
$groupid ||= 0;
|
||||
my ($groupbit) = (@_);
|
||||
$groupbit ||= 0;
|
||||
ConnectToDatabase();
|
||||
SendSQL("select isactive from groups where group_id=$groupid");
|
||||
SendSQL("select isactive from groups where group_bit = $groupbit");
|
||||
my $isactive = FetchOneColumn();
|
||||
return $isactive;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ use vars qw(
|
||||
# Establish a connection to the database backend.
|
||||
ConnectToDatabase();
|
||||
|
||||
# Check whether or not the user is logged in
|
||||
my $userid = quietly_check_login();
|
||||
# Check whether or not the user is logged in and, if so, set the $::userid
|
||||
# and $::usergroupset variables.
|
||||
quietly_check_login();
|
||||
|
||||
###############################################################################
|
||||
# Main Body Execution
|
||||
|
||||
@@ -27,54 +27,54 @@ use lib qw(.);
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use vars qw($userid @legal_keywords %FORM);
|
||||
use vars qw($userid $usergroupset @legal_keywords %FORM);
|
||||
|
||||
# Use global template variables.
|
||||
use vars qw($template $vars);
|
||||
|
||||
ConnectToDatabase();
|
||||
my $userid = quietly_check_login();
|
||||
|
||||
quietly_check_login();
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
my $generic_query = "
|
||||
select
|
||||
bugs.bug_id,
|
||||
bugs.product,
|
||||
bugs.version,
|
||||
bugs.rep_platform,
|
||||
bugs.op_sys,
|
||||
bugs.bug_status,
|
||||
bugs.bug_severity,
|
||||
bugs.priority,
|
||||
bugs.resolution,
|
||||
assign.login_name,
|
||||
report.login_name,
|
||||
bugs.component,
|
||||
bugs.bug_file_loc,
|
||||
bugs.short_desc,
|
||||
bugs.target_milestone,
|
||||
bugs.qa_contact,
|
||||
bugs.status_whiteboard,
|
||||
bugs.keywords
|
||||
from bugs,profiles assign,profiles report
|
||||
where assign.userid = bugs.assigned_to and report.userid = bugs.reporter";
|
||||
my $generic_query = "
|
||||
SELECT
|
||||
bugs.bug_id,
|
||||
bugs.product,
|
||||
bugs.version,
|
||||
bugs.rep_platform,
|
||||
bugs.op_sys,
|
||||
bugs.bug_status,
|
||||
bugs.resolution,
|
||||
bugs.priority,
|
||||
bugs.bug_severity,
|
||||
bugs.component,
|
||||
assign.login_name,
|
||||
report.login_name,
|
||||
bugs.bug_file_loc,
|
||||
bugs.short_desc,
|
||||
bugs.target_milestone,
|
||||
bugs.qa_contact,
|
||||
bugs.status_whiteboard,
|
||||
bugs.keywords
|
||||
FROM bugs,profiles assign,profiles report
|
||||
WHERE assign.userid = bugs.assigned_to AND report.userid = bugs.reporter";
|
||||
|
||||
my $buglist = $::FORM{'buglist'} ||
|
||||
$::FORM{'bug_id'} ||
|
||||
$::FORM{'id'} || "";
|
||||
|
||||
my @buglist = ();
|
||||
foreach my $bug (split(/[:,]/, $buglist)) {
|
||||
detaint_natural($bug) || next;
|
||||
push(@buglist, $bug);
|
||||
}
|
||||
|
||||
my $canseeref = CanSeeBug(\@buglist, $userid);
|
||||
|
||||
my @bugs;
|
||||
|
||||
foreach my $bug_id (@buglist) {
|
||||
trick_taint($buglist);
|
||||
my @canseebugs = split(/[:,]/, $buglist);
|
||||
my $canseeref = CanSeeBug(\@canseebugs, $::userid, $::usergroupset);
|
||||
|
||||
foreach my $bug_id (split(/[:,]/, $buglist)) {
|
||||
detaint_natural($bug_id) || next;
|
||||
|
||||
# Skip if we cannot see this bug
|
||||
next if !$canseeref->{$bug_id};
|
||||
|
||||
SendSQL("$generic_query AND bugs.bug_id = $bug_id");
|
||||
|
||||
@@ -80,7 +80,7 @@ if ( !defined $::FORM{'buglist'} ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
my $exporter = $::COOKIE{"Bugzilla_login"};
|
||||
my $movers = Param("movers");
|
||||
$movers =~ s/\w?,\w?/|/g;
|
||||
@@ -98,7 +98,7 @@ $xml .= Bug::XML_Header( Param("urlbase"), $::param{'version'},
|
||||
Param("maintainer"), $exporter );
|
||||
print "<P>\n";
|
||||
foreach my $id (split(/:/, $::FORM{'buglist'})) {
|
||||
my $bug = new Bug($id, $userid);
|
||||
my $bug = new Bug($id, $::userid);
|
||||
$xml .= $bug->emitXML;
|
||||
if (!$bug->error) {
|
||||
my $exporterid = DBNameToIdAndCheck($exporter);
|
||||
|
||||
@@ -186,58 +186,24 @@ sub have_vers {
|
||||
}
|
||||
|
||||
# Check versions of dependencies. 0 for version = any version acceptible
|
||||
my $modules = [
|
||||
{
|
||||
name => 'AppConfig',
|
||||
version => '1.52'
|
||||
},
|
||||
{
|
||||
name => 'CGI::Carp',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'Data::Dumper',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'Date::Parse',
|
||||
version => '0'
|
||||
},
|
||||
{
|
||||
name => 'DBI',
|
||||
version => '1.13'
|
||||
},
|
||||
{
|
||||
name => 'DBD::Pg',
|
||||
version => '1.13'
|
||||
},
|
||||
{
|
||||
name => 'File::Spec',
|
||||
version => '0.82'
|
||||
},
|
||||
{
|
||||
name => 'Template',
|
||||
version => '2.07'
|
||||
},
|
||||
{
|
||||
name => 'Text::Wrap',
|
||||
version => '2001.0131'
|
||||
}
|
||||
];
|
||||
|
||||
my %missing = ();
|
||||
foreach my $module (@{$modules}) {
|
||||
unless (have_vers($module->{name}, $module->{version})) {
|
||||
$missing{$module->{name}} = $module->{version};
|
||||
}
|
||||
}
|
||||
my @missing = ();
|
||||
unless (have_vers("DBI","1.13")) { push @missing,"DBI" }
|
||||
unless (have_vers("Data::Dumper",0)) { push @missing,"Data::Dumper" }
|
||||
unless (have_vers("DBD::Pg",0)) { push @missing,"DBD::Pg" }
|
||||
unless (have_vers("Date::Parse",0)) { push @missing,"Date::Parse" }
|
||||
unless (have_vers("MIME::Base64",0)) { push @missing, "MIME::Base64" }
|
||||
unless (have_vers("AppConfig","1.52")) { push @missing,"AppConfig" }
|
||||
unless (have_vers("Template","2.01")) { push @missing,"Template" }
|
||||
unless (have_vers("Text::Wrap","2001.0131")) { push @missing,"Text::Wrap" }
|
||||
unless (have_vers("File::Spec", "0.82")) { push @missing,"File::Spec" }
|
||||
|
||||
# If CGI::Carp was loaded successfully for version checking, it changes the
|
||||
# die and warn handlers, we don't want them changed, so we need to stash the
|
||||
# original ones and set them back afterwards -- justdave@syndicomm.com
|
||||
my $saved_die_handler = $::SIG{__DIE__};
|
||||
my $saved_warn_handler = $::SIG{__WARN__};
|
||||
unless (have_vers("CGI::Carp",0)) { $missing{'CGI::Carp'} = 0 }
|
||||
unless (have_vers("CGI::Carp",0)) { push @missing,"CGI::Carp" }
|
||||
$::SIG{__DIE__} = $saved_die_handler;
|
||||
$::SIG{__WARN__} = $saved_warn_handler;
|
||||
|
||||
@@ -247,6 +213,7 @@ $charts++ if have_vers("GD","1.19");
|
||||
$charts++ if have_vers("Chart::Base","0.99");
|
||||
my $xmlparser = have_vers("XML::Parser",0);
|
||||
|
||||
print "\n";
|
||||
if ($charts != 2) {
|
||||
print "If you you want to see graphical bug dependency charts, you may install\n",
|
||||
"the optional libgd and the Perl modules GD-1.19 and Chart::Base-0.99b, e.g. by\n",
|
||||
@@ -260,16 +227,12 @@ if (!$xmlparser) {
|
||||
"running (as root)\n\n",
|
||||
" perl -MCPAN -e'install \"XML::Parser\"'\n\n";
|
||||
}
|
||||
if (%missing) {
|
||||
if (@missing > 0) {
|
||||
print "\n\n";
|
||||
print "Bugzilla requires some Perl modules which are either missing from your\n",
|
||||
"system, or the version on your system is too old.\n",
|
||||
"They can be installed by running (as root) the following:\n";
|
||||
foreach my $module (keys %missing) {
|
||||
print "You are missing some Perl modules which are required by Bugzilla.\n";
|
||||
print "They can be installed by running (as root) the following:\n";
|
||||
foreach my $module (@missing) {
|
||||
print " perl -MCPAN -e 'install \"$module\"'\n";
|
||||
if ($missing{$module} > 0) {
|
||||
print " Minimum version required: $missing{$module}\n";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
exit;
|
||||
@@ -905,7 +868,7 @@ my $drh = DBI->install_driver($db_base)
|
||||
if ($my_db_check) {
|
||||
# Do we have the database itself?
|
||||
|
||||
my $sql_want = "7.2"; # minimum version of PostgreSQL
|
||||
my $sql_want = "7.1"; # minimum version of PostgreSQL
|
||||
|
||||
my $dsn = "dbi:$db_base:dbname=template1;host=$my_db_host";
|
||||
my $dbh = DBI->connect($dsn, "postgres", "")
|
||||
@@ -1054,6 +1017,7 @@ $table{attachstatusdefs} = '
|
||||
|
||||
$table{bugs} =
|
||||
'bug_id serial,
|
||||
groupset bigint not null,
|
||||
assigned_to integer not null,
|
||||
bug_file_loc varchar(4000),
|
||||
bug_severity varchar(255) not null,
|
||||
@@ -1168,7 +1132,8 @@ $index{dependencies} = [
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=75482
|
||||
|
||||
$table{groups} =
|
||||
'group_id serial,
|
||||
'group_id serial,
|
||||
group_bit bigint constraint groupbit_unique unique not null,
|
||||
name varchar(255) constraint groupname_unique unique not null,
|
||||
description text not null,
|
||||
isbuggroup integer not null,
|
||||
@@ -1208,10 +1173,11 @@ $table{profiles} =
|
||||
login_name varchar(255) constraint loginname_unique unique not null,
|
||||
cryptpassword varchar(34),
|
||||
realname varchar(255),
|
||||
groupset bigint not null,
|
||||
disabledtext varchar(4000),
|
||||
mybugslink integer not null default 1,
|
||||
emailflags text,
|
||||
admin integer default 0';
|
||||
blessgroupset bigint not null default 0,
|
||||
emailflags text';
|
||||
|
||||
|
||||
$table{profiles_activity} =
|
||||
@@ -1351,49 +1317,6 @@ $index{tokens} = [
|
||||
'userid'
|
||||
];
|
||||
|
||||
# 2001-09-18, dkl@redhat.com
|
||||
# Group tables for tracking group memberships, admin memberships,
|
||||
# product permissions, and bug permissions.
|
||||
#
|
||||
# This table determines the groups that a user belongs to
|
||||
# and the level that they can bless others to.
|
||||
# canbless:
|
||||
# 0 = Cannot bless others into the group
|
||||
# 1 = Can bless others into the group
|
||||
# 2 = Can give others permission to bless people into the group
|
||||
$table{user_group_map} =
|
||||
'user_id integer not null,
|
||||
group_id integer not null,
|
||||
canbless integer default 0,
|
||||
|
||||
unique(user_id, group_id)';
|
||||
|
||||
$index{user_group_map} = [
|
||||
'group_id'
|
||||
];
|
||||
|
||||
# This table determines which groups have permission to see a bug
|
||||
$table{bug_group_map} =
|
||||
'bug_id integer not null,
|
||||
group_id integer not null,
|
||||
|
||||
unique(bug_id, group_id)';
|
||||
|
||||
$index{bug_group_map} = [
|
||||
'group_id'
|
||||
];
|
||||
|
||||
# This table determines which groups may report bugs against a product
|
||||
$table{product_group_map} =
|
||||
'product_id integer not null,
|
||||
group_id integer not null,
|
||||
|
||||
unique(product_id, group_id)';
|
||||
|
||||
$index{product_group_map} = [
|
||||
'group_id'
|
||||
];
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Create tables
|
||||
@@ -1491,25 +1414,7 @@ sub AddIndex {
|
||||
# Populate groups table
|
||||
###########################################################################
|
||||
|
||||
# We need to add a couple of columns first if this is our first time
|
||||
# using the new group schema and populate the group ids
|
||||
# 2002/01/23 dkl@redhat.com
|
||||
if (&GetFieldDef('groups', 'bit')) {
|
||||
&AddField('groups', 'group_id', 'mediumint primary key auto_increment not null');
|
||||
&AddField('profiles', 'admin', 'smallint default 0');
|
||||
my $currentgroupid = 1;
|
||||
my $query = "select bit from groups order by bit";
|
||||
my $sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
while (my ($bit) = $sth->fetchrow_array()) {
|
||||
my $query = "update groups set group_id = $currentgroupid where bit = $bit";
|
||||
my $sth2 = $dbh->prepare($query);
|
||||
$sth2->execute();
|
||||
$currentgroupid++;
|
||||
}
|
||||
}
|
||||
|
||||
sub GroupDoesExist ($)
|
||||
sub GroupExists ($)
|
||||
{
|
||||
my ($name) = @_;
|
||||
my $sth = $dbh->prepare("SELECT name FROM groups WHERE name = " . $dbh->quote($name));
|
||||
@@ -1520,30 +1425,42 @@ sub GroupDoesExist ($)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# This subroutine checks if a group exist. If not, it will be automatically
|
||||
# created with the next available groupid
|
||||
# created with the next available bit set
|
||||
#
|
||||
|
||||
sub AddGroup {
|
||||
sub AddGroup
|
||||
{
|
||||
my ($name, $desc, $userregexp) = @_;
|
||||
$userregexp ||= "";
|
||||
|
||||
return if GroupDoesExist($name);
|
||||
return if GroupExists($name);
|
||||
|
||||
# get highest bit number
|
||||
my $sth = $dbh->prepare("SELECT group_bit FROM groups ORDER BY group_bit DESC");
|
||||
$sth->execute;
|
||||
my @row = $sth->fetchrow_array;
|
||||
|
||||
# normalize bits
|
||||
my $bit;
|
||||
if (defined $row[0]) {
|
||||
$bit = $row[0] << 1;
|
||||
} else {
|
||||
$bit = 1;
|
||||
}
|
||||
|
||||
|
||||
print "Adding group $name ...\n";
|
||||
my $sth = $dbh->prepare('INSERT INTO groups
|
||||
(name, description, userregexp, isbuggroup)
|
||||
VALUES (?, ?, ?, ?)');
|
||||
$sth->execute($name, $desc, $userregexp, 0);
|
||||
|
||||
$sth = $dbh->prepare("SELECT group_id FROM groups WHERE name = " . $dbh->quote($name));
|
||||
$sth->execute();
|
||||
my ($last) = $sth->fetchrow_array();
|
||||
|
||||
return $last;
|
||||
$sth = $dbh->prepare("INSERT INTO groups
|
||||
(group_bit, name, description, userregexp, isbuggroup)
|
||||
VALUES (?, ?, ?, ?, ?)");
|
||||
$sth->execute($bit, $name, $desc, $userregexp, 0);
|
||||
return $bit;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# BugZilla uses --GROUPS-- to assign various rights to its users.
|
||||
#
|
||||
@@ -1554,25 +1471,20 @@ AddGroup('creategroups', 'Can create and destroy groups.');
|
||||
AddGroup('editcomponents', 'Can create, destroy, and edit components.');
|
||||
AddGroup('editkeywords', 'Can create, destroy, and edit keywords.');
|
||||
|
||||
if (!GroupDoesExist("editbugs")) {
|
||||
my $id = AddGroup('editbugs', 'Can edit all aspects of any bug.', "");
|
||||
# my $sth = $dbh->prepare("SELECT userid FROM profiles ORDER BY userid");
|
||||
# $sth->execute();
|
||||
# while ( my ($userid) = $sth->fetchrow_array() ) {
|
||||
# $dbh->do("INSERT INTO user_group_map VALUES ($userid, $id)");
|
||||
# }
|
||||
# Add the groupset field here because this code is run before the
|
||||
# code that updates the database structure.
|
||||
&AddField('profiles', 'groupset', 'bigint not null');
|
||||
|
||||
if (!GroupExists("editbugs")) {
|
||||
my $id = AddGroup('editbugs', 'Can edit all aspects of any bug.', ".*");
|
||||
$dbh->do("UPDATE profiles SET groupset = groupset | int8($id)");
|
||||
}
|
||||
|
||||
if (!GroupDoesExist("canconfirm")) {
|
||||
my $id = AddGroup('canconfirm', 'Can confirm a bug.', "");
|
||||
# my $sth = $dbh->prepare("SELECT userid FROM profiles ORDER BY userid");
|
||||
# $sth->execute();
|
||||
# while ( my ($userid) = $sth->fetchrow_array() ) {
|
||||
# $dbh->do("INSERT INTO user_group_map VALUES ($userid, $id)");
|
||||
# }
|
||||
if (!GroupExists("canconfirm")) {
|
||||
my $id = AddGroup('canconfirm', 'Can confirm a bug.', ".*");
|
||||
$dbh->do("UPDATE profiles SET groupset = groupset | int8($id)");
|
||||
}
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Populate the list of fields.
|
||||
###########################################################################
|
||||
@@ -1749,7 +1661,7 @@ while ( my @row = $sth->fetchrow_array() ) {
|
||||
$sth = $dbh->prepare(<<_End_Of_SQL_);
|
||||
SELECT login_name
|
||||
FROM profiles
|
||||
WHERE admin = 1
|
||||
WHERE groupset = 9223372036854775807
|
||||
_End_Of_SQL_
|
||||
|
||||
$sth->execute;
|
||||
@@ -1883,54 +1795,25 @@ _End_Of_SQL_
|
||||
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
INSERT INTO profiles
|
||||
(login_name, realname, cryptpassword, admin)
|
||||
VALUES ($login, $realname, $cryptedpassword, 1)
|
||||
(login_name, realname, cryptpassword, groupset)
|
||||
VALUES ($login, $realname, $cryptedpassword, '0')
|
||||
_End_Of_SQL_
|
||||
|
||||
# Put the admin in each group if not already
|
||||
my $query = "select userid from profiles where login_name = $login";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
my ($userid) = $sth->fetchrow_array();
|
||||
|
||||
foreach my $group ( @groups ) {
|
||||
my $query = "SELECT user_id FROM user_group_map WHERE group_id = $group AND user_id = $userid";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
if ( !$sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $group, 1)");
|
||||
} else {
|
||||
$dbh->do("UPDATE user_group_map SET canbless = 1 WHERE user_id = $userid AND group_id = $group");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
UPDATE profiles
|
||||
SET admin = 1
|
||||
SET groupset = 9223372036854775807
|
||||
WHERE login_name = $login
|
||||
_End_Of_SQL_
|
||||
|
||||
# Put the admin in each group if not already
|
||||
my $query = "SELECT userid FROM profiles WHERE login_name = $login";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
my ($userid) = $sth->fetchrow_array();
|
||||
} else {
|
||||
|
||||
foreach my $group ( @groups ) {
|
||||
my $query = "SELECT user_id FROM user_group_map WHERE group_id = $group AND user_id = $userid";
|
||||
$sth = $dbh->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
if ( !$sth->fetchrow_array() ) {
|
||||
$dbh->do("INSERT INTO user_group_map VALUES ($userid, $group, 1)");
|
||||
} else {
|
||||
$dbh->do("UPDATE user_group_map SET canbless = 1 WHERE user_id = $userid AND group_id = $group");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n$login is now set up as the administrator account.\n";
|
||||
$dbh->do(<<_End_Of_SQL_);
|
||||
UPDATE profiles
|
||||
SET groupset = 9223372036854775807
|
||||
WHERE login_name = $login
|
||||
_End_Of_SQL_
|
||||
}
|
||||
print "\n$login is now set up as the administrator account.\n";
|
||||
}
|
||||
|
||||
sub Crypt {
|
||||
@@ -1970,10 +1853,11 @@ sub Crypt {
|
||||
# Create initial test product if there are no products present.
|
||||
###########################################################################
|
||||
|
||||
$sth = $dbh->prepare("SELECT userid FROM profiles WHERE admin = 1 LIMIT 1");
|
||||
$sth = $dbh->prepare("select userid from profiles where groupset = 9223372036854775807");
|
||||
$sth->execute;
|
||||
my ($adminuid) = $sth->fetchrow_array();
|
||||
|
||||
my ($adminuid) = $sth->fetchrow_array;
|
||||
if (!$adminuid) { die "No administator!" } # should never get here
|
||||
$sth = $dbh->prepare("SELECT product FROM products");
|
||||
$sth->execute;
|
||||
unless ($sth->rows) {
|
||||
@@ -2090,21 +1974,21 @@ sub TableExists ($)
|
||||
# really old fields that were added before pgsetup.pl existed
|
||||
# but aren't in very old bugzilla's (like 2.1)
|
||||
# Steve Stock (sstock@iconnect-inc.com)
|
||||
#AddField('bugs', 'target_milestone', "varchar(20) not null default '---'");
|
||||
#AddField('bugs', 'groupset', 'integer not null');
|
||||
#AddField('bugs', 'qa_contact', 'integer not null');
|
||||
#AddField('bugs', 'status_whiteboard', 'text not null');
|
||||
#AddField('products', 'disallownew', 'integer not null');
|
||||
#AddField('products', 'milestoneurl', 'varchar(2000) not null');
|
||||
#AddField('components', 'initialqacontact', 'varchar(2000) not null');
|
||||
#AddField('components', 'description', 'text not null');
|
||||
#ChangeFieldType('components', 'program', 'varchar');
|
||||
AddField('bugs', 'target_milestone', "varchar(20) not null default '---'");
|
||||
AddField('bugs', 'groupset', 'integer not null');
|
||||
AddField('bugs', 'qa_contact', 'integer not null');
|
||||
AddField('bugs', 'status_whiteboard', 'text not null');
|
||||
AddField('products', 'disallownew', 'integer not null');
|
||||
AddField('products', 'milestoneurl', 'varchar(2000) not null');
|
||||
AddField('components', 'initialqacontact', 'varchar(2000) not null');
|
||||
AddField('components', 'description', 'text not null');
|
||||
ChangeFieldType('components', 'program', 'varchar');
|
||||
|
||||
|
||||
# 1999-06-22 Added an entry to the attachments table to record who the
|
||||
# submitter was. Nothing uses this yet, but it still should be recorded.
|
||||
|
||||
#AddField('attachments', 'submitter_id', 'integer not null');
|
||||
AddField('attachments', 'submitter_id', 'integer not null');
|
||||
|
||||
#
|
||||
# One could even populate this field automatically, e.g. with
|
||||
@@ -2132,9 +2016,9 @@ RenameField ('bugs_activity', 'when', 'bug_when');
|
||||
# (P.S. All is not lost; it appears that the latest betas of MySQL support
|
||||
# a new table format which will allow 32 indices.)
|
||||
|
||||
#DropField('bugs', 'area');
|
||||
#AddField('bugs', 'votes', 'integer not null');
|
||||
#AddField('products', 'votesperuser', 'integer not null');
|
||||
DropField('bugs', 'area');
|
||||
AddField('bugs', 'votes', 'integer not null');
|
||||
AddField('products', 'votesperuser', 'integer not null');
|
||||
|
||||
|
||||
# The product name used to be very different in various tables.
|
||||
@@ -2147,10 +2031,10 @@ RenameField ('bugs_activity', 'when', 'bug_when');
|
||||
# varchar(2000) is equivalent to varchar(255), which is quite huge, so I change
|
||||
# them all to varchar(64).
|
||||
|
||||
#ChangeFieldType ('bugs', 'product', 'varchar(64)');
|
||||
#ChangeFieldType ('components', 'program', 'varchar(64)');
|
||||
#ChangeFieldType ('products', 'product', 'varchar(64)');
|
||||
#ChangeFieldType ('versions', 'program', 'varchar(64)');
|
||||
ChangeFieldType ('bugs', 'product', 'varchar(64)');
|
||||
ChangeFieldType ('components', 'program', 'varchar(64)');
|
||||
ChangeFieldType ('products', 'product', 'varchar(64)');
|
||||
ChangeFieldType ('versions', 'program', 'varchar(64)');
|
||||
|
||||
# 2000-01-16 Added a "keywords" field to the bugs table, which
|
||||
# contains a string copy of the entries of the keywords table for this
|
||||
@@ -2197,7 +2081,7 @@ if (!GetFieldDef('bugs', 'keywords')) {
|
||||
# empty, then this account has been disabled, and this field is to contain
|
||||
# text describing why.
|
||||
|
||||
#AddField('profiles', 'disabledtext', 'varchar(4000) not null');
|
||||
AddField('profiles', 'disabledtext', 'varchar(4000) not null');
|
||||
|
||||
|
||||
# 2000-01-20 Added a new "longdescs" table, which is supposed to have all the
|
||||
@@ -2335,33 +2219,32 @@ if (GetFieldDef('bugs', 'long_desc')) {
|
||||
# different fields we keep an activity log on. The bugs_activity table
|
||||
# now has a pointer into that table instead of recording the name directly.
|
||||
|
||||
#if (GetFieldDef('bugs_activity', 'field')) {
|
||||
# AddField('bugs_activity', 'fieldid', 'integer not null');
|
||||
#
|
||||
# print "Populating new fieldid field ...\n";
|
||||
#
|
||||
# my $sth = $dbh->prepare('SELECT DISTINCT field FROM bugs_activity');
|
||||
# $sth->execute();
|
||||
# my %ids;
|
||||
# while (my ($f) = ($sth->fetchrow_array())) {
|
||||
# my $q = $dbh->quote($f);
|
||||
# next if !$q || $q =~ /NULL/;
|
||||
# print "$q\n";
|
||||
# my $s2 = $dbh->prepare("SELECT fieldid FROM fielddefs WHERE name = $q");
|
||||
# $s2->execute();
|
||||
# my ($id) = ($s2->fetchrow_array());
|
||||
# if (!$id) {
|
||||
# $dbh->do("INSERT INTO fielddefs (name, description, mailhead, sortkey) VALUES " .
|
||||
# "($q, $q, 0, 0)");
|
||||
# $s2 = $dbh->prepare("select last_value from fielddefs_fieldid_seq");
|
||||
# $s2->execute();
|
||||
# ($id) = ($s2->fetchrow_array());
|
||||
# }
|
||||
# $dbh->do("UPDATE bugs_activity SET fieldid = $id WHERE field = $q");
|
||||
# }
|
||||
#
|
||||
# DropField('bugs_activity', 'field');
|
||||
#}
|
||||
if (GetFieldDef('bugs_activity', 'field')) {
|
||||
AddField('bugs_activity', 'fieldid', 'integer not null');
|
||||
|
||||
print "Populating new fieldid field ...\n";
|
||||
|
||||
my $sth = $dbh->prepare('SELECT DISTINCT field FROM bugs_activity');
|
||||
$sth->execute();
|
||||
my %ids;
|
||||
while (my ($f) = ($sth->fetchrow_array())) {
|
||||
my $q = $dbh->quote($f);
|
||||
my $s2 =
|
||||
$dbh->prepare("SELECT fieldid FROM fielddefs WHERE name = $q");
|
||||
$s2->execute();
|
||||
my ($id) = ($s2->fetchrow_array());
|
||||
if (!$id) {
|
||||
$dbh->do("INSERT INTO fielddefs (name, description) VALUES " .
|
||||
"($q, $q)");
|
||||
$s2 = $dbh->prepare("select last_value from fielddefs_fieldid_seq");
|
||||
$s2->execute();
|
||||
($id) = ($s2->fetchrow_array());
|
||||
}
|
||||
$dbh->do("UPDATE bugs_activity SET fieldid = $id WHERE field = $q");
|
||||
}
|
||||
|
||||
DropField('bugs_activity', 'field');
|
||||
}
|
||||
|
||||
|
||||
# 2000-01-18 New email-notification scheme uses a new field in the bug to
|
||||
@@ -2431,8 +2314,8 @@ if (!GetFieldDef('bugs', 'lastdiffed')) {
|
||||
# bugs" link appears at the bottom of each page. Also can control
|
||||
# whether each named query should show up there.
|
||||
|
||||
#AddField('profiles', 'mybugslink', 'integer not null default 1');
|
||||
#AddField('namedqueries', 'linkinfooter', 'integer not null');
|
||||
AddField('profiles', 'mybugslink', 'integer not null default 1');
|
||||
AddField('namedqueries', 'linkinfooter', 'integer not null');
|
||||
|
||||
|
||||
# 2000-02-12 Added a new state to bugs, UNCONFIRMED. Added ability to confirm
|
||||
@@ -2512,9 +2395,9 @@ if (!GetFieldDef('bugs', 'everconfirmed')) {
|
||||
AddField('bugs', 'everconfirmed', 'integer not null');
|
||||
$dbh->do("UPDATE bugs SET everconfirmed = 1, delta_ts = now()");
|
||||
}
|
||||
#AddField('products', 'maxvotesperbug', 'integer not null default 10000');
|
||||
#AddField('products', 'votestoconfirm', 'integer not null');
|
||||
#AddField('profiles', 'blessgroupset', 'integer not null');
|
||||
AddField('products', 'maxvotesperbug', 'integer not null default 10000');
|
||||
AddField('products', 'votestoconfirm', 'integer not null');
|
||||
AddField('profiles', 'blessgroupset', 'integer not null');
|
||||
|
||||
# 2000-03-21 Adding a table for target milestones to
|
||||
# database - matthew@zeroknowledge.com
|
||||
@@ -2557,8 +2440,8 @@ if (!($sth->fetchrow_arrayref()->[0])) {
|
||||
# doing), and made the size of the value field in the milestones table match
|
||||
# the size of the target_milestone field in the bugs table.
|
||||
|
||||
#ChangeFieldType('bugs', 'target_milestone', "varchar(20) default '---'");
|
||||
#ChangeFieldType('milestones', 'value', 'varchar(20)');
|
||||
ChangeFieldType('bugs', 'target_milestone', "varchar(20) default '---'");
|
||||
ChangeFieldType('milestones', 'value', 'varchar(20)');
|
||||
|
||||
|
||||
# 2000-03-23 Added a defaultmilestone field to the products table, so that
|
||||
@@ -2635,7 +2518,7 @@ if (!($sth->fetchrow_arrayref()->[0])) {
|
||||
|
||||
foreach $key (keys(%dupes))
|
||||
{
|
||||
$dupes{$key} =~ s/^.*\*\*\* This bug has been marked as a duplicate of (\d{1,5}?) \*\*\*.*/$1/sm;
|
||||
$dupes{$key} =~ s/.*\*\*\* This bug has been marked as a duplicate of (\d{1,5}) \*\*\*.*?/$1/sm;
|
||||
$dbh->do("INSERT INTO duplicates VALUES('$dupes{$key}', '$key')");
|
||||
# BugItsADupeOf Dupe
|
||||
}
|
||||
@@ -2678,13 +2561,13 @@ unless (-d 'data/duplicates') {
|
||||
# without enabling them to extend the life of the group by adding bugs to it.
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=75482
|
||||
#
|
||||
#AddField('groups', 'isactive', 'integer not null default 1');
|
||||
AddField('groups', 'isactive', 'integer not null default 1');
|
||||
|
||||
#
|
||||
# 2001-06-15 myk@mozilla.org:
|
||||
# isobsolete determines whether or not an attachment is pertinent/relevant/valid.
|
||||
#
|
||||
#AddField('attachments', 'isobsolete', 'integer not null default 0');
|
||||
AddField('attachments', 'isobsolete', 'integer not null default 0');
|
||||
|
||||
# 2001-04-29 jake@acutex.net - Remove oldemailtech
|
||||
# http://bugzilla.mozilla.org/show_bugs.cgi?id=71552
|
||||
@@ -2746,7 +2629,7 @@ ENDTEXT
|
||||
|
||||
# 2001-06-15 kiko@async.com.br - Change bug:version size to avoid
|
||||
# truncates re http://bugzilla.mozilla.org/show_bug.cgi?id=9352
|
||||
#ChangeFieldType('bugs', 'version','varchar(64) not null');
|
||||
ChangeFieldType('bugs', 'version','varchar(64) not null');
|
||||
|
||||
# 2001-07-20 jake@acutex.net - Change bugs_activity to only record changes
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=55161
|
||||
@@ -2823,155 +2706,45 @@ if (GetFieldDef('bugs_activity', 'oldvalue')) {
|
||||
|
||||
# 2001-07-24 jake@acutex.net - disabledtext was being handled inconsitantly
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=90933
|
||||
#ChangeFieldType("profiles", "disabledtext", "varchar(4000) not null");
|
||||
ChangeFieldType("profiles", "disabledtext", "varchar(4000) not null");
|
||||
|
||||
|
||||
# 2001-07-26 myk@mozilla.org bug39816:
|
||||
# Add fields to the bugs table that record whether or not the reporter,
|
||||
# assignee, QA contact, and users on the cc: list can see bugs even when
|
||||
# they are not members of groups to which the bugs are restricted.
|
||||
#AddField("bugs", "reporter_accessible", "integer not null default 1");
|
||||
AddField("bugs", "reporter_accessible", "integer not null default 1");
|
||||
#AddField("bugs", "assignee_accessible", "integer not null default 1");
|
||||
#AddField("bugs", "qacontact_accessible", "integer not null default 1");
|
||||
#AddField("bugs", "cclist_accessible", "integer not null default 1");
|
||||
AddField("bugs", "cclist_accessible", "integer not null default 1");
|
||||
|
||||
# 2001-08-21 myk@mozilla.org bug84338:
|
||||
# Add a field for the attachment ID to the bugs_activity table, so installations
|
||||
# using the attachment manager can record changes to attachments.
|
||||
#AddField("bugs_activity", "attach_id", "integer");
|
||||
|
||||
# 2002-01-20 dkl@redhat.com 68022
|
||||
# Drop bit, groupset, blessgroupset fields from certain tables after converting
|
||||
# all users and bugs to new group schema
|
||||
if (GetFieldDef('groups', 'bit')) {
|
||||
print "Converting bug database to new group schema format...\n";
|
||||
my $superusergroupset = '9223372036854775807';
|
||||
my %bit_groups = ();
|
||||
my $sth;
|
||||
my $sth2;
|
||||
my $sth3;
|
||||
|
||||
$sth = $dbh->prepare("select bit, group_id from groups order by bit");
|
||||
$sth->execute();
|
||||
while (my ($bit, $groupid) = $sth->fetchrow_array()) {
|
||||
$bit_groups{$bit} = $groupid;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
print "Populating user_group_map and bless_group_map table from users in profiles...\n";
|
||||
foreach my $bit (sort keys %bit_groups) {
|
||||
# Fix profiles table first
|
||||
$sth = $dbh->prepare("select userid from profiles where (groupset & $bit) != 0 order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select user_id from user_group_map where " .
|
||||
"user_id = $userid and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth2->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2 = $dbh->prepare("insert into user_group_map values ($userid, $bit_groups{$bit}, 0)");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
# Next fix bless group privileges
|
||||
$sth = $dbh->prepare("select userid from profiles where blessgroupset & $bit != 0 order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select user_id from user_group_map " .
|
||||
"where user_id = $userid and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2->prepare("update user_group_map set canbless = 1 where user_id = $userid " .
|
||||
"and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
} else {
|
||||
$sth2 = $dbh->prepare("insert into user_group_map values ($userid, $bit_groups{$bit}, 1)");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
# Fix super users by adding 1 to admin column
|
||||
# We shouldn't need to add them to any groups since that would have been done earlier.
|
||||
print "Populating profile's admin column for super users...\n";
|
||||
$sth = $dbh->prepare("select userid from profiles where groupset = $superusergroupset order by userid");
|
||||
$sth->execute();
|
||||
while (my ($userid) = $sth->fetchrow_array()) {
|
||||
my $sth2 = $dbh->prepare("update profiles set admin = 1 where userid = $userid");
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
# Fix bug groupsets
|
||||
print "Populating bug_group_map table with bugs that are marked private...\n";
|
||||
foreach my $bit (sort keys %bit_groups) {
|
||||
$sth = $dbh->prepare("select bug_id from bugs where (groupset & $bit) != 0 order by bug_id");
|
||||
$sth->execute();
|
||||
while (my ($id) = $sth->fetchrow_array()) {
|
||||
$sth2 = $dbh->prepare("select bug_id from bug_group_map " .
|
||||
"where bug_id = $id and group_id = $bit_groups{$bit}");
|
||||
$sth2->execute();
|
||||
my ($result) = $sth->fetchrow_array();
|
||||
if (!$result) {
|
||||
$sth2 = $dbh->prepare("insert into bug_group_map values ($id, $bit_groups{$bit})");
|
||||
$sth2->execute();
|
||||
}
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
DropField('bugs', 'groupset');
|
||||
DropField('profiles', 'groupset');
|
||||
DropField('profiles', 'blessgroupset');
|
||||
DropField('groups', 'bit');
|
||||
}
|
||||
|
||||
# Added product_group_map table for product privacy
|
||||
# Adding product_id column to products table to allow this to work
|
||||
# 2002/01/24 dkl@redhat.com
|
||||
if (!GetFieldDef('products', 'product_id')) {
|
||||
AddField('products', 'product_id', 'mediumint primary key auto_increment not null');
|
||||
my $sth = $dbh->prepare('select product from products');
|
||||
$sth->execute();
|
||||
my $currproductid = 1;
|
||||
while (my ($name) = $sth->fetchrow_array()) {
|
||||
my $sth2 = $dbh->prepare("update products set product_id = $currproductid where product = " .
|
||||
$dbh->quote($name));
|
||||
$sth2->execute();
|
||||
$sth2->finish;
|
||||
}
|
||||
$sth->finish;
|
||||
}
|
||||
|
||||
AddField("bugs_activity", "attach_id", "integer");
|
||||
|
||||
# 2002-02-04 bbaetz@student.usyd.edu.au bug 95732
|
||||
# Remove logincookies.cryptpassword, and delete entries which become
|
||||
# invalid
|
||||
#if (GetFieldDef("logincookies", "cryptpassword")) {
|
||||
# # We need to delete any cookies which are invalid, before dropping the
|
||||
# # column
|
||||
#
|
||||
# print "Removing invalid login cookies...\n";
|
||||
#
|
||||
# # mysql doesn't support DELETE with multi-table queries, so we have
|
||||
# # to iterate
|
||||
# my $sth = $dbh->prepare("SELECT cookie FROM logincookies, profiles " .
|
||||
# "WHERE logincookies.cryptpassword != " .
|
||||
# "profiles.cryptpassword AND " .
|
||||
# "logincookies.userid = profiles.userid");
|
||||
# $sth->execute();
|
||||
# while (my ($cookie) = $sth->fetchrow_array()) {
|
||||
# $dbh->do("DELETE FROM logincookies WHERE cookie = $cookie");
|
||||
# }
|
||||
#
|
||||
# DropField("logincookies", "cryptpassword");
|
||||
#}
|
||||
if (GetFieldDef("logincookies", "cryptpassword")) {
|
||||
# We need to delete any cookies which are invalid, before dropping the
|
||||
# column
|
||||
|
||||
print "Removing invalid login cookies...\n";
|
||||
|
||||
# mysql doesn't support DELETE with multi-table queries, so we have
|
||||
# to iterate
|
||||
my $sth = $dbh->prepare("SELECT cookie FROM logincookies, profiles " .
|
||||
"WHERE logincookies.cryptpassword != " .
|
||||
"profiles.cryptpassword AND " .
|
||||
"logincookies.userid = profiles.userid");
|
||||
$sth->execute();
|
||||
while (my ($cookie) = $sth->fetchrow_array()) {
|
||||
$dbh->do("DELETE FROM logincookies WHERE cookie = $cookie");
|
||||
}
|
||||
|
||||
DropField("logincookies", "cryptpassword");
|
||||
}
|
||||
|
||||
# 2002-02-13 bbaetz@student.usyd.edu.au - bug 97471
|
||||
# qacontact/assignee should always be able to see bugs,
|
||||
|
||||
@@ -35,6 +35,7 @@ require "bug_form.pl";
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::buffer;
|
||||
$zz = $::usergroupset;
|
||||
$zz = %::COOKIE;
|
||||
$zz = %::components;
|
||||
$zz = %::versions;
|
||||
@@ -44,13 +45,13 @@ sub sillyness {
|
||||
$zz = @::legal_product;
|
||||
$zz = @::legal_severity;
|
||||
$zz = %::target_milestone;
|
||||
$zz = $::driver;
|
||||
}
|
||||
|
||||
# Use global template variables.
|
||||
use vars qw($vars $template);
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
|
||||
# The format of the initial comment can be structured by adding fields to the
|
||||
# enter_bug template and then referencing them in the comment template.
|
||||
@@ -94,10 +95,12 @@ umask 0;
|
||||
ConnectToDatabase();
|
||||
|
||||
# Some sanity checking
|
||||
if(!CanSeeProduct($product, $userid)) {
|
||||
DisplayError("Sorry; you do not have the permissions necessary to enter
|
||||
a bug against this product.", "Permission Denied");
|
||||
exit;
|
||||
if(Param("usebuggroupsentry") && GroupExists($product)) {
|
||||
if(!UserInGroup($product)) {
|
||||
DisplayError("Sorry; you do not have the permissions necessary to enter
|
||||
a bug against this product.", "Permission Denied");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$::FORM{'component'}) {
|
||||
@@ -150,7 +153,7 @@ if (exists $::FORM{'bug_status'}) {
|
||||
# unconfirmed (so that a user can't override the below check), or if
|
||||
# the user doesn't have permission to change the default status anyway
|
||||
if ($::FORM{'bug_status'} eq $::unconfirmedstate
|
||||
|| (!UserInGroup($userid, "canedit") && !UserInGroup($userid, "canconfirm"))) {
|
||||
|| (!UserInGroup("canedit") && !UserInGroup("canconfirm"))) {
|
||||
delete $::FORM{'bug_status'};
|
||||
}
|
||||
}
|
||||
@@ -204,7 +207,7 @@ if (exists $::FORM{'bug_status'}
|
||||
|
||||
# Build up SQL string to add bug.
|
||||
my $sql = "INSERT INTO bugs " .
|
||||
"(" . join(",", @used_fields) . ", reporter, creation_ts) " .
|
||||
"(" . join(",", @used_fields) . ", reporter, creation_ts, groupset) " .
|
||||
"VALUES (";
|
||||
|
||||
foreach my $field (@used_fields) {
|
||||
@@ -217,14 +220,16 @@ $comment = trim($comment);
|
||||
# OK except for the fact that it causes e-mail to be suppressed.
|
||||
$comment = $comment ? $comment : " ";
|
||||
|
||||
$sql .= "$userid, now())";
|
||||
|
||||
my @groupids;
|
||||
if ($::driver eq 'mysql') {
|
||||
$sql .= "$::userid, now(), (0";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$sql .= "$::userid, now(), (int8(0)";
|
||||
}
|
||||
|
||||
# Groups
|
||||
foreach my $b (grep(/^group-\d*$/, keys %::FORM)) {
|
||||
foreach my $b (grep(/^bit-\d*$/, keys %::FORM)) {
|
||||
if ($::FORM{$b}) {
|
||||
my $v = substr($b, 6);
|
||||
my $v = substr($b, 4);
|
||||
$v =~ /^(\d+)$/
|
||||
|| ThrowCodeError("One of the group bits submitted was invalid.",
|
||||
undef, "abort");
|
||||
@@ -234,25 +239,32 @@ foreach my $b (grep(/^group-\d*$/, keys %::FORM)) {
|
||||
# hacked the "enter bug" form since otherwise the UI
|
||||
# for adding the bug to the group won't appear on that form.
|
||||
ThrowCodeError("Attempted to add bug to an inactive group, " .
|
||||
"identified by the id '$v'.", undef, "abort");
|
||||
"identified by the bit '$v'.", undef, "abort");
|
||||
}
|
||||
push @groupids, $v;
|
||||
$sql .= " + $v"; # Carefully written so that the math is
|
||||
# done by MySQL, which can handle 64-bit math,
|
||||
# and not by Perl, which I *think* can not.
|
||||
}
|
||||
}
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
$sql .= ") & $::usergroupset)\n";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$sql .= " & int8($::usergroupset)))\n";
|
||||
}
|
||||
|
||||
# Add the bug report to the DB.
|
||||
SendSQL($sql);
|
||||
my $id = CurrId("bugs_bug_id_seq");
|
||||
|
||||
# Lock tables before inserting records for the new bug into the database
|
||||
# if we are using a shadow database to prevent shadow database corruption
|
||||
# when two bugs get created at the same time.
|
||||
SendSQL("LOCK TABLES bugs WRITE, longdescs WRITE, cc WRITE, bug_group_map WRITE") if Param("shadowdb");
|
||||
|
||||
# Add the bug report to the DB.
|
||||
SendSQL($sql);
|
||||
|
||||
my $id = CurrId("bugs_bug_id_seq");
|
||||
SendSQL("LOCK TABLES bugs WRITE, longdescs WRITE, cc WRITE") if Param("shadowdb") && $::driver eq 'mysql';
|
||||
|
||||
# Add the comment
|
||||
SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext)
|
||||
VALUES ($id, $userid, now(), " . SqlQuote($comment) . ")");
|
||||
VALUES ($id, $::userid, now(), " . SqlQuote($comment) . ")");
|
||||
|
||||
my %ccids;
|
||||
my $ccid;
|
||||
@@ -272,10 +284,6 @@ if (defined $::FORM{'cc'}) {
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $group (@groupids) {
|
||||
SendSQL("INSERT INTO bug_group_map (bug_id, group_id) VALUES ($id, $group)");
|
||||
}
|
||||
|
||||
SendSQL("UNLOCK TABLES") if Param("shadowdb") && $::driver eq 'mysql';
|
||||
|
||||
# Assemble the -force* strings so this counts as "Added to this capacity"
|
||||
@@ -290,7 +298,7 @@ if (defined $::FORM{'qa_contact'}) {
|
||||
push (@ARGLIST, "-forceqacontact", DBID_to_name($::FORM{'qa_contact'}));
|
||||
}
|
||||
|
||||
push (@ARGLIST, "-forcereporter", DBID_to_name($userid));
|
||||
push (@ARGLIST, "-forcereporter", DBID_to_name($::userid));
|
||||
|
||||
push (@ARGLIST, $id, $::COOKIE{'Bugzilla_login'});
|
||||
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
my $hasEditGroup = -1;
|
||||
my $hasCanConfirmGroup = -1;
|
||||
|
||||
use lib qw(.);
|
||||
my $UserInEditGroupSet = -1;
|
||||
my $UserInCanConfirmGroupSet = -1;
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
@@ -52,6 +50,7 @@ use vars qw(%versions
|
||||
%settable_resolution
|
||||
%target_milestone
|
||||
%legal_severity
|
||||
%superusergroupset
|
||||
$userid
|
||||
$next_bug);
|
||||
|
||||
@@ -73,13 +72,13 @@ use vars qw($template $vars);
|
||||
# representing an existing bug that the user is authorized to access.
|
||||
my @idlist;
|
||||
if (defined $::FORM{'id'}) {
|
||||
ValidateBugID($::FORM{'id'}, $whoid);
|
||||
ValidateBugID($::FORM{'id'});
|
||||
push @idlist, $::FORM{'id'};
|
||||
} else {
|
||||
foreach my $i (keys %::FORM) {
|
||||
if ($i =~ /^id_([1-9][0-9]*)/) {
|
||||
my $id = $1;
|
||||
ValidateBugID($id, $whoid);
|
||||
ValidateBugID($id);
|
||||
push @idlist, $id;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +92,7 @@ scalar(@idlist)
|
||||
# If we are duping bugs, let's also make sure that we can change
|
||||
# the original. This takes care of issue A on bug 96085.
|
||||
if (defined $::FORM{'dup_id'} && $::FORM{'knob'} eq "duplicate") {
|
||||
ValidateBugID($::FORM{'dup_id'}, $whoid);
|
||||
ValidateBugID($::FORM{'dup_id'});
|
||||
|
||||
# Also, let's see if the reporter has authorization to see the bug
|
||||
# to which we are duping. If not we need to prompt.
|
||||
@@ -154,6 +153,7 @@ sub CheckonComment( $ ) {
|
||||
return( ! $ret ); # Return val has to be inverted
|
||||
}
|
||||
|
||||
|
||||
# Figure out whether or not the user is trying to change the product
|
||||
# (either the "product" variable is not set to "don't change" or the
|
||||
# user is changing a single bug and has changed the bug's product),
|
||||
@@ -251,10 +251,10 @@ sub CheckCanChangeField {
|
||||
if ($f eq "resolution") { # always OK this. if they really can't,
|
||||
return 1; # it'll flag it when "status" is checked.
|
||||
}
|
||||
if ($hasEditGroup < 0) {
|
||||
$hasEditGroup = UserInGroup($whoid, "editbugs");
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup("editbugs");
|
||||
}
|
||||
if ($hasEditGroup) {
|
||||
if ($UserInEditGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
if ($lastbugid != $bugid) {
|
||||
@@ -276,10 +276,10 @@ sub CheckCanChangeField {
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($hasCanConfirmGroup < 0) {
|
||||
$hasCanConfirmGroup = UserInGroup($whoid, "canconfirm");
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = UserInGroup("canconfirm");
|
||||
}
|
||||
if ($hasCanConfirmGroup) {
|
||||
if ($UserInCanConfirmGroupSet) {
|
||||
return 1;
|
||||
}
|
||||
SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $bugid");
|
||||
@@ -309,11 +309,13 @@ sub DuplicateUserConfirm {
|
||||
|
||||
my $dupe = trim($::FORM{'id'});
|
||||
my $original = trim($::FORM{'dup_id'});
|
||||
|
||||
|
||||
SendSQL("SELECT reporter FROM bugs WHERE bug_id = " . SqlQuote($dupe));
|
||||
my $reporter = FetchOneColumn();
|
||||
SendSQL("SELECT profiles.groupset FROM profiles WHERE profiles.userid =".SqlQuote($reporter));
|
||||
my $reportergroupset = FetchOneColumn();
|
||||
|
||||
if (CanSeeBug($original, $reporter)) {
|
||||
if (CanSeeBug($original, $reporter, $reportergroupset)) {
|
||||
$::FORM{'confirm_add_duplicate'} = "1";
|
||||
return;
|
||||
}
|
||||
@@ -381,13 +383,13 @@ sub DoComma {
|
||||
}
|
||||
|
||||
sub DoConfirm {
|
||||
if ($hasEditGroup < 0) {
|
||||
$hasEditGroup = UserInGroup($whoid, "editbugs");
|
||||
if ($UserInEditGroupSet < 0) {
|
||||
$UserInEditGroupSet = UserInGroup("editbugs");
|
||||
}
|
||||
if ($hasCanConfirmGroup < 0) {
|
||||
$hasCanConfirmGroup = UserInGroup($whoid, "canconfirm");
|
||||
if ($UserInCanConfirmGroupSet < 0) {
|
||||
$UserInCanConfirmGroupSet = UserInGroup("canconfirm");
|
||||
}
|
||||
if ($hasEditGroup || $hasCanConfirmGroup) {
|
||||
if ($UserInEditGroupSet || $UserInCanConfirmGroupSet) {
|
||||
DoComma();
|
||||
$::query .= "everconfirmed = 1";
|
||||
}
|
||||
@@ -439,6 +441,55 @@ sub ChangeResolution {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Changing this so that it will process groups from checkboxes instead of
|
||||
# select lists. This means that instead of looking for the bit-X values in
|
||||
# the form, we need to loop through all the bug groups this user has access
|
||||
# to, and for each one, see if it's selected.
|
||||
# In order to make mass changes work correctly, keep a sum of bits for groups
|
||||
# added, and another one for groups removed, and then let mysql do the bit
|
||||
# operations
|
||||
# If the form element isn't present, or the user isn't in the group, leave
|
||||
# it as-is
|
||||
if($::usergroupset ne '0') {
|
||||
my $groupAdd = "0";
|
||||
my $groupDel = "0";
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bit, isactive FROM groups WHERE " .
|
||||
"isbuggroup != 0 AND bit & $::usergroupset != 0 ORDER BY bit");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit, isactive FROM groups WHERE " .
|
||||
"isbuggroup != 0 AND group_bit & int8($::usergroupset) != 0 ORDER BY group_bit");
|
||||
}
|
||||
|
||||
while (my ($b, $isactive) = FetchSQLData()) {
|
||||
# The multiple change page may not show all groups a bug is in
|
||||
# (eg product groups when listing more than one product)
|
||||
# Only consider groups which were present on the form. We can't do this
|
||||
# for single bug changes because non-checked checkboxes aren't present.
|
||||
# All the checkboxes should be shown in that case, though, so its not
|
||||
# an issue there
|
||||
if ($::FORM{'id'} || exists $::FORM{"bit-$b"}) {
|
||||
if (!$::FORM{"bit-$b"}) {
|
||||
$groupDel .= "+$b";
|
||||
} elsif ($::FORM{"bit-$b"} == 1 && $isactive) {
|
||||
$groupAdd .= "+$b";
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($groupAdd ne "0" || $groupDel ne "0") {
|
||||
DoComma();
|
||||
# mysql < 3.23.5 doesn't support the ~ operator, even though
|
||||
# the docs say that it does
|
||||
if ($::driver eq 'mysql') {
|
||||
$::query .= "groupset = ((groupset & ($::superusergroupset - ($groupDel))) | ($groupAdd))";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$::query .= "groupset = ((groupset & (int8($::superusergroupset) - (int8($groupDel)))) | (int8($groupAdd)))";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $field ("rep_platform", "priority", "bug_severity",
|
||||
"summary", "component", "bug_file_loc", "short_desc",
|
||||
"product", "version", "op_sys",
|
||||
@@ -471,9 +522,15 @@ if (defined $::FORM{'qa_contact'}) {
|
||||
# and cc list can see the bug even if they are not members of all groups
|
||||
# to which the bug is restricted.
|
||||
if ( $::FORM{'id'} ) {
|
||||
SendSQL("SELECT count(*) FROM bug_group_map WHERE bug_id = $::FORM{'id'}");
|
||||
my $groups = FetchOneColumn();
|
||||
if ( $groups ) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT bit FROM groups WHERE bit & $::usergroupset != 0
|
||||
AND isbuggroup != 0 AND isactive = 1");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT group_bit FROM groups WHERE (group_bit & int8($::usergroupset)) != 0
|
||||
AND isbuggroup != 0 AND isactive = 1");
|
||||
}
|
||||
my ($groupbits) = FetchSQLData();
|
||||
if ( $groupbits ) {
|
||||
DoComma();
|
||||
$::FORM{'reporter_accessible'} = $::FORM{'reporter_accessible'} ? '1' : '0';
|
||||
$::query .= "reporter_accessible = $::FORM{'reporter_accessible'}";
|
||||
@@ -807,10 +864,10 @@ foreach my $id (@idlist) {
|
||||
# whether we do LOW_PRIORITY ...
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("LOCK TABLES bugs $write, bugs_activity $write, cc $write, " .
|
||||
"cc AS selectVisible_cc $write, " .
|
||||
"profiles $write, dependencies $write, votes $write, " .
|
||||
"keywords $write, longdescs $write, fielddefs $write, " .
|
||||
"keyworddefs READ, groups READ, attachments READ, products READ, " .
|
||||
"user_group_map READ, bug_group_map WRITE");
|
||||
"keyworddefs READ, groups READ, attachments READ, products READ");
|
||||
}
|
||||
my @oldvalues = SnapShotBug($id);
|
||||
my %oldhash;
|
||||
@@ -1084,6 +1141,76 @@ foreach my $id (@idlist) {
|
||||
}
|
||||
}
|
||||
|
||||
# When a bug changes products and the old or new product is associated
|
||||
# with a bug group, it may be necessary to remove the bug from the old
|
||||
# group or add it to the new one. There are a very specific series of
|
||||
# conditions under which these activities take place, more information
|
||||
# about which can be found in comments within the conditionals below.
|
||||
if (
|
||||
# the "usebuggroups" parameter is on, indicating that products
|
||||
# are associated with groups of the same name;
|
||||
Param('usebuggroups')
|
||||
|
||||
# the user has changed the product to which the bug belongs;
|
||||
&& defined $::FORM{'product'}
|
||||
&& $::FORM{'product'} ne $::dontchange
|
||||
&& $::FORM{'product'} ne $oldhash{'product'}
|
||||
) {
|
||||
if (
|
||||
# the user wants to add the bug to the new product's group;
|
||||
($::FORM{'addtonewgroup'} eq 'yes'
|
||||
|| ($::FORM{'addtonewgroup'} eq 'yesifinold'
|
||||
&& GroupNameToBit($oldhash{'product'}) & $oldhash{'groupset'}))
|
||||
|
||||
# the new product is associated with a group;
|
||||
&& GroupExists($::FORM{'product'})
|
||||
|
||||
# the bug is not already in the group; (This can happen when the user
|
||||
# goes to the "edit multiple bugs" form with a list of bugs at least
|
||||
# one of which is in the new group. In this situation, the user can
|
||||
# simultaneously change the bugs to a new product and move the bugs
|
||||
# into that product's group, which happens earlier in this script
|
||||
# and thus is already done. If we didn't check for this, then this
|
||||
# situation would cause us to add the bug to the group twice, which
|
||||
# would result in the bug being added to a totally different group.)
|
||||
&& !BugInGroup($id, $::FORM{'product'})
|
||||
|
||||
# the user is a member of the associated group, indicating they
|
||||
# are authorized to add bugs to that group, *or* the "usebuggroupsentry"
|
||||
# parameter is off, indicating that users can add bugs to a product
|
||||
# regardless of whether or not they belong to its associated group;
|
||||
&& (UserInGroup($::FORM{'product'}) || !Param('usebuggroupsentry'))
|
||||
|
||||
# the associated group is active, indicating it can accept new bugs;
|
||||
&& GroupIsActive(GroupNameToBit($::FORM{'product'}))
|
||||
) {
|
||||
# Add the bug to the group associated with its new product.
|
||||
my $groupbit = GroupNameToBit($::FORM{'product'});
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE bugs SET groupset = groupset + $groupbit WHERE bug_id = $id");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE bugs SET groupset = groupset + int8($groupbit) WHERE bug_id = $id");
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
# the old product is associated with a group;
|
||||
GroupExists($oldhash{'product'})
|
||||
|
||||
# the bug is a member of that group;
|
||||
&& BugInGroup($id, $oldhash{'product'})
|
||||
) {
|
||||
# Remove the bug from the group associated with its old product.
|
||||
my $groupbit = GroupNameToBit($oldhash{'product'});
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE bugs SET groupset = groupset - $groupbit WHERE bug_id = $id");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("UPDATE bugs SET groupset = groupset - int8($groupbit) WHERE bug_id = $id");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# get a snapshot of the newly set values out of the database,
|
||||
# and then generate any necessary bug activity entries by seeing
|
||||
# what has changed since before we wrote out the new values.
|
||||
@@ -1138,43 +1265,6 @@ foreach my $id (@idlist) {
|
||||
LogActivityEntry($id,$col,$old,$new);
|
||||
}
|
||||
}
|
||||
|
||||
# Make necessary group membership changes
|
||||
# Changing this so that it will process groups from checkboxes instead of
|
||||
# select lists. This means that instead of looking for the group-X values in
|
||||
# the form, we need to loop through all the bug groups this user has access
|
||||
# to, and for each one, see if it's selected.
|
||||
# Also, we don't want to clobber existing groups.
|
||||
if ($whoid) {
|
||||
my %buggroups = ();
|
||||
|
||||
# First, find out what groups this bug is currently private to.
|
||||
SendSQL("SELECT group_id FROM bug_group_map WHERE bug_id = $id");
|
||||
while (my ($groupid) = FetchSQLData()) {
|
||||
$buggroups{$groupid} = 1;
|
||||
}
|
||||
|
||||
# Second, find out what groups this person is a member of and see if they made changes.
|
||||
SendSQL("SELECT groups.group_id, groups.isactive FROM groups, user_group_map WHERE " .
|
||||
"groups.group_id = user_group_map.group_id AND user_group_map.user_id = $whoid");
|
||||
while (my ($groupid, $isactive) = FetchSQLData()) {
|
||||
# Box not checked so remove from group
|
||||
if (!$::FORM{"group-$groupid"}) {
|
||||
$buggroups{$groupid} = 0;
|
||||
# Box checked and is active so add to group
|
||||
} elsif ($::FORM{"group-$groupid"} == 1 && $isactive) {
|
||||
$buggroups{$groupid} = 1;
|
||||
} # Else leave alone
|
||||
}
|
||||
|
||||
# Update the bug_group table with new group values.
|
||||
SendSQL("DELETE FROM bug_group_map WHERE bug_id = $id");
|
||||
foreach my $group (keys %buggroups) {
|
||||
next if !$buggroups{$group};
|
||||
SendSQL("INSERT INTO bug_group_map VALUES ($id, $group)");
|
||||
}
|
||||
}
|
||||
|
||||
if ($bug_changed) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UPDATE bugs SET delta_ts = " . SqlQuote($timestamp) . " WHERE bug_id = $id");
|
||||
@@ -1272,7 +1362,7 @@ if ($::COOKIE{"BUGLIST"} && $::FORM{'id'}) {
|
||||
my $cur = lsearch(\@bugs, $::FORM{"id"});
|
||||
if ($cur >= 0 && $cur < $#bugs) {
|
||||
my $next_bug = $bugs[$cur + 1];
|
||||
if (detaint_natural($next_bug) && CanSeeBug($next_bug, $userid)) {
|
||||
if (detaint_natural($next_bug) && CanSeeBug($next_bug, $userid, $::usergroupset)) {
|
||||
$::FORM{'id'} = $next_bug;
|
||||
|
||||
$vars->{'next_id'} = $next_bug;
|
||||
|
||||
@@ -50,7 +50,7 @@ my %nomail;
|
||||
my @excludedAddresses = ();
|
||||
|
||||
# disable email flag for offline debugging work
|
||||
my $enableSendMail = 0;
|
||||
my $enableSendMail = 1;
|
||||
|
||||
my %force;
|
||||
@{$force{'QAcontact'}} = ();
|
||||
@@ -673,12 +673,16 @@ sub NewProcessOnePerson ($$$$$$$$$$$$) {
|
||||
if ($nomail{$person}) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $userid = DBname_to_id($person);
|
||||
|
||||
|
||||
SendSQL("SELECT userid, groupset " .
|
||||
"FROM profiles WHERE login_name = " . SqlQuote($person));
|
||||
my ($userid, $groupset) = (FetchSQLData());
|
||||
|
||||
$seen{$person} = 1;
|
||||
|
||||
detaint_natural($userid);
|
||||
detaint_natural($groupset);
|
||||
|
||||
# if this person doesn't have permission to see info on this bug,
|
||||
# return.
|
||||
@@ -688,7 +692,7 @@ sub NewProcessOnePerson ($$$$$$$$$$$$) {
|
||||
# see the action of restricting the bug itself; the bug will just
|
||||
# quietly disappear from their radar.
|
||||
#
|
||||
return unless CanSeeBug($id, $userid);
|
||||
return unless CanSeeBug($id, $userid, $groupset);
|
||||
|
||||
# We shouldn't send changedmail if this is a dependency mail, and any of
|
||||
# the depending bugs is not visible to the user.
|
||||
@@ -696,7 +700,7 @@ sub NewProcessOnePerson ($$$$$$$$$$$$) {
|
||||
my $save_id = $dep_id;
|
||||
detaint_natural($dep_id) || warn("Unexpected Error: \@depbugs contains a non-numeric value: '$save_id'")
|
||||
&& return;
|
||||
return unless CanSeeBug($dep_id, $userid);
|
||||
return unless CanSeeBug($dep_id, $userid, $groupset);
|
||||
}
|
||||
|
||||
my %mailhead = %defmailhead;
|
||||
|
||||
@@ -50,20 +50,18 @@ use vars qw(
|
||||
$vars
|
||||
);
|
||||
|
||||
my $userid = 0;
|
||||
ConnectToDatabase();
|
||||
if (defined $::FORM{"GoAheadAndLogIn"}) {
|
||||
# We got here from a login page, probably from relogin.cgi. We better
|
||||
# make sure the password is legit.
|
||||
$userid = confirm_login();
|
||||
confirm_login();
|
||||
} else {
|
||||
$userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
}
|
||||
|
||||
# Backwards compatibility 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. This is required for Bugzilla 2.8 and earlier.
|
||||
if ($userid) {
|
||||
if ($::userid) {
|
||||
my @oldquerycookies;
|
||||
foreach my $i (keys %::COOKIE) {
|
||||
if ($i =~ /^QUERY_(.*)$/) {
|
||||
@@ -200,7 +198,7 @@ foreach my $p (@::legal_product) {
|
||||
# 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 if (!CanSeeProduct($userid, $p));
|
||||
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.
|
||||
@@ -298,11 +296,12 @@ $vars->{'rep_platform'} = \@::legal_platform;
|
||||
$vars->{'op_sys'} = \@::legal_opsys;
|
||||
$vars->{'priority'} = \@::legal_priority;
|
||||
$vars->{'bug_severity'} = \@::legal_severity;
|
||||
$vars->{'userid'} = $userid;
|
||||
$vars->{'userid'} = $::userid;
|
||||
|
||||
# Boolean charts
|
||||
my @fields;
|
||||
push(@fields, { name => "noop", description => "---" });
|
||||
ConnectToDatabase();
|
||||
SendSQL("SELECT name, description FROM fielddefs ORDER BY sortkey");
|
||||
while (MoreSQLData()) {
|
||||
my ($name, $description) = FetchSQLData();
|
||||
@@ -345,10 +344,10 @@ for (my $chart = 0; $::FORM{"field$chart-0-0"}; $chart++) {
|
||||
$default{'charts'} = \@charts;
|
||||
|
||||
# Named queries
|
||||
if ($userid) {
|
||||
if ($::userid) {
|
||||
my @namedqueries;
|
||||
SendSQL("SELECT name FROM namedqueries " .
|
||||
"WHERE userid = $userid AND name != '$::defaultqueryname' " .
|
||||
"WHERE userid = $::userid AND name != '$::defaultqueryname' " .
|
||||
"ORDER BY name");
|
||||
while (MoreSQLData()) {
|
||||
push(@namedqueries, FetchOneColumn());
|
||||
|
||||
@@ -609,9 +609,9 @@ while (MoreSQLData()) {
|
||||
|
||||
print "</table><p>\n";
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
if (UserInGroup($userid, "editkeywords")) {
|
||||
if (UserInGroup("editkeywords")) {
|
||||
print qq{<p><a href="editkeywords.cgi">Edit keywords</a>\n};
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ SendSQL("SELECT product,description FROM products ORDER BY product");
|
||||
while (MoreSQLData()) {
|
||||
|
||||
my ($product, $productdesc) = FetchSQLData();
|
||||
next if (Param("usebuggroups") && GroupExists($product) && !UserInGroup($userid, $product));
|
||||
next if (Param("usebuggroups") && GroupExists($product) && !UserInGroup($product));
|
||||
push (@products, $product);
|
||||
|
||||
$line_count++;
|
||||
@@ -692,7 +692,7 @@ print qq{
|
||||
|
||||
</table></td></tr></table> };
|
||||
|
||||
if (UserInGroup($userid, "editcomponents")) {
|
||||
if (UserInGroup("editcomponents")) {
|
||||
print qq{<p><a href="editproducts.cgi">Edit products</a><p>};
|
||||
}
|
||||
|
||||
@@ -751,7 +751,7 @@ foreach $product (@products)
|
||||
}
|
||||
|
||||
print qq{</table>};
|
||||
if (UserInGroup($userid, "editcomponents")) {
|
||||
if (UserInGroup("editcomponents")) {
|
||||
print qq{<p><a href="editcomponents.cgi">Edit components</a><p>};
|
||||
}
|
||||
|
||||
@@ -817,7 +817,7 @@ Containing at least <INPUT NAME=votes SIZE=3 VALUE=""> votes
|
||||
<td>
|
||||
Where the field(s)
|
||||
<SELECT NAME="chfield" MULTIPLE SIZE=4>
|
||||
<OPTION VALUE="[Bug creation]">[Bug creation]<OPTION VALUE="assigned_to">assigned_to<OPTION VALUE="bug_file_loc">bug_file_loc<OPTION VALUE="bug_severity">bug_severity<OPTION VALUE="bug_status">bug_status<OPTION VALUE="component">component<OPTION VALUE="everconfirmed">everconfirmed<OPTION VALUE="keywords">keywords<OPTION VALUE="op_sys">op_sys<OPTION VALUE="priority">priority<OPTION VALUE="product">product<OPTION VALUE="qa_contact">qa_contact<OPTION VALUE="rep_platform">rep_platform<OPTION VALUE="reporter">reporter<OPTION VALUE="resolution">resolution<OPTION VALUE="short_desc">short_desc<OPTION VALUE="status_whiteboard">status_whiteboard<OPTION VALUE="target_milestone">target_milestone<OPTION VALUE="version">version<OPTION VALUE="votes">votes
|
||||
<OPTION VALUE="[Bug creation]">[Bug creation]<OPTION VALUE="assigned_to">assigned_to<OPTION VALUE="bug_file_loc">bug_file_loc<OPTION VALUE="bug_severity">bug_severity<OPTION VALUE="bug_status">bug_status<OPTION VALUE="component">component<OPTION VALUE="everconfirmed">everconfirmed<OPTION VALUE="groupset">groupset<OPTION VALUE="keywords">keywords<OPTION VALUE="op_sys">op_sys<OPTION VALUE="priority">priority<OPTION VALUE="product">product<OPTION VALUE="qa_contact">qa_contact<OPTION VALUE="rep_platform">rep_platform<OPTION VALUE="reporter">reporter<OPTION VALUE="resolution">resolution<OPTION VALUE="short_desc">short_desc<OPTION VALUE="status_whiteboard">status_whiteboard<OPTION VALUE="target_milestone">target_milestone<OPTION VALUE="version">version<OPTION VALUE="votes">votes
|
||||
</SELECT> changed to <INPUT NAME="chfieldvalue" SIZE="10">
|
||||
</td>
|
||||
</tr>
|
||||
@@ -906,6 +906,7 @@ queries, but it's not the easiest thing to learn (or explain).
|
||||
<table>
|
||||
<tr><td>
|
||||
<table><tr><td> </td><td><SELECT NAME="field0-0-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -985,6 +986,7 @@ Field 3: What the search term is<br>
|
||||
<table>
|
||||
<tr><td>
|
||||
<table><tr><td> </td><td><SELECT NAME="field0-0-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -1032,6 +1034,7 @@ Field 3: What the search term is<br>
|
||||
<OPTION VALUE="changedto">changed to
|
||||
<OPTION VALUE="changedby">changed by
|
||||
</SELECT><INPUT NAME="value0-0-0" VALUE=""></td></tr><tr><td><b>OR</b></td><td><SELECT NAME="field0-0-1"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -1113,6 +1116,7 @@ the query will be anything that matches either of the terms.
|
||||
<tr><td>
|
||||
|
||||
<table><tr><td> </td><td><SELECT NAME="field0-0-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -1160,6 +1164,7 @@ the query will be anything that matches either of the terms.
|
||||
<OPTION VALUE="changedto">changed to
|
||||
<OPTION VALUE="changedby">changed by
|
||||
</SELECT><INPUT NAME="value0-0-0" VALUE=""><INPUT TYPE="button" VALUE="Or" NAME="cmd-add0-0-1" ONCLICK="document.forms[0].action='query.cgi#chart' ; document.forms[0].method='POST' ; return 1;"></td></tr><tr><td> </td><td align="center" valign="middle"><b>AND</b></td></tr><tr><td> </td><td><SELECT NAME="field0-1-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -1242,6 +1247,7 @@ can think of the lines of "Or" as having parenthesis around them.
|
||||
<table>
|
||||
<tr><td>
|
||||
<table><tr><td> </td><td><SELECT NAME="field0-0-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
@@ -1295,6 +1301,7 @@ can think of the lines of "Or" as having parenthesis around them.
|
||||
<td colspan="2"><hr></td>
|
||||
</tr><tr><td> </td><td>
|
||||
<SELECT NAME="field1-0-0"><OPTION SELECTED VALUE="noop">---
|
||||
<OPTION VALUE="groupset">groupset
|
||||
<OPTION VALUE="bug_id">Bug #
|
||||
<OPTION VALUE="short_desc">Summary
|
||||
<OPTION VALUE="product">Product
|
||||
|
||||
@@ -51,25 +51,6 @@ if ($::userid) {
|
||||
"AND userid = $::userid");
|
||||
}
|
||||
|
||||
# We don't want to remove a random logincookie from the db, so
|
||||
# call quietly_check_login. If we're logged in after this, then
|
||||
# the logincookie must be correct
|
||||
|
||||
ConnectToDatabase();
|
||||
quietly_check_login();
|
||||
|
||||
if ($::userid) {
|
||||
# Even though we know the userid must match, we still check it in the
|
||||
# SQL as a sanity check, since there is no locking here, and if
|
||||
# the user logged out from two machines simulataniously, while someone
|
||||
# else logged in and got the same cookie, we could be logging the
|
||||
# other user out here. Yes, this is very very very unlikely, but why
|
||||
# take chances? - bbaetz
|
||||
SendSQL("DELETE FROM logincookies WHERE cookie = " .
|
||||
SqlQuote($::COOKIE{"Bugzilla_logincookie"}) .
|
||||
"AND userid = $::userid");
|
||||
}
|
||||
|
||||
my $cookiepath = Param("cookiepath");
|
||||
print "Set-Cookie: Bugzilla_login= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
Set-Cookie: Bugzilla_logincookie= ; path=$cookiepath; expires=Sun, 30-Jun-80 00:00:00 GMT
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
# Added -All- report, change "nobanner" to "banner" (it is strange to have a
|
||||
# list with 2 positive and 1 negative choice), default links on, add show
|
||||
# sql comment.
|
||||
# Joe Robins <jmrobins@tgix.com>,
|
||||
# If using the usebuggroups parameter, users shouldn't be able to see
|
||||
# reports for products they don't have access to.
|
||||
# Gervase Markham <gerv@gerv.net> and Adam Spiers <adam@spiers.net>
|
||||
# Added ability to chart any combination of resolutions/statuses.
|
||||
# Derive the choice of resolutions/statuses from the -All- data file
|
||||
@@ -70,19 +73,24 @@ my %reports =
|
||||
# If we're using bug groups for products, we should apply those restrictions
|
||||
# to viewing reports, as well. Time to check the login in that case.
|
||||
ConnectToDatabase(1);
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
# If the usebuggroups parameter is set, we don't want to list all products.
|
||||
# We only want those products that the user has permissions for.
|
||||
my @myproducts;
|
||||
push( @myproducts, "-All-");
|
||||
foreach my $this_product (@legal_product) {
|
||||
if (!CanSeeProduct($userid, $this_product)) {
|
||||
next;
|
||||
} else {
|
||||
push(@myproducts, $this_product)
|
||||
if(Param("usebuggroups")) {
|
||||
push( @myproducts, "-All-");
|
||||
foreach my $this_product (@legal_product) {
|
||||
if(GroupExists($this_product) && !UserInGroup($this_product)) {
|
||||
next;
|
||||
} else {
|
||||
push( @myproducts, $this_product )
|
||||
}
|
||||
}
|
||||
} else {
|
||||
push( @myproducts, "-All-", @legal_product );
|
||||
}
|
||||
|
||||
if (! defined $FORM{'product'}) {
|
||||
@@ -102,11 +110,12 @@ if (! defined $FORM{'product'}) {
|
||||
|
||||
# If usebuggroups is on, we don't want people to be able to view
|
||||
# reports for products they don't have permissions for...
|
||||
$::FORM{'product'} != '-All-'
|
||||
&& !CanSeeProduct($::FORM{'product'}, $userid)
|
||||
&& DisplayError("You do not have the permissions necessary to view reports for this product.")
|
||||
&& exit;
|
||||
|
||||
Param("usebuggroups")
|
||||
&& GroupExists($FORM{'product'})
|
||||
&& !UserInGroup($FORM{'product'})
|
||||
&& DisplayError("You do not have the permissions necessary to view reports for this product.")
|
||||
&& exit;
|
||||
|
||||
# For security and correctness, validate the value of the "output" form variable.
|
||||
# Valid values are the keys from the %reports hash defined above which appear in
|
||||
# the "output" drop-down menu on the report generation form.
|
||||
@@ -162,9 +171,8 @@ sub choose_product {
|
||||
print <<FIN;
|
||||
<center>
|
||||
<h1>Welcome to the Bugzilla Query Kitchen</h1>
|
||||
</center>
|
||||
<form method=get action=reports.cgi>
|
||||
<table border=1 cellpadding=5 align="center">
|
||||
<table border=1 cellpadding=5>
|
||||
<tr>
|
||||
<td align=center><b>Product:</b></td>
|
||||
<td align=center>
|
||||
@@ -294,13 +302,7 @@ FIN
|
||||
}
|
||||
|
||||
if ($FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($FORM{'product'});
|
||||
} else {
|
||||
my @sqlproducts = ();
|
||||
foreach my $p (@myproducts) {
|
||||
push (@sqlproducts, "product = " . SqlQuote($p));
|
||||
}
|
||||
$query .= " and (" . join (" or ", @sqlproducts) . ")";
|
||||
$query .= " AND bugs.product = ".SqlQuote($FORM{'product'});
|
||||
}
|
||||
|
||||
$query .= " AND bugs.bug_status IN ('NEW', 'ASSIGNED', 'REOPENED')";
|
||||
@@ -710,13 +712,7 @@ sub most_doomed_for_milestone {
|
||||
my $query;
|
||||
$query = "select distinct assigned_to from bugs where target_milestone = '$ms' ";
|
||||
if ($FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($FORM{'product'});
|
||||
} else {
|
||||
my @sqlproducts = ();
|
||||
foreach my $p (@myproducts) {
|
||||
push (@sqlproducts, "product = " . SqlQuote($p));
|
||||
}
|
||||
$query .= " and (" . join (" or ", @sqlproducts) . ")";
|
||||
$query .= " and bugs.product=".SqlQuote($FORM{'product'});
|
||||
}
|
||||
$query .= <<FIN;
|
||||
and
|
||||
@@ -742,13 +738,7 @@ FIN
|
||||
foreach $person (@people) {
|
||||
my $query = "select count(bug_id) from bugs,profiles where target_milestone = '$ms' and userid=assigned_to and userid = '$person' ";
|
||||
if( $FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($FORM{'product'});
|
||||
} else {
|
||||
my @sqlproducts = ();
|
||||
foreach my $p (@myproducts) {
|
||||
push (@sqlproducts, "product = " . SqlQuote($p));
|
||||
}
|
||||
$query .= " and (" . join (" or ", @sqlproducts) . ")";
|
||||
$query .= "and bugs.product=".SqlQuote($FORM{'product'});
|
||||
}
|
||||
$query .= <<FIN;
|
||||
and
|
||||
@@ -845,12 +835,6 @@ sub most_recently_doomed {
|
||||
my $query = "select distinct assigned_to from bugs where bugs.bug_status='NEW' and target_milestone='' and bug_severity!='enhancement' and status_whiteboard='' and (product='Browser' or product='MailNews')";
|
||||
if ($FORM{'product'} ne "-All-" ) {
|
||||
$query .= "and bugs.product=".SqlQuote($FORM{'product'});
|
||||
} else {
|
||||
my @sqlproducts = ();
|
||||
foreach my $p (@myproducts) {
|
||||
push (@sqlproducts, "product = " . SqlQuote($p));
|
||||
}
|
||||
$query .= " and (" . join (" or ", @sqlproducts) . ")";
|
||||
}
|
||||
|
||||
# End build up $query string
|
||||
|
||||
@@ -27,15 +27,13 @@ use POSIX;
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use vars %::FORM;
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
# Make sure the user is authorized to access sanitycheck.cgi. Access
|
||||
# is restricted to logged-in users who have "editbugs" privileges,
|
||||
@@ -44,7 +42,7 @@ my $userid = confirm_login();
|
||||
# and restricting access to this installation's administrators (which
|
||||
# prevents users with a legitimate interest in Bugzilla integrity
|
||||
# from accessing the script).
|
||||
UserInGroup($userid, "editbugs")
|
||||
UserInGroup("editbugs")
|
||||
|| DisplayError("You are not authorized to access this script,
|
||||
which is reserved for users with the ability to edit bugs.")
|
||||
&& exit;
|
||||
@@ -126,10 +124,6 @@ my @checklist;
|
||||
|
||||
PutHeader("Bugzilla Sanity Check");
|
||||
|
||||
###########################################################################
|
||||
# Fix vote cache
|
||||
###########################################################################
|
||||
|
||||
if (exists $::FORM{'rebuildvotecache'}) {
|
||||
Status("OK, now rebuilding vote cache.");
|
||||
if ($::driver eq 'mysql') {
|
||||
@@ -171,10 +165,6 @@ foreach my $field (("bug_severity", "bug_status", "op_sys",
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Perform referential (cross) checks
|
||||
###########################################################################
|
||||
|
||||
CrossCheck("keyworddefs", "id",
|
||||
["keywords", "keywordid"]);
|
||||
|
||||
@@ -242,25 +232,39 @@ CrossCheck("products", "product",
|
||||
["versions", "program", "value"],
|
||||
["attachstatusdefs", "product", "name"]);
|
||||
|
||||
###########################################################################
|
||||
# Perform group checks
|
||||
###########################################################################
|
||||
|
||||
Status("Checking groups");
|
||||
my %legal_groups = ();
|
||||
SendSQL("select group_id from groups order by group_id");
|
||||
while ( my @row = FetchSQLData() ) {
|
||||
$legal_groups{$row[0]} = 1;
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select bit from groups");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select group_bit from groups");
|
||||
}
|
||||
SendSQL("select distinct group_id from user_group_map order by group_id");
|
||||
while ( my @row = FetchSQLData() ) {
|
||||
Alert("Illegal group_id number found in user_group_map table: $row[0]") if !$legal_groups{$row[0]};
|
||||
while (my $bit = FetchOneColumn()) {
|
||||
if ( $bit != pow(2, int(log($bit) / log(2))) ) {
|
||||
Alert("Illegal bit number found in group table: $bit");
|
||||
}
|
||||
}
|
||||
SendSQL("select distinct group_id from bug_group_map order by group_id");
|
||||
while ( my @row = FetchSQLData() ) {
|
||||
Alert("Illegal group_id number found in bug_group_map table: $row[0]") if !$legal_groups{$row[0]};
|
||||
}
|
||||
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select sum(bit) from groups where isbuggroup != 0");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select sum(group_bit) from groups where isbuggroup != 0");
|
||||
}
|
||||
my $buggroupset = FetchOneColumn();
|
||||
if (!defined $buggroupset || $buggroupset eq "") {
|
||||
$buggroupset = 0;
|
||||
}
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("select bug_id, groupset from bugs where groupset & $buggroupset != groupset");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("select bug_id, groupset from bugs where (groupset & int8($buggroupset)) != groupset");
|
||||
}
|
||||
while (@row = FetchSQLData()) {
|
||||
Alert("Bad groupset $row[1] found in bug " . BugLink($row[0]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Status("Checking version/products");
|
||||
|
||||
@@ -334,24 +338,18 @@ foreach my $ref (@checklist) {
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Perform login checks
|
||||
###########################################################################
|
||||
|
||||
|
||||
Status("Checking profile logins");
|
||||
|
||||
my $emailregexp = Param("emailregexp");
|
||||
$emailregexp =~ s/'/\\'/g;
|
||||
SendSQL("SELECT userid, login_name FROM profiles " .
|
||||
"WHERE " . SqlRegEx("login_name", $emailregexp, "not"));
|
||||
"WHERE " . SqlRegEx("login_name", SqlQuote($emailregexp), "not"));
|
||||
|
||||
while (my ($id,$email) = (FetchSQLData())) {
|
||||
Alert "Bad profile email address, id=$id, <$email>."
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Perform vote/keyword cache checks
|
||||
###########################################################################
|
||||
|
||||
SendSQL("SELECT bug_id,votes,keywords FROM bugs " .
|
||||
"WHERE votes != 0 OR keywords != ''");
|
||||
@@ -705,6 +703,30 @@ if (@badbugs > 0) {
|
||||
}
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Unsent mail
|
||||
###########################################################################
|
||||
|
||||
Status("Checking for unsent mail");
|
||||
|
||||
@badbugs = ();
|
||||
|
||||
SendSQL("SELECT bug_id " .
|
||||
"FROM bugs WHERE lastdiffed < delta_ts AND ".
|
||||
"delta_ts < date_sub(now(), INTERVAL 30 minute) ".
|
||||
"ORDER BY bug_id");
|
||||
|
||||
while (@row = FetchSQLData()) {
|
||||
my ($id) = (@row);
|
||||
push(@badbugs, $id);
|
||||
}
|
||||
|
||||
if (@badbugs > 0) {
|
||||
Alert("Bugs that have changes but no mail sent for at least half an hour: " .
|
||||
join (", ", @badbugs));
|
||||
print("Run <code>processmail rescanall</code> to fix this<p>\n");
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# End
|
||||
###########################################################################
|
||||
|
||||
@@ -36,12 +36,15 @@ ConnectToDatabase();
|
||||
# Begin Data/Security Validation
|
||||
###############################################################################
|
||||
|
||||
# Check whether or not the user is currently logged in.
|
||||
my $userid = quietly_check_login();
|
||||
# Check whether or not the user is currently logged in. This function
|
||||
# sets the value of $::usergroupset, the binary number that records
|
||||
# the set of groups to which the user belongs and which we can use
|
||||
# to determine whether or not the user is authorized to access this bug.
|
||||
quietly_check_login();
|
||||
|
||||
# Make sure the bug ID is a positive integer representing an existing
|
||||
# bug that the user is authorized to access.
|
||||
ValidateBugID($::FORM{'id'}, $userid);
|
||||
ValidateBugID($::FORM{'id'});
|
||||
|
||||
###############################################################################
|
||||
# End Data/Security Validation
|
||||
|
||||
@@ -30,11 +30,10 @@ require "bug_form.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $userid = 0;
|
||||
if ($::FORM{'GoAheadAndLogIn'}) {
|
||||
$userid = confirm_login();
|
||||
confirm_login();
|
||||
} else {
|
||||
$userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
}
|
||||
|
||||
######################################################################
|
||||
@@ -44,7 +43,7 @@ if ($::FORM{'GoAheadAndLogIn'}) {
|
||||
# Make sure the bug ID is a positive integer representing an existing
|
||||
# bug that the user is authorized to access.
|
||||
if (defined ($::FORM{'id'})) {
|
||||
ValidateBugID($::FORM{'id'}, $userid);
|
||||
ValidateBugID($::FORM{'id'});
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
@@ -27,8 +27,6 @@ use MIME::Base64;
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Redirect to the new interface for displaying attachments.
|
||||
|
||||
@@ -30,9 +30,9 @@ require "CGI.pl";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
use vars qw($template $vars $userid);
|
||||
use vars qw($template $vars $userid $usergroupset);
|
||||
|
||||
my %seen;
|
||||
my %edgesdone;
|
||||
@@ -99,7 +99,7 @@ if ($::FORM{'doall'}) {
|
||||
} else {
|
||||
foreach my $i (split('[\s,]+', $::FORM{'id'})) {
|
||||
$i = trim($i);
|
||||
ValidateBugID($i, $userid);
|
||||
ValidateBugID($i);
|
||||
$baselist{$i} = 1;
|
||||
}
|
||||
|
||||
@@ -127,29 +127,31 @@ if ($::FORM{'doall'}) {
|
||||
}
|
||||
}
|
||||
|
||||
# Determine which bugs we can see or not
|
||||
my @canseebugs = keys %seen;
|
||||
my $canseeref = CanSeeBug(\@canseebugs, $userid);
|
||||
my $canseeref = CanSeeBug(\@canseebugs, $::userid, $::usergroupset);
|
||||
|
||||
foreach my $k (keys(%seen)) {
|
||||
# Skip this bug if we cannot see it
|
||||
next if !$canseeref->{$k};
|
||||
|
||||
my $summary = "";
|
||||
my $stat;
|
||||
if ($::FORM{'showsummary'}) {
|
||||
SendSQL("SELECT bug_status, short_desc FROM bugs WHERE bugs.bug_id = $k");
|
||||
($stat, $summary) = FetchSQLData();
|
||||
$stat = "NEW" if !defined $stat;
|
||||
$summary = "" if !defined $summary;
|
||||
if (!$canseeref->{$k}) {
|
||||
SendSQL("SELECT bug_status FROM bugs WHERE bug_id = $k");
|
||||
$stat = FetchOneColumn();
|
||||
} else {
|
||||
SendSQL("SELECT bug_status, short_desc FROM bugs WHERE bugs.bug_id = $k");
|
||||
($stat, $summary) = FetchSQLData();
|
||||
$stat = "NEW" if !defined $stat;
|
||||
$summary = "" if !defined $summary;
|
||||
}
|
||||
} else {
|
||||
SendSQL("SELECT bug_status FROM bugs WHERE bug_id = $k");
|
||||
$stat = FetchOneColumn();
|
||||
}
|
||||
my @params;
|
||||
|
||||
foreach my $k (keys(%baselist)) {
|
||||
$seen{$k} = 1;
|
||||
if ($summary ne "") {
|
||||
$summary =~ s/([\\\"])/\\$1/g;
|
||||
push(@params, qq{label="$k\\n$summary"});
|
||||
}
|
||||
|
||||
if (exists $baselist{$k}) {
|
||||
|
||||
@@ -36,10 +36,11 @@ use vars %::FORM;
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
# More warning suppression silliness.
|
||||
$::userid = $::userid;
|
||||
$::usergroupset = $::usergroupset;
|
||||
|
||||
################################################################################
|
||||
# Data/Security Validation #
|
||||
@@ -47,7 +48,7 @@ $::userid = $::userid;
|
||||
|
||||
# Make sure the bug ID is a positive integer representing an existing
|
||||
# bug that the user is authorized to access.
|
||||
ValidateBugID($::FORM{'id'}, $userid);
|
||||
ValidateBugID($::FORM{'id'});
|
||||
my $id = $::FORM{'id'};
|
||||
|
||||
my $hide_resolved = $::FORM{'hide_resolved'} ? 1 : 0;
|
||||
@@ -90,7 +91,7 @@ $vars->{'realdepth'} = $realdepth;
|
||||
$vars->{'bugid'} = $id;
|
||||
$vars->{'maxdepth'} = $maxdepth;
|
||||
$vars->{'hide_resolved'} = $hide_resolved;
|
||||
$vars->{'canedit'} = UserInGroup($userid, "editbugs");
|
||||
$vars->{'canedit'} = UserInGroup("editbugs");
|
||||
|
||||
print "Content-Type: text/html\n\n";
|
||||
$template->process("bug/dependency-tree.html.tmpl", $vars)
|
||||
@@ -143,9 +144,9 @@ sub GetBug {
|
||||
# Retrieves the necessary information about a bug, stores it in the bug cache,
|
||||
# and returns it to the calling code.
|
||||
my ($id) = @_;
|
||||
|
||||
return {} if !CanSeeBug($id, $userid);
|
||||
|
||||
|
||||
return {} if !CanSeeBug($id, $::userid, $::usergroupset);
|
||||
|
||||
SendSQL("SELECT 1,
|
||||
bug_status,
|
||||
short_desc,
|
||||
@@ -154,7 +155,7 @@ sub GetBug {
|
||||
assignee.login_name
|
||||
FROM bugs, profiles AS assignee
|
||||
WHERE bugs.bug_id = $id
|
||||
AND bugs.assigned_to = assignee.userid");
|
||||
AND bugs.assigned_to = assignee.userid");
|
||||
|
||||
my $bug = {};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
# Check to see if the user has logged in yet.
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
###############################################################################
|
||||
# Main Body Execution
|
||||
@@ -42,23 +42,23 @@ my $userid = quietly_check_login();
|
||||
|
||||
$vars->{'username'} = $::COOKIE{'Bugzilla_login'} || '';
|
||||
$vars->{'anyvotesallowed'} = $::anyvotesallowed;
|
||||
$vars->{'userid'} = $userid;
|
||||
|
||||
if ($userid) {
|
||||
SendSQL("SELECT mybugslink FROM profiles WHERE userid = $userid");
|
||||
my $mybugslink = FetchOneColumn();
|
||||
if (defined $::COOKIE{'Bugzilla_login'}) {
|
||||
SendSQL("SELECT mybugslink, userid, blessgroupset FROM profiles " .
|
||||
"WHERE login_name = " . SqlQuote($::COOKIE{'Bugzilla_login'}));
|
||||
my ($mybugslink, $userid, $blessgroupset) = (FetchSQLData());
|
||||
$vars->{'userid'} = $userid;
|
||||
$vars->{'blessgroupset'} = $blessgroupset;
|
||||
if ($mybugslink) {
|
||||
my $mybugstemplate = Param("mybugstemplate");
|
||||
my %substs = ( 'userid' => url_quote($::COOKIE{'Bugzilla_login'}) );
|
||||
$vars->{'mybugsurl'} = PerformSubsts($mybugstemplate, \%substs);
|
||||
}
|
||||
SendSQL("SELECT name FROM namedqueries WHERE userid = $userid AND linkinfooter = 1");
|
||||
SendSQL("SELECT name FROM namedqueries WHERE userid = $userid AND linkinfooter");
|
||||
while (MoreSQLData()) {
|
||||
my ($name) = FetchSQLData();
|
||||
push(@{$vars->{'namedqueries'}}, $name);
|
||||
}
|
||||
SendSQL("SELECT COUNT(*) FROM user_group_map WHERE user_id = $userid AND canbless >= 1");
|
||||
$vars->{'canbless'} = FetchOneColumn();
|
||||
}
|
||||
|
||||
# This sidebar is currently for use with Mozilla based web browsers.
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</p>
|
||||
|
||||
<form method="post" action="token.cgi">
|
||||
<input type="hidden" name="t" value="[% token FILTER html %]">
|
||||
<input type="hidden" name="t" value=[% token FILTER html %]>
|
||||
<input type="hidden" name="a" value="chgem">
|
||||
<table>
|
||||
<tr>
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
%]
|
||||
|
||||
<form method="get" action="token.cgi">
|
||||
<input type="hidden" name="a" value="reqpw">
|
||||
<input type="hidden" name="loginname" value="[% login FILTER html %]">
|
||||
<input type="hidden" name="a" value="reqpw" />
|
||||
<input type="hidden" name="loginname" value="[% login FILTER html %]" />
|
||||
A Bugzilla account for <tt>[% login FILTER html %]</tt> already exists. If you
|
||||
are the account holder and have forgotten your password,
|
||||
<input type="submit" value="submit a request to change it">.
|
||||
<input type="submit" value="submit a request to change it" />.
|
||||
</form>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
||||
@@ -26,27 +26,27 @@
|
||||
</p>
|
||||
|
||||
<form method="post" action="token.cgi">
|
||||
<input type="hidden" name="t" value="[% token FILTER html %]">
|
||||
<input type="hidden" name="a" value="chgpw">
|
||||
<input type="hidden" name="t" value="[% token FILTER html %]" />
|
||||
<input type="hidden" name="a" value="chgpw" />
|
||||
<table>
|
||||
<tr>
|
||||
<th align="right">New Password:</th>
|
||||
<td>
|
||||
<input type="password" name="password" size="16" maxlength="16">
|
||||
<input type="password" name="password" size="16" maxlength="16" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th align="right">New Password Again:</th>
|
||||
<td>
|
||||
<input type="password" name="matchpassword" size="16" maxlength="16">
|
||||
<input type="password" name="matchpassword" size="16" maxlength="16" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th align="right"> </th>
|
||||
<td>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="submit" value="Submit" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
<th align="right">Password:</th>
|
||||
<td>
|
||||
<input type="hidden" name="Bugzilla_login"
|
||||
value="[% login FILTER html %]">
|
||||
<input type="password" name="Bugzilla_password">
|
||||
value="[% login FILTER html %]" />
|
||||
<input type="password" name="Bugzilla_password" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -47,21 +47,21 @@
|
||||
<tr>
|
||||
<th align="right">New password:</th>
|
||||
<td>
|
||||
<input type="password" name="new_password1">
|
||||
<input type="password" name="new_password1" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th align="right">Re-enter new password:</th>
|
||||
<td>
|
||||
<input type="password" name="new_password2">
|
||||
<input type="password" name="new_password2" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th align="right">Your real name (optional, but encouraged):</th>
|
||||
<td>
|
||||
<input size="35" name="realname" value="[% realname FILTER html %]">
|
||||
<input size="35" name="realname" value="[% realname FILTER html %]" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
[% IF Param('supportwatchers') %]
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<hr>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<tr>
|
||||
<th align="right">Users to watch:</th>
|
||||
<td>
|
||||
<input size="35" name="watchedusers" value="[% watchedusers %]">
|
||||
<input size="35" name="watchedusers" value="[% watchedusers %]" />
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
@@ -68,7 +68,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
@@ -88,7 +88,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
<b>Field/recipient specific options:</b>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<input type="hidden" name="numqueries" value="[% queries.size %]">
|
||||
<input type="hidden" name="numqueries" value="[% queries.size %]" />
|
||||
[% IF queries.size %]
|
||||
[% FOREACH query = queries %]
|
||||
<tr>
|
||||
@@ -56,7 +56,7 @@
|
||||
</tr>
|
||||
|
||||
<input type="hidden" name="name-[% loop.index %]"
|
||||
value="[% query.name FILTER html %]">
|
||||
value="[% query.name FILTER html %]" />
|
||||
[% END %]
|
||||
|
||||
[% ELSE %]
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
[% IF set_bits.size %]
|
||||
And you can turn on or off the following bits for
|
||||
<a href="editusers.cgi">other users</a>:
|
||||
<a HREF="editusers.cgi">other users</a>:
|
||||
<p>
|
||||
<ul>
|
||||
[% FOREACH bit_description = set_bits %]
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</td>
|
||||
[% ELSE %]
|
||||
<td align="center" bgcolor="#BBBBEE" class="unselected_tab">
|
||||
<a href="userprefs.cgi?tab=[% tab.name %]">[% tab.description %]</a>
|
||||
<a HREF="userprefs.cgi?tab=[% tab.name %]">[% tab.description %]</a>
|
||||
</td>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
[% IF attachments.size %]
|
||||
[% FOREACH attachment = attachments %]
|
||||
<input type="checkbox" name="obsolete" value="[% attachment.id %]">
|
||||
<a href="attachment.cgi?id=[% attachment.id %]&action=edit">[% attachment.id %]: [% attachment.description FILTER html %]</a><br>
|
||||
<a href="attachment.cgi?id=[% attachment.id %]&action=edit">[% attachment.id %]: [% attachment.description FILTER html %]</a><br>
|
||||
[% END %]
|
||||
[% ELSE %]
|
||||
[no attachments can be made obsolete]
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
<h2>
|
||||
<a title="[% description FILTER html %]" href="attachment.cgi?id=[% attachid %]&action=edit">Attachment #[% attachid %]</a>
|
||||
<a title="[% description FILTER html %]" href="attachment.cgi?id=[% attachid %]&action=edit">Attachment #[% attachid %]</a>
|
||||
to <a href="show_bug.cgi?id=[% bugid %]">Bug #[% bugid %]</a> Created
|
||||
</h2>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<b>Note:</b> Bugzilla automatically detected the content type
|
||||
<em>[% contenttype %]</em> for this attachment. If this is
|
||||
incorrect, correct the value by
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=edit">editing the attachment</a>.
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=edit">editing the attachment</a>.
|
||||
</p>
|
||||
[% END %]
|
||||
</td>
|
||||
@@ -60,7 +60,7 @@
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<a href="attachment.cgi?bugid=[% bugid %]&action=enter">Create Another Attachment to Bug #[% bugid %]</a>
|
||||
<a href="attachment.cgi?bugid=[% bugid %]&action=enter">Create Another Attachment to Bug #[% bugid %]</a>
|
||||
</p>
|
||||
|
||||
[% PROCESS global/footer.html.tmpl %]
|
||||
|
||||
@@ -182,9 +182,9 @@
|
||||
[% IF isviewable %]
|
||||
<td width="75%">
|
||||
<textarea id="editFrame" name="comment" style="height: 400px; width: 100%; display: none;" cols="80" wrap="soft"></textarea>
|
||||
<iframe id="viewFrame" src="attachment.cgi?id=[% attachid %]&action=view" style="height: 400px; width: 100%;">
|
||||
<iframe id="viewFrame" src="attachment.cgi?id=[% attachid %]&action=view" style="height: 400px; width: 100%;">
|
||||
<b>You cannot view the attachment while editing it because your browser does not support IFRAMEs.
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=view">View the attachment on a separate page</a>.</b>
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=view">View the attachment on a separate page</a>.</b>
|
||||
</iframe>
|
||||
<script type="application/x-javascript" language="JavaScript">
|
||||
<!--
|
||||
@@ -200,7 +200,7 @@
|
||||
<td id="noview" width="50%">
|
||||
<p><b>
|
||||
Attachment cannot be viewed because its MIME type is not either text/*, image/*, or application/vnd.mozilla.*.
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=view">Download the attachment instead</a>.
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=view">Download the attachment instead</a>.
|
||||
</b></p>
|
||||
</td>
|
||||
[% END %]
|
||||
@@ -214,7 +214,7 @@
|
||||
[% IF a == attachid %]
|
||||
#[% a %]
|
||||
[% ELSE %]
|
||||
<a href="attachment.cgi?id=[% a %]&action=edit">#[% a %]</a>
|
||||
<a href="attachment.cgi?id=[% a %]&action=edit">#[% a %]</a>
|
||||
[% END %]
|
||||
[% "|" UNLESS loop.last() %]
|
||||
[% END %]
|
||||
|
||||
@@ -73,15 +73,15 @@
|
||||
</td>
|
||||
|
||||
<td valign="top">
|
||||
<a href="attachment.cgi?id=[% a.attachid %]&action=edit">Edit</a>
|
||||
<a href="attachment.cgi?id=[% a.attachid %]&action=edit">Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[% IF a.isviewable %]
|
||||
<iframe src="attachment.cgi?id=[% a.attachid %]&action=view" width="75%" height="350">
|
||||
<iframe src="attachment.cgi?id=[% a.attachid %]&action=view" width="75%" height="350">
|
||||
<b>You cannot view the attachment on this page because your browser does not support IFRAMEs.
|
||||
<a href="attachment.cgi?id=[% a.attachid %]&action=view">View the attachment on a separate page</a>.</b>
|
||||
<a href="attachment.cgi?id=[% a.attachid %]&action=view">View the attachment on a separate page</a>.</b>
|
||||
</iframe>
|
||||
[% ELSE %]
|
||||
<p><b>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
<h2>Changes to
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=edit">attachment [% attachid %]</a>
|
||||
<a href="attachment.cgi?id=[% attachid %]&action=edit">attachment [% attachid %]</a>
|
||||
of bug [% bugid %] submitted
|
||||
</h2>
|
||||
[% mailresults %]
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Changes made to bug $bug_id"
|
||||
h1 = "Activity log"
|
||||
h2 = "Bug <a href=\"show_bug.cgi?id=$bug_id\">$bug_id</a>"
|
||||
h2 = "Bug <a href='show_bug.cgi?id=$bug_id'>$bug_id</a>"
|
||||
%]
|
||||
|
||||
<br>
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
Display bugs as XML by entering a list of bug numbers here:
|
||||
</td>
|
||||
<td>
|
||||
<input name="id" size="30">
|
||||
<input type="submit" value="Display as XML">
|
||||
<input name="id" size="30" />
|
||||
<input type="submit" value="Display as XML" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
%]
|
||||
|
||||
<form method="post" action="post_bug.cgi">
|
||||
<input type="hidden" name="product" value="[% product FILTER html %]">
|
||||
<input type="hidden" name="product" value="[% product FILTER html %]" />
|
||||
|
||||
<table cellspacing="2" cellpadding="0" border="0">
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
[% sel = { description => 'Priority', name => 'priority' } %]
|
||||
[% INCLUDE select %]
|
||||
[% ELSE %]
|
||||
<input type="hidden" name="priority" value="[% default.priority %]">
|
||||
<input type="hidden" name="priority" value="[% default.priority %]" />
|
||||
[% END %]
|
||||
|
||||
[% sel = { description => 'Severity', name => 'bug_severity' } %]
|
||||
@@ -125,7 +125,7 @@
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
[% ELSE %]
|
||||
<input type="hidden" name="bug_status" value="[% default.bug_status %]">
|
||||
<input type="hidden" name="bug_status" value="[% default.bug_status %]" />
|
||||
[% END %]
|
||||
|
||||
<tr>
|
||||
@@ -136,7 +136,7 @@
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<input name="assigned_to" size="32"
|
||||
value="[% assigned_to FILTER html %]">
|
||||
value="[% assigned_to FILTER html %]" />
|
||||
(Leave blank to assign to default component owner)
|
||||
</td>
|
||||
</tr>
|
||||
@@ -144,7 +144,7 @@
|
||||
<tr>
|
||||
<td align="right"><strong>Cc:</strong></td>
|
||||
<td colspan="3">
|
||||
<input name="cc" size="45" value="[% cc FILTER html %]">
|
||||
<input name="cc" size="45" value="[% cc FILTER html %]" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -157,14 +157,14 @@
|
||||
<td align="right"<strong>URL:</strong></td>
|
||||
<td colspan="3">
|
||||
<input name="bug_file_loc" size="60"
|
||||
value="[% bug_file_loc FILTER html %]">
|
||||
value="[% bug_file_loc FILTER html %]" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="right"><strong>Summary:</strong></td>
|
||||
<td colspan="3">
|
||||
<input name="short_desc" size="60" value="[% short_desc FILTER html %]">
|
||||
<input name="short_desc" size="60" value="[% short_desc FILTER html %]" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -194,8 +194,8 @@
|
||||
<!-- Checkboxes -->
|
||||
[% FOREACH g = group %]
|
||||
|
||||
<input type="checkbox" name="group-[% g.bit %]" value="1"
|
||||
[% " checked=\"checked\"" IF g.checked %]>[% g.description %]<br>
|
||||
<input type="checkbox" name="bit-[% g.bit %]" value="1"
|
||||
[% " checked=\"checked\"" IF g.checked %] />[% g.description %]<br />
|
||||
[% END %]
|
||||
<br>
|
||||
[% END %]
|
||||
@@ -211,7 +211,7 @@
|
||||
return false; } return true;">
|
||||
|
||||
<input type="submit" name="maketemplate"
|
||||
value="Remember values as bookmarkable template">
|
||||
value="Remember values as bookmarkable template" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
[% IF NOT multiple_bugs AND NOT doall %]
|
||||
[% title = "$title for bug $bug_id"
|
||||
h1 = "$h1 for bug <a href=\"show_bug.cgi?id=$bug_id\">$bug_id</a>"
|
||||
h1 = "$h1 for bug <a href='show_bug.cgi?id=$bug_id'>$bug_id</a>"
|
||||
%]
|
||||
[% END %]
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<img src="[% image_url %]" usemap="#imagemap">
|
||||
[% ELSE %]
|
||||
<a href="[% map_url %]">
|
||||
<img src="[% image_url %]" ismap="ismap">
|
||||
<img src="[% image_url %]" ismap>
|
||||
</a>
|
||||
[% END %]
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
</td>
|
||||
<td rowspan="4" valign="top">
|
||||
[% IF bug.cc %]
|
||||
<select name="cc" multiple="multiple" size="5">
|
||||
<select name="cc" multiple size="5">
|
||||
[% FOREACH c = bug.cc %]
|
||||
<option value="[% c FILTER html %]">[% c FILTER html %]</option>
|
||||
[% END %]
|
||||
@@ -288,9 +288,9 @@
|
||||
</th>
|
||||
<td>
|
||||
[% bug.votes %]
|
||||
<a href="votes.cgi?action=show_bug&bug_id=[% bug.bug_id %]">Show
|
||||
<a href="votes.cgi?action=show_bug&bug_id=[% bug.bug_id %]">Show
|
||||
votes for this bug</a>
|
||||
<a href="votes.cgi?action=show_user&bug_id=[% bug.bug_id %]">Vote
|
||||
<a href="votes.cgi?action=show_user&bug_id=[% bug.bug_id %]">Vote
|
||||
for this bug</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -316,9 +316,9 @@
|
||||
|
||||
[% FOREACH group = groups %]
|
||||
|
||||
<input type="checkbox" name="group-[% group.bit %]" value="1"
|
||||
[% " checked=\"checked\"" IF group.ison %]
|
||||
[% " disabled=\"disabled\"" IF NOT group.ingroup %]>
|
||||
<input type="checkbox" name="bit-[% group.bit %]" value="1"
|
||||
[% " checked='checked'" IF group.ison %]
|
||||
[% " disabled='disabled'" IF NOT group.ingroup %]>
|
||||
[% group.description %]
|
||||
<br>
|
||||
[% END %]
|
||||
@@ -357,7 +357,7 @@
|
||||
[%# *** Knob *** %]
|
||||
|
||||
<br>
|
||||
<input type="radio" name="knob" value="none" checked="checked">
|
||||
<input type="radio" name="knob" value="none" checked>
|
||||
Leave as <b>[% bug.bug_status FILTER html %]
|
||||
[% bug.resolution FILTER html %]</b>
|
||||
<br>
|
||||
@@ -410,7 +410,7 @@
|
||||
[% knum = knum + 1 %]
|
||||
|
||||
<input type="radio" name="knob" value="reassign">
|
||||
<a href="bug_status.html#assigned_to">Reassign</a> bug to
|
||||
<a href="bug_status.html#assigned_to">Reassign</A> bug to
|
||||
<input name="assigned_to" size="32"
|
||||
onchange="if ((this.value != '[% bug.assigned_to_email FILTER js %]') &&
|
||||
(this.value != '')) {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<p>
|
||||
<input type="radio" name="addtonewgroup" value="no"><b>no</b><br>
|
||||
<input type="radio" name="addtonewgroup" value="yes"><b>yes</b><br>
|
||||
<input type="radio" name="addtonewgroup" value="yesifinold" checked="checked">
|
||||
<input type="radio" name="addtonewgroup" value="yesifinold" checked>
|
||||
<b>yes, but only if the bug was in its old product's group</b><br>
|
||||
</p>
|
||||
[% END %]
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<b>URL:</b>
|
||||
<a href="[% bug.bug_file_loc %]">[% bug.bug_file_loc FILTER html %]</a>
|
||||
<A HREF="[% bug.bug_file_loc %]">[% bug.bug_file_loc FILTER html %]</a>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
[% PROCESS global/header.html.tmpl
|
||||
title = "Show Votes"
|
||||
h2 = "Bug <a href=\"show_bug.cgi?id=$bug_id\">$bug_id</a>"
|
||||
h2 = "Bug <a href='show_bug.cgi?id=$bug_id'>$bug_id</a>"
|
||||
%]
|
||||
|
||||
<table cellspacing="4">
|
||||
@@ -41,7 +41,7 @@
|
||||
[% FOREACH user = users %]
|
||||
<tr>
|
||||
<td>
|
||||
<a href="votes.cgi?action=show_user&user=[% user.name %]">
|
||||
<a href="votes.cgi?action=show_user&user=[% user.name %]">
|
||||
[% user.name %]
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
[% "</strike>" IF NOT bug.opened %]
|
||||
</td>
|
||||
<td>
|
||||
<a href="votes.cgi?action=show_bug&bug_id=[% bug.id %]">
|
||||
<a href="votes.cgi?action=show_bug&bug_id=[% bug.id %]">
|
||||
[% bug.summary FILTER html %]
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<td valign="top" align="left">
|
||||
<table border="0" cellpadding="0" cellspacing="2">
|
||||
<tr>
|
||||
<td valign="top" align="left" nowrap="nowrap">
|
||||
<td valign="top" align="left" nowrap>
|
||||
<font size="+1"><b>[% h1 %]</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -78,7 +78,7 @@ function addSidebar() {
|
||||
</p>
|
||||
</form>
|
||||
</td>
|
||||
<td align="right"><img src="ant.jpg" width="329" height="220" border="2" alt="ant.jpg [8.5k]"></td>
|
||||
<td align="right"><img src="ant.jpg" width=329 height=220 border=2 alt="ant.jpg [8.5k]"></td>
|
||||
</tr></table>
|
||||
|
||||
<script type="text/javascript" language="JavaScript" src="localconfig.js"></script>
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
item.checked = value;
|
||||
}
|
||||
}
|
||||
document.write(' <input type="button" name="uncheck_all" value="Uncheck All" onclick="SetCheckboxes(false);">');
|
||||
document.write(' <input type="button" name="check_all" value="Check All" onclick="SetCheckboxes(true);">');
|
||||
document.write(' <input type="button" value="Uncheck All" onclick="SetCheckboxes(false);">');
|
||||
document.write(' <input type="button" value="Check All" onclick="SetCheckboxes(true);">');
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<p><font size="-1">
|
||||
To change multiple bugs:
|
||||
@@ -162,24 +162,24 @@
|
||||
|
||||
<input type="hidden" name="multiupdate" value="Y">
|
||||
|
||||
<label for="comment"><b>Additional Comments:</b></label><br>
|
||||
<textarea id="comment" name="comment" rows="5" cols="80" wrap="hard"></textarea><br>
|
||||
<label for="comment"><b>Additional Comments:</b></label><br />
|
||||
<textarea id="comment" name="comment" rows="5" cols="80" wrap="hard"></textarea><br />
|
||||
|
||||
[% IF groups.size > 0 %]
|
||||
|
||||
<b>Groupset:</b><br>
|
||||
<b>Groupset:</b><br />
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th>Don't<br>change<br>this group<br>restriction</td>
|
||||
<th>Remove<br>bugs<br>from this<br>group</td>
|
||||
<th>Add<br>bugs<br>to this<br>group</td>
|
||||
<th>Don't<br />change<br />this group<br />restriction</td>
|
||||
<th>Remove<br />bugs<br />from this<br />group</td>
|
||||
<th>Add<br />bugs<br />to this<br />group</td>
|
||||
<th>Group Name:</td>
|
||||
</tr>
|
||||
|
||||
[% FOREACH group = groups %]
|
||||
<tr>
|
||||
<td align="center">
|
||||
<input type="radio" name="bit-[% group.bit %]" value="-1" checked="checked">
|
||||
<input type="radio" name="bit-[% group.bit %]" value="-1" checked>
|
||||
</td>
|
||||
<td align="center">
|
||||
<input type="radio" name="bit-[% group.bit %]" value="0">
|
||||
@@ -208,7 +208,7 @@
|
||||
|
||||
[% IF foundinactive %]
|
||||
<font size="-1">(Note: Bugs may not be added to <strike>inactive
|
||||
groups</strike>, only removed.)</font><br>
|
||||
groups</strike>, only removed.)</font><br />
|
||||
[% END %]
|
||||
|
||||
[% END %]
|
||||
@@ -216,33 +216,33 @@
|
||||
|
||||
|
||||
[% knum = 0 %]
|
||||
<input id="knob-none" type="radio" name="knob" value="none" checked="checked">
|
||||
<label for="knob-none">Do nothing else</label><br>
|
||||
<input id="knob-none" type="radio" name="knob" value="none" CHECKED>
|
||||
<label for="knob-none">Do nothing else</label><br />
|
||||
|
||||
[% IF bugstatuses.size == 1 && bugstatuses.0 == unconfirmedstate %]
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-confirm" type="radio" name="knob" value="confirm">
|
||||
<label for="knob-confirm">
|
||||
Confirm bugs (change status to <b>NEW</b>)
|
||||
</label><br>
|
||||
</label><br />
|
||||
[% END %]
|
||||
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-accept" type="radio" name="knob" value="accept">
|
||||
<label for="knob-accept">
|
||||
Accept bugs (change status to <b>ASSIGNED</b>)
|
||||
</label><br>
|
||||
</label><br />
|
||||
|
||||
[%# If all the bugs being changed are open, allow the user to close them. %]
|
||||
[% IF !bugstatuses.containsany(closedstates) %]
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-clearresolution" type="radio" name="knob" value="clearresolution">
|
||||
<label for="knob-clearresolution">Clear the resolution</label><br>
|
||||
<label for="knob-clearresolution">Clear the resolution</label><br />
|
||||
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-resolve" type="radio" name="knob" value="resolve">
|
||||
<label for="knob-resolve">
|
||||
Resolve bugs, changing <a href="bug_status.html">resolution</a> to
|
||||
Resolve bugs, changing <A HREF="bug_status.html">resolution</A> to
|
||||
</label>
|
||||
<select name="resolution" onchange="document.forms.changeform.knob[[% knum %]].checked=true">
|
||||
[% FOREACH resolution = resolutions %]
|
||||
@@ -251,7 +251,7 @@
|
||||
[% resolution FILTER html %]
|
||||
</option>
|
||||
[% END %]
|
||||
</select><br>
|
||||
</select><br />
|
||||
|
||||
[% END %]
|
||||
|
||||
@@ -259,30 +259,30 @@
|
||||
[% IF !bugstatuses.containsany(openstates) %]
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-reopen" type="radio" name="knob" value="reopen">
|
||||
<label for="knob-reopen">Reopen bugs</label><br>
|
||||
<label for="knob-reopen">Reopen bugs</label><br />
|
||||
[% END %]
|
||||
|
||||
[% IF bugstatuses.size == 1 %]
|
||||
[% IF bugstatuses.contains('RESOLVED') %]
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-verify" type="radio" name="knob" value="verify">
|
||||
<label for="knob-verify">Mark bugs as <b>VERIFIED</b></label><br>
|
||||
<label for="knob-verify">Mark bugs as <b>VERIFIED</b></label><br />
|
||||
[% ELSIF bugstatuses.contains('VERIFIED') %]
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-close" type="radio" name="knob" value="close">
|
||||
<label for="knob-close">Mark bugs as <b>CLOSED</b></label><br>
|
||||
<label for="knob-close">Mark bugs as <b>CLOSED</b></label><br />
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-reassign" type="radio" name="knob" value="reassign">
|
||||
<label for="knob-reassign"><a href="bug_status.html#assigned_to">
|
||||
Reassign</a> bugs to
|
||||
Reassign</A> bugs to
|
||||
</label>
|
||||
<input name="assigned_to"
|
||||
value="[% user.login FILTER html %]"
|
||||
onchange="document.forms.changeform.knob[[% knum %]].checked = true;"
|
||||
size="32"><br>
|
||||
size="32"><br />
|
||||
|
||||
[% knum = knum + 1 %]
|
||||
<input id="knob-reassignbycomponent"
|
||||
@@ -291,7 +291,7 @@
|
||||
value="reassignbycomponent">
|
||||
<label for="knob-reassignbycomponent">
|
||||
Reassign bugs to owner of selected component
|
||||
</label><br>
|
||||
</label><br />
|
||||
|
||||
<input type="submit" value="Commit">
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
|
||||
[% BLOCK selectmenu %]
|
||||
<select id="[% menuname %]" name="[% menuname %]">
|
||||
<option value="[% dontchange FILTER html %]" selected="selected">
|
||||
<option value="[% dontchange FILTER html %]" selected>
|
||||
[% dontchange FILTER html %]
|
||||
</option>
|
||||
[% FOREACH menuitem = menuitems %]
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
<head>
|
||||
<title>[% title %]</title>
|
||||
<link href="css/buglist.css" rel="stylesheet" type="text/css">
|
||||
<link href="css/buglist.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
%]
|
||||
|
||||
<div align="center">
|
||||
<b>[% currenttime %]</b><br>
|
||||
<b>[% currenttime %]</b><br />
|
||||
|
||||
[% IF debug %]
|
||||
<p>[% query FILTER html %]</p>
|
||||
@@ -57,7 +57,7 @@
|
||||
</h2>
|
||||
[% END %]
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
|
||||
[%############################################################################%]
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
[% END %]
|
||||
|
||||
<br>
|
||||
<br />
|
||||
|
||||
|
||||
[%############################################################################%]
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
[% END %]
|
||||
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
</p>
|
||||
|
||||
<form method="post" action="quips.cgi">
|
||||
<input type="hidden" name="action" value="add">
|
||||
<input size="80" name="quip">
|
||||
<input type="hidden" name="action" value="add" />
|
||||
<input size="80" name="quip" />
|
||||
<p>
|
||||
<input type="submit" value="Add This Quip">
|
||||
<input type="submit" value="Add This Quip" />
|
||||
</p>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
[% INCLUDE describe_comp %]
|
||||
[% END %]
|
||||
<tr>
|
||||
<td colspan="[% numcols %]">
|
||||
<td colspan='[% numcols %]'>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -75,7 +75,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">
|
||||
<td rowspan='2'>
|
||||
<a name="[% comp.name FILTER html %]">[% comp.name FILTER html %]</a>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
[%# *** Column Headers *** %]
|
||||
|
||||
<table border>
|
||||
<tr bgcolor="#CCCCCC">
|
||||
<tr BGCOLOR="#CCCCCC">
|
||||
[% FOREACH column = [ { name => "id", description => "Bug #" },
|
||||
{ name => "count", description => "Dupe<br>Count" },
|
||||
{ name => "delta",
|
||||
@@ -111,7 +111,7 @@
|
||||
<td>
|
||||
<center>
|
||||
[% "<strike>" IF bug.resolution != "" %]
|
||||
<a href="show_bug.cgi?id=[% bug.id %]">[% bug.id %]</a>
|
||||
<A HREF="show_bug.cgi?id=[% bug.id %]">[% bug.id %]</a>
|
||||
[% "</strike>" IF bug.resolution != "" %]
|
||||
</center>
|
||||
</td>
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
<h3><a name="params">Change Parameters</a></h3>
|
||||
|
||||
<form method="get" action="duplicates.cgi">
|
||||
<input type="hidden" name="sortby" value="[% sortby %]">
|
||||
<input type="hidden" name="reverse" value="[% reverse %]">
|
||||
<input type="hidden" name="sortby" value="[% sortby %]" />
|
||||
<input type="hidden" name="reverse" value="[% reverse %]" />
|
||||
<input type="hidden" name="bug_id" value="[% bug_ids_string %]">
|
||||
<table>
|
||||
<tr>
|
||||
@@ -68,20 +68,20 @@
|
||||
work with:</td>
|
||||
<td>
|
||||
<input type="radio" name="sortvisible" id="entirelist" value="0"
|
||||
[% "checked" IF NOT sortvisible %]>
|
||||
[% "checked" IF NOT sortvisible %] />
|
||||
<label for="entirelist">
|
||||
entire list
|
||||
</label>
|
||||
<br>
|
||||
<br />
|
||||
<input type="radio" name="sortvisible" id="visiblelist" value="1"
|
||||
[% "checked" IF sortvisible %]>
|
||||
[% "checked" IF sortvisible %] />
|
||||
<label for="visiblelist">
|
||||
currently visible list
|
||||
</label>
|
||||
</td>
|
||||
<td rowspan="4" valign="top">Restrict to products:</td>
|
||||
<td rowspan="4" valign="top">
|
||||
<select name="product" size="5" multiple="multiple">
|
||||
<select name="product" size="5" multiple>
|
||||
[% FOREACH p = products %]
|
||||
<option name="[% p %]"
|
||||
[% " selected" IF product == p %]>[% p %]</option>
|
||||
@@ -93,14 +93,14 @@
|
||||
<tr>
|
||||
<td>Max rows:</td>
|
||||
<td>
|
||||
<input size="4" name="maxrows" value="[% maxrows %]">
|
||||
<input size="4" name="maxrows" value="[% maxrows %]" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Change column is change in the last:</td>
|
||||
<td>
|
||||
<input size="4" name="changedsince" value="[% changedsince %]"> days
|
||||
<input size="4" name="changedsince" value="[% changedsince %]" /> days
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -112,13 +112,13 @@
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="openonly" id="openonly" value="1"
|
||||
[% "checked" IF openonly %]>
|
||||
[% "checked" IF openonly %] />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<input type="submit" value="Change">
|
||||
<input type="submit" value="Change" />
|
||||
</form>
|
||||
|
||||
<form method="post" action="buglist.cgi">
|
||||
@@ -128,7 +128,7 @@
|
||||
(Note: the order may not be the same.)
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<b>
|
||||
<a name="explanation">What are "Most Frequently Reported Bugs"?</a>
|
||||
|
||||
@@ -368,7 +368,7 @@ function selectProduct(f) {
|
||||
[%# Can't use the select block here because of onChange and the fact that
|
||||
'component' is a toolkit reserved word - we use 'component_' instead. %]
|
||||
<td align="left">
|
||||
<select name="product" multiple="multiple" size="5" onchange="selectProduct(this.form);">
|
||||
<select name="product" multiple size="5" onChange="selectProduct(this.form);">
|
||||
[% FOREACH p = product %]
|
||||
<option value="[% p FILTER html %]"
|
||||
[% " selected" IF lsearch(default.product, p) != -1 %]>
|
||||
@@ -378,7 +378,7 @@ function selectProduct(f) {
|
||||
</td>
|
||||
|
||||
<td align="left">
|
||||
<select name="component" multiple="multiple" size="5">
|
||||
<select name="component" multiple size="5">
|
||||
[% FOREACH c = component_ %]
|
||||
<option value="[% c FILTER html %]"
|
||||
[% " selected" IF lsearch(default.component, c) != -1 %]>
|
||||
@@ -618,13 +618,13 @@ function selectProduct(f) {
|
||||
|
||||
<dl>
|
||||
<dt>Only bugs changed in the last </dt>
|
||||
<dd><input name="changedin" size="3" value="[% default.changedin.0 FILTER html %]"> days</dd>
|
||||
<dd><input name=changedin size=3 value="[% default.changedin.0 FILTER html %]"> days</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt>Only bugs where any of the fields</dt>
|
||||
<dd>
|
||||
<select name="chfield" multiple="multiple" size="4">
|
||||
<select name="chfield" multiple size="4">
|
||||
[% FOREACH field = chfield %]
|
||||
<option value="[% field FILTER html %]"
|
||||
[% " selected" IF lsearch(default.chfield, field) != -1 %]>
|
||||
@@ -659,7 +659,7 @@ function selectProduct(f) {
|
||||
|
||||
[% BLOCK select %]
|
||||
<td align="left">
|
||||
<select name="[% sel.name %]" multiple="multiple" size="[% sel.size %]">
|
||||
<select name="[% sel.name %]" multiple size="[% sel.size %]">
|
||||
[% FOREACH name = ${sel.name} %]
|
||||
<option value="[% name FILTER html %]"
|
||||
[% " selected" IF lsearch(default.${sel.name}, name) != -1 %]>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<input type="hidden" name="cmdtype" value="doit">
|
||||
[% ELSE %]
|
||||
<br>
|
||||
<input type="radio" name="cmdtype" value="doit" checked="checked"> Run this query
|
||||
<input type="radio" name="cmdtype" value="doit" checked> Run this query
|
||||
<br>
|
||||
|
||||
[% IF namedqueries.size > 0 %]
|
||||
|
||||
@@ -229,7 +229,19 @@ sub changePassword {
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
sub confirmChangeEmail {
|
||||
# Return HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
$vars->{'title'} = "Confirm Change Email";
|
||||
$vars->{'token'} = $::token;
|
||||
|
||||
$template->process("account/email/confirm.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
sub changeEmail {
|
||||
|
||||
# Get the user's ID from the tokens table.
|
||||
SendSQL("SELECT userid, eventdata FROM tokens
|
||||
WHERE token = $::quotedtoken");
|
||||
@@ -261,24 +273,15 @@ sub changeEmail {
|
||||
AND tokentype = 'emailnew'");
|
||||
SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
|
||||
InvalidateLogins($userid);
|
||||
|
||||
$vars->{'title'} = "Password Changed";
|
||||
$vars->{'message'} = "Your password has been changed.";
|
||||
|
||||
print "Content-Type: text/html\n\n";
|
||||
$template->process("global/message.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
sub confirmChangeEmail {
|
||||
# Return HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
$vars->{'title'} = "Confirm Change Email";
|
||||
$vars->{'token'} = $::token;
|
||||
# Let the user know their email address has been changed.
|
||||
|
||||
$template->process("account/email/confirm.html.tmpl", $vars)
|
||||
$vars->{'title'} = "Bugzilla Login Changed";
|
||||
$vars->{'message'} = "Your Bugzilla login has been changed.";
|
||||
|
||||
$template->process("global/message.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ use RelationSet;
|
||||
sub sillyness {
|
||||
my $zz;
|
||||
$zz = $::defaultqueryname;
|
||||
$zz = $::usergroupset;
|
||||
}
|
||||
|
||||
# Use global template variables.
|
||||
@@ -337,22 +338,32 @@ sub SaveFooter {
|
||||
|
||||
sub DoPermissions {
|
||||
my (@has_bits, @set_bits);
|
||||
|
||||
SendSQL("SELECT description FROM groups, user_group_map " .
|
||||
"WHERE groups.group_id = user_group_map.group_id " .
|
||||
"AND user_group_map.user_id = $userid " .
|
||||
"ORDER BY description");
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE (bit & $::usergroupset) != 0 " .
|
||||
"ORDER BY bit");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE (group_bit & int8($::usergroupset)) != 0 " .
|
||||
"ORDER BY group_bit");
|
||||
}
|
||||
while (MoreSQLData()) {
|
||||
push(@has_bits, FetchSQLData());
|
||||
}
|
||||
SendSQL("SELECT COUNT(*) FROM user_group_map WHERE user_id = $userid AND canbless >= 1");
|
||||
my $blessgroups = FetchOneColumn();
|
||||
if ($blessgroups) {
|
||||
SendSQL("SELECT description FROM groups, user_group_map " .
|
||||
"WHERE groups.group_id = user_group_map.group_id " .
|
||||
"AND user_group_map.user_id = $userid " .
|
||||
"AND canbless = 1 " .
|
||||
"ORDER BY description");
|
||||
|
||||
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid");
|
||||
my $blessgroupset = FetchOneColumn();
|
||||
if ($blessgroupset) {
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE (bit & $blessgroupset) != 0 " .
|
||||
"ORDER BY bit");
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
SendSQL("SELECT description FROM groups " .
|
||||
"WHERE (group_bit & int8($blessgroupset)) != 0 " .
|
||||
"ORDER BY group_bit");
|
||||
}
|
||||
while (MoreSQLData()) {
|
||||
push(@set_bits, FetchSQLData());
|
||||
}
|
||||
@@ -367,7 +378,7 @@ sub DoPermissions {
|
||||
###############################################################################
|
||||
# Live code (not subroutine definitions) starts here
|
||||
###############################################################################
|
||||
$userid = confirm_login();
|
||||
confirm_login();
|
||||
|
||||
GetVersionTable();
|
||||
|
||||
@@ -405,4 +416,3 @@ SWITCH: for ($current_tab_name) {
|
||||
print "Content-type: text/html\n\n";
|
||||
$template->process("account/prefs/prefs.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ use lib ".";
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
use vars qw($usergroupset);
|
||||
|
||||
# Use global template variables
|
||||
use vars qw($template $vars);
|
||||
|
||||
@@ -45,14 +47,13 @@ ConnectToDatabase();
|
||||
my $action = $::FORM{'action'} ||
|
||||
($::FORM{'bug_id'} ? "show_bug" : "show_user");
|
||||
|
||||
my $userid = 0;
|
||||
if ($action eq "show_bug" ||
|
||||
($action eq "show_user" && defined($::FORM{'user'})))
|
||||
{
|
||||
$userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
}
|
||||
else {
|
||||
$userid = confirm_login();
|
||||
confirm_login();
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -62,7 +63,7 @@ else {
|
||||
# Make sure the bug ID is a positive integer representing an existing
|
||||
# bug that the user is authorized to access.
|
||||
if (defined $::FORM{'bug_id'}) {
|
||||
ValidateBugID($::FORM{'bug_id'}, $userid);
|
||||
ValidateBugID($::FORM{'bug_id'});
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -187,7 +188,7 @@ sub show_user {
|
||||
# and they can see there are votes 'missing', but not on what bug
|
||||
# they are. This seems a reasonable compromise; the alternative is
|
||||
# to lie in the totals.
|
||||
next if !CanSeeBug($id, $who);
|
||||
next if !CanSeeBug($id, $who, $usergroupset);
|
||||
|
||||
push (@bugs, { id => $id,
|
||||
summary => $summary,
|
||||
@@ -252,7 +253,7 @@ sub record_votes {
|
||||
# a non-negative integer (a series of digits not preceded by a
|
||||
# minus sign).
|
||||
foreach my $id (@buglist) {
|
||||
ValidateBugID($id, $userid);
|
||||
ValidateBugID($id);
|
||||
detaint_natural($::FORM{$id})
|
||||
|| DisplayError("Only use non-negative numbers for your bug votes.")
|
||||
&& exit;
|
||||
|
||||
@@ -39,7 +39,7 @@ if (!defined $::FORM{'id'} || !$::FORM{'id'}) {
|
||||
exit;
|
||||
}
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
quietly_check_login();
|
||||
|
||||
my $exporter = $::COOKIE{"Bugzilla_login"} || undef;
|
||||
|
||||
@@ -49,7 +49,7 @@ print "Content-type: text/xml\n\n";
|
||||
print Bug::XML_Header(Param("urlbase"), $::param{'version'},
|
||||
Param("maintainer"), $exporter);
|
||||
foreach my $id (@ids) {
|
||||
my $bug = new Bug(trim($id), $userid);
|
||||
my $bug = new Bug(trim($id), $::userid);
|
||||
print $bug->emitXML;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user