summaryrefslogtreecommitdiffstats
path: root/Bugzilla
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla')
-rw-r--r--Bugzilla/Config/GroupSecurity.pm8
-rw-r--r--Bugzilla/DB/Schema.pm29
-rw-r--r--Bugzilla/User.pm87
3 files changed, 103 insertions, 21 deletions
diff --git a/Bugzilla/Config/GroupSecurity.pm b/Bugzilla/Config/GroupSecurity.pm
index 0235a8cb1..1dee703d0 100644
--- a/Bugzilla/Config/GroupSecurity.pm
+++ b/Bugzilla/Config/GroupSecurity.pm
@@ -79,6 +79,14 @@ sub get_param_list {
},
{
+ name => 'querysharegroup',
+ type => 's',
+ choices => \&_get_all_group_names,
+ default => 'editbugs',
+ checker => \&check_group
+ },
+
+ {
name => 'usevisibilitygroups',
type => 'b',
default => 0
diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm
index 62a3da445..7c848bd5b 100644
--- a/Bugzilla/DB/Schema.pm
+++ b/Bugzilla/DB/Schema.pm
@@ -666,9 +666,10 @@ use constant ABSTRACT_SCHEMA => {
namedqueries => {
FIELDS => [
+ id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1,
+ PRIMARYKEY => 1},
userid => {TYPE => 'INT3', NOTNULL => 1},
name => {TYPE => 'varchar(64)', NOTNULL => 1},
- linkinfooter => {TYPE => 'BOOLEAN', NOTNULL => 1},
query => {TYPE => 'MEDIUMTEXT', NOTNULL => 1},
query_type => {TYPE => 'BOOLEAN', NOTNULL => 1},
],
@@ -678,6 +679,18 @@ use constant ABSTRACT_SCHEMA => {
],
},
+ namedqueries_link_in_footer => {
+ FIELDS => [
+ namedquery_id => {TYPE => 'INT3', NOTNULL => 1},
+ user_id => {TYPE => 'INT3', NOTNULL => 1},
+ ],
+ INDEXES => [
+ namedqueries_link_in_footer_id_idx => {FIELDS => [qw(namedquery_id user_id)],
+ TYPE => 'UNIQUE'},
+ namedqueries_link_in_footer_userid_idx => ['user_id'],
+ ],
+ },
+
# Authentication
# --------------
@@ -806,6 +819,20 @@ use constant ABSTRACT_SCHEMA => {
],
},
+ # This table determines which groups a user must be a member of
+ # in order to see a named query somebody else shares.
+ namedquery_group_map => {
+ FIELDS => [
+ namedquery_id => {TYPE => 'INT3', NOTNULL => 1},
+ group_id => {TYPE => 'INT3', NOTNULL => 1},
+ ],
+ INDEXES => [
+ namedquery_group_map_namedquery_id_idx =>
+ {FIELDS => [qw(namedquery_id)], TYPE => 'UNIQUE'},
+ namedquery_group_map_group_id_idx => ['group_id'],
+ ],
+ },
+
category_group_map => {
FIELDS => [
category_id => {TYPE => 'INT2', NOTNULL => 1},
diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm
index 9977ca86c..e962ae7ae 100644
--- a/Bugzilla/User.pm
+++ b/Bugzilla/User.pm
@@ -204,25 +204,46 @@ sub queries {
return [] unless $self->id;
my $dbh = Bugzilla->dbh;
- my $used_in_whine_ref = $dbh->selectcol_arrayref(q{
+ my $used_in_whine_ref = $dbh->selectall_hashref('
SELECT DISTINCT query_name
FROM whine_events we
INNER JOIN whine_queries wq
ON we.id = wq.eventid
- WHERE we.owner_userid = ?}, undef, $self->{id});
-
- my $queries_ref = $dbh->selectall_arrayref(q{
- SELECT name, query, linkinfooter, query_type
- FROM namedqueries
- WHERE userid = ?
- ORDER BY UPPER(name)},{'Slice'=>{}}, $self->{id});
-
- foreach my $name (@$used_in_whine_ref) {
- foreach my $queries_hash (@$queries_ref) {
- if ($queries_hash->{name} eq $name) {
- $queries_hash->{usedinwhine} = 1;
- last;
- }
+ WHERE we.owner_userid = ?',
+ 'query_name', undef, $self->id);
+
+ # If the user is in any group, there may be shared queries to be included.
+ my $or_nqgm_group_id_in_usergroups = '';
+ if ($self->groups_as_string) {
+ $or_nqgm_group_id_in_usergroups =
+ 'OR MAX(nqgm.group_id) IN (' . $self->groups_as_string . ') ';
+ }
+
+ my $queries_ref = $dbh->selectall_arrayref('
+ SELECT nq.id, MAX(userid) AS userid, name, query, query_type,
+ MAX(nqgm.group_id) AS shared_with_group,
+ COUNT(nql.namedquery_id) AS link_in_footer
+ FROM namedqueries AS nq
+ LEFT JOIN namedquery_group_map nqgm
+ ON nqgm.namedquery_id = nq.id
+ LEFT JOIN namedqueries_link_in_footer AS nql
+ ON nql.namedquery_id = nq.id
+ AND nql.user_id = ? ' .
+ $dbh->sql_group_by('nq.id', 'name, query, query_type') .
+ ' HAVING MAX(nq.userid) = ? ' .
+ $or_nqgm_group_id_in_usergroups .
+ ' ORDER BY UPPER(name)',
+ {'Slice'=>{}}, $self->id, $self->id);
+
+ foreach my $queries_hash (@$queries_ref) {
+ # For each query, determine whether it's being used in a whine.
+ if (exists($$used_in_whine_ref{$queries_hash->{'name'}})) {
+ $queries_hash->{'usedinwhine'} = 1;
+ }
+
+ # For shared queries, provide the sharer's user object.
+ if ($queries_hash->{'userid'} != $self->id) {
+ $queries_hash->{'user'} = new Bugzilla::User($queries_hash->{'userid'});
}
}
$self->{queries} = $queries_ref;
@@ -660,6 +681,24 @@ sub visible_groups_as_string {
return join(', ', @{$self->visible_groups_inherited()});
}
+# This function defines the groups a user may share a query with.
+# More restrictive sites may want to build this reference to a list of group IDs
+# from bless_groups instead of mirroring visible_groups_inherited, perhaps.
+sub queryshare_groups {
+ my $self = shift;
+ if ($self->in_group(Bugzilla->params->{'querysharegroup'})) {
+ return $self->visible_groups_inherited();
+ }
+ else {
+ return [];
+ }
+}
+
+sub queryshare_groups_as_string {
+ my $self = shift;
+ return join(', ', @{$self->queryshare_groups()});
+}
+
sub derive_regexp_groups {
my ($self) = @_;
@@ -734,8 +773,8 @@ sub can_bless {
}
# Otherwise, we're checking a specific group
- my $group_name = shift;
- return (grep {$$_{'name'} eq $group_name} (@{$self->bless_groups})) ? 1 : 0;
+ my $group_id = shift;
+ return (grep {$$_{'id'} eq $group_id} (@{$self->bless_groups})) ? 1 : 0;
}
sub flatten_group_membership {
@@ -1576,12 +1615,20 @@ Should only be called by C<Bugzilla::Auth::login>, for the most part.
=item C<queries>
Returns an array of the user's named queries, sorted in a case-insensitive
-order by name. Each entry is a hash with three keys:
+order by name. Each entry is a hash with five keys:
=over
=item *
+id - The ID of the query
+
+=item *
+
+userid - The query owner's user ID
+
+=item *
+
name - The name of the query
=item *
@@ -1590,7 +1637,7 @@ query - The text for the query
=item *
-linkinfooter - Whether or not the query should be displayed in the footer.
+link_in_footer - Whether or not the query should be displayed in the footer.
=back
@@ -1783,7 +1830,7 @@ When called with no arguments:
Returns C<1> if the user can bless at least one group, returns C<0> otherwise.
When called with one argument:
-Returns C<1> if the user can bless the group with that name, returns
+Returns C<1> if the user can bless the group with that id, returns
C<0> otherwise.
=item C<wants_bug_mail>