checker => \&check_group
},
+ {
+ name => 'querysharegroup',
+ type => 's',
+ choices => \&_get_all_group_names,
+ default => 'editbugs',
+ checker => \&check_group
+ },
+
{
name => 'usevisibilitygroups',
type => 'b',
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},
],
],
},
+ 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
# --------------
],
},
+ # 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},
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;
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) = @_;
}
# 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 {
=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 *
=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
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>
}
sub LookupNamedQuery {
- my ($name) = @_;
+ my ($name, $sharer_id) = @_;
my $user = Bugzilla->login(LOGIN_REQUIRED);
my $dbh = Bugzilla->dbh;
- # $name is safe -- we only use it below in a SELECT placeholder and then
- # in error messages (which are always HTML-filtered).
+ my $owner_id;
+
+ # $name and $sharer_id are safe -- we only use them below in SELECT
+ # placeholders and then in error messages (which are always HTML-filtered).
$name || ThrowUserError("query_name_missing");
trick_taint($name);
- my $result = $dbh->selectrow_array("SELECT query FROM namedqueries"
- . " WHERE userid = ? AND name = ?"
- , undef, ($user->id, $name));
+ if ($sharer_id) {
+ trick_taint($sharer_id);
+ $owner_id = $sharer_id;
+ }
+ else {
+ $owner_id = $user->id;
+ }
+
+ my ($id, $result) = $dbh->selectrow_array('SELECT id, query
+ FROM namedqueries
+ WHERE userid = ? AND name = ?',
+ undef, ($owner_id, $name));
+ defined($result)
+ || ThrowUserError("missing_query", {'queryname' => $name,
+ 'sharer_id' => $sharer_id});
+
+ if ($sharer_id) {
+ my $group = $dbh->selectrow_array('SELECT group_id
+ FROM namedquery_group_map
+ WHERE namedquery_id = ?',
+ undef, $id);
+ if (!grep {$_ == $group} values(%{$user->groups()})) {
+ ThrowUserError("missing_query", {'queryname' => $name,
+ 'sharer_id' => $sharer_id});
+ }
+ }
- defined($result) || ThrowUserError("missing_query", {'queryname' => $name});
$result
|| ThrowUserError("buglist_parameters_required", {'queryname' => $name});
# it when we display it to the user.
trick_taint($query);
- $dbh->bz_lock_tables('namedqueries WRITE');
+ $dbh->bz_lock_tables('namedqueries WRITE',
+ 'namedqueries_link_in_footer WRITE');
my $result = $dbh->selectrow_array("SELECT userid FROM namedqueries"
. " WHERE userid = ? AND name = ?"
if ($result) {
$query_existed_before = 1;
$dbh->do("UPDATE namedqueries"
- . " SET query = ?, linkinfooter = ?, query_type = ?"
+ . " SET query = ?, query_type = ?"
. " WHERE userid = ? AND name = ?"
- , undef, ($query, $link_in_footer, $query_type, $userid, $query_name));
+ , undef, ($query, $query_type, $userid, $query_name));
} else {
$query_existed_before = 0;
$dbh->do("INSERT INTO namedqueries"
- . " (userid, name, query, linkinfooter, query_type)"
- . " VALUES (?, ?, ?, ?, ?)"
- , undef, ($userid, $query_name, $query, $link_in_footer, $query_type));
+ . " (userid, name, query, query_type)"
+ . " VALUES (?, ?, ?, ?)"
+ , undef, ($userid, $query_name, $query, $query_type));
+ if ($link_in_footer) {
+ $dbh->do('INSERT INTO namedqueries_link_in_footer
+ (namedquery_id, user_id)
+ VALUES (?, ?)',
+ undef,
+ ($dbh->bz_last_key('namedqueries', 'id'), $userid));
+ }
}
$dbh->bz_unlock_tables();
# Take appropriate action based on user's request.
if ($cgi->param('cmdtype') eq "dorem") {
if ($cgi->param('remaction') eq "run") {
- $buffer = LookupNamedQuery(scalar $cgi->param("namedcmd"));
- $vars->{'searchname'} = $cgi->param('namedcmd');
- $vars->{'searchtype'} = "saved";
+ $buffer = LookupNamedQuery(scalar $cgi->param("namedcmd"),
+ scalar $cgi->param('sharer_id'));
+ # If this is the user's own query, remember information about it
+ # so that it can be modified easily.
+ if (!$cgi->param('sharer_id') ||
+ $cgi->param('sharer_id') == Bugzilla->user->id) {
+ $vars->{'searchname'} = $cgi->param('namedcmd');
+ $vars->{'searchtype'} = "saved";
+ }
$params = new Bugzilla::CGI($buffer);
$order = $params->param('order') || $order;
}
# If we are here, then we can safely remove the saved search
- $dbh->do("DELETE FROM namedqueries"
- . " WHERE userid = ? AND name = ?"
- , undef, ($user->id, $qname));
+ my ($query_id) = $dbh->selectrow_array('SELECT id FROM namedqueries
+ WHERE userid = ?
+ AND name = ?',
+ undef, ($user->id, $qname));
+ if (!$query_id) {
+ # The user has no query of this name. Play along.
+ }
+ else {
+ $dbh->do('DELETE FROM namedqueries
+ WHERE id = ?',
+ undef, $query_id);
+ $dbh->do('DELETE FROM namedqueries_link_in_footer
+ WHERE namedquery_id = ?',
+ undef, $query_id);
+ $dbh->do('DELETE FROM namedquery_group_map
+ WHERE namedquery_id = ?',
+ undef, $query_id);
+ }
# Now reset the cached queries
$user->flush_queries_cache();
print $cgi->header();
# Generate and return the UI (HTML page) from the appropriate template.
$vars->{'message'} = "buglist_query_gone";
- $vars->{'namedcmd'} = $cgi->param('namedcmd');
+ $vars->{'namedcmd'} = $qname;
$vars->{'url'} = "query.cgi";
$template->process("global/message.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
$dbh->bz_add_column('profiles', 'mybugslink', {TYPE => 'BOOLEAN', NOTNULL => 1,
DEFAULT => 'TRUE'});
-$dbh->bz_add_column('namedqueries', 'linkinfooter',
- {TYPE => 'BOOLEAN', NOTNULL => 1}, 0);
my $comp_init_owner = $dbh->bz_column_info('components', 'initialowner');
if ($comp_init_owner && $comp_init_owner->{TYPE} eq 'TINYTEXT') {
unlink "$datadir/versioncache";
}
+# 2006-07-01 wurblzap@gmail.com -- Bug 69000
+$dbh->bz_add_column('namedqueries', 'id',
+ {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
+if ($dbh->bz_column_info("namedqueries", "linkinfooter")) {
+ # Move link-in-footer information into a table of its own.
+ my $sth_read = $dbh->prepare('SELECT id, userid
+ FROM namedqueries
+ WHERE linkinfooter = 1');
+ my $sth_write = $dbh->prepare('INSERT INTO namedqueries_link_in_footer
+ (namedquery_id, user_id) VALUES (?, ?)');
+ $sth_read->execute();
+ while (my ($id, $userid) = $sth_read->fetchrow_array()) {
+ $sth_write->execute($id, $userid);
+ }
+ $dbh->bz_drop_column("namedqueries", "linkinfooter");
+}
# If you had to change the --TABLE-- definition in any way, then add your
# differential change code *** A B O V E *** this comment.
returns bugs where the content of the field matches any one of the selected
values. If none is selected, then the field can take any value.</para>
- <para>Once you've run a search, you can save it as a Saved Search, which
- appears in the page footer.</para>
+ <para>
+ Once you've run a search, you can save it as a Saved Search, which
+ appears in the page footer.
+ On the Saved Searches tab of your User Preferences page (the Prefs link
+ in Bugzilla's footer), members of the group defined in the
+ querysharegroup parameter can share such Saved Searches with user groups
+ so that other users may use them.
+ At the same place, you can see Saved Searches other users are sharing, and
+ have them show up in your personal Bugzilla footer along with your own
+ Saved Searches.
+ If somebody is sharing a Search with a group she or he is allowed to
+ <xref linkend="groups">assign users to</a>, it will show up in the
+ group's direct members' footers by default.
+ </para>
<section id="boolean">
<title>Boolean Charts</title>
WHERE group_id IN ($grouplist) AND isbless = 0 " .
$dbh->sql_limit(1)) || 0;
+ my ($shared_queries) =
+ $dbh->selectrow_array('SELECT COUNT(*)
+ FROM namedquery_group_map
+ WHERE group_id = ?',
+ undef, $gid);
+
my $bug_ids = $dbh->selectcol_arrayref('SELECT bug_id FROM bug_group_map
WHERE group_id = ?', undef, $gid);
$dbh->sql_limit(1),
undef, ($gid, $gid)) || 0;
- $vars->{'gid'} = $gid;
- $vars->{'name'} = $name;
- $vars->{'description'} = $desc;
- $vars->{'hasusers'} = $hasusers;
- $vars->{'hasbugs'} = $hasbugs;
- $vars->{'hasproduct'} = $hasproduct;
- $vars->{'hasflags'} = $hasflags;
- $vars->{'buglist'} = $buglist;
+ $vars->{'gid'} = $gid;
+ $vars->{'name'} = $name;
+ $vars->{'description'} = $desc;
+ $vars->{'hasusers'} = $hasusers;
+ $vars->{'hasbugs'} = $hasbugs;
+ $vars->{'hasproduct'} = $hasproduct;
+ $vars->{'hasflags'} = $hasflags;
+ $vars->{'shared_queries'} = $shared_queries;
+ $vars->{'buglist'} = $buglist;
print $cgi->header();
$template->process("admin/groups/delete.html.tmpl", $vars)
$dbh->do('UPDATE flagtypes SET request_group_id = ?
WHERE request_group_id = ?',
undef, (undef, $gid));
+ $dbh->do('DELETE FROM namedquery_group_map WHERE group_id = ?',
+ undef, $gid);
$dbh->do('DELETE FROM user_group_map WHERE group_id = ?',
undef, $gid);
$dbh->do('DELETE FROM group_group_map
$vars->{'longdescs'} = $dbh->selectrow_array(
'SELECT COUNT(*) FROM longdescs WHERE who = ?',
undef, $otherUserID);
- $vars->{'namedqueries'} = $dbh->selectrow_array(
- 'SELECT COUNT(*) FROM namedqueries WHERE userid = ?',
- undef, $otherUserID);
+ $vars->{'namedqueries'} = $dbh->selectcol_arrayref(
+ 'SELECT id FROM namedqueries WHERE userid = ?',
+ undef,
+ $otherUserID);
+ if (@{$vars->{'namedqueries'}}) {
+ $vars->{'namedquery_group_map'} = $dbh->selectrow_array(
+ 'SELECT COUNT(*) FROM namedquery_group_map WHERE namedquery_id IN' .
+ ' (' . join(', ', @{$vars->{'namedqueries'}}) . ')');
+ }
+ else {
+ $vars->{'namedquery_group_map'} = 0;
+ }
$vars->{'profile_setting'} = $dbh->selectrow_array(
'SELECT COUNT(*) FROM profile_setting WHERE user_id = ?',
undef, $otherUserID);
'flagtypes READ',
'cc WRITE',
'namedqueries WRITE',
+ 'namedqueries_link_in_footer WRITE',
+ 'namedquery_group_map WRITE',
'tokens WRITE',
'votes WRITE',
'watch WRITE',
Bugzilla->logout_user($otherUser);
+ # Get the named query list so we can delete namedquery_group_map entries.
+ my $namedqueries_as_string = join(', ', $dbh->selectcol_arrayref(
+ 'SELECT id FROM namedqueries WHERE userid = ?',
+ undef,
+ $otherUserID));
+
# Get the timestamp for LogActivityEntry.
my $timestamp = $dbh->selectrow_array('SELECT NOW()');
$otherUserID);
$dbh->do('DELETE FROM logincookies WHERE userid = ?', undef, $otherUserID);
$dbh->do('DELETE FROM namedqueries WHERE userid = ?', undef, $otherUserID);
+ $dbh->do('DELETE FROM namedqueries_link_in_footer WHERE user_id = ?', undef,
+ $otherUserID);
+ if ($namedqueries_as_string) {
+ $dbh->do('DELETE FROM namedquery_group_map WHERE namedquery_id IN ' .
+ "($namedqueries_as_string)");
+ }
$dbh->do('DELETE FROM profile_setting WHERE user_id = ?', undef,
$otherUserID);
$dbh->do('DELETE FROM profiles_activity WHERE userid = ? OR who = ?', undef,
["group_group_map", "grantor_id"],
["group_group_map", "member_id"],
["group_control_map", "group_id"],
+ ["namedquery_group_map", "group_id"],
["user_group_map", "group_id"]);
+CrossCheck("namedqueries", "id",
+ ["namedqueries_link_in_footer", "namedquery_id"],
+ ["namedquery_group_map", "namedquery_id"],
+ );
+
CrossCheck("profiles", "userid",
['profiles_activity', 'userid'],
['profiles_activity', 'who'],
["longdescs", "who", "bug_id"],
["logincookies", "userid"],
["namedqueries", "userid"],
+ ["namedqueries_link_in_footer", "user_id"],
['series', 'creator', 'series_id', ['0']],
["watch", "watcher"],
["watch", "watched"],
display: inline;
}
- #footer span
- {
- display: block;
- }
-
#footer .btn, #footer .txt
{
font-size: 0.8em;
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
+[%# INTERFACE:
+ # queries: list of the named queries visible to the user, both own and shared
+ # by others. Cleaned-up result of Bugzilla::User::queries.
+ # queryshare_groups: list of groups the user may share queries with
+ # (id, name).
+ #%]
+
<p>Your saved searches are as follows:</p>
<blockquote>
Show in
Footer
</th>
+ [% querysharegroup_regexp = '^' _ Param('querysharegroup') _ '$' %]
+ [% may_share = user.groups.keys.grep($querysharegroup_regexp).size %]
+ [% IF may_share %]
+ <th>
+ Share With
+ a Group
+ [% UNLESS queryshare_groups.size %]
+ (there are no groups you may share queries with)
+ [% END %]
+ </th>
+ [% END %]
</tr>
<tr>
<td>My Bugs</td>
value="1"
[% " checked" IF user.showmybugslink %]>
</td>
+ <td>
+ —
+ </td>
</tr>
[% FOREACH q = queries %]
+ [% NEXT UNLESS q.userid == user.id %]
<tr>
<td>[% q.name FILTER html %]</td>
<td>
</td>
<td align="center">
<input type="checkbox"
- name="linkinfooter_[% q.name FILTER html %]"
+ name="link_in_footer_[% q.id FILTER html %]"
+ value="1"
+ [% " checked" IF q.link_in_footer %]>
+ </td>
+ <td>
+ [% IF queryshare_groups.size %]
+ <select name="share_[% q.id FILTER html %]">
+ <option value="">Don't share</option>
+ [% FOREACH group = queryshare_groups %]
+ <option value="[% group.id %]"
+ [% ' selected="selected"' IF q.shared_with_group == group.id %]>[% group.name FILTER html %]</option>
+ [% END %]
+ </select>
+ [% ELSE %]
+ —
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ </table>
+</blockquote>
+
+<p>You may use these searches saved and shared by others:</p>
+
+<blockquote>
+ <table border="1" cellpadding="3">
+ <tr>
+ <th>
+ Search
+ </th>
+ <th>
+ Shared By
+ </th>
+ <th>
+ Run
+ </th>
+ <th>
+ Show in
+ Footer
+ </th>
+ </tr>
+ [% found_shared_query = 0 %]
+ [% FOREACH q = queries %]
+ [% NEXT IF q.userid == user.id %]
+ [% found_shared_query = 1 %]
+ <tr>
+ <td>[% q.name FILTER html %]</td>
+ <td>[% q.user.identity FILTER html %]</td>
+ <td>
+ <a href="buglist.cgi?cmdtype=dorem&remaction=run&namedcmd=
+ [% q.name FILTER url_quote %]&sharer_id=
+ [% q.userid FILTER url_quote %]">Run</a>
+ </td>
+ <td align="center">
+ <input type="checkbox"
+ name="link_in_footer_[% q.id FILTER html %]"
value="1"
- [% " checked" IF q.linkinfooter %]>
+ [% " checked" IF q.link_in_footer %]>
+ </td>
+ </tr>
+ [% END %]
+ [% IF !found_shared_query %]
+ <tr>
+ <td colspan="4" style="text-align: center">
+ <None>
</td>
</tr>
[% END %]
# hasbugs: boolean int. True if the group includes bugs in it.
# hasproduct: boolean int. True if the group is binded to a product.
# hasflags: boolean int. True if the group is used by a flag type.
+ # shared_queries: int. Number of saved searches being shared with this group.
# buglist: string. The list of bugs included in this group.
#%]
flag types from this group for me.</p>
[% END %]
+ [% IF shared_queries %]
+ <p>
+ <b>There
+ [% IF shared_queries > 1 %]
+ are [% shared_queries %] saved searches
+ [% ELSE %]
+ is a saved search
+ [% END %]
+ being shared with this group.</b>
+ If you delete this group,
+ [% IF shared_queries > 1 %]
+ these saved searches
+ [% ELSE %]
+ this saved search
+ [% END %]
+ will fall back to being private again.
+ </p>
+ [% END %]
+
<h2>Confirmation</h2>
<p>Do you really want to delete this group?</p>
timetrackinggroup => "The name of the group of users who can see/change time tracking " _
"information.",
+ querysharegroup => "The name of the group of users who can share their " _
+ "saved searches with others.",
+
usevisibilitygroups => "Do you wish to restrict visibility of users to members of " _
"specific groups?",
# flags.requestee: number of flags the viewed user is being asked for
# flags.setter: number of flags the viewed user has set
# longdescs: number of bug comments the viewed user has written
- # namedqueries: number of named queries the user has created
+ # namedqueries: array of IDs of named queries the user has created
+ # namedquery_group_map: number of named queries the user has shared
# profiles_activity: number of named queries the user has created
# series: number of series the viewed user has created
# votes: number of bugs the viewed user has voted on
[% IF namedqueries %]
<li>
[% otheruser.login FILTER html %] has
- [% IF namedqueries == 1 %]
- a named query
+ [% IF namedqueries.size == 1 %]
+ a [% 'shared' IF namedquery_group_map %] named search
[% ELSE %]
- [%+ namedqueries %] named queries
+ [%+ namedqueries.size %] named searches
[% END %].
- [% IF namedqueries == 1 %]
- This named query
+ [% IF namedqueries.size == 1 %]
+ This named search
[% ELSE %]
- These named queries
+ These named searches
[% END %]
will be deleted along with the user account.
+ [% IF namedquery_group_map %]
+ [% IF namedqueries.size > 1 %]
+ Of these,
+ [% IF namedquery_group_map > 1 %]
+ [%+ namedquery_group_map FILTER html %] are
+ [% ELSE %]
+ one is
+ [% END %]
+ shared.
+ [% END %]
+ Other users will not be able to use
+ [% IF namedquery_group_map > 1 %]
+ these shared named searches
+ [% ELSE %]
+ this shared named search
+ [% END %]
+ any more.
+ [% END %]
</li>
[% END %]
[% IF profile_setting %]
'comp.bug_count'
],
+'admin/groups/delete.html.tmpl' => [
+ 'shared_queries'
+],
+
'admin/users/confirm-delete.html.tmpl' => [
'andstring',
'responsibilityterms.$responsibility',
'flags.requestee',
'flags.setter',
'longdescs',
- 'namedqueries',
'votes',
'series',
'watch.watched',
'current_tab.name',
],
+'account/prefs/saved-searches.html.tmpl' => [
+ 'group.id',
+],
+
'account/prefs/settings.html.tmpl' => [
'name',
'default_name'
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
# Svetlana Harisova <light@rathedg.com>
+ # Marc Schumann <wurblzap@gmail.com>
#%]
[%# Migration note: this whole file corresponds to the old %commandmenu%
<div id="links-saved">
<div class="label">
[% IF user.showmybugslink OR user.queries.size %]
- Saved Searches:
+ Saved Searches:
[% END %]
</div>
<div class="links">
- [% IF user.showmybugslink %]
- [% filtered_username = user.login FILTER url_quote %]
- <a href="[% Param('mybugstemplate').replace('%userid%', filtered_username) %]">My [% terms.Bugs %]</a>
+ [% IF user.showmybugslink %]
+ [% filtered_username = user.login FILTER url_quote %]
+ <a href="[% Param('mybugstemplate').replace('%userid%', filtered_username) %]">My [% terms.Bugs %]</a>
+ [% print_pipe = 1 %]
+ [% END %]
+
+ [% FOREACH q = user.queries %]
+ [% NEXT IF q.userid != user.id %]
+ [% IF q.link_in_footer %]
+ [% " | " IF print_pipe %]
+ <a href="buglist.cgi?cmdtype=dorem&remaction=run&namedcmd=
+ [% q.name FILTER url_quote %]">[% q.name FILTER html FILTER no_break %]</a>
[% print_pipe = 1 %]
[% END %]
+ [% END %]
- [% FOREACH q = user.queries %]
- [% IF q.linkinfooter %]
- [% " | " IF print_pipe %]
- <a href="buglist.cgi?cmdtype=runnamed&namedcmd=[% q.name FILTER url_quote %]">[% q.name FILTER html FILTER no_break %]</a>
- [% print_pipe = 1 %]
- [% END %]
+ [% " <br> " IF print_pipe %]
+ [% print_pipe = 0 %]
+ [% FOREACH q = user.queries %]
+ [% NEXT IF q.userid == user.id %]
+ [% IF q.link_in_footer %]
+ [% " | " IF print_pipe %]
+ <a href="buglist.cgi?cmdtype=dorem&remaction=run&namedcmd=
+ [% q.name FILTER url_quote %]&sharer_id=
+ [% q.userid FILTER url_quote %]"
+ class="shared"
+ title="Shared by [% q.user.identity FILTER html %]">[% q.name FILTER html FILTER no_break %]</a>
+ [% print_pipe = 1 %]
[% END %]
+ [% END %]
</div>
</div>
[% ELSIF error == "missing_query" %]
[% title = "Missing Search" %]
- The search named <em>[% queryname FILTER html %]</em> does not
- exist.
+ [% docslinks = {'query.html' => "Searching for $terms.bugs",
+ 'list.html' => "$terms.Bug lists"} %]
+ The search named <em>[% queryname FILTER html %]</em>
+ [% IF sharer_id %]
+ has not been made visible to you.
+ [% ELSE %]
+ does not exist.
+ [% END %]
[% ELSIF error == "move_bugs_disabled" %]
[% title = BLOCK %][% terms.Bug %] Moving Disabled[% END %]
my ($nam, $desc) = @$group;
push(@has_bits, {"desc" => $desc, "name" => $nam});
}
- $groups = $dbh->selectall_arrayref(
- "SELECT DISTINCT name, description FROM groups ORDER BY name");
+ $groups = $dbh->selectall_arrayref('SELECT DISTINCT id, name, description
+ FROM groups
+ ORDER BY name');
foreach my $group (@$groups) {
- my ($nam, $desc) = @$group;
- if ($user->can_bless($nam)) {
+ my ($group_id, $nam, $desc) = @$group;
+ if ($user->can_bless($group_id)) {
push(@set_bits, {"desc" => $desc, "name" => $nam});
}
}
sub DoSavedSearches {
# 2004-12-13 - colin.ogilvie@gmail.com, bug 274397
# Need to work around the possibly missing query_format=advanced
+ my $dbh = Bugzilla->dbh;
my $user = Bugzilla->user;
my @queries = @{$user->queries};
push @newqueries, $q;
}
$vars->{'queries'} = \@newqueries;
+ if ($user->queryshare_groups_as_string) {
+ $vars->{'queryshare_groups'} = $dbh->selectall_arrayref(
+ 'SELECT id, name FROM groups WHERE id IN ' .
+ '(' . $user->queryshare_groups_as_string .')',
+ {'Slice' => {}});
+ }
}
sub SaveSavedSearches {
my $dbh = Bugzilla->dbh;
my $user = Bugzilla->user;
+ # We'll need this in a loop, so do the call once.
+ my $user_id = $user->id;
+
my @queries = @{$user->queries};
- my $sth = $dbh->prepare("UPDATE namedqueries SET linkinfooter = ?
- WHERE userid = ?
- AND name = ?");
+ my $sth_check_nl = $dbh->prepare('SELECT COUNT(*)
+ FROM namedqueries_link_in_footer
+ WHERE namedquery_id = ?
+ AND user_id = ?');
+ my $sth_insert_nl = $dbh->prepare('INSERT INTO namedqueries_link_in_footer
+ (namedquery_id, user_id)
+ VALUES (?, ?)');
+ my $sth_delete_nl = $dbh->prepare('DELETE FROM namedqueries_link_in_footer
+ WHERE namedquery_id = ?
+ AND user_id = ?');
+ my $sth_check_ngm = $dbh->prepare('SELECT COUNT(*)
+ FROM namedquery_group_map
+ WHERE namedquery_id = ?');
+ my $sth_insert_ngm = $dbh->prepare('INSERT INTO namedquery_group_map
+ (namedquery_id, group_id)
+ VALUES (?, ?)');
+ my $sth_update_ngm = $dbh->prepare('UPDATE namedquery_group_map
+ SET group_id = ?
+ WHERE namedquery_id = ?');
+ my $sth_delete_ngm = $dbh->prepare('DELETE FROM namedquery_group_map
+ WHERE namedquery_id = ?');
+ my $sth_direct_group_members =
+ $dbh->prepare('SELECT user_id
+ FROM user_group_map
+ WHERE group_id = ?
+ AND isbless = ' . GROUP_MEMBERSHIP . '
+ AND grant_type = ' . GRANT_DIRECT);
foreach my $q (@queries) {
- my $linkinfooter =
- defined($cgi->param("linkinfooter_$q->{'name'}")) ? 1 : 0;
- $sth->execute($linkinfooter, $user->id, $q->{'name'});
+ # Update namedqueries_link_in_footer.
+ $sth_check_nl->execute($q->{'id'}, $user_id);
+ my ($link_in_footer_entries) = $sth_check_nl->fetchrow_array();
+ if (defined($cgi->param("link_in_footer_$q->{'id'}"))) {
+ if ($link_in_footer_entries == 0) {
+ $sth_insert_nl->execute($q->{'id'}, $user_id);
+ }
+ }
+ else {
+ if ($link_in_footer_entries > 0) {
+ $sth_delete_nl->execute($q->{'id'}, $user_id);
+ }
+ }
+
+ # For user's own queries, update namedquery_group_map.
+ if ($q->{'userid'} == $user_id) {
+ my ($group_id, $group_map_entries);
+ if ($user->in_group(Bugzilla->params->{'querysharegroup'})) {
+ $sth_check_ngm->execute($q->{'id'});
+ ($group_map_entries) = $sth_check_ngm->fetchrow_array();
+ $group_id = $cgi->param("share_$q->{'id'}") || '';
+ }
+ if ($group_id) {
+ if (grep(/^\Q$group_id\E$/, @{$user->queryshare_groups()})) {
+ # $group_id is now definitely a valid ID of a group the
+ # user can see, so we can trick_taint.
+ trick_taint($group_id);
+ if ($group_map_entries == 0) {
+ $sth_insert_ngm->execute($q->{'id'}, $group_id);
+ }
+ else {
+ $sth_update_ngm->execute($group_id, $q->{'id'});
+ }
+
+ # If we're sharing our query with a group we can bless,
+ # we're subscribing direct group members to our search
+ # automatically. Otherwise, the group members need to
+ # opt in. This behaviour is deemed most likely to fit
+ # users' needs.
+ if ($user->can_bless($group_id)) {
+ $sth_direct_group_members->execute($group_id);
+ my $user_id;
+ while ($user_id =
+ $sth_direct_group_members->fetchrow_array()) {
+ next if $user_id == $user->id;
+
+ $sth_check_nl->execute($q->{'id'}, $user_id);
+ my ($already_shown_in_footer) =
+ $sth_check_nl->fetchrow_array();
+ if (! $already_shown_in_footer) {
+ $sth_insert_nl->execute($q->{'id'}, $user_id);
+ }
+ }
+ }
+ }
+ else {
+ # In the unlikely case somebody removed visibility to the
+ # group in the meantime, don't modify sharing.
+ }
+ }
+ else {
+ if ($group_map_entries > 0) {
+ $sth_delete_ngm->execute($q->{'id'});
+ }
+
+ # Don't remove namedqueries_link_in_footer entries for users
+ # subscribing to the shared query. The idea is that they will
+ # probably want to be subscribers again should the sharing
+ # user choose to share the query again.
+ }
+ }
}
$user->flush_queries_cache;
+ # Update profiles.mybugslink.
my $showmybugslink = defined($cgi->param("showmybugslink")) ? 1 : 0;
$dbh->do("UPDATE profiles SET mybugslink = ? WHERE userid = ?",
undef, ($showmybugslink, $user->id));