added some safeguards for the mail to community members/conference

participants: to wit, any user can opt-out from ALL those mailings with one
setting; each message now carries a standard disKlaimer indicating how the
user can opt-out (and it's REAL opt-out, not this fakey stuff the spammers do)
This commit is contained in:
Eric J. Bowersox 2001-12-04 20:50:04 +00:00
parent e35045acf4
commit 9cc34facf6
11 changed files with 142 additions and 12 deletions

View File

@ -485,6 +485,55 @@ click the "Manage" button, and click the "Stop Subscribing To This Topic" link.
<!-- Parameters: message.poster, topic.name, topic.locator, conference.name, community.name --> <!-- Parameters: message.poster, topic.name, topic.locator, conference.name, community.name -->
<subj-mail-post>New Post in ${topic.name}</subj-mail-post> <subj-mail-post>New Post in ${topic.name}</subj-mail-post>
<!-- Mass mail notification reminder for communities -->
<!-- Parameters: community.name -->
<mass-community-notice><![CDATA[
You are receiving this message because you are a member of the Venice community "${community.name}".
The sender is a host of this community. To stop receiving mass E-mailed notices from all
Venice community and conference hosts, visit Venice, click on the "Profile" link, check the box labeled
"Don't send me mass E-mail from community/conference hosts," and click Update to save this preference.
]]></mass-community-notice>
<!-- Mass mail notification reminder for conference posters -->
<!-- Parameters: community.name, conference.name -->
<mass-conference-notice-poster><![CDATA[
You are receiving this message because you are a participant in the "${conference.name}" conference
in the Venice community "${community.name}". The sender is a host of this conference. To stop receiving
mass E-mailed notices from all Venice community and conference hosts, visit Venice, click on the "Profile"
link, check the box labeled "Don't send me mass E-mail from community/conference hosts," and click Update
to save this preference.
]]></mass-conference-notice-poster>
<!-- Mass mail notification reminder for conference readers -->
<!-- Parameters: community.name, conference.name -->
<mass-conference-notice-reader><![CDATA[
You are receiving this message because you are a reader of the "${conference.name}" conference
in the Venice community "${community.name}". The sender is a host of this conference. To stop receiving
mass E-mailed notices from all Venice community and conference hosts, visit Venice, click on the "Profile"
link, check the box labeled "Don't send me mass E-mail from community/conference hosts," and click Update
to save this preference.
]]></mass-conference-notice-reader>
<!-- Mass mail notification reminder for topic posters -->
<!-- Parameters: community.name, conference.name, topic.name -->
<mass-topic-notice-poster><![CDATA[
You are receiving this message because you are a participant in the "${topic.name}" topic in the
"${conference.name}" conference in the Venice community "${community.name}". The sender is a host of the
"${conference.name}" conference. To stop receiving mass E-mailed notices from all Venice community and
conference hosts, visit Venice, click on the "Profile" link, check the box labeled "Don't send me mass
E-mail from community/conference hosts," and click Update to save this preference.
]]></mass-topic-notice-poster>
<!-- Mass mail notification reminder for topic readers -->
<!-- Parameters: community.name, conference.name, topic.name -->
<mass-topic-notice-reader><![CDATA[
You are receiving this message because you are a reader of the "${topic.name}" topic in the
"${conference.name}" conference in the Venice community "${community.name}". The sender is a host of the
"${conference.name}" conference. To stop receiving mass E-mailed notices from all Venice community and
conference hosts, visit Venice, click on the "Profile" link, check the box labeled "Don't send me mass
E-mail from community/conference hosts," and click Update to save this preference.
]]></mass-topic-notice-reader>
</messages> </messages>
</venice-config> </venice-config>

View File

@ -257,4 +257,17 @@ public class OptionSet extends BitSet
} // end asString } // end asString
/*--------------------------------------------------------------------------------
* External static operations
*--------------------------------------------------------------------------------
*/
public static final char getOptionChar(int index)
{
if ((index<0) || (index>=ALPHA.length()))
throw new IndexOutOfBoundsException();
return ALPHA.charAt(index);
} // end getOptionChar
} // end class OptionSet } // end class OptionSet

View File

@ -25,6 +25,7 @@ public class UserProperties
*/ */
private boolean display_post_pictures; private boolean display_post_pictures;
private boolean mass_mail_opt_out;
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Constructor * Constructor
@ -34,6 +35,7 @@ public class UserProperties
public UserProperties() public UserProperties()
{ {
display_post_pictures = false; display_post_pictures = false;
mass_mail_opt_out = false;
} // end constructor } // end constructor
@ -54,4 +56,16 @@ public class UserProperties
} // end setDisplayPostPictures } // end setDisplayPostPictures
public final boolean getMassMailOptOut()
{
return mass_mail_opt_out;
} // end getMassMailOptOut
public final void setMassMailOptOut(boolean b)
{
mass_mail_opt_out = b;
} // end setMassMailOptOut
} // end class UserProperties } // end class UserProperties

