implementation of the "bozo filter" on a topic level, including a topic-level

"Manage" screen (to hang "Rename Topic" from later, too).
This commit is contained in:
Eric J. Bowersox
2001-11-09 00:10:36 +00:00
parent bc859178f2
commit 0bb2e795a4
13 changed files with 727 additions and 38 deletions

View File

@@ -0,0 +1,146 @@
/*
* 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 Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util;
import java.util.BitSet;
public class OptionSet extends BitSet
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static final String ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ "!#$%&()*+,-./:;<=>?@[]^_`{|}~";
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public OptionSet()
{
super();
} // end constructor
public OptionSet(int nbits)
{
super(Math.min(nbits,ALPHA.length()));
} // end constructor
public OptionSet(char[] options)
{
super(); // initialize all bits to 0
for (int i=0; i<options.length; i++)
{ // look at all the chars in the option string and set bits accordingly
int ndx = ALPHA.indexOf(options[i]);
if (ndx>=0)
super.set(ndx);
} // end for
} // end constructor
public OptionSet(String options)
{
this(options.toCharArray());
} // end constructor
private StringBuffer asStringBuffer()
{
StringBuffer b = new StringBuffer();
for (int i=0; i<super.length(); i++)
if (super.get(i))
b.append(ALPHA.charAt(i));
return b;
} // end asStringBuffer
/*--------------------------------------------------------------------------------
* Overrides from class BitSet
*--------------------------------------------------------------------------------
*/
public void clear(int bitIndex)
{
if (bitIndex>=ALPHA.length())
throw new IndexOutOfBoundsException();
super.clear(bitIndex);
} // end clear
public boolean get(int bitIndex)
{
if (bitIndex>=ALPHA.length())
throw new IndexOutOfBoundsException();
return super.get(bitIndex);
} // end get
public void set(int bitIndex)
{
if (bitIndex>=ALPHA.length())
throw new IndexOutOfBoundsException();
super.set(bitIndex);
} // end set
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public void assign(char[] options)
{
int i;
for (i=0; i<super.length(); i++)
super.clear(i);
for (i=0; i<options.length; i++)
{ // look at all the chars in the option string and set bits accordingly
int ndx = ALPHA.indexOf(options[i]);
if (ndx>=0)
super.set(ndx);
} // end for
} // end assign
public void assign(String options)
{
assign(options.toCharArray());
} // end assign
public char[] asCharArray()
{
return asStringBuffer().toString().toCharArray();
} // end asCharArray
public String asString()
{
return asStringBuffer().toString();
} // end asString
} // end class OptionSet

View File

@@ -90,5 +90,13 @@ public interface TopicContext
public abstract List getActiveReaders() throws DataException, AccessError;
public abstract boolean isBozo(int other_uid) throws DataException;
public abstract void setBozo(int other_uid, boolean bozo) throws DataException;
public abstract boolean canSetBozo(int other_uid);
public abstract List getBozos() throws DataException;
} // end interface TopicContext

View File

