No longer CC a user by default
Its annoying to CC a user on every change they make through the web interface, if they performed the change then they know they did it and don't need a carbon-copy cluttering up their inbox. Add a user level preference setting to control whether or not we should CC the user if we are sending an email on their behalf. By default disable it, because this is a common complaint. Bug: issue 311 Change-Id: I431cc0e5df34ef44114bf3e5c92c4f2d5e3f0354 Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -29,6 +29,7 @@ public interface AccountConstants extends Constants {
|
|||||||
String contextWholeFile();
|
String contextWholeFile();
|
||||||
String showSiteHeader();
|
String showSiteHeader();
|
||||||
String useFlashClipboard();
|
String useFlashClipboard();
|
||||||
|
String copySelfOnEmails();
|
||||||
String buttonSaveChanges();
|
String buttonSaveChanges();
|
||||||
|
|
||||||
String tabPreferences();
|
String tabPreferences();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ registeredOn = Registered
|
|||||||
accountId = Account ID
|
accountId = Account ID
|
||||||
showSiteHeader = Show Site Header
|
showSiteHeader = Show Site Header
|
||||||
useFlashClipboard = Use Flash Clipboard Widget
|
useFlashClipboard = Use Flash Clipboard Widget
|
||||||
|
copySelfOnEmails = CC Me On Comments I Write
|
||||||
defaultContextFieldLabel = Default Context:
|
defaultContextFieldLabel = Default Context:
|
||||||
maximumPageSizeFieldLabel = Maximum Page Size:
|
maximumPageSizeFieldLabel = Maximum Page Size:
|
||||||
contextWholeFile = Whole File
|
contextWholeFile = Whole File
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import com.google.gwtjsonrpc.client.VoidResult;
|
|||||||
class PreferencePanel extends Composite {
|
class PreferencePanel extends Composite {
|
||||||
private CheckBox showSiteHeader;
|
private CheckBox showSiteHeader;
|
||||||
private CheckBox useFlashClipboard;
|
private CheckBox useFlashClipboard;
|
||||||
|
private CheckBox copySelfOnEmails;
|
||||||
private ListBox defaultContext;
|
private ListBox defaultContext;
|
||||||
private ListBox maximumPageSize;
|
private ListBox maximumPageSize;
|
||||||
private Button save;
|
private Button save;
|
||||||
@@ -66,6 +67,9 @@ class PreferencePanel extends Composite {
|
|||||||
useFlashClipboard = new CheckBox(Util.C.useFlashClipboard());
|
useFlashClipboard = new CheckBox(Util.C.useFlashClipboard());
|
||||||
useFlashClipboard.addClickHandler(onClickSave);
|
useFlashClipboard.addClickHandler(onClickSave);
|
||||||
|
|
||||||
|
copySelfOnEmails = new CheckBox(Util.C.copySelfOnEmails());
|
||||||
|
copySelfOnEmails.addClickHandler(onClickSave);
|
||||||
|
|
||||||
maximumPageSize = new ListBox();
|
maximumPageSize = new ListBox();
|
||||||
for (final short v : PAGESIZE_CHOICES) {
|
for (final short v : PAGESIZE_CHOICES) {
|
||||||
maximumPageSize.addItem(Util.M.rowsPerPage(v), String.valueOf(v));
|
maximumPageSize.addItem(Util.M.rowsPerPage(v), String.valueOf(v));
|
||||||
@@ -92,7 +96,7 @@ class PreferencePanel extends Composite {
|
|||||||
labelIdx = 0;
|
labelIdx = 0;
|
||||||
fieldIdx = 1;
|
fieldIdx = 1;
|
||||||
}
|
}
|
||||||
final Grid formGrid = new Grid(4, 2);
|
final Grid formGrid = new Grid(5, 2);
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
formGrid.setText(row, labelIdx, "");
|
formGrid.setText(row, labelIdx, "");
|
||||||
@@ -103,6 +107,10 @@ class PreferencePanel extends Composite {
|
|||||||
formGrid.setWidget(row, fieldIdx, useFlashClipboard);
|
formGrid.setWidget(row, fieldIdx, useFlashClipboard);
|
||||||
row++;
|
row++;
|
||||||
|
|
||||||
|
formGrid.setText(row, labelIdx, "");
|
||||||
|
formGrid.setWidget(row, fieldIdx, copySelfOnEmails);
|
||||||
|
row++;
|
||||||
|
|
||||||
formGrid.setText(row, labelIdx, Util.C.maximumPageSizeFieldLabel());
|
formGrid.setText(row, labelIdx, Util.C.maximumPageSizeFieldLabel());
|
||||||
formGrid.setWidget(row, fieldIdx, maximumPageSize);
|
formGrid.setWidget(row, fieldIdx, maximumPageSize);
|
||||||
row++;
|
row++;
|
||||||
@@ -140,6 +148,7 @@ class PreferencePanel extends Composite {
|
|||||||
private void enable(final boolean on) {
|
private void enable(final boolean on) {
|
||||||
showSiteHeader.setEnabled(on);
|
showSiteHeader.setEnabled(on);
|
||||||
useFlashClipboard.setEnabled(on);
|
useFlashClipboard.setEnabled(on);
|
||||||
|
copySelfOnEmails.setEnabled(on);
|
||||||
maximumPageSize.setEnabled(on);
|
maximumPageSize.setEnabled(on);
|
||||||
defaultContext.setEnabled(on);
|
defaultContext.setEnabled(on);
|
||||||
}
|
}
|
||||||
@@ -147,6 +156,7 @@ class PreferencePanel extends Composite {
|
|||||||
private void display(final AccountGeneralPreferences p) {
|
private void display(final AccountGeneralPreferences p) {
|
||||||
showSiteHeader.setValue(p.isShowSiteHeader());
|
showSiteHeader.setValue(p.isShowSiteHeader());
|
||||||
useFlashClipboard.setValue(p.isUseFlashClipboard());
|
useFlashClipboard.setValue(p.isUseFlashClipboard());
|
||||||
|
copySelfOnEmails.setValue(p.isCopySelfOnEmails());
|
||||||
setListBox(maximumPageSize, DEFAULT_PAGESIZE, p.getMaximumPageSize());
|
setListBox(maximumPageSize, DEFAULT_PAGESIZE, p.getMaximumPageSize());
|
||||||
setListBox(defaultContext, DEFAULT_CONTEXT, p.getDefaultContext());
|
setListBox(defaultContext, DEFAULT_CONTEXT, p.getDefaultContext());
|
||||||
}
|
}
|
||||||
@@ -177,6 +187,7 @@ class PreferencePanel extends Composite {
|
|||||||
final AccountGeneralPreferences p = new AccountGeneralPreferences();
|
final AccountGeneralPreferences p = new AccountGeneralPreferences();
|
||||||
p.setShowSiteHeader(showSiteHeader.getValue());
|
p.setShowSiteHeader(showSiteHeader.getValue());
|
||||||
p.setUseFlashClipboard(useFlashClipboard.getValue());
|
p.setUseFlashClipboard(useFlashClipboard.getValue());
|
||||||
|
p.setCopySelfOnEmails(copySelfOnEmails.getValue());
|
||||||
p.setMaximumPageSize(getListBox(maximumPageSize, DEFAULT_PAGESIZE));
|
p.setMaximumPageSize(getListBox(maximumPageSize, DEFAULT_PAGESIZE));
|
||||||
p.setDefaultContext(getListBox(defaultContext, DEFAULT_CONTEXT));
|
p.setDefaultContext(getListBox(defaultContext, DEFAULT_CONTEXT));
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ public final class AccountGeneralPreferences {
|
|||||||
@Column(id = 6, length = 20, notNull = false)
|
@Column(id = 6, length = 20, notNull = false)
|
||||||
protected String downloadCommand;
|
protected String downloadCommand;
|
||||||
|
|
||||||
|
/** If true we CC the user on their own changes. */
|
||||||
|
@Column(id = 7)
|
||||||
|
protected boolean copySelfOnEmail;
|
||||||
|
|
||||||
public AccountGeneralPreferences() {
|
public AccountGeneralPreferences() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,11 +139,20 @@ public final class AccountGeneralPreferences {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCopySelfOnEmails() {
|
||||||
|
return copySelfOnEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopySelfOnEmails(boolean includeSelfOnEmail) {
|
||||||
|
copySelfOnEmail = includeSelfOnEmail;
|
||||||
|
}
|
||||||
|
|
||||||
public void resetToDefaults() {
|
public void resetToDefaults() {
|
||||||
defaultContext = DEFAULT_CONTEXT;
|
defaultContext = DEFAULT_CONTEXT;
|
||||||
maximumPageSize = DEFAULT_PAGESIZE;
|
maximumPageSize = DEFAULT_PAGESIZE;
|
||||||
showSiteHeader = true;
|
showSiteHeader = true;
|
||||||
useFlashClipboard = true;
|
useFlashClipboard = true;
|
||||||
|
copySelfOnEmail = false;
|
||||||
downloadUrl = null;
|
downloadUrl = null;
|
||||||
downloadCommand = null;
|
downloadCommand = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -118,6 +119,14 @@ abstract class EmailHeader {
|
|||||||
list.add(addr);
|
list.add(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remove(java.lang.String email) {
|
||||||
|
for (Iterator<Address> i = list.iterator(); i.hasNext();) {
|
||||||
|
if (i.next().email.equals(email)) {
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
return list.isEmpty();
|
return list.isEmpty();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.google.gerrit.server.account.AccountState;
|
|||||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||||
import com.google.gerrit.server.config.WildProjectName;
|
import com.google.gerrit.server.config.WildProjectName;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
|
import com.google.gerrit.server.mail.EmailHeader.AddressList;
|
||||||
import com.google.gerrit.server.patch.PatchList;
|
import com.google.gerrit.server.patch.PatchList;
|
||||||
import com.google.gerrit.server.patch.PatchListCache;
|
import com.google.gerrit.server.patch.PatchListCache;
|
||||||
import com.google.gerrit.server.patch.PatchListEntry;
|
import com.google.gerrit.server.patch.PatchListEntry;
|
||||||
@@ -52,6 +53,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -165,12 +167,37 @@ public abstract class OutgoingEmail {
|
|||||||
format();
|
format();
|
||||||
if (shouldSendMessage()) {
|
if (shouldSendMessage()) {
|
||||||
if (fromId != null) {
|
if (fromId != null) {
|
||||||
|
final Account fromUser = accountCache.get(fromId).getAccount();
|
||||||
|
|
||||||
|
if (fromUser.getGeneralPreferences().isCopySelfOnEmails()) {
|
||||||
// If we are impersonating a user, make sure they receive a CC of
|
// If we are impersonating a user, make sure they receive a CC of
|
||||||
// this message so they can always review and audit what we sent
|
// this message so they can always review and audit what we sent
|
||||||
// on their behalf to others.
|
// on their behalf to others.
|
||||||
//
|
//
|
||||||
add(RecipientType.CC, fromId);
|
add(RecipientType.CC, fromId);
|
||||||
|
|
||||||
|
} else if (rcptTo.remove(fromId)) {
|
||||||
|
// If they don't want a copy, but we queued one up anyway,
|
||||||
|
// drop them from the recipient lists.
|
||||||
|
//
|
||||||
|
if (rcptTo.isEmpty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String fromEmail = fromUser.getPreferredEmail();
|
||||||
|
for (Iterator<Address> i = smtpRcptTo.iterator(); i.hasNext();) {
|
||||||
|
if (i.next().email.equals(fromEmail)) {
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (EmailHeader hdr : headers.values()) {
|
||||||
|
if (hdr instanceof AddressList) {
|
||||||
|
((AddressList) hdr).remove(fromEmail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (change != null) {
|
if (change != null) {
|
||||||
if (getChangeUrl() != null) {
|
if (getChangeUrl() != null) {
|
||||||
openFooter();
|
openFooter();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import java.util.List;
|
|||||||
/** A version of the database schema. */
|
/** A version of the database schema. */
|
||||||
public abstract class SchemaVersion {
|
public abstract class SchemaVersion {
|
||||||
/** The current schema version. */
|
/** The current schema version. */
|
||||||
private static final Class<? extends SchemaVersion> C = Schema_36.class;
|
private static final Class<? extends SchemaVersion> C = Schema_37.class;
|
||||||
|
|
||||||
public static class Module extends AbstractModule {
|
public static class Module extends AbstractModule {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (C) 2010 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.server.schema;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
public class Schema_37 extends SchemaVersion {
|
||||||
|
@Inject
|
||||||
|
Schema_37(Provider<Schema_36> prior) {
|
||||||
|
super(prior);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user