diff options
Diffstat (limited to 'Bugzilla')
-rw-r--r-- | Bugzilla/Config/GroupSecurity.pm | 8 | ||||
-rw-r--r-- | Bugzilla/DB/Schema.pm | 29 | ||||
-rw-r--r-- | Bugzilla/User.pm | 87 |
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> |