implement move message between topics in a conference

This commit is contained in:
Eric J. Bowersox
2002-02-02 07:16:28 +00:00
parent 25c5817a67
commit a404987a42
18 changed files with 770 additions and 90 deletions

View File

@@ -85,4 +85,8 @@ public interface TopicMessageContext
public abstract String getPostLink() throws DataException;
public abstract void moveToTopic(int newtopicid) throws DataException, AccessError;
public abstract boolean canMove();
} // end interface TopicMessageContext

View File

@@ -1087,6 +1087,194 @@ class TopicMessageUserContextImpl implements TopicMessageContext
} // end getPostLink
public void moveToTopic(int newtopicid) throws DataException, AccessError
{
if (!(env.getConference().userCanNuke()) || !(env.getConference().userCanPost()))
{ // we must have both Nuke and Post privileges in this conference to be able to move
logger.error("trying to move post w/o permission!");
throw new AccessError("You are not permitted to move this message to another topic.");
} // end if
if (newtopicid==topicid)
return; // attempting to move to the same topic is a no-op
if (nuked)
{ // we can't move a nuked message!
logger.error("unable to move message because message nuked");
throw new DataException("Cannot move a message that has been nuked.");
} // end if
if (scribble_date!=null)
{ // we can't move a scribbled message!
logger.error("unable to move because message scribbled");
throw new DataException("Cannot move a message that has been scribbled.");
} // end if
Connection conn = null;
AuditRecord ar = null;
ArrayList mailto_addrs = null;
int new_topic_num = -1;
String new_topic_name = null, my_text = null;
ResultSet rs;
StringBuffer sql = new StringBuffer();
try
{ // get a database connection
conn = env.getConnection();
Statement stmt = conn.createStatement();
// lock the tables we reference
stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, posts WRITE, topicsettings READ;");
ArrayList mailto_uids = null;
int old_topicid;
try
{ // verify that we're not trying to move post 0 when that's the only one that exists
if (num==0)
{ // if we're moving post 0, check the number of posts in the topic
rs = stmt.executeQuery("SELECT top_message FROM topics WHERE topicid = " + topicid + ";");
if (!(rs.next()))
throw new InternalStateError("unable to get current message's topic?!?!?");
if (rs.getInt(1)==0)
throw new DataException("You cannot move the only message out of a topic.");
} // end if
// verify that the target topic exists
rs = stmt.executeQuery("SELECT confid, num, top_message, name FROM topics WHERE topicid = "
+ newtopicid + ";");
if (!(rs.next()))
throw new DataException("The specified topic to move the message to does not exist.");
if (env.getConfID()!=rs.getInt(1))
throw new AccessError("The topic to move the message to must be within the same conference.");
int newconfid = rs.getInt(1);
new_topic_num = rs.getInt(2);
int new_post_num = rs.getInt(3) + 1;
new_topic_name = rs.getString(4);
// save off the old parent, topic ID, and old post number
long old_parent = parent;
old_topicid = topicid;
int old_post_num = num;
// adjust the post record in the database so it's part of the new topic
sql.append("UPDATE posts SET parent = 0, topicid = ").append(newtopicid).append(", num = ");
sql.append(new_post_num).append(" WHERE postid = ").append(postid).append(';');
if (logger.isDebugEnabled())
logger.debug("SQL: " + sql.toString());
stmt.executeUpdate(sql.toString());
parent = 0;
topicid = newtopicid;
num = new_post_num;
// Touch the topic values to reflect the added post.
sql.setLength(0);
java.util.Date now = new java.util.Date();
sql.append("UPDATE topics SET top_message = ").append(new_post_num).append(", lastupdate = '");
sql.append(SQLUtil.encodeDate(now)).append("' WHERE topicid = ").append(newtopicid).append(';');
if (logger.isDebugEnabled())
logger.debug("SQL: " + sql.toString());
stmt.executeUpdate(sql.toString());
// Now we have to renumber the remaining posts in the "old" topic, just as if the post had been
// nuked rather than moved.
// -----
// Phase 1 of renumber - Renumber all posts IN THIS TOPIC that had a number higher than the one
// we just shifted over.
stmt.executeUpdate("UPDATE posts SET num = (num - 1) WHERE topicid = " + old_topicid + " AND num > "
+ old_post_num + ";");
// Phase 2 of renumber - The topic now has one less post in it. Reflect that.
stmt.executeUpdate("UPDATE topics SET top_message = (top_message - 1) WHERE topicid = "
+ old_topicid + ";");
// Also reparent any posts that had this one as a parent.
stmt.executeUpdate("UPDATE posts SET parent = " + old_parent + " WHERE parent = " + postid + ";");
// Touch the "conference updated" indicator.
env.getConference().touchUpdate(conn,now);
// Who's subscribed to the new topic? Whoever it is, they need to get this post via E-mail.
sql.setLength(0);
sql.append("SELECT uid FROM topicsettings WHERE topicid = ").append(newtopicid);
sql.append(" AND subscribe = 1;");
if (logger.isDebugEnabled())
logger.debug("SQL: " + sql.toString());
rs = stmt.executeQuery(sql.toString());
while (rs.next())
{ // load the UIDs here
if (mailto_uids==null)
mailto_uids = new ArrayList();
mailto_uids.add(new Integer(rs.getInt(1)));
} // end while
} // end try
finally
{ // unlock the tables before we go
Statement ulk_stmt = conn.createStatement();
ulk_stmt.executeUpdate("UNLOCK TABLES;");
} // end finally
// record what we did in an audit record
ar = env.newAudit(AuditRecord.MOVE_MESSAGE,"conf=" + env.getConfID() + ",post=" + postid,
"fromtopic=" + old_topicid,"totopic=" + newtopicid);
if (mailto_uids!=null)
{ // We need to translate the "mailto" UIDs to E-mail addresses while we still have the database open!
mailto_addrs = new ArrayList(mailto_uids.size());
sql.setLength(0);
sql.append("SELECT c.email FROM users u, contacts c WHERE u.contactid = c.contactid AND u.uid ");
if (mailto_uids.size()==1)
sql.append("= ").append(mailto_uids.get(0)).append(';');
else
sql.append("IN (").append(StringUtil.join(mailto_uids,", ")).append(");");
if (logger.isDebugEnabled())
logger.debug("SQL: " + sql.toString());
rs = stmt.executeQuery(sql.toString());
while (rs.next())
mailto_addrs.add(rs.getString(1));
// also load the message's text for E-mailing
my_text = this.getBodyText();
} // end if
} // end try
catch (SQLException e)
{ // just trap SQL exceptions and log them
logger.error("unable to move message: " + e.getMessage(),e);
throw new DataException("unable to move message: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
AuditRecord.store(conn,ar);
env.releaseConnection(conn);
} // end finally
if (mailto_addrs!=null)
{ // spin off a background thread to generate the E-mails
PostDeliveryAgent agent = new PostDeliveryAgent(env,my_text,pseud,new_topic_name,new_topic_num,
mailto_addrs);
agent.start();
} // end if
} // end moveToTopic
public boolean canMove()
{
return (env.getConference().userCanNuke() && env.getConference().userCanPost());
} // end canMove
/*--------------------------------------------------------------------------------
* External static operations
*--------------------------------------------------------------------------------

View File

@@ -67,5 +67,6 @@ public interface Audit
public static final int NUKE_MESSAGE = 313;
public static final int UPLOAD_ATTACHMENT = 314;
public static final int DELETE_CONF = 315;
public static final int MOVE_MESSAGE = 316;
} // end interface Audit

View File

@@ -11,7 +11,7 @@
*
* 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.
* Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
@@ -27,7 +27,7 @@ import com.silverwrist.venice.ui.*;
public class FrameContentHereTag extends VeniceTagSupport
{
/*--------------------------------------------------------------------------------
* Overrides from class TagSupport
* Static data members
*--------------------------------------------------------------------------------
*/

View File

@@ -0,0 +1,86 @@
/*
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.ui.jsp;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.view.NestedJSPView;
public class UtilCallJSPTag extends VeniceTagSupport
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private String name = null;
/*--------------------------------------------------------------------------------
* Overrides from class TagSupport
*--------------------------------------------------------------------------------
*/
public int doStartTag() throws JspException
{
if (name==null)
throw new JspTagException("<call_jsp/> tag specified without a JSP name");
try
{ // do what we came here to accomplish
JspWriter out = pageContext.getOut();
out.flush();
getRequestOutput().output(out,new NestedJSPView(getContent(),name));
} // end try
catch (IOException e)
{ // convert the I/O error into something the servlet engine can deal with
throw new JspTagException("error writing comment start - " + e.getMessage());
} // end catch
catch (ServletException se)
{ // convert the servlet exception into something we can deal with, too
throw new JspTagException("Servlet error writing frame content - " + se.getMessage());
} // end catch
return SKIP_BODY;
} // end doStartTag
public void release()
{
super.release();
name = null;
} // end release
/*--------------------------------------------------------------------------------
* Attribute set functions
*--------------------------------------------------------------------------------
*/
public void setName(String s)
{
name = s;
} // end setName
} // end class UtilCallJSPTag

