implemented the rest of the functions on the "posts" page; fixed post links
so they work now; added the HTML Reference (originally from CW); added the post output filtering to turn the "pseudo-URIs" in the database into real URIs
13
TODO
|
@ -25,19 +25,6 @@ Lots!
|
|||
statements in the case of joined queries (no need to SELECT table.column
|
||||
AS name).
|
||||
|
||||
- Functions still to do on conferencing "posts" page:
|
||||
Hide/Show Topic
|
||||
Next & Keep New (make it actually Keep New)
|
||||
Freeze/Unfreeze Topic
|
||||
Archive/Unarchive Topic
|
||||
Delete Topic
|
||||
Make number of "viewable" posts per page a config option
|
||||
Display the message locator (i.e. <Playground.56.123>) above each message
|
||||
Hide/Show Post
|
||||
Scribble Post
|
||||
Nuke Post
|
||||
Put the HTML Guide in (for all pages w/post boxes)
|
||||
|
||||
- Slippage during posting is still untested.
|
||||
|
||||
- Functions still to do on conferencing "topics" page:
|
||||
|
|
|
@ -30,6 +30,7 @@ fucking
|
|||
hairstyle
|
||||
hairstyles
|
||||
hasn't
|
||||
haven't
|
||||
he'd
|
||||
html
|
||||
i'd
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
<!-- Base URL for all images loaded by the server code. MUST include the trailing slash. -->
|
||||
<image>http://delenn:8080/venice/images/</image>
|
||||
|
||||
<!-- Base URL for all static pages linked to by the engine. MUST include the trailing slash. -->
|
||||
<static>http://delenn:8080/venice/static/</static>
|
||||
|
||||
<!-- The fully-qualified URL to the site logo. The image should be 140x80 pixels. -->
|
||||
<site-logo>http://delenn:8080/venice/images/powered-by-venice.gif</site-logo>
|
||||
</paths>
|
||||
|
|
45
etc/web.xml
|
@ -11,7 +11,7 @@
|
|||
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 Community System.
|
||||
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
|
||||
|
@ -21,9 +21,9 @@
|
|||
-->
|
||||
<web-app>
|
||||
|
||||
<display-name>Venice Web Community System</display-name>
|
||||
<display-name>Venice Web Communities System</display-name>
|
||||
<description>
|
||||
The Venice Web conferencing system provides an online conferencing
|
||||
The Venice Web Communities System provides an online conferencing
|
||||
environment, including discussions, online services, and other
|
||||
things. Written by Eric J. Bowersox (erbo@silcom.com).
|
||||
</description>
|
||||
|
@ -158,6 +158,30 @@
|
|||
<servlet-class>com.silverwrist.venice.servlets.Attachment</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>topicoperations</servlet-name>
|
||||
<description>
|
||||
General topic operations.
|
||||
</description>
|
||||
<servlet-class>com.silverwrist.venice.servlets.TopicOperations</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>postoperations</servlet-name>
|
||||
<description>
|
||||
General post operations.
|
||||
</description>
|
||||
<servlet-class>com.silverwrist.venice.servlets.PostOperations</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>postshortcut</servlet-name>
|
||||
<description>
|
||||
Processes post links and redirects to the appropriate page.
|
||||
</description>
|
||||
<servlet-class>com.silverwrist.venice.servlets.PostShortcut</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<!-- the following are test servlets, they should go away -->
|
||||
|
||||
<servlet>
|
||||
|
@ -226,6 +250,21 @@
|
|||
<url-pattern>/attachment</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>topicoperations</servlet-name>
|
||||
<url-pattern>/topicops</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>postoperations</servlet-name>
|
||||
<url-pattern>/postops</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>postshortcut</servlet-name>
|
||||
<url-pattern>/go/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- the following are test servlets, they should go away -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>testformdata</servlet-name>
|
||||
|
|
|
@ -30,6 +30,14 @@ USE venice;
|
|||
# Table Creation
|
||||
##############################################################################
|
||||
|
||||
# The global parameters table. This is used for stuff that a Venice admin would be
|
||||
# likely to edit "on the fly." Stuff that can only be updated with a shutdown should go
|
||||
# in the XML config file. This table has ONLY ONE ROW!
|
||||
CREATE TABLE globals (
|
||||
posts_per_page INT NOT NULL,
|
||||
old_posts_at_top INT NOT NULL
|
||||
);
|
||||
|
||||
# The audit records table. Most "major" events add a record to this table.
|
||||
CREATE TABLE audit (
|
||||
record BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
|
@ -1282,6 +1290,10 @@ INSERT INTO refsigftr (ftr_code, is_default, is_locked, is_hidden, require_read,
|
|||
# Database Initialization
|
||||
##############################################################################
|
||||
|
||||
# Initialize the system globals table.
|
||||
INSERT INTO globals (posts_per_page, old_posts_at_top)
|
||||
VALUES (20, 2);
|
||||
|
||||
# Add the 'Anonymous Honyak' user to the users table.
|
||||
# (Do 'SELECT * FROM users WHERE is_anon = 1' to retrieve the AC user details.)
|
||||
# (UID = 1, CONTACTID = 1)
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.silverwrist.venice.core;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.silverwrist.venice.htmlcheck.HTMLChecker;
|
||||
|
||||
public interface ConferenceContext
|
||||
{
|
||||
|
@ -114,4 +115,6 @@ public interface ConferenceContext
|
|||
|
||||
public abstract TopicMessageContext getMessageByPostID(long postid) throws DataException, AccessError;
|
||||
|
||||
public abstract HTMLChecker getNewTopicPreviewChecker();
|
||||
|
||||
} // end interface ConferenceContext
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -72,4 +72,30 @@ public class IDUtils
|
|||
|
||||
} // end isValidConfirmationNumber
|
||||
|
||||
public static boolean isValidVeniceIDChar(char c)
|
||||
{
|
||||
if ((c>='A') && (c<='Z'))
|
||||
return true; // upper-case letters are OK
|
||||
if ((c>='a') && (c<='z'))
|
||||
return true; // lower-case letters are OK
|
||||
if ((c>='0') && (c<='9'))
|
||||
return true; // digits are OK
|
||||
return (EXTRA_VALID.indexOf(c)>=0);
|
||||
|
||||
} // end isValidVeniceIDChar
|
||||
|
||||
public static boolean isValidPostLinkChar(char c)
|
||||
{
|
||||
if ((c>='A') && (c<='Z'))
|
||||
return true; // upper-case letters are OK
|
||||
if ((c>='a') && (c<='z'))
|
||||
return true; // lower-case letters are OK
|
||||
if ((c>='0') && (c<='9'))
|
||||
return true; // digits are OK
|
||||
if (EXTRA_VALID.indexOf(c)>=0)
|
||||
return true; // other characters from Venice IDs are OK
|
||||
return ((c=='.') || (c=='!')); // also dots and bangs
|
||||
|
||||
} // end isValidPostLinkChar
|
||||
|
||||
} // end class IDUtils
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.silverwrist.venice.core;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.silverwrist.venice.htmlcheck.HTMLChecker;
|
||||
|
||||
public interface TopicContext
|
||||
{
|
||||
|
@ -71,4 +72,11 @@ public interface TopicContext
|
|||
public abstract TopicMessageContext postNewMessage(long parent, String pseud, String text)
|
||||
throws DataException, AccessError;
|
||||
|
||||
public abstract HTMLChecker getPreviewChecker();
|
||||
|
||||
public abstract boolean canDelete();
|
||||
|
||||
public abstract void delete() throws DataException, AccessError;
|
||||
|
||||
} // end interface TopicContext
|
||||
|
||||
|
|
|
@ -61,8 +61,10 @@ public interface VeniceEngine extends SearchMode
|
|||
|
||||
public abstract boolean confAliasExists(String alias);
|
||||
|
||||
public abstract HTMLChecker getPreviewChecker();
|
||||
|
||||
public abstract HTMLChecker getEscapingChecker();
|
||||
|
||||
public abstract int getNumPostsPerPage();
|
||||
|
||||
public abstract int getNumOldPostsBeforeNew();
|
||||
|
||||
} // end interface VeniceEngine
|
||||
|
|
112
src/com/silverwrist/venice/core/impl/BackgroundTopicPurge.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.core.impl;
|
||||
|
||||
import java.sql.*;
|
||||
import org.apache.log4j.*;
|
||||
import com.silverwrist.venice.db.*;
|
||||
|
||||
class BackgroundTopicPurge implements Runnable
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static Category logger = Category.getInstance(BackgroundTopicPurge.class.getName());
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private DataPool datapool;
|
||||
private int topicid;
|
||||
private int num_posts;
|
||||
private long max_postid;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
BackgroundTopicPurge(DataPool datapool, int topicid, int num_posts, long max_postid)
|
||||
{
|
||||
this.datapool = datapool;
|
||||
this.topicid = topicid;
|
||||
this.num_posts = num_posts;
|
||||
this.max_postid = max_postid;
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface Runnable
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void run()
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("BackgroundTopicPurge running on topic #" + String.valueOf(topicid));
|
||||
|
||||
long[] postids = new long[num_posts]; // stores the post IDs
|
||||
Connection conn = null; // pooled database connection
|
||||
|
||||
try
|
||||
{ // get a database connection from the pool
|
||||
conn = datapool.getConnection();
|
||||
Statement stmt = conn.createStatement();
|
||||
|
||||
// look up all the post IDs that are present for this topic
|
||||
StringBuffer sql = new StringBuffer("SELECT postid FROM posts WHERE topicid = ");
|
||||
sql.append(topicid).append(" AND postid <= ").append(max_postid).append(" ORDER BY postid;");
|
||||
ResultSet rs = stmt.executeQuery(sql.toString());
|
||||
int posts = 0;
|
||||
while (rs.next())
|
||||
postids[posts++] = rs.getLong(1);
|
||||
|
||||
for (int i=0; i<posts; i++)
|
||||
{ // remove all references to the posts in question
|
||||
stmt.executeUpdate("DELETE FROM posts WHERE postid = " + String.valueOf(postids[i]) + ";");
|
||||
stmt.executeUpdate("DELETE FROM postdata WHERE postid = " + String.valueOf(postids[i]) + ";");
|
||||
stmt.executeUpdate("DELETE FROM postattach WHERE postid = " + String.valueOf(postids[i]) + ";");
|
||||
stmt.executeUpdate("DELETE FROM postdogear WHERE postid = " + String.valueOf(postids[i]) + ";");
|
||||
|
||||
} // end for
|
||||
|
||||
// all done, Bunky!
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("BackgroundTopicPurge complete for topic #" + String.valueOf(topicid));
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // on an error, just die
|
||||
logger.error("BackgroundTopicPurge FATAL EXCEPTION purging #" + String.valueOf(topicid) + ": "
|
||||
+ e.getMessage(),e);
|
||||
|
||||
} // end catch
|
||||
finally
|
||||
{ // make sure we release the connection before we go
|
||||
if (conn!=null)
|
||||
datapool.releaseConnection(conn);
|
||||
|
||||
} // end finally
|
||||
|
||||
} // end run
|
||||
|
||||
} // end class BackgroundTopicPurge
|
|
@ -20,6 +20,7 @@ package com.silverwrist.venice.core.impl;
|
|||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import com.silverwrist.venice.db.PostLinkDecoderContext;
|
||||
import com.silverwrist.venice.core.DataException;
|
||||
|
||||
public interface ConferenceBackend extends SIGBackend
|
||||
|
@ -44,4 +45,6 @@ public interface ConferenceBackend extends SIGBackend
|
|||
|
||||
public abstract void touchUpdate(Connection conn, java.util.Date date) throws DataException;
|
||||
|
||||
public abstract PostLinkDecoderContext createDecoderContext(short topicid);
|
||||
|
||||
} // end interface ConferenceBackend
|
||||
|
|
|
@ -56,6 +56,7 @@ class ConferenceCoreData implements ConferenceData
|
|||
private String name; // the name of the conference
|
||||
private String description; // the conference's description
|
||||
private String cached_alias = null; // the cached alias (for getAnAlias)
|
||||
private boolean creating_topic = false; // is somebody creating a topic?
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructors
|
||||
|
@ -817,8 +818,8 @@ class ConferenceCoreData implements ConferenceData
|
|||
|
||||
} // end getAnAlias
|
||||
|
||||
public ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body,
|
||||
int body_lines) throws DataException
|
||||
public synchronized ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud,
|
||||
String body, int body_lines) throws DataException
|
||||
{
|
||||
Connection conn = null; // database connection
|
||||
AuditRecord ar = null; // audit record
|
||||
|
@ -963,6 +964,40 @@ class ConferenceCoreData implements ConferenceData
|
|||
|
||||
} // end touchUpdate
|
||||
|
||||
public synchronized short enterCreateTopic()
|
||||
{
|
||||
while (creating_topic)
|
||||
{ // we're ready to create a topic
|
||||
try
|
||||
{ // wait for another thread to relinquish the topic create mechanism
|
||||
wait();
|
||||
|
||||
} // end try
|
||||
catch (InterruptedException e)
|
||||
{ // do nothing
|
||||
} // end catch
|
||||
|
||||
} // end while
|
||||
|
||||
creating_topic = true;
|
||||
// new topic number, needed to properly parse post links in new topic's zero post
|
||||
return (short)(top_topic + 1);
|
||||
|
||||
} // end enterCreateTopic
|
||||
|
||||
public synchronized void exitCreateTopic()
|
||||
{
|
||||
creating_topic = false;
|
||||
notify(); // wake somebody up if they were going to create a topic
|
||||
|
||||
} // end exitCreateTopic
|
||||
|
||||
public short getTopTopic()
|
||||
{
|
||||
return top_topic;
|
||||
|
||||
} // end getTopTopic
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External static operations (usable only from within package)
|
||||
*--------------------------------------------------------------------------------
|
||||
|
|
|
@ -86,4 +86,10 @@ public interface ConferenceData extends ReferencedData
|
|||
|
||||
public abstract void touchUpdate(Connection conn, Date date) throws DataException;
|
||||
|
||||
public abstract short enterCreateTopic();
|
||||
|
||||
public abstract void exitCreateTopic();
|
||||
|
||||
public abstract short getTopTopic();
|
||||
|
||||
} // end interface ConferenceData
|
||||
|
|
|
@ -89,8 +89,8 @@ public interface ConferenceSIGContext extends ReferencedData
|
|||
|
||||
public abstract String getAnAlias() throws DataException;
|
||||
|
||||
public abstract ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body,
|
||||
int body_lines) throws DataException;
|
||||
public abstract ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body)
|
||||
throws DataException;
|
||||
|
||||
public abstract boolean canScribblePosts(int level);
|
||||
|
||||
|
@ -98,4 +98,6 @@ public interface ConferenceSIGContext extends ReferencedData
|
|||
|
||||
public abstract void touchUpdate(Connection conn, Date date) throws DataException;
|
||||
|
||||
public abstract short getTopTopic();
|
||||
|
||||
} // end interface ConferenceSIGContext
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.sql.*;
|
|||
import java.util.*;
|
||||
import org.apache.log4j.*;
|
||||
import com.silverwrist.venice.db.*;
|
||||
import com.silverwrist.venice.htmlcheck.*;
|
||||
import com.silverwrist.venice.security.AuditRecord;
|
||||
import com.silverwrist.venice.core.*;
|
||||
|
||||
|
@ -611,10 +612,48 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext
|
|||
|
||||
} // end getAnAlias
|
||||
|
||||
public ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body,
|
||||
int body_lines) throws DataException
|
||||
public ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body)
|
||||
throws DataException
|
||||
{
|
||||
return getConferenceData().createNewTopic(sig,title,pseud,body,body_lines);
|
||||
ConferenceData d = getConferenceData();
|
||||
String conf_alias = d.getAnAlias();
|
||||
short new_topic = d.enterCreateTopic();
|
||||
|
||||
try
|
||||
{ // preprocess the body argument through the HTML checker
|
||||
HTMLChecker text_ch = engine.createCheckerObject(engine.HTMLC_POST_BODY);
|
||||
text_ch.setContextValue("PostLinkDecoderContext",
|
||||
new PostLinkDecoderContext(sig.realSIGAlias(),conf_alias,new_topic));
|
||||
|
||||
try
|
||||
{ // run through the HTML checker
|
||||
text_ch.append(body);
|
||||
text_ch.finish();
|
||||
|
||||
} // end try
|
||||
catch (AlreadyFinishedException e)
|
||||
{ // this isn't right...
|
||||
throw new InternalStateError("HTMLChecker erroneously throwing AlreadyFinishedException",e);
|
||||
|
||||
} // end catch
|
||||
|
||||
try
|
||||
{ // call down to create the new topic!
|
||||
return d.createNewTopic(sig,title,pseud,text_ch.getValue(),text_ch.getLines());
|
||||
|
||||
} // end try
|
||||
catch (NotYetFinishedException e)
|
||||
{ // this isn't right either!
|
||||
throw new InternalStateError("HTMLChecker erroneously throwing NotYetFinishedException",e);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end try
|
||||
finally
|
||||
{ // make sure we relinquish the topic creation no matter what happens
|
||||
d.exitCreateTopic();
|
||||
|
||||
} // end finally
|
||||
|
||||
} // end createNewTopic
|
||||
|
||||
|
@ -648,4 +687,14 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext
|
|||
|
||||
} // end touchUpdate
|
||||
|
||||
public short getTopTopic()
|
||||
{
|
||||
ConferenceData c = getConferenceDataNE();
|
||||
if (c==null)
|
||||
return -1;
|
||||
else
|
||||
return c.getTopTopic();
|
||||
|
||||
} // end getTopTopic
|
||||
|
||||
} // end class ConferenceSIGContextImpl
|
||||
|
|
|
@ -821,19 +821,16 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
|
|||
|
||||
} // end if
|
||||
|
||||
// preprocess the three arguments through HTML checkers
|
||||
// preprocess the pseud and title arguments through HTML checkers
|
||||
HTMLChecker title_ch = engine.createCheckerObject(engine.HTMLC_POST_PSEUD);
|
||||
HTMLChecker zp_pseud_ch = engine.createCheckerObject(engine.HTMLC_POST_PSEUD);
|
||||
HTMLChecker zp_text_ch = engine.createCheckerObject(engine.HTMLC_POST_BODY);
|
||||
|
||||
try
|
||||
{ // run all three arguments through the HTML checker
|
||||
{ // run arguments through the HTML checker
|
||||
title_ch.append(title);
|
||||
title_ch.finish();
|
||||
zp_pseud_ch.append(zp_pseud);
|
||||
zp_pseud_ch.finish();
|
||||
zp_text_ch.append(zp_text);
|
||||
zp_text_ch.finish();
|
||||
|
||||
} // end try
|
||||
catch (AlreadyFinishedException e)
|
||||
|
@ -848,8 +845,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
|
|||
try
|
||||
{ // call down to create the new topic!
|
||||
real_title = title_ch.getValue();
|
||||
new_topic_inf = getConferenceData().createNewTopic(sig,real_title,zp_pseud_ch.getValue(),
|
||||
zp_text_ch.getValue(),zp_text_ch.getLines());
|
||||
new_topic_inf = getConferenceData().createNewTopic(sig,real_title,zp_pseud_ch.getValue(),zp_text);
|
||||
|
||||
} // end try
|
||||
catch (NotYetFinishedException e)
|
||||
|
@ -898,6 +894,20 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
|
|||
|
||||
} // end getMessageByPostID
|
||||
|
||||
public HTMLChecker getNewTopicPreviewChecker()
|
||||
{
|
||||
ConferenceSIGContext c = getConferenceDataNE();
|
||||
short new_topic;
|
||||
if (c==null)
|
||||
new_topic = 0;
|
||||
else
|
||||
new_topic = (short)(c.getTopTopic() + 1);
|
||||
HTMLChecker rc = engine.createCheckerObject(engine.HTMLC_PREVIEW_BODY);
|
||||
rc.setContextValue("PostLinkDecoderContext",createDecoderContext(new_topic));
|
||||
return rc;
|
||||
|
||||
} // end getNewTopicPreviewChecker
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface UserBackend
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -1097,6 +1107,12 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
|
|||
|
||||
} // end getConferenceData
|
||||
|
||||
public PostLinkDecoderContext createDecoderContext(short topicid)
|
||||
{
|
||||
return new PostLinkDecoderContext(sig.realSIGAlias(),realConfAlias(),topicid);
|
||||
|
||||
} // end createDecoderContext
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static functions usable only from within the package
|
||||
*--------------------------------------------------------------------------------
|
||||
|
|
|
@ -30,6 +30,9 @@ public interface EngineBackend
|
|||
public static final int HTMLC_PREVIEW_BODY = 2;
|
||||
public static final int HTMLC_ESCAPE_BODY_PSEUD = 3;
|
||||
|
||||
public static final int IP_POSTSPERPAGE = 0;
|
||||
public static final int IP_POSTSATTOP = 1;
|
||||
|
||||
public abstract SimpleEmailer createEmailer();
|
||||
|
||||
public abstract String getStockMessage(String key);
|
||||
|
@ -66,4 +69,8 @@ public interface EngineBackend
|
|||
|
||||
public abstract HTMLChecker createCheckerObject(int type);
|
||||
|
||||
public abstract int getParamInt(int selector);
|
||||
|
||||
public abstract void forceParamReload() throws DataException;
|
||||
|
||||
} // end interface EngineBackend
|
||||
|
|
|
@ -134,9 +134,10 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
|||
private void refresh(Connection conn) throws SQLException
|
||||
{
|
||||
Statement stmt = conn.createStatement();
|
||||
StringBuffer sql = new StringBuffer("SELECT p.hidden, p.scribble_uid, p.scribble_date, p.pseud, "
|
||||
+ "a.datalen, a.filename, a.mimetype FROM posts p LEFT JOIN "
|
||||
+ "postattach a ON p.postid = a.postid WHERE p.postid = ");
|
||||
StringBuffer sql = new StringBuffer("SELECT posts.hidden, posts.scribble_uid, posts.scribble_date, "
|
||||
+ "posts.pseud, postattach.datalen, postattach.filename, "
|
||||
+ "postattach.mimetype FROM posts LEFT JOIN postattach ON "
|
||||
+ "posts.postid = postattach.postid WHERE posts.postid = ");
|
||||
sql.append(postid).append(';');
|
||||
ResultSet rs = stmt.executeQuery(sql.toString());
|
||||
if (rs.next())
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -617,6 +617,7 @@ class TopicUserContextImpl implements TopicContext
|
|||
// preprocess the two arguments through HTML checkers
|
||||
HTMLChecker pseud_ch = engine.createCheckerObject(engine.HTMLC_POST_PSEUD);
|
||||
HTMLChecker text_ch = engine.createCheckerObject(engine.HTMLC_POST_BODY);
|
||||
text_ch.setContextValue("PostLinkDecoderContext",conf.createDecoderContext(topicnum));
|
||||
try
|
||||
{ // run both arguments through the HTML checker
|
||||
pseud_ch.append(pseud);
|
||||
|
@ -773,6 +774,117 @@ class TopicUserContextImpl implements TopicContext
|
|||
|
||||
} // end postMessage
|
||||
|
||||
public HTMLChecker getPreviewChecker()
|
||||
{
|
||||
HTMLChecker rc = engine.createCheckerObject(engine.HTMLC_PREVIEW_BODY);
|
||||
rc.setContextValue("PostLinkDecoderContext",conf.createDecoderContext(topicnum));
|
||||
return rc;
|
||||
|
||||
} // end getPreviewChecker
|
||||
|
||||
public boolean canDelete()
|
||||
{
|
||||
return conf.userCanNuke();
|
||||
|
||||
} // end canDelete
|
||||
|
||||
public void delete() throws DataException, AccessError
|
||||
{
|
||||
if (!(conf.userCanNuke()))
|
||||
{ // we can't delete the topic!
|
||||
logger.error("trying to delete w/o permission!");
|
||||
throw new AccessError("You do not have permission to delete this topic.");
|
||||
|
||||
} // end if
|
||||
|
||||
if (deleted)
|
||||
return; // an exercise in futility...
|
||||
|
||||
Connection conn = null;
|
||||
AuditRecord ar = null;
|
||||
int post_count;
|
||||
long post_max;
|
||||
|
||||
try
|
||||
{ // get a database connection
|
||||
conn = datapool.getConnection();
|
||||
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;");
|
||||
try
|
||||
{ // first delete the topic record itself
|
||||
StringBuffer sql = new StringBuffer("DELETE FROM topics WHERE topicid = ");
|
||||
sql.append(topicid).append(';');
|
||||
stmt.executeUpdate(sql.toString());
|
||||
|
||||
// now delete all topicsettings records
|
||||
sql.setLength(0);
|
||||
sql.append("DELETE FROM topicsettings WHERE topicid = ").append(topicid).append(';');
|
||||
stmt.executeUpdate(sql.toString());
|
||||
|
||||
// and indicate that we updated the conference
|
||||
conf.touchUpdate(conn,new java.util.Date());
|
||||
|
||||
// determine the number of posts in this topic, and the maximum post ID
|
||||
sql.setLength(0);
|
||||
sql.append("SELECT COUNT(*), MAX(postid) FROM posts WHERE topicid = ").append(topicid).append(';');
|
||||
ResultSet rs = stmt.executeQuery(sql.toString());
|
||||
if (!(rs.next()))
|
||||
throw new InternalStateError("TopicContext.delete screwup on post SELECT");
|
||||
post_count = rs.getInt(1);
|
||||
post_max = rs.getLong(2);
|
||||
|
||||
// and record that we're now deleted
|
||||
makeDeleted();
|
||||
|
||||
} // end try
|
||||
finally
|
||||
{ // make sure and unlock before we're done
|
||||
Statement ulk_stmt = conn.createStatement();
|
||||
ulk_stmt.executeUpdate("UNLOCK TABLES;");
|
||||
|
||||
} // end finally
|
||||
|
||||
// record what we did in an audit record
|
||||
ar = new AuditRecord(AuditRecord.DELETE_TOPIC,conf.realUID(),conf.userRemoteAddress(),
|
||||
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",topic="
|
||||
+ String.valueOf(topicid));
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // turn SQLException into data exception
|
||||
logger.error("DB error deleting topic: " + e.getMessage(),e);
|
||||
throw new DataException("unable to delete topic: " + e.getMessage(),e);
|
||||
|
||||
} // end catch
|
||||
finally
|
||||
{ // make sure we release the connection before we go
|
||||
try
|
||||
{ // save off the audit record before we go, though
|
||||
if ((ar!=null) && (conn!=null))
|
||||
ar.store(conn);
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // we couldn't store the audit record!
|
||||
logger.error("DB error saving audit record: " + e.getMessage(),e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (conn!=null)
|
||||
datapool.releaseConnection(conn);
|
||||
|
||||
} // end finally
|
||||
|
||||
// Delete the rest of the gunk in the background; spin off another thread to handle it.
|
||||
BackgroundTopicPurge purger = new BackgroundTopicPurge(datapool,topicid,post_count,post_max);
|
||||
Thread thrd = new Thread(purger);
|
||||
thrd.setPriority(Thread.NORM_PRIORITY-1);
|
||||
thrd.start();
|
||||
|
||||
} // end delete
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations usable only from within the package
|
||||
*--------------------------------------------------------------------------------
|
||||
|
|
|
@ -213,6 +213,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
private Hashtable feature_syms = new Hashtable(); // hashtable mapping symbols to features
|
||||
private Hashtable conf_objects = new Hashtable(); // holder for ConferenceCoreData objects
|
||||
private HTMLCheckerConfig[] html_configs; // holder for HTML checker configurations
|
||||
private int[] gp_ints; // global integer parameters
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
|
@ -239,6 +240,19 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
|
||||
} // end checkInitialized
|
||||
|
||||
private void loadDefaults(Statement stmt) throws SQLException, DataException
|
||||
{
|
||||
final String query = "SELECT posts_per_page, old_posts_at_top FROM globals;";
|
||||
ResultSet rs = stmt.executeQuery(query);
|
||||
if (!(rs.next()))
|
||||
throw new DataException("Globals table does not appear to be loaded!");
|
||||
|
||||
// stash the globals from the database
|
||||
gp_ints[IP_POSTSPERPAGE] = rs.getInt(1);
|
||||
gp_ints[IP_POSTSATTOP] = rs.getInt(2);
|
||||
|
||||
} // end loadDefaults
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface VeniceEngine
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -378,6 +392,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
|
||||
} // end catch
|
||||
|
||||
// Allocate the global parameter arrays.
|
||||
gp_ints = new int[2];
|
||||
|
||||
// initialize anything that requires us to pull from the database
|
||||
Connection conn = null;
|
||||
try
|
||||
|
@ -404,6 +421,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
if (logger.isDebugEnabled())
|
||||
logger.debug(String.valueOf(max_value) + " features loaded from database");
|
||||
|
||||
// load the global defaults
|
||||
loadDefaults(stmt);
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // convert exceptions to DataException
|
||||
|
@ -1207,18 +1227,24 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
|
||||
} // end confAliasExists
|
||||
|
||||
public HTMLChecker getPreviewChecker()
|
||||
{
|
||||
return html_configs[HTMLC_PREVIEW_BODY].createHTMLChecker();
|
||||
|
||||
} // end getPreviewChecker
|
||||
|
||||
public HTMLChecker getEscapingChecker()
|
||||
{
|
||||
return html_configs[HTMLC_ESCAPE_BODY_PSEUD].createHTMLChecker();
|
||||
|
||||
} // end getEscapingChecker
|
||||
|
||||
public int getNumPostsPerPage()
|
||||
{
|
||||
return gp_ints[IP_POSTSPERPAGE];
|
||||
|
||||
} // end getNumPostsPerPage
|
||||
|
||||
public int getNumOldPostsBeforeNew()
|
||||
{
|
||||
return gp_ints[IP_POSTSATTOP];
|
||||
|
||||
} // end getNumOldPostsBeforeNew
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface EngineBackend
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -1557,4 +1583,36 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
|
|||
|
||||
} // end createCheckerObject
|
||||
|
||||
public int getParamInt(int selector)
|
||||
{
|
||||
return gp_ints[selector];
|
||||
|
||||
} // end getParamInt
|
||||
|
||||
public void forceParamReload() throws DataException
|
||||
{
|
||||
Connection conn = null; // data pooled connection
|
||||
|
||||
try
|
||||
{ // get a connection and use it to reload
|
||||
conn = datapool.getConnection();
|
||||
Statement stmt = conn.createStatement();
|
||||
loadDefaults(stmt);
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // just log an error if we screwed up
|
||||
logger.error("DB error loading parameters: " + e.getMessage(),e);
|
||||
throw new DataException("Database error reloading parameters: " + e.getMessage(),e);
|
||||
|
||||
} // end catch
|
||||
finally
|
||||
{ // make sure the connection is released before we go
|
||||
if (conn!=null)
|
||||
datapool.releaseConnection(conn);
|
||||
|
||||
} // end finally
|
||||
|
||||
} // end forceParamReload
|
||||
|
||||
} // end class VeniceEngineImpl
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -27,6 +27,13 @@ import com.silverwrist.venice.core.IDUtils;
|
|||
|
||||
public class PostLinkRewriter implements Rewriter
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static final String URI_PREFIX = "x-postlink:";
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -52,7 +59,7 @@ public class PostLinkRewriter implements Rewriter
|
|||
|
||||
private static String buildPostLink(PostLinkDecoder pl, PostLinkDecoderContext ctxt)
|
||||
{
|
||||
StringBuffer b = new StringBuffer("x-postlink:");
|
||||
StringBuffer b = new StringBuffer(URI_PREFIX);
|
||||
boolean started = false;
|
||||
if (pl.getSIG()==null)
|
||||
b.append(ctxt.getSIGName());
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -26,6 +26,13 @@ import com.silverwrist.venice.core.IDUtils;
|
|||
|
||||
public class UserNameRewriter implements Rewriter
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static final String URI_PREFIX = "x-userlink:";
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -85,8 +92,9 @@ public class UserNameRewriter implements Rewriter
|
|||
|
||||
} // end finally
|
||||
|
||||
StringBuffer open_a = new StringBuffer("<A HREF=\"x-userlink:");
|
||||
open_a.append(data).append("\"");
|
||||
// build the markup data and return it
|
||||
StringBuffer open_a = new StringBuffer("<A HREF=\"");
|
||||
open_a.append(URI_PREFIX).append(data).append("\"");
|
||||
String catenate = svc.getRewriterAttrValue("ANCHORTAIL");
|
||||
if (!(StringUtil.isStringEmpty(catenate)))
|
||||
open_a.append(' ').append(catenate);
|
||||
|
|
|
@ -224,7 +224,7 @@ public class ConfDisplay extends VeniceServlet
|
|||
|
||||
} // end getViewSortDefaults
|
||||
|
||||
private static PostInterval getInterval(ServletRequest request, TopicContext topic)
|
||||
private static PostInterval getInterval(VeniceEngine engine, ServletRequest request, TopicContext topic)
|
||||
throws ValidationException
|
||||
{
|
||||
int first, last;
|
||||
|
@ -274,10 +274,10 @@ public class ConfDisplay extends VeniceServlet
|
|||
{ // no range specified - cook up a default one
|
||||
last = topic.getTotalMessages();
|
||||
int ur = topic.getUnreadMessages();
|
||||
if ((ur==0) || (ur>=20)) // TODO: configurable
|
||||
first = last - 20;
|
||||
if ((ur==0) || (ur>=engine.getNumPostsPerPage()))
|
||||
first = last - engine.getNumPostsPerPage();
|
||||
else
|
||||
first = last - (ur+2);
|
||||
first = last - (ur + engine.getNumOldPostsBeforeNew());
|
||||
last--;
|
||||
|
||||
} // end if
|
||||
|
@ -324,6 +324,72 @@ public class ConfDisplay extends VeniceServlet
|
|||
|
||||
} // end getInterval
|
||||
|
||||
private static void restorePosts(ServletRequest request, ConferenceContext conf)
|
||||
{
|
||||
String xtopic = request.getParameter("rtop");
|
||||
if (StringUtil.isStringEmpty(xtopic))
|
||||
return;
|
||||
String xcount = request.getParameter("rct");
|
||||
if (StringUtil.isStringEmpty(xcount))
|
||||
return;
|
||||
|
||||
TopicContext topic;
|
||||
try
|
||||
{ // get the topic corresponding to the first parameter
|
||||
topic = conf.getTopic(Short.parseShort(xtopic));
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // the topic number was invalid - forget it
|
||||
logger.warn("restorePosts: error translating topic number");
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
catch (DataException de)
|
||||
{ // could not get the topic...
|
||||
logger.warn("restorePosts: DataException getting topic - " + de.getMessage(),de);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // no access to the topic
|
||||
logger.warn("restorePosts: AccessError getting topic - " + ae.getMessage(),ae);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
int nunread;
|
||||
try
|
||||
{ // translate the number of unread posts to set
|
||||
nunread = Integer.parseInt(xcount);
|
||||
if ((nunread<=0) || (nunread>topic.getTotalMessages()))
|
||||
{ // must be in the range [1, #messages]...
|
||||
logger.warn("restorePosts: unread post count out of range");
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // the number of unread posts was invalid - forget it
|
||||
logger.warn("restorePosts: error translating unread post count");
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
try
|
||||
{ // now try to set the unread messages
|
||||
topic.setUnreadMessages(nunread);
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // could not get the topic...
|
||||
logger.warn("restorePosts: DataException setting unread messages - " + de.getMessage(),de);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end restorePosts
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class HttpServlet
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -428,14 +494,18 @@ public class ConfDisplay extends VeniceServlet
|
|||
if (logger.isDebugEnabled())
|
||||
logger.debug("MODE: display messages in topic");
|
||||
|
||||
// if this request is restoring the number of unread posts in another topic, try to do so
|
||||
restorePosts(request,conf);
|
||||
|
||||
try
|
||||
{ // determine what the post interval is we want to display
|
||||
PostInterval piv = getInterval(request,topic);
|
||||
VeniceEngine engine = getVeniceEngine();
|
||||
PostInterval piv = getInterval(engine,request,topic);
|
||||
boolean read_new = !(StringUtil.isStringEmpty(request.getParameter("rnm")));
|
||||
boolean show_adv = !(StringUtil.isStringEmpty(request.getParameter("shac")));
|
||||
|
||||
// create the post display
|
||||
TopicPosts tpos = new TopicPosts(request,sig,conf,topic,piv.getFirst(),piv.getLast(),
|
||||
TopicPosts tpos = new TopicPosts(request,engine,sig,conf,topic,piv.getFirst(),piv.getLast(),
|
||||
read_new,show_adv);
|
||||
content = tpos;
|
||||
page_title = topic.getName() + ": " + String.valueOf(topic.getTotalMessages()) + " Total; "
|
||||
|
|
|
@ -414,7 +414,7 @@ public class ConfOperations extends VeniceServlet
|
|||
|
||||
try
|
||||
{ // do a preview generation
|
||||
ntf.generatePreview(getVeniceEngine(),request);
|
||||
ntf.generatePreview(getVeniceEngine(),conf,request);
|
||||
|
||||
if (ntf.isNullRequest())
|
||||
{ // no title or text specified - this is a "204 No Content" return
|
||||
|
|
393
src/com/silverwrist/venice/servlets/PostOperations.java
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import org.apache.log4j.*;
|
||||
import com.silverwrist.util.StringUtil;
|
||||
import com.silverwrist.venice.ValidationException;
|
||||
import com.silverwrist.venice.core.*;
|
||||
import com.silverwrist.venice.servlets.format.*;
|
||||
|
||||
public class PostOperations extends VeniceServlet
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String NUKE_CONFIRM_ATTR = "servlets.PostOperations.nuke.confirm";
|
||||
private static final String NUKE_CONFIRM_PARAM = "confirm";
|
||||
|
||||
private static Category logger = Category.getInstance(TopicOperations.class.getName());
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal functions
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static SIGContext getSIGParameter(ServletRequest request, UserContext user)
|
||||
throws ValidationException, DataException
|
||||
{
|
||||
String str = request.getParameter("sig");
|
||||
if (str==null)
|
||||
{ // no SIG parameter - bail out now!
|
||||
logger.error("SIG parameter not specified!");
|
||||
throw new ValidationException("No SIG specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a SIGID, and thence to a SIGContext
|
||||
int sigid = Integer.parseInt(str);
|
||||
return user.getSIGContext(sigid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert SIG parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid SIG parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getSIGParameter
|
||||
|
||||
private static ConferenceContext getConferenceParameter(ServletRequest request, SIGContext sig)
|
||||
throws ValidationException, DataException, AccessError
|
||||
{
|
||||
String str = request.getParameter("conf");
|
||||
if (str==null)
|
||||
{ // no conference parameter - bail out now!
|
||||
logger.error("Conference parameter not specified!");
|
||||
throw new ValidationException("No conference specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a ConfID, and thence to a ConferenceContext
|
||||
int confid = Integer.parseInt(str);
|
||||
return sig.getConferenceContext(confid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert conference parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid conference parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getConferenceParameter
|
||||
|
||||
private static TopicContext getTopicParameter(ServletRequest request, ConferenceContext conf)
|
||||
throws ValidationException, DataException, AccessError
|
||||
{
|
||||
String str = request.getParameter("top");
|
||||
if (StringUtil.isStringEmpty(str))
|
||||
{ // no topic parameter - bail out now!
|
||||
logger.error("Topic parameter not specified!");
|
||||
throw new ValidationException("No topic specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a TopicID, and thence to a TopicContext
|
||||
short topicid = Short.parseShort(str);
|
||||
return conf.getTopic(topicid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert topic parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid topic parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getTopicParameter
|
||||
|
||||
private static TopicMessageContext getMessageParameter(ServletRequest request, TopicContext topic)
|
||||
throws ValidationException, DataException, AccessError
|
||||
{
|
||||
String str = request.getParameter("msg");
|
||||
if (StringUtil.isStringEmpty(str))
|
||||
{ // no topic parameter - bail out now!
|
||||
logger.error("Message parameter not specified!");
|
||||
throw new ValidationException("No message specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a TopicID, and thence to a TopicContext
|
||||
int message_num = Integer.parseInt(str);
|
||||
return topic.getMessage(message_num);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert message parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid message parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getMessageParameter
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class HttpServlet
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getServletInfo()
|
||||
{
|
||||
String rc = "PostOperations servlet - General post operations (hide, scribble, etc.)\n"
|
||||
+ "Part of the Venice Web Communities System\n";
|
||||
return rc;
|
||||
|
||||
} // end getServletInfo
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
UserContext user = getUserContext(request);
|
||||
RenderData rdat = createRenderData(request,response);
|
||||
String location = "top";
|
||||
String locator = null;
|
||||
String page_title = null;
|
||||
Object content = null;
|
||||
SIGContext sig = null; // SIG context
|
||||
ConferenceContext conf = null; // conference context
|
||||
TopicContext topic = null; // topic context
|
||||
TopicMessageContext msg = null; // message context
|
||||
|
||||
try
|
||||
{ // this outer try is to catch ValidationException
|
||||
try
|
||||
{ // all commands require a SIG parameter
|
||||
sig = getSIGParameter(request,user);
|
||||
changeMenuSIG(request,sig);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found SIG #" + String.valueOf(sig.getSIGID()));
|
||||
locator = "sig=" + String.valueOf(sig.getSIGID());
|
||||
location = "sigprofile?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the SIG
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding SIG: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (content==null)
|
||||
{ // we got the SIG parameter OK
|
||||
try
|
||||
{ // all commands require a conference parameter
|
||||
conf = getConferenceParameter(request,sig);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found conf #" + String.valueOf(conf.getConfID()));
|
||||
locator += "&conf=" + String.valueOf(conf.getConfID());
|
||||
location = "confdisp?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the conference
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding conference: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (content==null)
|
||||
{ // we got the conference parameter OK
|
||||
try
|
||||
{ // now we need a topic parameter
|
||||
topic = getTopicParameter(request,conf);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found topic #" + String.valueOf(topic.getTopicID()));
|
||||
locator += "&top=" + String.valueOf(topic.getTopicID());
|
||||
location = "confdisp?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the conference
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding topic: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (content==null)
|
||||
{ // we got the topic parameter OK
|
||||
try
|
||||
{ // now we need a message parameter
|
||||
msg = getMessageParameter(request,topic);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found message #" + String.valueOf(msg.getPostID()));
|
||||
location = "confdisp?" + locator + "&p1=" + msg.getPostNumber() + "&shac=1";
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the conference
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding message: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
} // end try
|
||||
catch (ValidationException ve)
|
||||
{ // these all get handled in pretty much the same way
|
||||
page_title = "Error";
|
||||
content = new ErrorBox(null,ve.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // these all get handled in pretty much the same way
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (content==null)
|
||||
{ // figure out what command we want to perform
|
||||
String cmd = request.getParameter("cmd");
|
||||
if (cmd==null)
|
||||
cmd = "???";
|
||||
|
||||
if (cmd.equals("HY") || cmd.equals("HN"))
|
||||
{ // we want to hide or show the message
|
||||
try
|
||||
{ // attempt to hide or show the message
|
||||
msg.setHidden(cmd.equals("HY"));
|
||||
|
||||
// go back and display stuff
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error setting hidden status: " + de.getMessage(),
|
||||
location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if ("hide" or "show")
|
||||
else if (cmd.equals("SCR"))
|
||||
{ // we want to scribble the message
|
||||
try
|
||||
{ // attempt to scribble the message
|
||||
msg.scribble();
|
||||
|
||||
// go back and display stuff
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error scribbling message: " + de.getMessage(),
|
||||
location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end else if ("scribble")
|
||||
else if (cmd.equals("NUKE"))
|
||||
{ // nuking requires confirmation
|
||||
try
|
||||
{ // we need confirmation on this operation!
|
||||
if (ConfirmBox.isConfirmed(request,NUKE_CONFIRM_ATTR,NUKE_CONFIRM_PARAM))
|
||||
{ // OK, go ahead, nuke the message!
|
||||
msg.nuke();
|
||||
|
||||
// after which, redirect to topic view
|
||||
rdat.redirectTo("confdisp?" + locator);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
else
|
||||
{ // not a proper confirmation - better display one
|
||||
List aliases = conf.getAliases();
|
||||
String message = "You are about to nuke message <" + (String)(aliases.get(0)) + "."
|
||||
+ String.valueOf(topic.getTopicNumber()) + "." + String.valueOf(msg.getPostNumber())
|
||||
+ ">, originally composed by <" + msg.getCreatorName()
|
||||
+ ">! Are you sure you want to do this?";
|
||||
String confirm_url = "postops?" + locator + "&msg=" + msg.getPostNumber() + "&cmd=NUKE";
|
||||
|
||||
page_title = "Nuke Message";
|
||||
content = new ConfirmBox(request,NUKE_CONFIRM_ATTR,NUKE_CONFIRM_PARAM,page_title,
|
||||
message,confirm_url,location);
|
||||
|
||||
} // end else
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error nuking message: " + de.getMessage(),
|
||||
location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end else if ("nuke")
|
||||
else
|
||||
{ // unrecognized command!
|
||||
page_title = "Internal Error";
|
||||
logger.error("invalid command to PostOperations.doGet: " + cmd);
|
||||
content = new ErrorBox(page_title,"Invalid command to PostOperations.doGet",location);
|
||||
|
||||
} // end else
|
||||
|
||||
} // end if (got parameters OK)
|
||||
|
||||
BaseJSPData basedat = new BaseJSPData(page_title,location,content);
|
||||
basedat.transfer(getServletContext(),rdat);
|
||||
|
||||
} // end doGet
|
||||
|
||||
} // end class PostOperations
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
161
src/com/silverwrist/venice/servlets/PostShortcut.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import com.silverwrist.venice.ValidationException;
|
||||
import com.silverwrist.venice.core.*;
|
||||
import com.silverwrist.venice.db.PostLinkDecoder;
|
||||
import com.silverwrist.venice.servlets.format.*;
|
||||
|
||||
public class PostShortcut extends VeniceServlet
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class HttpServlet
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getServletInfo()
|
||||
{
|
||||
String rc = "PostShortcut servlet - Decodes a post link and redirects to it\n"
|
||||
+ "Part of the Venice Web Communities System\n";
|
||||
return rc;
|
||||
|
||||
} // end getServletInfo
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
UserContext user = getUserContext(request);
|
||||
RenderData rdat = createRenderData(request,response);
|
||||
String raw_link = request.getPathInfo().substring(1);
|
||||
PostLinkDecoder decoder;
|
||||
|
||||
try
|
||||
{ // attempt to decode the path link information
|
||||
decoder = new PostLinkDecoder(raw_link);
|
||||
if (decoder.getSIG()==null) // it must include the SIG
|
||||
throw new ValidationException("ambiguous post link (no SIG)");
|
||||
|
||||
} // end try
|
||||
catch (ValidationException e)
|
||||
{ // display an error message for validation
|
||||
String page_title = "Invalid Post Link";
|
||||
ContentRender content = new ErrorBox(page_title,"Invalid post link \"" + raw_link + "\": "
|
||||
+ e.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
SIGContext sig;
|
||||
try
|
||||
{ // get the SIG represented by that alias
|
||||
sig = user.getSIGContext(decoder.getSIG());
|
||||
|
||||
} // end try
|
||||
catch (DataException e)
|
||||
{ // can't find the SIG - we're screwed
|
||||
String page_title = "Invalid Post Link";
|
||||
ContentRender content = new ErrorBox(page_title,"Invalid post link \"" + raw_link
|
||||
+ "\": cannot find SIG: " + e.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
if (decoder.getConference()==null)
|
||||
{ // it's a SIG link only - redirect to the SIG's default page
|
||||
rdat.redirectTo("sig/" + decoder.getSIG());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
ConferenceContext conf;
|
||||
try
|
||||
{ // get the conference represented by that alias
|
||||
conf = sig.getConferenceContext(decoder.getConference());
|
||||
|
||||
} // end try
|
||||
catch (DataException e)
|
||||
{ // can't find the conference - we're screwed
|
||||
String page_title = "Invalid Post Link";
|
||||
ContentRender content = new ErrorBox(page_title,"Invalid post link \"" + raw_link
|
||||
+ "\": cannot find conference: " + e.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // we can't get to the conference...
|
||||
String page_title = "Access Error";
|
||||
ContentRender content = new ErrorBox(page_title,ae.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
// compute an elementary "locator"
|
||||
String locator = "sig=" + String.valueOf(sig.getSIGID()) + "&conf=" + String.valueOf(conf.getConfID());
|
||||
|
||||
if (decoder.getTopic()==-1)
|
||||
{ // just a conference link - go to the top-level display
|
||||
rdat.redirectTo("confdisp?" + locator);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
TopicContext topic;
|
||||
try
|
||||
{ // get the topic number specified within that topic
|
||||
topic = conf.getTopic(decoder.getTopic());
|
||||
|
||||
} // end try
|
||||
catch (DataException e)
|
||||
{ // we can't find the topic - we're screwed
|
||||
String page_title = "Invalid Post Link";
|
||||
ContentRender content = new ErrorBox(page_title,"Invalid post link \"" + raw_link
|
||||
+ "\": cannot find topic: " + e.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // we can't get to the topic...
|
||||
String page_title = "Access Error";
|
||||
ContentRender content = new ErrorBox(page_title,ae.getMessage(),null);
|
||||
new BaseJSPData(page_title,"top",content).transfer(getServletContext(),rdat);
|
||||
return;
|
||||
|
||||
} // end catch
|
||||
|
||||
// add the topic to our locator
|
||||
locator += "&top=" + String.valueOf(decoder.getTopic());
|
||||
|
||||
if (decoder.getFirstPost()==-1) // we're just referencing the topic
|
||||
rdat.redirectTo("confdisp?" + locator + "&rnm=1");
|
||||
else // we're referencing a post range within the topic
|
||||
rdat.redirectTo("confdisp?" + locator + "&p1=" + String.valueOf(decoder.getFirstPost()) + "&p2="
|
||||
+ String.valueOf(decoder.getLastPost()));
|
||||
|
||||
} // end doGet
|
||||
|
||||
} // end class PostShortcut
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -25,10 +25,15 @@ import com.silverwrist.venice.servlets.format.*;
|
|||
|
||||
public class SIGFrontEnd extends VeniceServlet
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class HttpServlet
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getServletInfo()
|
||||
{
|
||||
String rc = "SIGFrontEnd servlet - Redirects to the \"default feature\" of a SIG\n"
|
||||
+ "Part of the Venice Web conferencing system\n";
|
||||
+ "Part of the Venice Web Communities System\n";
|
||||
return rc;
|
||||
|
||||
} // end getServletInfo
|
||||
|
|
357
src/com/silverwrist/venice/servlets/TopicOperations.java
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import org.apache.log4j.*;
|
||||
import com.silverwrist.util.StringUtil;
|
||||
import com.silverwrist.venice.ValidationException;
|
||||
import com.silverwrist.venice.core.*;
|
||||
import com.silverwrist.venice.servlets.format.*;
|
||||
|
||||
public class TopicOperations extends VeniceServlet
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String DELETE_CONFIRM_ATTR = "servlets.TopicOperations.delete.confirm";
|
||||
private static final String DELETE_CONFIRM_PARAM = "confirm";
|
||||
|
||||
private static Category logger = Category.getInstance(TopicOperations.class.getName());
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal functions
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static SIGContext getSIGParameter(ServletRequest request, UserContext user)
|
||||
throws ValidationException, DataException
|
||||
{
|
||||
String str = request.getParameter("sig");
|
||||
if (str==null)
|
||||
{ // no SIG parameter - bail out now!
|
||||
logger.error("SIG parameter not specified!");
|
||||
throw new ValidationException("No SIG specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a SIGID, and thence to a SIGContext
|
||||
int sigid = Integer.parseInt(str);
|
||||
return user.getSIGContext(sigid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert SIG parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid SIG parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getSIGParameter
|
||||
|
||||
private static ConferenceContext getConferenceParameter(ServletRequest request, SIGContext sig)
|
||||
throws ValidationException, DataException, AccessError
|
||||
{
|
||||
String str = request.getParameter("conf");
|
||||
if (str==null)
|
||||
{ // no conference parameter - bail out now!
|
||||
logger.error("Conference parameter not specified!");
|
||||
throw new ValidationException("No conference specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a ConfID, and thence to a ConferenceContext
|
||||
int confid = Integer.parseInt(str);
|
||||
return sig.getConferenceContext(confid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert conference parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid conference parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getConferenceParameter
|
||||
|
||||
private static TopicContext getTopicParameter(ServletRequest request, ConferenceContext conf)
|
||||
throws ValidationException, DataException, AccessError
|
||||
{
|
||||
String str = request.getParameter("top");
|
||||
if (StringUtil.isStringEmpty(str))
|
||||
{ // no topic parameter - bail out now!
|
||||
logger.error("Topic parameter not specified!");
|
||||
throw new ValidationException("No topic specified.");
|
||||
|
||||
} // end if
|
||||
|
||||
try
|
||||
{ // turn the string into a TopicID, and thence to a TopicContext
|
||||
short topicid = Short.parseShort(str);
|
||||
return conf.getTopic(topicid);
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException nfe)
|
||||
{ // error in Integer.parseInt
|
||||
logger.error("Cannot convert topic parameter '" + str + "'!");
|
||||
throw new ValidationException("Invalid topic parameter.");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end getTopicParameter
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Overrides from class HttpServlet
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public String getServletInfo()
|
||||
{
|
||||
String rc = "TopicOperations servlet - General topic operations (freeze, archive, etc.)\n"
|
||||
+ "Part of the Venice Web Communities System\n";
|
||||
return rc;
|
||||
|
||||
} // end getServletInfo
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
UserContext user = getUserContext(request);
|
||||
RenderData rdat = createRenderData(request,response);
|
||||
String location = "top";
|
||||
String locator = null;
|
||||
String page_title = null;
|
||||
Object content = null;
|
||||
SIGContext sig = null; // SIG context
|
||||
ConferenceContext conf = null; // conference context
|
||||
TopicContext topic = null; // topic context
|
||||
|
||||
try
|
||||
{ // this outer try is to catch ValidationException
|
||||
try
|
||||
{ // all commands require a SIG parameter
|
||||
sig = getSIGParameter(request,user);
|
||||
changeMenuSIG(request,sig);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found SIG #" + String.valueOf(sig.getSIGID()));
|
||||
locator = "sig=" + String.valueOf(sig.getSIGID());
|
||||
location = "sigprofile?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the SIG
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding SIG: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (content==null)
|
||||
{ // we got the SIG parameter OK
|
||||
try
|
||||
{ // all commands require a conference parameter
|
||||
conf = getConferenceParameter(request,sig);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found conf #" + String.valueOf(conf.getConfID()));
|
||||
locator += "&conf=" + String.valueOf(conf.getConfID());
|
||||
location = "confdisp?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the conference
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding conference: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (content==null)
|
||||
{ // we got the conference parameter OK
|
||||
try
|
||||
{ // now we need a topic parameter
|
||||
topic = getTopicParameter(request,conf);
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("found topic #" + String.valueOf(topic.getTopicID()));
|
||||
locator += "&top=" + String.valueOf(topic.getTopicNumber());
|
||||
location = "confdisp?" + locator;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // error looking up the conference
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error finding topic: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
} // end try
|
||||
catch (ValidationException ve)
|
||||
{ // these all get handled in pretty much the same way
|
||||
page_title = "Error";
|
||||
content = new ErrorBox(null,ve.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // these all get handled in pretty much the same way
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (content==null)
|
||||
{ // figure out what command we want to perform...
|
||||
String cmd = request.getParameter("cmd");
|
||||
if (cmd==null)
|
||||
cmd = "???";
|
||||
|
||||
if (cmd.equals("HY") || cmd.equals("HN"))
|
||||
{ // we want to set the hide status of the topic
|
||||
try
|
||||
{ // call down to set the topic!
|
||||
topic.setHidden(cmd.equals("HY"));
|
||||
|
||||
// go back to the topic view
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error setting hide status: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if ("hide" or "show")
|
||||
else if (cmd.equals("FY") || cmd.equals("FN"))
|
||||
{ // we want to set the frozen status of the topic
|
||||
try
|
||||
{ // call down to set the topic!
|
||||
topic.setFrozen(cmd.equals("FY"));
|
||||
|
||||
// go back to the topic view
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error setting freeze status: " + de.getMessage(),
|
||||
location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end else if ("freeze" or "unfreeze")
|
||||
else if (cmd.equals("AY") || cmd.equals("AN"))
|
||||
{ // we want to change the archived status of the topic
|
||||
try
|
||||
{ // call down to set the topic!
|
||||
topic.setArchived(cmd.equals("AY"));
|
||||
|
||||
// go back to the topic view
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error setting archive status: " + de.getMessage(),
|
||||
location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end else if ("archive" or "unarchive")
|
||||
else if (cmd.equals("DEL"))
|
||||
{ // we need confirmation on this operation!
|
||||
if (ConfirmBox.isConfirmed(request,DELETE_CONFIRM_ATTR,DELETE_CONFIRM_PARAM))
|
||||
{ // OK, go ahead, delete the topic!
|
||||
location = "confdisp?sig=" + String.valueOf(sig.getSIGID()) + "&conf="
|
||||
+ String.valueOf(conf.getConfID());
|
||||
|
||||
try
|
||||
{ // delete the bloody topic!
|
||||
topic.delete();
|
||||
|
||||
// after which, redirect to conference view
|
||||
rdat.redirectTo(location);
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (DataException de)
|
||||
{ // there was a database error
|
||||
page_title = "Database Error";
|
||||
content = new ErrorBox(page_title,"Database error deleting topic: " + de.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
catch (AccessError ae)
|
||||
{ // naughty naughty = you can't do this!
|
||||
page_title = "Access Error";
|
||||
content = new ErrorBox(page_title,ae.getMessage(),location);
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
else
|
||||
{ // not a proper confirmation - better display one
|
||||
String message = "You are about to delete topic " + String.valueOf(topic.getTopicNumber())
|
||||
+ " from the \"" + conf.getName() + "\" conference! Are you sure you want to do this?";
|
||||
String confirm_url = "topicops?" + locator + "&cmd=DEL";
|
||||
page_title = "Delete Topic";
|
||||
content = new ConfirmBox(request,DELETE_CONFIRM_ATTR,DELETE_CONFIRM_PARAM,page_title,
|
||||
message,confirm_url,location);
|
||||
|
||||
} // end else
|
||||
|
||||
} // end else if ("delete")
|
||||
else
|
||||
{ // unrecognized command
|
||||
page_title = "Internal Error";
|
||||
logger.error("invalid command to TopicOperations.doGet: " + cmd);
|
||||
content = new ErrorBox(page_title,"Invalid command to TopicOperations.doGet",location);
|
||||
|
||||
} // end else
|
||||
|
||||
} // end if
|
||||
|
||||
BaseJSPData basedat = new BaseJSPData(page_title,location,content);
|
||||
basedat.transfer(getServletContext(),rdat);
|
||||
|
||||
} // end doGet
|
||||
|
||||
} // end class TopicOperations
|
|
@ -101,7 +101,8 @@ public class NewTopicForm implements JSPRender
|
|||
|
||||
} // end setupNewRequest
|
||||
|
||||
public void generatePreview(VeniceEngine engine, ServletRequest request) throws ValidationException
|
||||
public void generatePreview(VeniceEngine engine, ConferenceContext conf, ServletRequest request)
|
||||
throws ValidationException
|
||||
{
|
||||
HTMLChecker check;
|
||||
|
||||
|
@ -136,7 +137,7 @@ public class NewTopicForm implements JSPRender
|
|||
post_box = check.getValue();
|
||||
|
||||
// generate the body text preview
|
||||
check = engine.getPreviewChecker();
|
||||
check = conf.getNewTopicPreviewChecker();
|
||||
check.append(foo);
|
||||
check.finish();
|
||||
preview = check.getValue();
|
||||
|
|
|
@ -79,7 +79,7 @@ public class PostPreview implements JSPRender
|
|||
this.data = check.getValue();
|
||||
|
||||
// now generate the preview
|
||||
check = engine.getPreviewChecker();
|
||||
check = topic.getPreviewChecker();
|
||||
check.append(data);
|
||||
check.finish();
|
||||
this.preview = check.getValue();
|
||||
|
|
|
@ -47,6 +47,7 @@ public class PostSlippage implements JSPRender
|
|||
private String pseud;
|
||||
private String text;
|
||||
private boolean attach;
|
||||
private String topic_stem;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
|
@ -63,6 +64,8 @@ public class PostSlippage implements JSPRender
|
|||
this.messages = topic.getMessages(lastval,topic.getTotalMessages()-1);
|
||||
this.next = next;
|
||||
this.attach = attach;
|
||||
List aliases = conf.getAliases();
|
||||
topic_stem = (String)(aliases.get(0)) + "." + String.valueOf(topic.getTopicNumber()) + ".";
|
||||
|
||||
try
|
||||
{ // run the text and pseud through an HTML checker to escape them
|
||||
|
@ -213,4 +216,10 @@ public class PostSlippage implements JSPRender
|
|||
|
||||
} // end getBodyText
|
||||
|
||||
public String getMessageReference(TopicMessageContext msg)
|
||||
{
|
||||
return topic_stem + String.valueOf(msg.getPostNumber());
|
||||
|
||||
} // end getMessageReference
|
||||
|
||||
} // end class PostSlippage
|
||||
|
|
|
@ -54,6 +54,7 @@ public class RenderConfig
|
|||
private String font_face;
|
||||
private String base_url;
|
||||
private String image_url;
|
||||
private String static_url;
|
||||
private String site_logo;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
|
@ -148,6 +149,17 @@ public class RenderConfig
|
|||
if (logger.isDebugEnabled())
|
||||
logger.debug("Image path: " + image_url);
|
||||
|
||||
static_url = paths_sect_h.getSubElementText("static");
|
||||
if (static_url==null)
|
||||
{ // no <static/> tag - bail out now!
|
||||
logger.fatal("<paths/> section has no <static/> element");
|
||||
throw new ConfigException("no <static/> found in <paths/> section",paths_sect);
|
||||
|
||||
} // end if
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Static files path: " + static_url);
|
||||
|
||||
site_logo = paths_sect_h.getSubElementText("site-logo");
|
||||
if (site_logo==null)
|
||||
{ // no <image/> tag - bail out now!
|
||||
|
@ -256,6 +268,14 @@ public class RenderConfig
|
|||
|
||||
} // end getFullImagePath
|
||||
|
||||
String getStaticFilePath(String name)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(static_url).append(name);
|
||||
return buf.toString();
|
||||
|
||||
} // end getStaticFilePath
|
||||
|
||||
String getTitleTag(String specific)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* 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 Community System.
|
||||
* 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
|
||||
|
@ -24,6 +24,9 @@ import javax.servlet.*;
|
|||
import javax.servlet.http.*;
|
||||
import org.apache.log4j.*;
|
||||
import com.silverwrist.util.StringUtil;
|
||||
import com.silverwrist.venice.core.IDUtils;
|
||||
import com.silverwrist.venice.db.PostLinkRewriter;
|
||||
import com.silverwrist.venice.db.UserNameRewriter;
|
||||
|
||||
public class RenderData
|
||||
{
|
||||
|
@ -128,6 +131,12 @@ public class RenderData
|
|||
|
||||
} // end getFullImagePath
|
||||
|
||||
public String getStaticFilePath(String name)
|
||||
{
|
||||
return rconf.getStaticFilePath(name);
|
||||
|
||||
} // end getStaticFilePath
|
||||
|
||||
public String getFormatJSPPath(String name)
|
||||
{
|
||||
return "/format/" + name;
|
||||
|
@ -320,4 +329,87 @@ public class RenderData
|
|||
|
||||
} // end sendBinaryData
|
||||
|
||||
public String rewritePostData(String data)
|
||||
{
|
||||
if ((data.indexOf(PostLinkRewriter.URI_PREFIX)<0) && (data.indexOf(UserNameRewriter.URI_PREFIX)<0))
|
||||
return data;
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
String interm;
|
||||
|
||||
if (data.indexOf(PostLinkRewriter.URI_PREFIX)>=0)
|
||||
{ // begin replacing everything with post links
|
||||
String t = data;
|
||||
int p = t.indexOf(PostLinkRewriter.URI_PREFIX);
|
||||
while (p>=0)
|
||||
{ // break off the start of the string
|
||||
if (p>0)
|
||||
buf.append(t.substring(0,p));
|
||||
t = t.substring(p + PostLinkRewriter.URI_PREFIX.length());
|
||||
|
||||
// find the end of the post link...
|
||||
p = 0;
|
||||
while (IDUtils.isValidPostLinkChar(t.charAt(p)))
|
||||
p++;
|
||||
|
||||
if (p>0)
|
||||
{ // append the post link to the "go" servlet path, and encode the lot
|
||||
buf.append(getEncodedServletPath("go/" + t.substring(0,p)));
|
||||
t = t.substring(p);
|
||||
|
||||
} // end if
|
||||
else // false alarm
|
||||
buf.append(PostLinkRewriter.URI_PREFIX);
|
||||
|
||||
// and now look again...
|
||||
p = t.indexOf(PostLinkRewriter.URI_PREFIX);
|
||||
|
||||
} // end while
|
||||
|
||||
buf.append(t);
|
||||
interm = buf.toString();
|
||||
buf.setLength(0);
|
||||
|
||||
} // end if
|
||||
else // no post link strings, this is the intermediate form
|
||||
interm = data;
|
||||
|
||||
if (interm.indexOf(UserNameRewriter.URI_PREFIX)>=0)
|
||||
{ // begin replacing everything with user links
|
||||
String t = interm;
|
||||
int p = t.indexOf(UserNameRewriter.URI_PREFIX);
|
||||
while (p>=0)
|
||||
{ // break off the start of the string
|
||||
if (p>0)
|
||||
buf.append(t.substring(0,p));
|
||||
t = t.substring(p + UserNameRewriter.URI_PREFIX.length());
|
||||
|
||||
// find the end of the user link...
|
||||
p = 0;
|
||||
while (IDUtils.isValidVeniceIDChar(t.charAt(p)))
|
||||
p++;
|
||||
|
||||
if (p>0)
|
||||
{ // append the post link to the "user" servlet path, and encode the lot
|
||||
buf.append(getEncodedServletPath("user/" + t.substring(0,p)));
|
||||
t = t.substring(p);
|
||||
|
||||
} // end if
|
||||
else // false alarm
|
||||
buf.append(UserNameRewriter.URI_PREFIX);
|
||||
|
||||
// and now look again...
|
||||
p = t.indexOf(UserNameRewriter.URI_PREFIX);
|
||||
|
||||
} // end while
|
||||
|
||||
buf.append(t);
|
||||
return buf.toString();
|
||||
|
||||
} // end if
|
||||
else // no more to find - just return this
|
||||
return interm;
|
||||
|
||||
} // end rewritePostData
|
||||
|
||||
} // end class RenderData
|
||||
|
|
|
@ -38,6 +38,7 @@ public class TopicPosts implements JSPRender
|
|||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private VeniceEngine engine;
|
||||
private SIGContext sig;
|
||||
private ConferenceContext conf;
|
||||
private TopicContext topic;
|
||||
|
@ -47,6 +48,7 @@ public class TopicPosts implements JSPRender
|
|||
private int unread;
|
||||
private List messages;
|
||||
private TopicVisitOrder visit_order;
|
||||
private String topic_stem;
|
||||
private String cache_locator = null;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
|
@ -54,10 +56,11 @@ public class TopicPosts implements JSPRender
|
|||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public TopicPosts(HttpServletRequest request, SIGContext sig, ConferenceContext conf, TopicContext topic,
|
||||
int first, int last, boolean read_new, boolean show_advanced)
|
||||
public TopicPosts(HttpServletRequest request, VeniceEngine engine, SIGContext sig, ConferenceContext conf,
|
||||
TopicContext topic, int first, int last, boolean read_new, boolean show_advanced)
|
||||
throws DataException, AccessError
|
||||
{
|
||||
this.engine = engine;
|
||||
this.sig = sig;
|
||||
this.conf = conf;
|
||||
this.topic = topic;
|
||||
|
@ -70,6 +73,8 @@ public class TopicPosts implements JSPRender
|
|||
this.messages = topic.getMessages(first,last);
|
||||
this.visit_order = TopicVisitOrder.retrieve(request.getSession(true),conf.getConfID());
|
||||
visit_order.visit(topic.getTopicNumber());
|
||||
List aliases = conf.getAliases();
|
||||
topic_stem = (String)(aliases.get(0)) + "." + String.valueOf(topic.getTopicNumber()) + ".";
|
||||
|
||||
} // end constructor
|
||||
|
||||
|
@ -192,6 +197,14 @@ public class TopicPosts implements JSPRender
|
|||
|
||||
} // end getNextLocator
|
||||
|
||||
public String getRestoreLocator()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer("rtop=");
|
||||
buf.append(topic.getTopicNumber()).append("&rct=").append(unread);
|
||||
return buf.toString();
|
||||
|
||||
} // end getRestoreLocator
|
||||
|
||||
public String getIdentifyingData()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer("Posts ");
|
||||
|
@ -262,7 +275,7 @@ public class TopicPosts implements JSPRender
|
|||
|
||||
public boolean canDeleteTopic()
|
||||
{
|
||||
return false; // TODO: fix me
|
||||
return topic.canDelete();
|
||||
|
||||
} // end canDeleteTopic
|
||||
|
||||
|
@ -274,7 +287,7 @@ public class TopicPosts implements JSPRender
|
|||
|
||||
public String getScrollUpLocator()
|
||||
{
|
||||
int new_first = first - 20; // TODO: configurable
|
||||
int new_first = first - engine.getNumPostsPerPage();
|
||||
int new_last = last - 1;
|
||||
if (new_first<0)
|
||||
{ // normalize so we start at 0
|
||||
|
@ -291,14 +304,14 @@ public class TopicPosts implements JSPRender
|
|||
|
||||
public boolean canScrollDown()
|
||||
{
|
||||
return ((topic.getTotalMessages() - (1 + last))>=20); // TODO: configurable
|
||||
return ((topic.getTotalMessages() - (1 + last))>=engine.getNumPostsPerPage());
|
||||
|
||||
} // end canScrollDown
|
||||
|
||||
public String getScrollDownLocator()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer("p1=");
|
||||
buf.append(last+1).append("&p2=").append(last+20); // TODO: configurable
|
||||
buf.append(last+1).append("&p2=").append(last+engine.getNumPostsPerPage());
|
||||
return buf.toString();
|
||||
|
||||
} // end getScrollDownLocator
|
||||
|
@ -313,7 +326,7 @@ public class TopicPosts implements JSPRender
|
|||
{
|
||||
int my_last = topic.getTotalMessages();
|
||||
StringBuffer buf = new StringBuffer("p1=");
|
||||
buf.append(my_last-20).append("&p2=").append(my_last-1); // TODO: configurable
|
||||
buf.append(my_last-engine.getNumPostsPerPage()).append("&p2=").append(my_last-1);
|
||||
return buf.toString();
|
||||
|
||||
} // end getScrollToEndLocator
|
||||
|
@ -351,4 +364,16 @@ public class TopicPosts implements JSPRender
|
|||
|
||||
} // end getDefaultPseud
|
||||
|
||||
public String getMessageReference(TopicMessageContext msg)
|
||||
{
|
||||
return topic_stem + String.valueOf(msg.getPostNumber());
|
||||
|
||||
} // end getMessageReference
|
||||
|
||||
public int getNumPostsPerPage()
|
||||
{
|
||||
return engine.getNumPostsPerPage();
|
||||
|
||||
} // end getNumPostsPerPage
|
||||
|
||||
} // end class TopicPosts
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
There were <%= data.getNumSpellingErrors() %> spelling errors in your post.
|
||||
<% } // end if %>
|
||||
</B></FONT>
|
||||
<P><PRE><%= data.getPreviewData() %></PRE><HR>
|
||||
<P><PRE><%= rdat.rewritePostData(data.getPreviewData()) %></PRE><HR>
|
||||
<% } // end if %>
|
||||
|
||||
<FORM METHOD="POST" ACTION="<%= rdat.getEncodedServletPath("confops") %>">
|
||||
|
@ -59,7 +59,7 @@
|
|||
<TR>
|
||||
<TD ALIGN=LEFT><%= rdat.getStdFontTag(null,2) %>Message:</FONT></TD>
|
||||
<TD ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<A HREF="TODO" TARGET="_blank">HTML Guide</A>
|
||||
<A HREF="<%= rdat.getStaticFilePath("html-reference.html") %>" TARGET="_blank">HTML Guide</A>
|
||||
</FONT></TD>
|
||||
</TR>
|
||||
<TR><TD ALIGN=LEFT COLSPAN=2>
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
BORDER=0></A>
|
||||
|
||||
<% if (data.isTopicHidden()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=HN") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_show_topic.gif") %>" ALT="Show Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } else { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=HY") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_hide_topic.gif") %>" ALT="Hide Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
|
@ -62,8 +62,8 @@
|
|||
BORDER=0></A>
|
||||
|
||||
<% if (data.getNewMessages()>0) { %>
|
||||
<%-- TODO: this doesn't do Keep New yet --%>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator() + "&rnm=1") %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator() + "&"
|
||||
+ data.getRestoreLocator() + "&rnm=1") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_next_keep_new.gif") %>" ALT="Next & Keep New" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
|
||||
|
@ -75,11 +75,11 @@
|
|||
<% if (data.canFreezeTopic()) { %>
|
||||
|
||||
<% if (data.isTopicFrozen()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=FN") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_unfreeze_topic.gif") %>" ALT="Unfreeze Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } else { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=FY") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_freeze_topic.gif") %>" ALT="Freeze Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
|
@ -87,18 +87,18 @@
|
|||
<% if (data.canArchiveTopic()) { %>
|
||||
|
||||
<% if (data.isTopicArchived()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=AN") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_unarchive_topic.gif") %>" ALT="Unarchive Topic" WIDTH=80
|
||||
HEIGHT=24 BORDER=0></A>
|
||||
<% } else { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=AY") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_archive_topic.gif") %>" ALT="Archive Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
<% } // end if %>
|
||||
<% if (data.canDeleteTopic()) { %>
|
||||
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=DEL") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_delete_topic.gif") %>" ALT="Delete Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
|
@ -119,18 +119,17 @@
|
|||
</TD>
|
||||
<TD NOWRAP ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<% if (rdat.useHTMLComments()) { %><!-- Upper navigation linkset --><% } %>
|
||||
<%-- TODO: the number "20" should be configurable --%>
|
||||
<A NAME="top">[</A>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&p1=0&p2=-1") %>">View All</A>
|
||||
<% if (data.canScrollUp()) { %>
|
||||
|
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&"
|
||||
+ data.getScrollUpLocator()) %>">Scroll Up 20</A>
|
||||
+ data.getScrollUpLocator()) %>">Scroll Up <%= data.getNumPostsPerPage() %></A>
|
||||
<% } // end if %>
|
||||
<% if (data.canScrollDown()) { %>
|
||||
|
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&"
|
||||
+ data.getScrollDownLocator()) %>">Scroll Down 20</A>
|
||||
+ data.getScrollDownLocator()) %>">Scroll Down <%= data.getNumPostsPerPage() %></A>
|
||||
<% } // end if %>
|
||||
<% if (data.canScrollDown()) { %>
|
||||
|
|
||||
|
@ -165,7 +164,11 @@
|
|||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&shac=1&p1="
|
||||
+ String.valueOf(msg.getPostNumber())) %>"><%= msg.getPostNumber() %></A> of
|
||||
<A HREF="<%= last_post %>"><%= data.getTotalMessages() - 1 %></A>
|
||||
<%= rdat.getStdFontTag(null,1) %><<%= "TODO" %>></FONT><BR>
|
||||
<%= rdat.getStdFontTag(null,1) %><<%= data.getMessageReference(msg) %>></FONT>
|
||||
<% if (data.showAdvanced() && msg.isHidden()) { %>
|
||||
<B><EM>(Hidden)</EM></B>
|
||||
<% } // end if %>
|
||||
<BR>
|
||||
<B><%= msg.getPseud() %></B>
|
||||
(<EM>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("user/" + poster) %>" TARGET="_blank"><%= poster %></A>,
|
||||
|
@ -183,36 +186,37 @@
|
|||
<TT><EM><B>
|
||||
(Scribbled by <%= data.getMessageBodyText(msg) %> on
|
||||
<%= rdat.formatDateForDisplay(msg.getScribbleDate()) %>)
|
||||
</B></EM></TT>
|
||||
</B></EM></TT><P>
|
||||
<% } else if (msg.isHidden() && !(data.showAdvanced())) { %>
|
||||
<TT><EM><B>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&shac=1&p1="
|
||||
+ String.valueOf(msg.getPostNumber())) %>">(Hidden
|
||||
Message: <%= msg.getNumLines() %> <% if (msg.getNumLines()==1) { %>Line<% } else { %>Lines<% } %></A>
|
||||
</B></EM></TT>
|
||||
Message: <%= msg.getNumLines() %> <% if (msg.getNumLines()==1) { %>Line<% } else { %>Lines<% } %>)</A>
|
||||
</B></EM></TT><P>
|
||||
<% } else { %>
|
||||
<PRE><%= data.getMessageBodyText(msg) %></PRE>
|
||||
<PRE><%= rdat.rewritePostData(data.getMessageBodyText(msg)) %></PRE>
|
||||
<% } // end if %>
|
||||
<% if (data.showAdvanced()) { %>
|
||||
<% String po_loc = data.getLocator() + "&msg=" + String.valueOf(msg.getPostNumber()); %>
|
||||
</TD><TD NOWRAP ALIGN=RIGHT>
|
||||
<% if (!(msg.isScribbled())) { %>
|
||||
<% if (msg.canHide()) { %>
|
||||
<% if (msg.isHidden()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("postops?" + po_loc + "&cmd=HN") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_show.gif") %>" ALT="Show" WIDTH=80 HEIGHT=24 BORDER=0></A><P>
|
||||
<% } else { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("postops?" + po_loc + "&cmd=HY") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_hide.gif") %>" ALT="Hide" WIDTH=80 HEIGHT=24 BORDER=0></A><P>
|
||||
<% } // end if %>
|
||||
<% } // end if (can hide) %>
|
||||
<% if (msg.canScribble()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("postops?" + po_loc + "&cmd=SCR") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_scribble.gif") %>" ALT="Scribble" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A><P>
|
||||
<% } // end if (can scribble) %>
|
||||
<% } // end if (not already scribbled) %>
|
||||
<% if (msg.canNuke()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("postops?" + po_loc + "&cmd=NUKE") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_nuke.gif") %>" ALT="Nuke" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A><P>
|
||||
<% } // end if (can nuke) %>
|
||||
|
@ -227,18 +231,17 @@
|
|||
<TD NOWRAP ALIGN=LEFT> </TD>
|
||||
<TD NOWRAP ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<% if (rdat.useHTMLComments()) { %><!-- Upper navigation linkset --><% } %>
|
||||
<%-- TODO: the number "20" should be configurable --%>
|
||||
<A NAME="bottom">[</A>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&p1=0&p2=-1") %>">View All</A>
|
||||
<% if (data.canScrollUp()) { %>
|
||||
|
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&"
|
||||
+ data.getScrollUpLocator()) %>">Scroll Up 20</A>
|
||||
+ data.getScrollUpLocator()) %>">Scroll Up <%= data.getNumPostsPerPage() %></A>
|
||||
<% } // end if %>
|
||||
<% if (data.canScrollDown()) { %>
|
||||
|
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getLocator() + "&"
|
||||
+ data.getScrollDownLocator()) %>">Scroll Down 20</A>
|
||||
+ data.getScrollDownLocator()) %>">Scroll Down <%= data.getNumPostsPerPage() %></A>
|
||||
<% } // end if %>
|
||||
<% if (data.canScrollDown()) { %>
|
||||
|
|
||||
|
@ -258,11 +261,11 @@
|
|||
BORDER=0></A>
|
||||
|
||||
<% if (data.isTopicHidden()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=HN") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_show_topic.gif") %>" ALT="Show Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } else { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("TODO?" + data.getLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("topicops?" + data.getLocator() + "&cmd=HY") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_hide_topic.gif") %>" ALT="Hide Topic" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
|
@ -273,8 +276,8 @@
|
|||
BORDER=0></A>
|
||||
|
||||
<% if (data.getNewMessages()>0) { %>
|
||||
<%-- TODO: this doesn't do Keep New yet --%>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator() + "&rnm=1") %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator() + "&"
|
||||
+ data.getRestoreLocator() + "&rnm=1") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_next_keep_new.gif") %>" ALT="Next & Keep New" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
|
||||
|
@ -305,7 +308,7 @@
|
|||
<TR>
|
||||
<TD ALIGN=LEFT><%= rdat.getStdFontTag(null,2) %>Message:</FONT></TD>
|
||||
<TD ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<A HREF="TODO" TARGET="_blank">HTML Guide</A>
|
||||
<A HREF="<%= rdat.getStaticFilePath("html-reference.html") %>" TARGET="_blank">HTML Guide</A>
|
||||
</FONT></TD>
|
||||
</TR>
|
||||
<TR><TD ALIGN=LEFT COLSPAN=2>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
There were <%= data.getNumSpellingErrors() %> spelling errors in your post.
|
||||
<% } // end if %>
|
||||
</B></FONT>
|
||||
<P><PRE><%= data.getPreviewData() %></PRE><HR>
|
||||
<P><PRE><%= rdat.rewritePostData(data.getPreviewData()) %></PRE><HR>
|
||||
|
||||
<FORM METHOD="POST" ACTION="<%= rdat.getEncodedServletPath("post") %>">
|
||||
<INPUT TYPE="HIDDEN" NAME="sig" VALUE="<%= data.getSIGID() %>">
|
||||
|
@ -55,7 +55,7 @@
|
|||
<TR>
|
||||
<TD ALIGN=LEFT><%= rdat.getStdFontTag(null,2) %>Message:</FONT></TD>
|
||||
<TD ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<A HREF="TODO" TARGET="_blank">HTML Guide</A>
|
||||
<A HREF="<%= rdat.getStaticFilePath("html-reference.html") %>" TARGET="_blank">HTML Guide</A>
|
||||
</FONT></TD>
|
||||
</TR>
|
||||
<TR><TD ALIGN=LEFT COLSPAN=2>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
%>
|
||||
<%= rdat.getStdFontTag(null,2) %>
|
||||
<B><%= msg.getPostNumber() %></B> of <B><%= data.getTotalMessages() - 1 %></B>
|
||||
<%= rdat.getStdFontTag(null,1) %><<%= "TODO" %>></FONT><BR>
|
||||
<%= rdat.getStdFontTag(null,1) %><<%= data.getMessageReference(msg) %>></FONT><BR>
|
||||
<B><%= msg.getPseud() %></B>
|
||||
(<EM>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("user/" + poster) %>" TARGET="_blank"><%= poster %></A>,
|
||||
|
@ -54,7 +54,7 @@
|
|||
<%= rdat.formatDateForDisplay(msg.getScribbleDate()) %>)
|
||||
</B></EM></TT>
|
||||
<% } else { %>
|
||||
<PRE><%= data.getMessageBodyText(msg) %></PRE>
|
||||
<PRE><%= rdat.rewritePostData(data.getMessageBodyText(msg)) %></PRE>
|
||||
<% } // end if %>
|
||||
<% } // end while %>
|
||||
<% if (rdat.useHTMLComments()) { %><!-- End Slipped Messages --><% } %>
|
||||
|
@ -79,7 +79,7 @@
|
|||
<TR>
|
||||
<TD ALIGN=LEFT><%= rdat.getStdFontTag(null,2) %>Message:</FONT></TD>
|
||||
<TD ALIGN=RIGHT><%= rdat.getStdFontTag(null,2) %>
|
||||
<A HREF="TODO" TARGET="_blank">HTML Guide</A>
|
||||
<A HREF="<%= rdat.getStaticFilePath("html-reference.html") %>" TARGET="_blank">HTML Guide</A>
|
||||
</FONT></TD>
|
||||
</TR>
|
||||
<TR><TD ALIGN=LEFT COLSPAN=2>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
String tmp;
|
||||
%>
|
||||
<% if (rdat.useHTMLComments()) { %><!-- Topic list for conf #<%= data.getConfID() %> --><% } %>
|
||||
<% rdat.writeContentHeader(out,data.getConfName() + " Topics",null); %>
|
||||
<% rdat.writeContentHeader(out,"Topics in " + data.getConfName(),null); %>
|
||||
<%= rdat.getStdFontTag(null,2) %>
|
||||
<DIV ALIGN="LEFT">
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confops?sig=" + String.valueOf(data.getSIGID())) %>"><IMG
|
||||
|
@ -40,7 +40,7 @@
|
|||
WIDTH=80 HEIGHT=24 BORDER=0></A>
|
||||
<% } // end if %>
|
||||
<% if (data.canDoReadNew()) { %>
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator()) %>"><IMG
|
||||
<A HREF="<%= rdat.getEncodedServletPath("confdisp?" + data.getNextLocator() + "&rnm=1") %>"><IMG
|
||||
SRC="<%= rdat.getFullImagePath("bn_read_new.gif") %>" ALT="Read New" WIDTH=80 HEIGHT=24
|
||||
BORDER=0></A>
|
||||
<% } // end if %>
|
||||
|
|
1570
web/static/html-reference.html
Normal file
BIN
web/static/images/ref-c0.gif
Normal file
After Width: | Height: | Size: 109 B |
BIN
web/static/images/ref-c1.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c2.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c3.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c4.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c5.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c6.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c7.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c8.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-c9.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-ca.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-cb.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-cc.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-cd.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-ce.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref-cf.gif
Normal file
After Width: | Height: | Size: 151 B |
BIN
web/static/images/ref32smi.gif
Normal file
After Width: | Height: | Size: 943 B |
BIN
web/static/images/ref64yr.gif
Normal file
After Width: | Height: | Size: 1.0 KiB |