@@ -96,6 +96,7 @@ class BackgroundConferencePurge implements Runnable
{ // delete the topic header and settings rows first
stmt.executeUpdate("DELETE FROM topics WHERE topicid = " + topicids[i] + ";");
stmt.executeUpdate("DELETE FROM topicsettings WHERE topicid = " + topicids[i] + ";");
stmt.executeUpdate("DELETE FROM topicbozo WHERE topicid = " + topicids[i] + ";");
// figure out how many posts are in this topic and create a BackgroundTopicPurge.
sql.setLength(0);

View File

@@ -54,6 +54,7 @@ class TopicUserContextImpl implements TopicContext
private boolean hidden;
private int unread;
private boolean deleted = false;
private HashSet bozo_uids = null;
/*--------------------------------------------------------------------------------
* Constructors
@@ -99,6 +100,7 @@ class TopicUserContextImpl implements TopicContext
this.name = name;
this.hidden = false;
this.unread = 1;
this.bozo_uids = new HashSet(); // no bozos yet
} // end constructor
@@ -160,6 +162,18 @@ class TopicUserContextImpl implements TopicContext
} // end refresh
private void loadBozo(Connection conn) throws SQLException
{
Statement stmt = conn.createStatement();
StringBuffer sql = new StringBuffer("SELECT bozo_uid FROM topicbozo WHERE topicid = ");
sql.append(topicid).append(" AND uid = ").append(conf.realUID()).append(';');
ResultSet rs = stmt.executeQuery(sql.toString());
bozo_uids = new HashSet();
while (rs.next())
bozo_uids.add(new Integer(rs.getInt(1)));
} // end loadBozo
/*--------------------------------------------------------------------------------
* Implementations from interface TopicContext
*--------------------------------------------------------------------------------
@@ -874,7 +888,8 @@ class TopicUserContextImpl implements TopicContext
Statement stmt = conn.createStatement();
// lock some tables while we do the critical parts of the delete
stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, posts READ;");
stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, topicbozo WRITE, "
+ "posts READ;");
try
{ // first delete the topic record itself
StringBuffer sql = new StringBuffer("DELETE FROM topics WHERE topicid = ");
@@ -886,6 +901,11 @@ class TopicUserContextImpl implements TopicContext
sql.append("DELETE FROM topicsettings WHERE topicid = ").append(topicid).append(';');
stmt.executeUpdate(sql.toString());
// and all topicbozo records
sql.setLength(0);
sql.append("DELETE FROM topicbozo WHERE topicid = ").append(topicid).append(';');
stmt.executeUpdate(sql.toString());
// and indicate that we updated the conference
conf.touchUpdate(conn,new java.util.Date());
@@ -1068,6 +1088,145 @@ class TopicUserContextImpl implements TopicContext
} // end getActiveReaders
public boolean isBozo(int other_uid) throws DataException
{
if (deleted || conf.userIsAnonymous() || (other_uid==conf.realUID()))
return false; // no-op
if (bozo_uids==null)
{ // the bozo UIDs need to be loaded!
Connection conn = null;
try
{ // load the bozo filter UIDs from the database
conn = datapool.getConnection();
loadBozo(conn);
} // end try
catch (SQLException e)
{ // this becomes a DataException
logger.error("DB error getting bozo list: " + e.getMessage(),e);
throw new DataException("unable to get bozo filter listing: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end if
return bozo_uids.contains(new Integer(other_uid));
} // end isBozo
public void setBozo(int other_uid, boolean bozo) throws DataException
{
if (deleted || conf.userIsAnonymous() || (other_uid==conf.realUID()))
return; // no-op
Connection conn = null;
try
{ // figure out what to do here
conn = datapool.getConnection();
refresh(conn);
if (deleted)
return; // one more check to make sure we're not deleted
if (bozo_uids==null)
loadBozo(conn); // load the bozo filter if we don't already have it
Integer uid_key = new Integer(other_uid);
Statement stmt;
StringBuffer sql;
if (bozo)
{ // this user is a bozo...
if (!(bozo_uids.contains(uid_key)))
{ // add them to the bozo list
sql = new StringBuffer("INSERT INTO topicbozo (topicid, uid, bozo_uid) VALUES (");
sql.append(topicid).append(", ").append(conf.realUID()).append(", ").append(other_uid).append(");");
stmt = conn.createStatement();
stmt.executeUpdate(sql.toString());
bozo_uids.add(uid_key);
} // end if
// else this is a no-op
} // end if
else
{ // this user is no longer a bozo
if (bozo_uids.contains(uid_key))
{ // remove them from the bozo list
sql = new StringBuffer("DELETE FROM topicbozo WHERE topicid = ");
sql.append(topicid).append(" AND uid = ").append(conf.realUID()).append(" AND bozo_uid = ");
sql.append(other_uid).append(';');
stmt = conn.createStatement();
stmt.executeUpdate(sql.toString());
bozo_uids.remove(uid_key);
} // end if
// else this is a no-op
} // end else
} // end try
catch (SQLException e)
{ // this becomes a DataException
logger.error("DB error updating bozo list: " + e.getMessage(),e);
throw new DataException("unable to update bozo filter list: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end setBozo
public boolean canSetBozo(int other_uid)
{
// 1. You can't set bozo filters on a deleted topic.
// 2. You can't set bozo filters if you're the anonymous user.
// 3. You can't bozo-filter yourself, silly.
return !(deleted || conf.userIsAnonymous() || (other_uid==conf.realUID()));
} // end canSetBozoFilter
public List getBozos() throws DataException
{
if (deleted || conf.userIsAnonymous())
return Collections.EMPTY_LIST; // no-op
if (bozo_uids==null)
{ // the bozo UIDs need to be loaded!
Connection conn = null;
try
{ // load the bozo filter UIDs from the database
conn = datapool.getConnection();
loadBozo(conn);
} // end try
catch (SQLException e)
{ // this becomes a DataException
logger.error("DB error getting bozo list: " + e.getMessage(),e);
throw new DataException("unable to get bozo filter listing: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end if
return Collections.unmodifiableList(new ArrayList(bozo_uids));
} // end getBozos
/*--------------------------------------------------------------------------------
* External operations usable only from within the package
*--------------------------------------------------------------------------------

View File

@@ -364,12 +364,13 @@ public class ConfDisplay extends VeniceServlet
PostInterval piv = getInterval(engine,request,topic,on_error);
boolean read_new = do_readnew && !(StringUtil.isStringEmpty(request.getParameter("rnm")));
boolean show_adv = !(StringUtil.isStringEmpty(request.getParameter("shac")));
boolean no_bozos = !(StringUtil.isStringEmpty(request.getParameter("nbz")));
// Create the post display.
TopicPosts tpos = null;
try
{ // create the display
tpos = new TopicPosts(request,engine,comm,conf,topic,piv.getFirst(),piv.getLast(),read_new,show_adv);
return new TopicPosts(request,engine,comm,conf,topic,piv.getFirst(),piv.getLast(),read_new,show_adv,
no_bozos);
} // end try
catch (DataException de)
@@ -383,8 +384,6 @@ public class ConfDisplay extends VeniceServlet
} // end catch
return tpos;
} // end if (messages in a topic)
else
{ // we're displaying the conference's topic list
@@ -403,8 +402,6 @@ public class ConfDisplay extends VeniceServlet
if (read_new)
{ // we need to generate a TopicPosts view
TopicPosts tpos = null;
try
{ // generate a topic list first
List topic_list = conf.getTopicList(opts.getViewOption(conf.getConfID()),
@@ -433,7 +430,7 @@ public class ConfDisplay extends VeniceServlet
PostInterval piv = getInterval(engine,request,topic,on_error);
// create the topic posts view
return new TopicPosts(request,engine,comm,conf,topic,piv.getFirst(),piv.getLast(),true,false);
return new TopicPosts(request,engine,comm,conf,topic,piv.getFirst(),piv.getLast(),true,false,false);
} // end try
catch (DataException de)

View File

@@ -133,6 +133,25 @@ public class PostOperations extends VeniceServlet
} // end if ("scribble")
if (cmd.equals("BY") || cmd.equals("BN"))
{ // we want to add or remove the bozo filter from the user here
try
{ // attempt to set the bozo filter status
topic.setBozo(msg.getCreatorUID(),cmd.equals("BY"));
// go back and display stuff
throw new RedirectResult(location);
} // end try
catch (DataException de)
{ // there was a database error
return new ErrorBox("Database Error","Database error setting filter status: " + de.getMessage(),
location);
} // end catch
} // end if
if (cmd.equals("NUKE"))
{ // nuking requires confirmation
try

View File

@@ -183,9 +183,51 @@ public class TopicOperations extends VeniceServlet
} // end if (delete)
// unrecognized command
logger.error("invalid command to TopicOperations.doGet: " + cmd);
return new ErrorBox("Internal Error","Invalid command to TopicOperations.doGet",location);
if (cmd.equals("RB"))
{ // "RB" = "Remove Bozo" (UID specified as parameter "u")
int uid = -1;
try
{ // get the user ID to un-bozo
String foo = request.getParameter("u");
if (foo!=null)
uid = Integer.parseInt(foo);
} // end try
catch (NumberFormatException nfe)
{ // just don't do anything on error
uid = -1;
} // end catch
try
{ // remove "bozo" status from this user
if (uid>0)
topic.setBozo(uid,false);
setMyLocation(request,"topicops?" + locator);
return new ManageTopic(user,comm,conf,topic);
} // end try
catch (DataException de)
{ // whoops! this is a problem!
return new ErrorBox("Database Error","Database error removing filtered user: " + de.getMessage(),
"topicops?" + locator);
} // end catch
} // end if (remove bozo)
// unrecognized command - load the "Manage Topic menu"
try
{ // return that "Manage Topic" page
setMyLocation(request,"topicops?" + locator);
return new ManageTopic(user,comm,conf,topic);
} // end try
catch (DataException de)
{ // whoops! this is a problem!
return new ErrorBox("Database Error","Database error loading manage page: " + de.getMessage(),location);
} // end catch
} // end doVeniceGet

View File

@@ -0,0 +1,175 @@
/*
* 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 Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.servlets.format;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.silverwrist.venice.core.*;
public class ManageTopic implements JSPRender
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
// Attribute name for request attribute
protected static final String ATTR_NAME = "com.silverwrist.venice.content.ManageTopic";
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private CommunityContext comm; // the community we're in
private ConferenceContext conf; // the conference being listed
private TopicContext topic; // the topic being managed
private String locator = null; // the locator we use
private List bozos_list; // the list of "bozo" users
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public ManageTopic(UserContext user, CommunityContext comm, ConferenceContext conf, TopicContext topic)
throws DataException
{
this.comm = comm;
this.conf = conf;
this.topic = topic;
// Load up the list of bozos, sorting them in user name order.
List bozo_uids = topic.getBozos();
if (bozo_uids.size()>0)
{ // use a TreeMap to do the sorting
TreeMap load_map = new TreeMap();
Iterator it = bozo_uids.iterator();
while (it.hasNext())
{ // fill in the list of user profiles
Integer uid = (Integer)(it.next());
UserProfile prof = user.getProfile(uid.intValue());
load_map.put(prof.getUserName(),prof);
} // end while
bozos_list = new ArrayList(load_map.values());
} // end if
else // no bozos - just set empty list
bozos_list = Collections.EMPTY_LIST;
} // end constructor
/*--------------------------------------------------------------------------------
* External static functions
*--------------------------------------------------------------------------------
*/
public static ManageTopic retrieve(ServletRequest request)
{
return (ManageTopic)(request.getAttribute(ATTR_NAME));
} // end retrieve
/*--------------------------------------------------------------------------------
* Implementations from interface VeniceContent
*--------------------------------------------------------------------------------
*/
public String getPageTitle(RenderData rdat)
{
return "Manage Topic: " + topic.getName();
} // end getPageTitle
public String getPageQID()
{
return null;
} // end getPageQID
/*--------------------------------------------------------------------------------
* Implementations from interface JSPRender
*--------------------------------------------------------------------------------
*/
public void store(ServletRequest request)
{
request.setAttribute(ATTR_NAME,this);
} // end store
public String getTargetJSPName()
{
return "manage_topic.jsp";
} // end getTargetJSPName
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public int getCommunityID()
{
return comm.getCommunityID();
} // end getCommunityID
public int getConfID()
{
return conf.getConfID();
} // end getConfID
public int getTopicNumber()
{
return topic.getTopicNumber();
} // end getTopicID
public String getTopicName()
{
return topic.getName();
} // end getConfName
public String getLocator()
{
if (locator==null)
locator = "sig=" + comm.getCommunityID() + "&conf=" + conf.getConfID() + "&top="
+ topic.getTopicNumber();
return locator;
} // end getLocator
public int getNumBozos()
{
return bozos_list.size();
} // end getNumBozos()
public Iterator getBozosIterator()
{
return bozos_list.iterator();
} // end getBozosIterator
} // end class ManageTopic

