Commit 29fe9ea7 authored by gerv%gerv.net's avatar gerv%gerv.net

Bug 117060 - templatise userprefs.cgi. We also get a nice new set of tabs and a…

Bug 117060 - templatise userprefs.cgi. We also get a nice new set of tabs and a properly-tabulated email prefs section.
parent 57c0fd68
[%# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
# realname: string. The user's real name, if any.
# login: string. The user's Bugzilla login email address.
#%]
<table>
<tr>
<th align="right">Old password:</th>
<td>
<input type="hidden" name="Bugzilla_login"
value="[% login FILTER html %]" />
<input type="password" name="Bugzilla_password" />
</td>
</tr>
<tr>
<th align="right">New password:</th>
<td>
<input type="password" name="new_password1" />
</td>
</tr>
<tr>
<th align="right">Re-enter new password:</th>
<td>
<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 %]" />
</td>
</tr>
</table>
[%# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
# watchedusers: string.
# Comma-separated list of email addresses this user watches.
# excludeself: boolean.
# True if user is not receiving self-generated mail.
# <rolename>: Multiple hashes, one for each rolename (e.g. owner; see
# below), keyed by reasonname (e.g. comments; again, see
# below). The value is a boolean - true if the user is
# receiving mail for that reason when in that role.
# Also references the 'supportwatchers' Param.
#%]
<table>
[% IF Param('supportwatchers') %]
<tr>
<td colspan="4">
<hr />
</td>
</tr>
<tr>
<td colspan="4">
If you want to help cover for someone when they're on vacation, or if
you need to do the QA related to all of their bugs, you can tell
Bugzilla to send mail related to their bugs to you also. List the
email addresses of any users you wish to watch here, separated by
commas.
</td>
</tr>
<tr>
<th align="right">Users to watch:</th>
<td>
<input size="35" name="watchedusers" value="[% watchedusers %]" />
</td>
</tr>
[% END %]
<tr>
<td colspan="2">
<p>
If you don't like getting a notification for "trivial"
changes to bugs, you can use the settings below to
filter some (or even all) notifications.
</p>
</td>
</tr>
</table>
<hr />
<table>
<tr>
<td colspan="2">
<b>Global options:</b>
</td>
</tr>
<tr>
<td width="150"></td>
<td>
Only email me reports of changes made by other people
<input type="checkbox" name="ExcludeSelf" value="on"
[% " checked" IF excludeself %]>
<br />
</td>
</tr>
</table>
<hr />
<b>Field/recipient specific options:</b>
<br />
<br />
<table width="100%" border="1">
<tr>
<td colspan="5" align="center" width="50%">
<b>When my relationship to this bug is:</b>
</td>
<td rowspan="2" width="50%">
<b>I want to receive mail when:</b>
</td>
</tr>
<tr>
<td align="center" width="10%">
<b>Reporter</b>
</td>
<td align="center" width="10%">
<b>Assignee</b>
</td>
<td align="center" width="10%">
<b>QA Contact</b>
</td>
<td align="center" width="10%">
<b>CC</b>
</td>
<td align="center" width="10%">
<b>Voter</b>
</td>
</tr>
[% FOREACH reason = [
{ name = 'Removeme',
description = 'I\'m added to or removed from this capacity' },
{ name = 'Comments',
description = 'New Comments are added' },
{ name = 'Attachments',
description = 'New Attachments are added' },
{ name = 'Status',
description = 'Priority, status, severity, and/or milestone changes' },
{ name = 'Resolved',
description = 'The bug is resolved or verified' },
{ name = 'Keywords',
description = 'Keywords field changes' },
{ name = 'CC',
description = 'CC field changes' },
{ name = 'Other',
description = 'Any field not mentioned above changes' } ] %]
<tr>
[% FOREACH role = [ "Owner", "Reporter", "QAcontact", "CClist", "Voter" ]
%]
<td align="center">
<input type="checkbox" name="email[% role %][% reason.name %]" value="on"
[% " checked" IF $role.${reason.name} %]>
</td>
[% END %]
<td>
[% reason.description %]
</td>
</tr>
[% END %]
</table>
<br />
[%# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
# mybugslink: boolean. True if the user wishes the My Bugs link to appear.
# queries: array of hashes. May be empty. Each hash has two members:
# name: string. The name of the query.
# footer: boolean. True if the query appears in the footer.
#%]
<table>
<tr>
<th align="right">The 'My bugs' link:</th>
<td>
<select name="mybugslink">
<option value="1">should appear on the footer of every page</option>
<option value="0"
[% " selected" IF NOT mybugslink %]>should not be displayed
</option>
</select>
</td>
</tr>
<input type="hidden" name="numqueries" value="[% queries.size %]" />
[% IF queries.size %]
[% FOREACH query = queries %]
<tr>
<th align="right">Your query named '[% query.name FILTER html %]':</th>
<td>
<select name="query-[% loop.index %]">
<option value="0">should only appear in the query page</option>
<option value="1"
[% " selected" IF query.footer %]>
should appear on the footer of every page
</option>
</select>
</td>
</tr>
<input type="hidden" name="name-[% loop.index %]"
value="[% query.name FILTER html %]" />
[% END %]
[% ELSE %]
<tr>
<td colspan="4">
<br />
If you create remembered queries using the
<a href="query.cgi">query page</a>,
you can then come to this page and choose to have some of them
appear in the footer of each Bugzilla page.
<br />
<br />
</td>
</tr>
[% END %]
</table>
[%# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
# has_bits: array of strings. May be empty.
# Descriptions of the permission bits the user has.
# set_bits: array of strings. May be empty.
# Descriptions of the permission bits the user can set for
# other people.
#%]
<table>
<tr>
<td>
[% IF has_bits.size %]
You have the following permission bits set on your account:
<ul>
[% FOREACH bit_description = has_bits %]
<li>[% bit_description %]</li>
[% END %]
</ul>
[% ELSE %]
There are no permission bits set on your account.
[% END %]
[% IF set_bits.size %]
And you can turn on or off the following bits for
<a HREF="editusers.cgi">other users</a>:
<p>
<ul>
[% FOREACH bit_description = set_bits %]
<li>[% bit_description %]</li>
[% END %]
</ul>
</p>
[% END %]
</td>
</tr>
</table>
[%# 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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[%# INTERFACE:
# login: string. The user's Bugzilla login email address.
# tabs: List of hashes. May not be empty. Each hash has three members:
# name: string. Name of the tab (used internally.)
# description: string. Description of the tab (used in tab title.)
# saveable: boolean. True if tab has a form which can be submitted.
# True if user is not receiving self-generated mail.
# Note: For each tab name, a template "prefs/${tab.name}.tmpl" must exist,
# and its interface must be fulfilled.
# current_tab: A direct reference to one of the hashes in the tabs list.
# This tab will be displayed.
# changes_saved: boolean. True if the CGI processed form data before
# displaying anything.
#%]
[% INCLUDE global/header
title = "User Preferences"
h2 = login
style = "td.selected_tab {
border-width: 2px 2px 0px;
border-style: solid;
}
td.unselected_tab, td.spacer {
border-width: 0px 0px 2px 0px;
border-style: solid;
}"
%]
<center>
<table cellspacing="0" cellpadding="10" border="0" width="100%">
<tr>
<td class="spacer">&nbsp;</td>
[% FOREACH tab = tabs %]
[% IF tab.name == current_tab.name %]
<td align="center" bgcolor="lightblue" class="selected_tab">
[% tab.description %]
</td>
[% ELSE %]
<td align="center" bgcolor="#BBBBEE" class="unselected_tab">
<a HREF="userprefs.cgi?tab=[% tab.name %]">[% tab.description %]</a>
</td>
[% END %]
[% END %]
<td class="spacer">&nbsp;</td>
</tr>
</table>
</center>
[% IF changes_saved %]
<p>
<font color="red">
The changes to your
[% current_tab.description FILTER lower %] have been saved.
</font>
</p>
[% END %]
<h3>[% current_tab.description %]</h3>
<form method="post">
<input type="hidden" name="tab" value="[% current_tab.name %]">
[% INCLUDE "prefs/${current_tab.name}.tmpl" %]
[% IF current_tab.saveable %]
<input type="hidden" name="dosave" value="1">
<table>
<tr>
<td width="150"></td>
<td>
<input type="submit" value="Submit Changes">
</td>
</tr>
</table>
[% END %]
</form>
[% INCLUDE global/footer %]
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# Alan Raetz <al_raetz@yahoo.com> # Alan Raetz <al_raetz@yahoo.com>
# David Miller <justdave@syndicomm.com> # David Miller <justdave@syndicomm.com>
# Christopher Aillon <christopher@aillon.com> # Christopher Aillon <christopher@aillon.com>
# Gervase Markham <gerv@gerv.net>
use diagnostics; use diagnostics;
use strict; use strict;
...@@ -28,7 +29,7 @@ require "CGI.pl"; ...@@ -28,7 +29,7 @@ require "CGI.pl";
use RelationSet; use RelationSet;
# Shut up misguided -w warnings about "used only once". "use vars" just # Shut up misguided -w warnings about "used only once". "use vars" just
# doesn't work for me. # doesn't work for me.
sub sillyness { sub sillyness {
my $zz; my $zz;
...@@ -36,618 +37,313 @@ sub sillyness { ...@@ -36,618 +37,313 @@ sub sillyness {
$zz = $::usergroupset; $zz = $::usergroupset;
} }
# Use global template variables.
use vars qw($template $vars);
my $userid; my $userid;
my $showNewEmailTech; # The default email flags leave all email on.
my $defaultflagstring = "ExcludeSelf~on~";
# Note the use of arrays instead of hashes: we want the items
# displayed in the same order as they appear in the array.
my @emailGroups = (
'Owner', 'the Bug Owner',
'Reporter', 'the Reporter',
'QAcontact', 'the QA contact',
'CClist', 'on the CC list',
'Voter', 'a Voter'
);
my @emailFlags = (
'Removeme', 'When I\'m added to or removed from this capacity',
'Comments', 'New Comments',
'Attachments', 'New Attachments',
'Status', 'Priority, status, severity, and milestone changes',
'Resolved', 'When the bug is resolved or verified',
'Keywords', 'Keywords field changes',
'CC', 'CC field changes',
'Other', 'Any field not mentioned above changes'
);
my $defaultEmailFlagString =
'ExcludeSelf~' . 'on~' .
'emailOwnerRemoveme~' . 'on~' .
'emailOwnerComments~' . 'on~' .
'emailOwnerAttachments~' . 'on~' .
'emailOwnerStatus~' . 'on~' .
'emailOwnerResolved~' . 'on~' .
'emailOwnerKeywords~' . 'on~' .
'emailOwnerCC~' . 'on~' .
'emailOwnerOther~' . 'on~' .
'emailReporterRemoveme~' . 'on~' .
'emailReporterComments~' . 'on~' .
'emailReporterAttachments~' . 'on~' .
'emailReporterStatus~' . 'on~' .
'emailReporterResolved~' . 'on~' .
'emailReporterKeywords~' . 'on~' .
'emailReporterCC~' . 'on~' .
'emailReporterOther~' . 'on~' .
'emailQAcontactRemoveme~' . 'on~' .
'emailQAcontactComments~' . 'on~' .
'emailQAcontactAttachments~' . 'on~' .
'emailQAcontactStatus~' . 'on~' .
'emailQAcontactResolved~' . 'on~' .
'emailQAcontactKeywords~' . 'on~' .
'emailQAcontactCC~' . 'on~' .
'emailQAcontactOther~' . 'on~' .
'emailCClistRemoveme~' . 'on~' .
'emailCClistComments~' . 'on~' .
'emailCClistAttachments~' . 'on~' .
'emailCClistStatus~' . 'on~' .
'emailCClistResolved~' . 'on~' .
'emailCClistKeywords~' . 'on~' .
'emailCClistCC~' . 'on~' .
'emailCClistOther~' . 'on~' .
'emailVoterRemoveme~' . 'on~' .
'emailVoterComments~' . 'on~' .
'emailVoterAttachments~' . 'on~' .
'emailVoterStatus~' . 'on~' .
'emailVoterResolved~' . 'on~' .
'emailVoterKeywords~' . 'on~' .
'emailVoterCC~' . 'on~' .
'emailVoterOther~' . 'on' ;
sub EmitEntry {
my ($description, $entry) = (@_);
print qq{<TR><TH ALIGN="right">$description:</TH><TD>$entry</TD></TR>\n};
}
sub Error { foreach my $role ("Owner", "Reporter", "QAcontact", "CClist", "Voter") {
my ($msg) = (@_); foreach my $reason ("Removeme", "Comments", "Attachments", "Status",
print qq{ "Resolved", "Keywords", "CC", "Other")
$msg {
<P> $defaultflagstring .= "email$role$reason~on~";
Please hit <B>back</B> and try again. }
};
PutFooter();
exit();
} }
# Remove final "~".
chop $defaultflagstring;
sub ShowAccount { ###############################################################################
# Each panel has two functions - panel Foo has a DoFoo, to get the data
# necessary for displaying the panel, and a SaveFoo, to save the panel's
# contents from the form data (if appropriate.)
# SaveFoo may be called before DoFoo.
###############################################################################
sub DoAccount {
SendSQL("SELECT realname FROM profiles WHERE userid = $userid"); SendSQL("SELECT realname FROM profiles WHERE userid = $userid");
my ($realname) = (FetchSQLData()); $vars->{'realname'} = FetchSQLData();
$realname = value_quote($realname);
EmitEntry("Old password",
qq|<input type=hidden name="Bugzilla_login" value="$::COOKIE{Bugzilla_login}">| .
qq|<input type=password name="Bugzilla_password">|);
EmitEntry("New password",
qq{<input type=password name="pwd1">});
EmitEntry("Re-enter new password",
qq{<input type=password name="pwd2">});
EmitEntry("Your real name (optional)",
qq{<INPUT SIZE=35 NAME="realname" VALUE="$realname">});
} }
sub SaveAccount { sub SaveAccount {
if ($::FORM{'Bugzilla_password'} ne "" if ($::FORM{'Bugzilla_password'} ne "" ||
|| $::FORM{'pwd1'} ne "" || $::FORM{'pwd2'} ne "") { $::FORM{'new_password1'} ne "" ||
$::FORM{'new_password2'} ne "")
{
my $old = SqlQuote($::FORM{'Bugzilla_password'}); my $old = SqlQuote($::FORM{'Bugzilla_password'});
my $pwd1 = SqlQuote($::FORM{'pwd1'}); my $pwd1 = SqlQuote($::FORM{'new_password1'});
my $pwd2 = SqlQuote($::FORM{'pwd2'}); my $pwd2 = SqlQuote($::FORM{'new_password2'});
SendSQL("SELECT cryptpassword FROM profiles WHERE userid = $userid"); SendSQL("SELECT cryptpassword FROM profiles WHERE userid = $userid");
my $oldcryptedpwd = FetchOneColumn(); my $oldcryptedpwd = FetchOneColumn();
if ( !$oldcryptedpwd ) { if (!$oldcryptedpwd) {
Error("I was unable to retrieve your old password from the database."); DisplayError("I was unable to retrieve your old password from the database.");
exit;
} }
if ( crypt($::FORM{'Bugzilla_password'}, $oldcryptedpwd) ne $oldcryptedpwd ) { if (crypt($::FORM{'Bugzilla_password'}, $oldcryptedpwd) ne
Error("You did not enter your old password correctly."); $oldcryptedpwd)
{
DisplayError("You did not enter your old password correctly.");
exit;
} }
if ($pwd1 ne $pwd2) { if ($pwd1 ne $pwd2) {
Error("The two passwords you entered did not match."); DisplayError("The two passwords you entered did not match.");
exit;
} }
if ($::FORM{'pwd1'} eq '') { if ($::FORM{'new_password1'} eq '') {
Error("You must enter a new password."); DisplayError("You must enter a new password.");
exit;
} }
my $passworderror = ValidatePassword($::FORM{'pwd1'}); my $passworderror = ValidatePassword($::FORM{'new_password1'});
Error($passworderror) if $passworderror; (DisplayError($passworderror) && exit) if $passworderror;
my $cryptedpassword = SqlQuote(Crypt($::FORM{'pwd1'})); my $cryptedpassword = SqlQuote(Crypt($::FORM{'new_password1'}));
SendSQL("UPDATE profiles SendSQL("UPDATE profiles
SET cryptpassword = $cryptedpassword SET cryptpassword = $cryptedpassword
WHERE userid = $userid"); WHERE userid = $userid");
# Invalidate all logins except for the current one # Invalidate all logins except for the current one
InvalidateLogins($userid, $::COOKIE{"Bugzilla_logincookie"}); InvalidateLogins($userid, $::COOKIE{"Bugzilla_logincookie"});
} }
SendSQL("UPDATE profiles SET " . SendSQL("UPDATE profiles SET " .
"realname = " . SqlQuote(trim($::FORM{'realname'})) . "realname = " . SqlQuote(trim($::FORM{'realname'})) .
" WHERE userid = $userid"); " WHERE userid = $userid");
} }
#
# Set email flags in database based on the parameter string.
#
sub setEmailFlags ($) {
my $emailFlagString = $_[0];
SendSQL("UPDATE profiles SET emailflags = " .
SqlQuote($emailFlagString) . " WHERE userid = $userid");
}
sub ShowEmailOptions () {
sub DoEmail {
if (Param("supportwatchers")) { if (Param("supportwatchers")) {
my $watcheduserSet = new RelationSet; my $watcheduserSet = new RelationSet;
$watcheduserSet->mergeFromDB("SELECT watched FROM watch WHERE" . $watcheduserSet->mergeFromDB("SELECT watched FROM watch WHERE" .
" watcher=$userid"); " watcher=$userid");
my $watchedusers = $watcheduserSet->toString(); $vars->{'watchedusers'} = $watcheduserSet->toString();
print qq{
<TR><TD COLSPAN="4"><HR></TD></TR>
<TR><TD COLSPAN="4">
If you want to help cover for someone when they're on vacation, or if
you need to do the QA related to all of their bugs, you can tell bugzilla
to send mail related to their bugs to you also. List the email addresses
of any users you wish to watch here, separated by commas.
</TD></TR>};
EmitEntry("Users to watch",
qq{<INPUT SIZE=35 NAME="watchedusers" VALUE="$watchedusers">});
} }
print qq{<TR><TD COLSPAN="2"><HR></TD></TR>};
showAdvancedEmailFilterOptions();
print qq {
<TABLE CELLSPACING="0" CELLPADDING="10" BORDER=0 WIDTH="100%">
<TR><TD>};
}
sub showAdvancedEmailFilterOptions () {
my $flags;
my $notify;
my %userEmailFlags = ();
print qq{
<TR><TD COLSPAN="2"><center>
<font size=+1>Advanced Email Filtering Options</font>
</center>
</TD></TR><tr><td colspan="2">
<p>
<center>
If you don't like getting a notification for "trivial"
changes to bugs, you can use the settings below to
filter some (or even all) notifications.
</center></td></tr></table>
<hr width=800 align=center>
};
SendSQL("SELECT emailflags FROM profiles WHERE userid = $userid"); SendSQL("SELECT emailflags FROM profiles WHERE userid = $userid");
($flags) = FetchSQLData(); my ($flagstring) = FetchSQLData();
# if the emailflags haven't been set before, that means that this user # If the emailflags haven't been set before, that means that this user
# hasn't been to (the email pane of?) userprefs.cgi since the change to # hasn't been to the email pane of userprefs.cgi since the change to
# use emailflags. create a default flagset for them, based on # use emailflags. Create a default flagset for them, based on
# static defaults. # static defaults.
# if (!$flagstring) {
if ( !$flags ) { $flagstring = $defaultflagstring;
$flags = $defaultEmailFlagString; SendSQL("UPDATE profiles SET emailflags = " .
setEmailFlags($flags); SqlQuote($flagstring) . " WHERE userid = $userid");
} }
# the 255 param is here, because without a third param, split will # The 255 param is here, because without a third param, split will
# trim any trailing null fields, which causes perl to eject lots of # trim any trailing null fields, which causes Perl to eject lots of
# warnings. any suitably large number would do. # warnings. Any suitably large number would do.
# my %emailflags = split(/~/, $flagstring, 255);
%userEmailFlags = split(/~/ , $flags, 255);
showExcludeSelf(\%userEmailFlags);
# print STDERR "$flags\n";
print qq{
<hr width=800 align=left>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b>Field/recipient specific options:</b><br><br>
};
my @tmpGroups = @emailGroups;
while ((my $groupName,my $groupText) = splice(@tmpGroups,0,2) ) {
printEmailPrefGroup($groupName,$groupText,\%userEmailFlags);
}
}
sub showExcludeSelf (\%) {
my %CurrentFlags = %{$_[0]}; $vars->{'excludeself'} = 0;
my $excludeSelf = " ";
while ( my ($key,$value) = each (%CurrentFlags) ) { # Parse the info into a hash of hashes; the first hash keyed by role,
# the second by reason, and the value being 1 or 0 (undef).
# print qq{flag name: $key value: $value<br>}; foreach my $key (keys %emailflags) {
# ExcludeSelf is special.
if ( $key eq 'ExcludeSelf' ) { if ($key eq 'ExcludeSelf' && $emailflags{$key} eq 'on') {
$vars->{'excludeself'} = 1;
if ( $value eq 'on' ) { next;
$excludeSelf = "CHECKED";
}
}
} }
print qq { # All other keys match this regexp.
<table><tr><td colspan=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $key =~ /email([A-Z]+[a-z]+)([A-Z]+[a-z]*)/;
<b>Global options:</b></tr>
<tr><td width=150></td><td> # Create a new hash if we don't have one...
Only email me reports of changes made by other people if (!defined($vars->{$1})) {
<input type="checkbox" name="ExcludeSelf" VALUE="on" $excludeSelf> $vars->{$1} = {};
<br> }
</td>
</tr> if ($emailflags{$key} eq "on") {
</table> $vars->{$1}{$2} = 1;
}; }
}
sub printEmailPrefGroup ($$\%) {
my ($groupName,$textName,$refCurrentFlags) = @_[0,1,2];
my @tmpFlags = @emailFlags;
print qq {<table cellspacing=0 cellpadding=6> };
print qq {<tr><td colspan=2> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
When I\'m $textName, email me:</td></tr> };
while ((my $flagName,my $flagText) = splice(@tmpFlags,0,2)) {
printEmailOption($groupName . $flagName, $flagText, $refCurrentFlags);
}
print qq { </table> };
print qq { <hr WIDTH=320 ALIGN=left> };
}
sub printEmailOption ($$\%) {
my $value= '';
my ($optionName,$description,$refCurrentFlags) = @_[0,1,2];
#print qq{ email$optionName: $$refCurrentFlags{"email$optionName"} <br>};
# if the db value is 'on', then mark that checkbox
if ($$refCurrentFlags{"email$optionName"} eq 'on'){
$value = 'CHECKED';
}
# **** Kludge ... also mark on if the value in $$refCurrentFlags in undef
if (!defined($$refCurrentFlags{"email$optionName"})) {
$value = 'CHECKED';
} }
print qq{
<tr><td width=320></td>
<td><input type="checkbox" name="email$optionName" VALUE="on" $value>
$description</td>
</tr>
};
} }
sub SaveEmailOptions () { # Note: we no longer store "off" values in the database.
sub SaveEmail {
# I don't understand: global variables and %FORM variables are my $updateString = "";
# not preserved between ShowEmailOptions() and SaveEmailOptions()
# The form value here is from a hidden variable just before the SUBMIT. if (defined $::FORM{'ExcludeSelf'}) {
my $useNewEmailTech = $::FORM{'savedEmailTech'};
my $updateString;
if ( defined $::FORM{'ExcludeSelf'}) {
$updateString .= 'ExcludeSelf~on'; $updateString .= 'ExcludeSelf~on';
} else { } else {
$updateString .= 'ExcludeSelf~'; $updateString .= 'ExcludeSelf~';
} }
my @tmpGroups = @emailGroups;
foreach my $key (keys %::FORM) {
while ((my $groupName,my $groupText) = splice(@tmpGroups,0,2) ) { if ($key =~ /email([A-Z]+[a-z]+)([A-Z]+[a-z]*)/) {
$updateString .= "~$key~on";
my @tmpFlags = @emailFlags;
while ((my $flagName,my $flagText) = splice(@tmpFlags,0,2) ) {
my $entry = 'email' . $groupName . $flagName;
my $entryValue;
if (!defined $::FORM{$entry} ) {
$entryValue = "";
} else {
$entryValue = $::FORM{$entry};
}
$updateString .= '~' . $entry . '~' . $entryValue;
} }
} }
#open(FID,">updateString"); SendSQL("UPDATE profiles SET emailflags = " . SqlQuote($updateString) .
#print qq{UPDATE STRING: $updateString <br>}; " WHERE userid = $userid");
#close(FID);
if (Param("supportwatchers") && exists $::FORM{'watchedusers'}) {
SendSQL("UPDATE profiles SET emailflags = " . # Just in case. Note that this much locking is actually overkill:
SqlQuote($updateString) . " WHERE userid = $userid"); # we don't really care if anyone reads the watch table. So
# some small amount of contention could be gotten rid of by
if (Param("supportwatchers") ) { # using user-defined locks rather than table locking.
SendSQL("LOCK TABLES watch WRITE, profiles READ");
if (exists $::FORM{'watchedusers'}) {
# what the db looks like now
# Just in case. Note that this much locking is actually overkill: my $origWatchedUsers = new RelationSet;
# we don't really care if anyone reads the watch table. So $origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" .
# some small amount of contention could be gotten rid of by " watcher=$userid");
# using user-defined locks rather than table locking.
# # Update the database to look like the form
SendSQL("LOCK TABLES watch WRITE, profiles READ"); my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'});
my @CCDELTAS = $origWatchedUsers->generateSqlDeltas(
# what the db looks like now $newWatchedUsers,
# "watch",
my $origWatchedUsers = new RelationSet; "watcher",
$origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" . $userid,
" watcher=$userid"); "watched");
($CCDELTAS[0] eq "") || SendSQL($CCDELTAS[0]);
# update the database to look like the form ($CCDELTAS[1] eq "") || SendSQL($CCDELTAS[1]);
#
my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'}); SendSQL("UNLOCK TABLES");
my @CCDELTAS = $origWatchedUsers->generateSqlDeltas(
$newWatchedUsers,
"watch",
"watcher",
$userid,
"watched");
$CCDELTAS[0] eq "" || SendSQL($CCDELTAS[0]);
$CCDELTAS[1] eq "" || SendSQL($CCDELTAS[1]);
# all done
#
SendSQL("UNLOCK TABLES");
}
} }
} }
sub DoFooter {
sub ShowFooter {
SendSQL("SELECT mybugslink FROM profiles " . SendSQL("SELECT mybugslink FROM profiles " .
"WHERE userid = $userid"); "WHERE userid = $userid");
my ($mybugslink) = (FetchSQLData()); $vars->{'mybugslink'} = FetchSQLData();
my $entry =
BuildPulldown("mybugslink",
[["1", "should appear"],
["0", "should not be displayed"]],
$mybugslink);
EmitEntry("The 'My bugs' link at the footer of each page", $entry);
SendSQL("SELECT name, linkinfooter FROM namedqueries " . SendSQL("SELECT name, linkinfooter FROM namedqueries " .
"WHERE userid = $userid"); "WHERE userid = $userid");
my $count = 0;
my @queries;
while (MoreSQLData()) { while (MoreSQLData()) {
my ($name, $linkinfooter) = (FetchSQLData()); my ($name, $footer) = (FetchSQLData());
if ($name eq $::defaultqueryname) { next if ($name eq $::defaultqueryname);
next;
} push (@queries, { name => $name, footer => $footer });
my $entry =
BuildPulldown("query-$count",
[["0", "should only appear in the query page"],
["1", "should appear on the footer of every page"]],
$linkinfooter);
EmitEntry("Your query named '$name'", $entry);
my $q = value_quote($name);
print qq{<INPUT TYPE=HIDDEN NAME="name-$count" VALUE="$q">\n};
$count++;
}
print qq{<INPUT TYPE=HIDDEN NAME="numqueries" VALUE="$count">\n};
if (!$count) {
print qq{
<TR><TD COLSPAN="4">
If you go create remembered queries in the <A HREF="query.cgi">query page</A>,
you can then come to this page and choose to have some of them appear in the
footer of each Bugzilla page.
</TD></TR>};
} }
$vars->{'queries'} = \@queries;
} }
sub SaveFooter { sub SaveFooter {
my %old; my %old;
SendSQL("SELECT name, linkinfooter FROM namedqueries " . SendSQL("SELECT name, linkinfooter FROM namedqueries " .
"WHERE userid = $userid"); "WHERE userid = $userid");
while (MoreSQLData()) { while (MoreSQLData()) {
my ($name, $linkinfooter) = (FetchSQLData()); my ($name, $footer) = (FetchSQLData());
$old{$name} = $linkinfooter; $old{$name} = $footer;
} }
for (my $c=0 ; $c<$::FORM{'numqueries'} ; $c++) { for (my $c = 0; $c < $::FORM{'numqueries'}; $c++) {
my $name = $::FORM{"name-$c"}; my $name = $::FORM{"name-$c"};
if (exists $old{$name}) { if (exists $old{$name}) {
my $new = $::FORM{"query-$c"}; my $new = $::FORM{"query-$c"};
if ($new ne $old{$name}) { if ($new ne $old{$name}) {
detaint_natural($new);
SendSQL("UPDATE namedqueries SET linkinfooter = $new " . SendSQL("UPDATE namedqueries SET linkinfooter = $new " .
"WHERE userid = $userid " . "WHERE userid = $userid " .
"AND name = " . SqlQuote($name)); "AND name = " . SqlQuote($name));
} }
} else { } else {
Error("Hmm, the $name query seems to have gone away."); DisplayError("Hmm, the $name query seems to have gone away.");
} }
} }
SendSQL("UPDATE profiles SET mybugslink = " . SqlQuote($::FORM{'mybugslink'}) . SendSQL("UPDATE profiles SET mybugslink = " .
" WHERE userid = $userid"); SqlQuote($::FORM{'mybugslink'}) . " WHERE userid = $userid");
} }
sub DoPermissions {
sub ShowPermissions { my (@has_bits, @set_bits);
print "<TR><TD>You have the following permission bits set on your account:\n";
print "<P><UL>\n";
my $found = 0;
SendSQL("SELECT description FROM groups " . SendSQL("SELECT description FROM groups " .
"WHERE bit & $::usergroupset != 0 " . "WHERE bit & $::usergroupset != 0 " .
"ORDER BY bit"); "ORDER BY bit");
while (MoreSQLData()) { while (MoreSQLData()) {
my ($description) = (FetchSQLData()); push(@has_bits, FetchSQLData());
print "<LI>$description\n";
$found = 1;
}
if ($found == 0) {
print "<LI>(No extra permission bits have been set).\n";
} }
print "</UL>\n";
SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid"); SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid");
my $blessgroupset = FetchOneColumn(); my $blessgroupset = FetchOneColumn();
if ($blessgroupset) { if ($blessgroupset) {
print "And you can turn on or off the following bits for\n";
print qq{<A HREF="editusers.cgi">other users</A>:\n};
print "<P><UL>\n";
SendSQL("SELECT description FROM groups " . SendSQL("SELECT description FROM groups " .
"WHERE bit & $blessgroupset != 0 " . "WHERE bit & $blessgroupset != 0 " .
"ORDER BY bit"); "ORDER BY bit");
while (MoreSQLData()) { while (MoreSQLData()) {
my ($description) = (FetchSQLData()); push(@set_bits, FetchSQLData());
print "<LI>$description\n";
} }
print "</UL>\n";
} }
print "</TR></TD>\n";
$vars->{'has_bits'} = \@has_bits;
$vars->{'set_bits'} = \@set_bits;
} }
######################################################################
################# Live code (not sub defs) starts here ###############
# No SavePermissions() because this panel has no changeable fields.
###############################################################################
# Live code (not subroutine definitions) starts here
###############################################################################
confirm_login(); confirm_login();
print "Content-type: text/html\n\n";
GetVersionTable(); GetVersionTable();
PutHeader("User Preferences", "User Preferences", $::COOKIE{'Bugzilla_login'}); $userid = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'});
# foreach my $k (sort(keys(%::FORM))) {
# print "<pre>" . value_quote($k) . ": " . value_quote($::FORM{$k}) . "\n</pre>";
# }
my $bank = $::FORM{'bank'} || "account";
my @banklist = (
["account", "Account settings",
\&ShowAccount, \&SaveAccount],
["diffs", "Email settings",
\&ShowEmailOptions, \&SaveEmailOptions],
["footer", "Page footer",
\&ShowFooter, \&SaveFooter],
["permissions", "Permissions",
\&ShowPermissions, undef]
);
$vars->{'login'} = $::COOKIE{'Bugzilla_login'};
$vars->{'changes_saved'} = $::FORM{'dosave'};
my $numbanks = @banklist; my $current_tab_name = $::FORM{'tab'} || "account";
my $numcols = $numbanks + 2;
my $headcol = '"lightblue"'; my @tabs = ( { name => "account", description => "Account settings",
saveable => "1" },
{ name => "email", description => "Email settings",
saveable => "1" },
{ name => "footer", description => "Page footer",
saveable => "1" },
{ name => "permissions", description => "Permissions",
saveable => "0" } );
print qq{ # Work out the current tab
<CENTER> foreach my $tab (@tabs) {
<TABLE CELLSPACING="0" CELLPADDING="10" BORDER=0 WIDTH="100%"> if ($tab->{'name'} eq $current_tab_name) {
<TR> $vars->{'current_tab'} = $tab;
<TH COLSPAN="$numcols" BGCOLOR="lightblue">User preferences</TH> last;
</TR>
<TR><TD BGCOLOR=$headcol>&nbsp;</TD>
};
my $bankdescription;
my $showfunc;
my $savefunc;
foreach my $i (@banklist) {
my ($name, $description) = (@$i);
my $color = "";
if ($name eq $bank) {
print qq{<TD ALIGN="center">$description</TD>};
my $zz;
($zz, $bankdescription, $showfunc, $savefunc) = (@$i);
} else {
print qq{<TD ALIGN="center" BGCOLOR="lightblue"><A HREF="userprefs.cgi?bank=$name">$description</A></TD>};
} }
} }
print qq{
<TD BGCOLOR=$headcol>&nbsp;</TD></TR>
</TABLE>
</CENTER>
<P>
};
if (defined $bankdescription) { $vars->{'tabs'} = \@tabs;
$userid = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'});
if ($::FORM{'dosave'}) { # Do any saving, and then display the current tab.
&$savefunc; SWITCH: for ($current_tab_name) {
print "Your changes have been saved."; /^account$/ && do {
} SaveAccount() if $::FORM{'dosave'};
print qq{<H3>$bankdescription</H3><FORM METHOD="POST"><TABLE>}; DoAccount();
last SWITCH;
# execute subroutine from @banklist based on bank selected. };
&$showfunc; /^email$/ && do {
SaveEmail() if $::FORM{'dosave'};
print qq{</TABLE><INPUT TYPE="hidden" NAME="dosave" VALUE="1">}; DoEmail();
print qq{<INPUT TYPE="hidden" NAME="savedEmailTech" VALUE="}; last SWITCH;
};
# default this to 0 if it's not already set /^footer$/ && do {
# SaveFooter() if $::FORM{'dosave'};
if (defined $showNewEmailTech) { DoFooter();
print qq{$showNewEmailTech">}; last SWITCH;
} else { };
print qq{0">}; /^permissions$/ && do {
} DoPermissions();
print qq{<INPUT TYPE="hidden" NAME="bank" VALUE="$bank"> }; last SWITCH;
};
if ($savefunc) {
print qq{<table><tr><td width=150></td><td>
<INPUT TYPE="submit" VALUE="Submit Changes">
</td></tr></table> };
}
print qq{</FORM>\n};
} else {
print "<P>Please choose from the above links which settings you wish to change.</P>";
} }
# Generate and return the UI (HTML page) from the appropriate template.
print "Content-type: text/html\n\n";
$template->process("prefs/userprefs.tmpl", $vars)
|| DisplayError("Template process failed: " . $template->error())
&& exit;
print "<P>";
PutFooter();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment