From 29fe9ea7b41a7363d9a8c02598e371bc817f2d3c Mon Sep 17 00:00:00 2001 From: "gerv%gerv.net" <> Date: Thu, 28 Feb 2002 08:13:56 +0000 Subject: Bug 117060 - templatise userprefs.cgi. We also get a nice new set of tabs and a properly-tabulated email prefs section. --- template/default/prefs/account.tmpl | 56 +++ template/default/prefs/email.tmpl | 156 +++++++ template/default/prefs/footer.tmpl | 75 ++++ template/default/prefs/permissions.tmpl | 56 +++ template/default/prefs/userprefs.tmpl | 105 +++++ userprefs.cgi | 696 +++++++++----------------------- 6 files changed, 644 insertions(+), 500 deletions(-) create mode 100644 template/default/prefs/account.tmpl create mode 100644 template/default/prefs/email.tmpl create mode 100644 template/default/prefs/footer.tmpl create mode 100644 template/default/prefs/permissions.tmpl create mode 100644 template/default/prefs/userprefs.tmpl diff --git a/template/default/prefs/account.tmpl b/template/default/prefs/account.tmpl new file mode 100644 index 000000000..486aba082 --- /dev/null +++ b/template/default/prefs/account.tmpl @@ -0,0 +1,56 @@ +[%# 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 + #%] + +[%# INTERFACE: + # realname: string. The user's real name, if any. + # login: string. The user's Bugzilla login email address. + #%] + + + + + + + + + + + + + + + + + + + + + +
Old password: + + +
New password: + +
Re-enter new password: + +
Your real name (optional, but encouraged): + +
diff --git a/template/default/prefs/email.tmpl b/template/default/prefs/email.tmpl new file mode 100644 index 000000000..2210f2716 --- /dev/null +++ b/template/default/prefs/email.tmpl @@ -0,0 +1,156 @@ +[%# 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 + #%] + +[%# INTERFACE: + # watchedusers: string. + # Comma-separated list of email addresses this user watches. + # excludeself: boolean. + # True if user is not receiving self-generated mail. + # : 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. + #%] + + + [% IF Param('supportwatchers') %] + + + + + + + + + + + + + [% END %] + + + + +
+
+
+ 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. +
Users to watch: + +
+

+ 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. +

+
+ +
+ + + + + + + + + + +
+ Global options: +
+ Only email me reports of changes made by other people + +
+
+ +
+Field/recipient specific options: +
+
+ + + + + + + + + + + + + + + + + [% 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' } ] %] + + [% FOREACH role = [ "Owner", "Reporter", "QAcontact", "CClist", "Voter" ] + %] + + [% END %] + + + [% END %] +
+ When my relationship to this bug is: + + I want to receive mail when: +
+ Reporter + + Assignee + + QA Contact + + CC + + Voter +
+ + + [% reason.description %] +
+ +
diff --git a/template/default/prefs/footer.tmpl b/template/default/prefs/footer.tmpl new file mode 100644 index 000000000..7b0756dbf --- /dev/null +++ b/template/default/prefs/footer.tmpl @@ -0,0 +1,75 @@ +[%# 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 + #%] + +[%# 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. + #%] + + + + + + + + + [% IF queries.size %] + [% FOREACH query = queries %] + + + + + + + [% END %] + + [% ELSE %] + + + + [% END %] + +
The 'My bugs' link: + +
Your query named '[% query.name FILTER html %]': + +
+
+ If you create remembered queries using the + query page, + you can then come to this page and choose to have some of them + appear in the footer of each Bugzilla page. +
+
+
diff --git a/template/default/prefs/permissions.tmpl b/template/default/prefs/permissions.tmpl new file mode 100644 index 000000000..56429a78d --- /dev/null +++ b/template/default/prefs/permissions.tmpl @@ -0,0 +1,56 @@ +[%# 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 + #%] + +[%# 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. + #%] + + + + + +
+ [% IF has_bits.size %] + You have the following permission bits set on your account: +
    + [% FOREACH bit_description = has_bits %] +
  • [% bit_description %]
  • + [% END %] +
+ [% 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 + other users: +

+

    + [% FOREACH bit_description = set_bits %] +
  • [% bit_description %]
  • + [% END %] +
+

+ [% END %] +
diff --git a/template/default/prefs/userprefs.tmpl b/template/default/prefs/userprefs.tmpl new file mode 100644 index 000000000..ba14521df --- /dev/null +++ b/template/default/prefs/userprefs.tmpl @@ -0,0 +1,105 @@ +[%# 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 + #%] + +[%# 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; + }" + %] + +
+ + + + + [% FOREACH tab = tabs %] + [% IF tab.name == current_tab.name %] + + [% ELSE %] + + [% END %] + [% END %] + + + +
  + [% tab.description %] + + [% tab.description %] +  
+
+ +[% IF changes_saved %] +

+ + The changes to your + [% current_tab.description FILTER lower %] have been saved. + +

+[% END %] + +

[% current_tab.description %]

+ +
+ + + [% INCLUDE "prefs/${current_tab.name}.tmpl" %] + + [% IF current_tab.saveable %] + + + + + + + +
+ +
+ [% END %] + +
+ +[% INCLUDE global/footer %] + + + diff --git a/userprefs.cgi b/userprefs.cgi index eb823326a..d86282d08 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -18,6 +18,7 @@ # Alan Raetz # David Miller # Christopher Aillon +# Gervase Markham use diagnostics; use strict; @@ -28,7 +29,7 @@ require "CGI.pl"; 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. sub sillyness { my $zz; @@ -36,618 +37,313 @@ sub sillyness { $zz = $::usergroupset; } +# Use global template variables. +use vars qw($template $vars); + my $userid; -my $showNewEmailTech; - -# 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{$description:$entry\n}; -} +# The default email flags leave all email on. +my $defaultflagstring = "ExcludeSelf~on~"; -sub Error { - my ($msg) = (@_); - print qq{ -$msg -

-Please hit back and try again. -}; - PutFooter(); - exit(); +foreach my $role ("Owner", "Reporter", "QAcontact", "CClist", "Voter") { + foreach my $reason ("Removeme", "Comments", "Attachments", "Status", + "Resolved", "Keywords", "CC", "Other") + { + $defaultflagstring .= "email$role$reason~on~"; + } } +# 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"); - my ($realname) = (FetchSQLData()); - - $realname = value_quote($realname); - - EmitEntry("Old password", - qq|| . - qq||); - EmitEntry("New password", - qq{}); - EmitEntry("Re-enter new password", - qq{}); - EmitEntry("Your real name (optional)", - qq{}); + $vars->{'realname'} = FetchSQLData(); } sub SaveAccount { - if ($::FORM{'Bugzilla_password'} ne "" - || $::FORM{'pwd1'} ne "" || $::FORM{'pwd2'} ne "") { + if ($::FORM{'Bugzilla_password'} ne "" || + $::FORM{'new_password1'} ne "" || + $::FORM{'new_password2'} ne "") + { my $old = SqlQuote($::FORM{'Bugzilla_password'}); - my $pwd1 = SqlQuote($::FORM{'pwd1'}); - my $pwd2 = SqlQuote($::FORM{'pwd2'}); + my $pwd1 = SqlQuote($::FORM{'new_password1'}); + my $pwd2 = SqlQuote($::FORM{'new_password2'}); SendSQL("SELECT cryptpassword FROM profiles WHERE userid = $userid"); my $oldcryptedpwd = FetchOneColumn(); - if ( !$oldcryptedpwd ) { - Error("I was unable to retrieve your old password from the database."); + if (!$oldcryptedpwd) { + DisplayError("I was unable to retrieve your old password from the database."); + exit; } - if ( crypt($::FORM{'Bugzilla_password'}, $oldcryptedpwd) ne $oldcryptedpwd ) { - Error("You did not enter your old password correctly."); + if (crypt($::FORM{'Bugzilla_password'}, $oldcryptedpwd) ne + $oldcryptedpwd) + { + DisplayError("You did not enter your old password correctly."); + exit; } 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 '') { - Error("You must enter a new password."); + if ($::FORM{'new_password1'} eq '') { + DisplayError("You must enter a new password."); + exit; } - my $passworderror = ValidatePassword($::FORM{'pwd1'}); - Error($passworderror) if $passworderror; - - my $cryptedpassword = SqlQuote(Crypt($::FORM{'pwd1'})); - SendSQL("UPDATE profiles - SET cryptpassword = $cryptedpassword - WHERE userid = $userid"); + my $passworderror = ValidatePassword($::FORM{'new_password1'}); + (DisplayError($passworderror) && exit) if $passworderror; + + my $cryptedpassword = SqlQuote(Crypt($::FORM{'new_password1'})); + SendSQL("UPDATE profiles + SET cryptpassword = $cryptedpassword + WHERE userid = $userid"); # Invalidate all logins except for the current one InvalidateLogins($userid, $::COOKIE{"Bugzilla_logincookie"}); } + SendSQL("UPDATE profiles SET " . "realname = " . SqlQuote(trim($::FORM{'realname'})) . " 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")) { my $watcheduserSet = new RelationSet; $watcheduserSet->mergeFromDB("SELECT watched FROM watch WHERE" . " watcher=$userid"); - my $watchedusers = $watcheduserSet->toString(); - - print qq{ -


- -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. -}; - - EmitEntry("Users to watch", - qq{}); + $vars->{'watchedusers'} = $watcheduserSet->toString(); } - print qq{
}; - - showAdvancedEmailFilterOptions(); - -print qq { - -
}; - -} - -sub showAdvancedEmailFilterOptions () { - - my $flags; - my $notify; - my %userEmailFlags = (); - - print qq{ -
- Advanced Email Filtering Options -
-
-

-

- 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. -
-
- }; - 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 - # hasn't been to (the email pane of?) userprefs.cgi since the change to - # use emailflags. create a default flagset for them, based on + # 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 + # use emailflags. Create a default flagset for them, based on # static defaults. - # - if ( !$flags ) { - $flags = $defaultEmailFlagString; - setEmailFlags($flags); + if (!$flagstring) { + $flagstring = $defaultflagstring; + SendSQL("UPDATE profiles SET emailflags = " . + SqlQuote($flagstring) . " WHERE userid = $userid"); } - # the 255 param is here, because without a third param, split will - # trim any trailing null fields, which causes perl to eject lots of - # warnings. any suitably large number would do. - # - %userEmailFlags = split(/~/ , $flags, 255); - - showExcludeSelf(\%userEmailFlags); - - # print STDERR "$flags\n"; - - print qq{ -
-       - Field/recipient specific options:

- }; - - - my @tmpGroups = @emailGroups; - while ((my $groupName,my $groupText) = splice(@tmpGroups,0,2) ) { - printEmailPrefGroup($groupName,$groupText,\%userEmailFlags); - } - -} - -sub showExcludeSelf (\%) { + # The 255 param is here, because without a third param, split will + # trim any trailing null fields, which causes Perl to eject lots of + # warnings. Any suitably large number would do. + my %emailflags = split(/~/, $flagstring, 255); - my %CurrentFlags = %{$_[0]}; - - my $excludeSelf = " "; + $vars->{'excludeself'} = 0; - while ( my ($key,$value) = each (%CurrentFlags) ) { - - # print qq{flag name: $key value: $value
}; - - if ( $key eq 'ExcludeSelf' ) { - - if ( $value eq 'on' ) { - - $excludeSelf = "CHECKED"; - } - } + # 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). + foreach my $key (keys %emailflags) { + # ExcludeSelf is special. + if ($key eq 'ExcludeSelf' && $emailflags{$key} eq 'on') { + $vars->{'excludeself'} = 1; + next; } - print qq { - - - -
      - Global options:
- Only email me reports of changes made by other people - -
-
- }; - -} - -sub printEmailPrefGroup ($$\%) { - - my ($groupName,$textName,$refCurrentFlags) = @_[0,1,2]; - my @tmpFlags = @emailFlags; - - print qq { }; - print qq { }; - - while ((my $flagName,my $flagText) = splice(@tmpFlags,0,2)) { - - printEmailOption($groupName . $flagName, $flagText, $refCurrentFlags); - } - print qq {
      - When I\'m $textName, email me:
}; - print qq {
}; -} - -sub printEmailOption ($$\%) { - - my $value= ''; - - my ($optionName,$description,$refCurrentFlags) = @_[0,1,2]; - - #print qq{ email$optionName: $$refCurrentFlags{"email$optionName"}
}; - - # 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'; + # All other keys match this regexp. + $key =~ /email([A-Z]+[a-z]+)([A-Z]+[a-z]*)/; + + # Create a new hash if we don't have one... + if (!defined($vars->{$1})) { + $vars->{$1} = {}; + } + + if ($emailflags{$key} eq "on") { + $vars->{$1}{$2} = 1; + } } - - print qq{ - - - $description - - }; } -sub SaveEmailOptions () { - - # I don't understand: global variables and %FORM variables are - # not preserved between ShowEmailOptions() and SaveEmailOptions() - # The form value here is from a hidden variable just before the SUBMIT. - - my $useNewEmailTech = $::FORM{'savedEmailTech'}; - my $updateString; - - if ( defined $::FORM{'ExcludeSelf'}) { +# Note: we no longer store "off" values in the database. +sub SaveEmail { + my $updateString = ""; + + if (defined $::FORM{'ExcludeSelf'}) { $updateString .= 'ExcludeSelf~on'; } else { $updateString .= 'ExcludeSelf~'; } - my @tmpGroups = @emailGroups; - - while ((my $groupName,my $groupText) = splice(@tmpGroups,0,2) ) { - - 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; + + foreach my $key (keys %::FORM) { + if ($key =~ /email([A-Z]+[a-z]+)([A-Z]+[a-z]*)/) { + $updateString .= "~$key~on"; } } - - #open(FID,">updateString"); - #print qq{UPDATE STRING: $updateString
}; - #close(FID); - - SendSQL("UPDATE profiles SET emailflags = " . - SqlQuote($updateString) . " WHERE userid = $userid"); - - if (Param("supportwatchers") ) { - - if (exists $::FORM{'watchedusers'}) { - - # Just in case. Note that this much locking is actually overkill: - # we don't really care if anyone reads the watch table. So - # some small amount of contention could be gotten rid of by - # using user-defined locks rather than table locking. - # - SendSQL("LOCK TABLES watch WRITE, profiles READ"); - - # what the db looks like now - # - my $origWatchedUsers = new RelationSet; - $origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" . - " watcher=$userid"); - - # update the database to look like the form - # - my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'}); - 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"); - - } + + SendSQL("UPDATE profiles SET emailflags = " . SqlQuote($updateString) . + " WHERE userid = $userid"); + + if (Param("supportwatchers") && exists $::FORM{'watchedusers'}) { + # Just in case. Note that this much locking is actually overkill: + # we don't really care if anyone reads the watch table. So + # some small amount of contention could be gotten rid of by + # using user-defined locks rather than table locking. + SendSQL("LOCK TABLES watch WRITE, profiles READ"); + + # what the db looks like now + my $origWatchedUsers = new RelationSet; + $origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" . + " watcher=$userid"); + + # Update the database to look like the form + my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'}); + my @CCDELTAS = $origWatchedUsers->generateSqlDeltas( + $newWatchedUsers, + "watch", + "watcher", + $userid, + "watched"); + ($CCDELTAS[0] eq "") || SendSQL($CCDELTAS[0]); + ($CCDELTAS[1] eq "") || SendSQL($CCDELTAS[1]); + + SendSQL("UNLOCK TABLES"); } } - -sub ShowFooter { +sub DoFooter { SendSQL("SELECT mybugslink FROM profiles " . "WHERE userid = $userid"); - my ($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); + $vars->{'mybugslink'} = FetchSQLData(); + SendSQL("SELECT name, linkinfooter FROM namedqueries " . "WHERE userid = $userid"); - my $count = 0; + + my @queries; while (MoreSQLData()) { - my ($name, $linkinfooter) = (FetchSQLData()); - if ($name eq $::defaultqueryname) { - next; - } - 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{\n}; - $count++; - } - print qq{\n}; - if (!$count) { - print qq{ - -If you go create remembered queries in the query page, -you can then come to this page and choose to have some of them appear in the -footer of each Bugzilla page. -}; + my ($name, $footer) = (FetchSQLData()); + next if ($name eq $::defaultqueryname); + + push (@queries, { name => $name, footer => $footer }); } + + $vars->{'queries'} = \@queries; } - sub SaveFooter { my %old; SendSQL("SELECT name, linkinfooter FROM namedqueries " . "WHERE userid = $userid"); while (MoreSQLData()) { - my ($name, $linkinfooter) = (FetchSQLData()); - $old{$name} = $linkinfooter; + my ($name, $footer) = (FetchSQLData()); + $old{$name} = $footer; } - for (my $c=0 ; $c<$::FORM{'numqueries'} ; $c++) { + for (my $c = 0; $c < $::FORM{'numqueries'}; $c++) { my $name = $::FORM{"name-$c"}; if (exists $old{$name}) { my $new = $::FORM{"query-$c"}; if ($new ne $old{$name}) { + detaint_natural($new); SendSQL("UPDATE namedqueries SET linkinfooter = $new " . "WHERE userid = $userid " . "AND name = " . SqlQuote($name)); } } 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'}) . - " WHERE userid = $userid"); + SendSQL("UPDATE profiles SET mybugslink = " . + SqlQuote($::FORM{'mybugslink'}) . " WHERE userid = $userid"); } - - -sub ShowPermissions { - print "You have the following permission bits set on your account:\n"; - print "

    \n"; - my $found = 0; + +sub DoPermissions { + my (@has_bits, @set_bits); + SendSQL("SELECT description FROM groups " . "WHERE bit & $::usergroupset != 0 " . "ORDER BY bit"); while (MoreSQLData()) { - my ($description) = (FetchSQLData()); - print "
  • $description\n"; - $found = 1; - } - if ($found == 0) { - print "
  • (No extra permission bits have been set).\n"; + push(@has_bits, FetchSQLData()); } - print "
\n"; + SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $userid"); my $blessgroupset = FetchOneColumn(); if ($blessgroupset) { - print "And you can turn on or off the following bits for\n"; - print qq{other users:\n}; - print "

    \n"; SendSQL("SELECT description FROM groups " . "WHERE bit & $blessgroupset != 0 " . "ORDER BY bit"); while (MoreSQLData()) { - my ($description) = (FetchSQLData()); - print "
  • $description\n"; + push(@set_bits, FetchSQLData()); } - print "
\n"; } - print "\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(); -print "Content-type: text/html\n\n"; - GetVersionTable(); -PutHeader("User Preferences", "User Preferences", $::COOKIE{'Bugzilla_login'}); - -# foreach my $k (sort(keys(%::FORM))) { -# print "
" . value_quote($k) . ": " . value_quote($::FORM{$k}) . "\n
"; -# } - -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] - ); +$userid = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'}); +$vars->{'login'} = $::COOKIE{'Bugzilla_login'}; +$vars->{'changes_saved'} = $::FORM{'dosave'}; -my $numbanks = @banklist; -my $numcols = $numbanks + 2; +my $current_tab_name = $::FORM{'tab'} || "account"; -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{ -
- - - - - -}; - - -my $bankdescription; -my $showfunc; -my $savefunc; - -foreach my $i (@banklist) { - my ($name, $description) = (@$i); - my $color = ""; - if ($name eq $bank) { - print qq{}; - my $zz; - ($zz, $bankdescription, $showfunc, $savefunc) = (@$i); - } else { - print qq{}; +# Work out the current tab +foreach my $tab (@tabs) { + if ($tab->{'name'} eq $current_tab_name) { + $vars->{'current_tab'} = $tab; + last; } } -print qq{ - -
User preferences
 $description$description 
-
-

-}; - - - -if (defined $bankdescription) { - $userid = DBNameToIdAndCheck($::COOKIE{'Bugzilla_login'}); +$vars->{'tabs'} = \@tabs; - if ($::FORM{'dosave'}) { - &$savefunc; - print "Your changes have been saved."; - } - print qq{

$bankdescription

}; - - # execute subroutine from @banklist based on bank selected. - &$showfunc; - - print qq{
}; - print qq{}; - } else { - print qq{0">}; - } - print qq{ }; - - if ($savefunc) { - print qq{
- -
}; - } - print qq{
\n}; -} else { - print "

Please choose from the above links which settings you wish to change.

"; +# Do any saving, and then display the current tab. +SWITCH: for ($current_tab_name) { + /^account$/ && do { + SaveAccount() if $::FORM{'dosave'}; + DoAccount(); + last SWITCH; + }; + /^email$/ && do { + SaveEmail() if $::FORM{'dosave'}; + DoEmail(); + last SWITCH; + }; + /^footer$/ && do { + SaveFooter() if $::FORM{'dosave'}; + DoFooter(); + last SWITCH; + }; + /^permissions$/ && do { + DoPermissions(); + last SWITCH; + }; } +# 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 "

"; - - -PutFooter(); -- cgit v1.2.3-24-g4f1b