View File

@@ -48,12 +48,14 @@ public class TopicPosts implements JSPRender
private int first;
private int last;
private boolean show_advanced;
private boolean no_bozos;
private int unread;
private List messages;
private TopicVisitOrder visit_order;
private String topic_stem;
private String topic_qid;
private String cache_locator = null;
private HashSet bozo_uids = new HashSet();
/*--------------------------------------------------------------------------------
* Constructor
@@ -62,12 +64,12 @@ public class TopicPosts implements JSPRender
public TopicPosts(HttpServletRequest request, VeniceEngine engine, CommunityContext comm,
ConferenceContext conf, TopicContext topic, int first, int last, boolean read_new,
boolean show_advanced) throws DataException, AccessError
boolean show_advanced, boolean no_bozos) throws DataException, AccessError
{
if (logger.isDebugEnabled())
logger.debug("TopicPosts: comm=" + comm.getCommunityID() + ", conf=" + conf.getConfID() + ", topic="
+ topic.getTopicNumber() + ", range=[" + first + ", " + last + "], rnm=" + read_new
+ ", shac=" + show_advanced);
+ ", shac=" + show_advanced + ", nbz=" + no_bozos);
this.engine = engine;
this.comm = comm;
this.conf = conf;
@@ -75,6 +77,7 @@ public class TopicPosts implements JSPRender
this.first = first;
this.last = last;
this.show_advanced = show_advanced;
this.no_bozos = no_bozos;
this.unread = topic.getUnreadMessages();
if (read_new)
topic.setUnreadMessages(0);
@@ -88,6 +91,23 @@ public class TopicPosts implements JSPRender
topic_stem = (String)(aliases.get(0)) + "." + topic.getTopicNumber() + ".";
topic_qid = "go/" + comm.getAlias() + "!" + (String)(aliases.get(0)) + "." + topic.getTopicNumber();
// build up the list of users IN THIS VIEW that are bozo-filtered
HashSet saw_users = new HashSet();
Iterator it = messages.iterator();
while (it.hasNext())
{ // get the user IDs of all messages on this page
TopicMessageContext msg = (TopicMessageContext)(it.next());
Integer the_uid = new Integer(msg.getCreatorUID());
if (!(saw_users.contains(the_uid)))
{ // only check user IDs once per display operation
saw_users.add(the_uid);
if (topic.isBozo(the_uid.intValue()))
bozo_uids.add(the_uid);
} // end if
} // end while
} // end constructor
/*--------------------------------------------------------------------------------
@@ -426,4 +446,28 @@ public class TopicPosts implements JSPRender
} // end displayAttachmentInNewWindow
public boolean bozoFilterUser(int uid)
{
if (no_bozos)
return false;
else
return bozo_uids.contains(new Integer(uid));
} // end bozoFilterUser
public boolean showBozoFilteredIndicator(int uid)
{
if (no_bozos)
return bozo_uids.contains(new Integer(uid));
else
return false;
} // end showBozoFilteredIndicator
public boolean showFilterButton(int uid)
{
return !(bozo_uids.contains(new Integer(uid))) && topic.canSetBozo(uid);
} // end showFilterButton
} // end class TopicPosts