View File

@@ -93,6 +93,14 @@ public class ScriptLibrary
} // end castSideBoxDescriptor
public final TopicContext castTopicContext(Object o)
{
if (o instanceof TopicContext)
return (TopicContext)o;
throw new ClassCastException("ScriptLibrary.castTopicContext: invalid cast");
} // end castTopicContext
public final TopicMessageContext castTopicMessageContext(Object o)
{
if (o instanceof TopicMessageContext)

View File

@@ -0,0 +1,163 @@
/*
* 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) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.ui.view;
import java.util.Date;
import javax.servlet.*;
import com.silverwrist.venice.core.CommunityContext;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.servlet.RequestImpl;
public class NestedJSPView implements ContentJSP
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Content outer;
private String jspname;
private RequestInput rinput = null;
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public NestedJSPView(Content outer, String jspname)
{
this.outer = outer;
this.jspname = jspname;
} // end constructor
/*--------------------------------------------------------------------------------
* Implementations from interface Content
*--------------------------------------------------------------------------------
*/
public boolean needFrame()
{
return outer.needFrame();
} // end needFrame
public int getMenuSelector()
{
return outer.getMenuSelector();
} // end getMenuSelector
public String getPageTitle(RequestOutput ro)
{
return outer.getPageTitle(ro);
} // end getPageTitle
public String getPageQID()
{
return outer.getPageQID();
} // end getPageQID
/*--------------------------------------------------------------------------------
* Implementations from interface ContentJSP
*--------------------------------------------------------------------------------
*/
public String getJSPName()
{
return jspname;
} // end getJSPName
public void initialize(RequestInput req)
{
rinput = req;
} // end initialize
public void terminate(RequestInput req)
{
rinput = null;
} // end terminate
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public final Content getOuterView()
{
return outer;
} // end getOuterView
public final Object getRequestAttribute(String s)
{
return ((rinput==null) ? null : rinput.getRequestAttribute(s));
} // end getRequestAttribute
public final String formatDate(Date date)
{
return ((rinput==null) ? null : rinput.formatDate(date));
} // end formatDate
public final CommunityContext getCommunity()
{
return ((rinput==null) ? null : rinput.getCommunity());
} // end getCommunity
public final String getActivityString(Date date)
{
return ((rinput==null) ? null : rinput.getActivityString(date));
} // end getActivityString
/*--------------------------------------------------------------------------------
* External static operations
*--------------------------------------------------------------------------------
*/
public static final NestedJSPView get(ServletRequest sreq) throws ServletException
{
Object obj = sreq.getAttribute(RequestImpl.REQUEST_CONTENT);
if (obj==null)
throw new ServletException("NestedJSPView.get: unable to get request content");
if (obj instanceof NestedJSPView)
return (NestedJSPView)obj;
throw new ServletException("NestedJSPView.get: request content is not a NestedJSPView object");
} // end get
public static final RequestOutput getRequestOutput(ServletRequest sreq) throws ServletException
{
Object obj = sreq.getAttribute(RequestImpl.REQUEST_OUTPUT);
if (obj==null)
throw new ServletException("NestedJSPView.getRequestOutput: unable to get request object");
if (obj instanceof RequestOutput)
return (RequestOutput)obj;
throw new ServletException("NestedJSPView.getRequestOutput: request object is not a RequestOutput object");
} // end getRequestOutput
} // end class NestedJSPView