View File

@ -144,6 +144,7 @@ class AdminUserContextImpl implements AdminUserContext
AdminUserProperties rc = new AdminUserProperties(); AdminUserProperties rc = new AdminUserProperties();
rc.setDisplayPostPictures(flags.get(UserContextImpl.BF_POSTPICTURES)); rc.setDisplayPostPictures(flags.get(UserContextImpl.BF_POSTPICTURES));
rc.setDisallowPhoto(flags.get(UserContextImpl.BF_ADM_NOPHOTO)); rc.setDisallowPhoto(flags.get(UserContextImpl.BF_ADM_NOPHOTO));
rc.setMassMailOptOut(flags.get(UserContextImpl.BF_MASSMAIL_OPTOUT));
return rc; return rc;
} // end createProperties } // end createProperties
@ -156,6 +157,8 @@ class AdminUserContextImpl implements AdminUserContext
rc.set(UserContextImpl.PROP_FLAGS); rc.set(UserContextImpl.PROP_FLAGS);
if (flags.assign(UserContextImpl.BF_ADM_NOPHOTO,props.getDisallowPhoto())) if (flags.assign(UserContextImpl.BF_ADM_NOPHOTO,props.getDisallowPhoto()))
rc.set(UserContextImpl.PROP_FLAGS); rc.set(UserContextImpl.PROP_FLAGS);
if (flags.assign(UserContextImpl.BF_MASSMAIL_OPTOUT,props.getMassMailOptOut()))
rc.set(UserContextImpl.PROP_FLAGS);
return rc; return rc;

View File

@ -1838,9 +1838,11 @@ class CommunityCoreData implements CommunityData, CommunityDataBackend
// create the SQL statement // create the SQL statement
StringBuffer sql = StringBuffer sql =
new StringBuffer("SELECT c.email FROM contacts c, users u, sigmember m " new StringBuffer("SELECT c.email FROM contacts c, users u, sigmember m, propuser p "
+ "WHERE c.contactid = u.contactid AND u.uid = m.uid AND m.sigid = "); + "WHERE c.contactid = u.contactid AND u.uid = m.uid AND m.sigid = ");
sql.append(cid).append(" AND u.is_anon = 0;"); sql.append(cid).append(" AND u.is_anon = 0 AND p.uid = u.uid AND p.ndx = ");
sql.append(UserContextImpl.PROP_FLAGS).append(" AND p.data NOT LIKE '%");
sql.append(OptionSet.getOptionChar(UserContextImpl.BF_MASSMAIL_OPTOUT)).append("%';");
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("SQL: " + sql.toString()); logger.debug("SQL: " + sql.toString());

View File

@ -1378,9 +1378,16 @@ class CommunityUserContextImpl implements CommunityContext, CommunityBackend
// get the mailing list // get the mailing list
List mail_list = getData().getMassMailList(); List mail_list = getData().getMassMailList();
if (mail_list.size()>0) if (mail_list.size()>0)
{ // send the mail in the background! { // prepare the E-mail message text; append the disKlaimer at the end
HashMap vars = new HashMap();
vars.put("community.name",env.getCommunityName());
String disklaimer = env.getStockMessage("mass-community-notice");
StringBuffer buf = new StringBuffer(text);
buf.append("\n\n").append(StringUtil.replaceAllVariables(disklaimer,vars));
// send the mail in the background!
MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(), MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(),
mail_list,subject,text); mail_list,subject,buf.toString());
agent.start(); agent.start();
} // end if } // end if

View File

@ -1528,8 +1528,11 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
sql.append("s.last_post"); sql.append("s.last_post");
else else
sql.append("s.last_read"); sql.append("s.last_read");
sql.append(" FROM contacts c, users u, confsettings s WHERE c.contactid = u.contactid " sql.append(" FROM contacts c, users u, confsettings s, propuser p WHERE c.contactid = u.contactid "
+ "AND u.uid = s.uid AND s.confid = ").append(confid).append(" AND u.is_anon = 0 AND "); + "AND u.uid = s.uid AND s.confid = ").append(confid);
sql.append(" AND u.is_anon = 0 AND u.uid = p.uid AND p.ndx = ").append(UserContextImpl.PROP_FLAGS);
sql.append(" AND p.data NOT LIKE '%");
sql.append(OptionSet.getOptionChar(UserContextImpl.BF_MASSMAIL_OPTOUT)).append("%' AND ");
if (posters) if (posters)
sql.append("ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC;"); sql.append("ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC;");
else else
@ -1570,9 +1573,18 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
} // end finally } // end finally
if (rc.size()>0) if (rc.size()>0)
{ // send the actual E-mail messages in the background { // prepare the E-mail message text; append the disKlaimer at the end
HashMap vars = new HashMap();
vars.put("community.name",env.getCommunityName());
vars.put("conference.name",env.getConferenceName());
String disklaimer =
env.getStockMessage(posters ? "mass-conference-notice-poster" : "mass-conference-notice-reader");
StringBuffer buf = new StringBuffer(text);
buf.append("\n\n").append(StringUtil.replaceAllVariables(disklaimer,vars));
// send the actual E-mail messages in the background
MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(), MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(),
rc,subject,text); rc,subject,buf.toString());
agent.start(); agent.start();
} // end if } // end if

View File

@ -20,6 +20,7 @@ package com.silverwrist.venice.core.impl;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import org.apache.log4j.*; import org.apache.log4j.*;
import com.silverwrist.util.OptionSet;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.core.*; import com.silverwrist.venice.core.*;
import com.silverwrist.venice.core.internals.*; import com.silverwrist.venice.core.internals.*;
@ -1343,8 +1344,11 @@ class TopicUserContextImpl implements TopicContext
sql.append("s.last_post"); sql.append("s.last_post");
else else
sql.append("s.last_read"); sql.append("s.last_read");
sql.append(" FROM contacts c, users u, topicsettings s WHERE c.contactid = u.contactid " sql.append(" FROM contacts c, users u, topicsettings s, propuser p WHERE c.contactid = u.contactid "
+ "AND u.uid = s.uid AND s.topicid = ").append(topicid).append(" AND u.is_anon = 0 AND "); + "AND u.uid = s.uid AND s.topicid = ").append(topicid);
sql.append(" AND u.is_anon = 0 AND u.uid = p.uid AND p.ndx = ").append(UserContextImpl.PROP_FLAGS);
sql.append(" AND p.data NOT LIKE '%");
sql.append(OptionSet.getOptionChar(UserContextImpl.BF_MASSMAIL_OPTOUT)).append("%' AND ");
if (posters) if (posters)
sql.append("ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC;"); sql.append("ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC;");
else else
@ -1385,9 +1389,19 @@ class TopicUserContextImpl implements TopicContext
} // end finally } // end finally
if (rc.size()>0) if (rc.size()>0)
{ // send the actual E-mail messages in the background { // prepare the E-mail message text; append the disKlaimer at the end
HashMap vars = new HashMap();
vars.put("community.name",env.getCommunityName());
vars.put("conference.name",env.getConferenceName());
vars.put("topic.name",name);
String disklaimer =
env.getStockMessage(posters ? "mass-topic-notice-poster" : "mass-topic-notice-reader");
StringBuffer buf = new StringBuffer(text);
buf.append("\n\n").append(StringUtil.replaceAllVariables(disklaimer,vars));
// send the actual E-mail messages in the background
MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(), MailerAgent agent = new MailerAgent(env,env.getUser().realUserName(),env.getUser().realEmailAddress(),
rc,subject,text); rc,subject,buf.toString());
agent.start(); agent.start();
} // end if } // end if

View File

@ -43,6 +43,7 @@ class UserContextImpl implements UserContext, UserBackend
// Boolean flag indexes // Boolean flag indexes
static final int BF_POSTPICTURES = 0; static final int BF_POSTPICTURES = 0;
static final int BF_ADM_NOPHOTO = 1; static final int BF_ADM_NOPHOTO = 1;
static final int BF_MASSMAIL_OPTOUT = 2;
private static Category logger = Category.getInstance(UserContextImpl.class); private static Category logger = Category.getInstance(UserContextImpl.class);
@ -311,6 +312,7 @@ class UserContextImpl implements UserContext, UserBackend
{ {
UserProperties rc = new UserProperties(); UserProperties rc = new UserProperties();
rc.setDisplayPostPictures(flags.get(BF_POSTPICTURES)); rc.setDisplayPostPictures(flags.get(BF_POSTPICTURES));
rc.setMassMailOptOut(flags.get(BF_MASSMAIL_OPTOUT));
return rc; return rc;
} // end createProperties } // end createProperties
@ -321,6 +323,8 @@ class UserContextImpl implements UserContext, UserBackend
if (flags.assign(BF_POSTPICTURES,props.getDisplayPostPictures())) if (flags.assign(BF_POSTPICTURES,props.getDisplayPostPictures()))
rc.set(PROP_FLAGS); rc.set(PROP_FLAGS);
if (flags.assign(BF_MASSMAIL_OPTOUT,props.getMassMailOptOut()))
rc.set(PROP_FLAGS);
return rc; return rc;

View File

@ -148,6 +148,9 @@ public class AdminModifyUserDialog extends ContentDialog
addFormField(new CDFormCategoryHeader("User Preferences")); addFormField(new CDFormCategoryHeader("User Preferences"));
addFormField(new CDCheckBoxFormField("pic_in_post","Display user photos next to conference posts", addFormField(new CDCheckBoxFormField("pic_in_post","Display user photos next to conference posts",
"(where applicable)",YES)); "(where applicable)",YES));
addFormField(new CDCheckBoxFormField("no_mass_mail",
"Don't send user mass E-mail from community/conference hosts",
null,YES));
addFormField(new CDLocaleListFormField("locale","Default locale","(for formatting dates/times)",true)); addFormField(new CDLocaleListFormField("locale","Default locale","(for formatting dates/times)",true));
addFormField(new CDTimeZoneListFormField("tz","Default time zone",null,true)); addFormField(new CDTimeZoneListFormField("tz","Default time zone",null,true));
addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24)); addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24));
@ -289,6 +292,8 @@ public class AdminModifyUserDialog extends ContentDialog
photo_control.setLinkURL("adminuserphoto?uid=" + admuser.getUID()); photo_control.setLinkURL("adminuserphoto?uid=" + admuser.getUID());
if (props.getDisplayPostPictures()) if (props.getDisplayPostPictures())
setFieldValue("pic_in_post",YES); setFieldValue("pic_in_post",YES);
if (props.getMassMailOptOut())
setFieldValue("no_mass_mail",YES);
setFieldValue("locale",admuser.getLocale().toString()); setFieldValue("locale",admuser.getLocale().toString());
setFieldValue("tz",admuser.getTimeZone().getID()); setFieldValue("tz",admuser.getTimeZone().getID());
@ -348,6 +353,7 @@ public class AdminModifyUserDialog extends ContentDialog
ci.setPrivateEmail(YES.equals(getFieldValue("pvt_email"))); ci.setPrivateEmail(YES.equals(getFieldValue("pvt_email")));
ci.setURL(getFieldValue("url")); ci.setURL(getFieldValue("url"));
props.setDisplayPostPictures(YES.equals(getFieldValue("pic_in_post"))); props.setDisplayPostPictures(YES.equals(getFieldValue("pic_in_post")));
props.setMassMailOptOut(YES.equals(getFieldValue("no_mass_mail")));
// Store the completed contact info. // Store the completed contact info.
admuser.putContactInfo(ci); admuser.putContactInfo(ci);

View File

@ -141,6 +141,9 @@ public class EditProfileDialog extends ContentDialog
addFormField(new CDFormCategoryHeader("User Preferences")); addFormField(new CDFormCategoryHeader("User Preferences"));
addFormField(new CDCheckBoxFormField("pic_in_post","Display user photos next to conference posts", addFormField(new CDCheckBoxFormField("pic_in_post","Display user photos next to conference posts",
"(where applicable)",YES)); "(where applicable)",YES));
addFormField(new CDCheckBoxFormField("no_mass_mail",
"Don't send me mass E-mail from community/conference hosts",
null,YES));
addFormField(new CDLocaleListFormField("locale","Default locale","(for formatting dates/times)",true)); addFormField(new CDLocaleListFormField("locale","Default locale","(for formatting dates/times)",true));
addFormField(new CDTimeZoneListFormField("tz","Default time zone",null,true)); addFormField(new CDTimeZoneListFormField("tz","Default time zone",null,true));
addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24)); addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24));
@ -241,6 +244,8 @@ public class EditProfileDialog extends ContentDialog
photo_control.setLinkURL("userphoto?tgt=" + URLEncoder.encode(target)); photo_control.setLinkURL("userphoto?tgt=" + URLEncoder.encode(target));
if (props.getDisplayPostPictures()) if (props.getDisplayPostPictures())
setFieldValue("pic_in_post",YES); setFieldValue("pic_in_post",YES);
if (props.getMassMailOptOut())
setFieldValue("no_mass_mail",YES);
setFieldValue("locale",uc.getLocale().toString()); setFieldValue("locale",uc.getLocale().toString());
setFieldValue("tz",uc.getTimeZone().getID()); setFieldValue("tz",uc.getTimeZone().getID());
@ -285,6 +290,7 @@ public class EditProfileDialog extends ContentDialog
// Save off the properties. // Save off the properties.
props.setDisplayPostPictures(YES.equals(getFieldValue("pic_in_post"))); props.setDisplayPostPictures(YES.equals(getFieldValue("pic_in_post")));
props.setMassMailOptOut(YES.equals(getFieldValue("no_mass_mail")));
uc.setProperties(props); uc.setProperties(props);
// Save off the user's description and preferences. // Save off the user's description and preferences.