implemented front page content management, finally wired up the user locale

and timezone default mechanism, and did some other bugfixing and stuff
This commit is contained in:
Eric J. Bowersox 2001-02-28 07:55:00 +00:00
parent 129b69973b
commit 2e455b4bdd
37 changed files with 1555 additions and 109 deletions

5
TODO
View File

@ -17,11 +17,6 @@ Lots!
- Unimplemented functions on the Top page: - Unimplemented functions on the Top page:
Customize Sideboxes Customize Sideboxes
- The plan for the "main" part of the Top page is to let a sysadmin put
notices there by "publishing" selected conference messages to the front page.
We may include a welcome message up top to be displayed if the user's not
logged in.
- Slippage during posting is still untested. - Slippage during posting is still untested.
- Not everybody likes purple. Provide a way to change the default colors. - Not everybody likes purple. Provide a way to change the default colors.

View File

@ -1,5 +1,6 @@
advogato advogato
ain't ain't
anime
anla'shok anla'shok
bajor bajor
bios bios

View File

@ -50,4 +50,20 @@
<site-logo>http://delenn:8080/venice/images/powered-by-venice.gif</site-logo> <site-logo>http://delenn:8080/venice/images/powered-by-venice.gif</site-logo>
</paths> </paths>
<!-- Contains standard messages displayed by front end -->
<messages>
<!-- The message displayed at the top of "top" when you're not logged in -->
<welcome>
Welcome to the Venice Web Communities System. To get the most out of this site, you should log in or create
an account, using one of the links above.
</welcome>
<!-- The headline for the welcome message -->
<welcome-top>Welcome to Venice</welcome-top>
<!-- The headline for the "currents" box -->
<currents-top>Venice Currents</currents-top>
</messages>
</render-config> </render-config>

View File

@ -1,4 +1,3 @@
# MySQL script for initializing the Venice database. # MySQL script for initializing the Venice database.
# Written by Eric J. Bowersox <erbo@silcom.com> # Written by Eric J. Bowersox <erbo@silcom.com>
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -39,7 +38,8 @@ CREATE TABLE globals (
old_posts_at_top INT NOT NULL, old_posts_at_top INT NOT NULL,
max_search_page INT NOT NULL, max_search_page INT NOT NULL,
max_sig_mbr_page INT NOT NULL, max_sig_mbr_page INT NOT NULL,
max_conf_mbr_page INT NOT NULL max_conf_mbr_page INT NOT NULL,
fp_posts INT NOT NULL
); );
# The audit records table. Most "major" events add a record to this table. # The audit records table. Most "major" events add a record to this table.
@ -87,7 +87,7 @@ CREATE TABLE users (
CREATE TABLE userprefs ( CREATE TABLE userprefs (
uid INT NOT NULL PRIMARY KEY, uid INT NOT NULL PRIMARY KEY,
tzid VARCHAR(64) DEFAULT 'UTC', tzid VARCHAR(64) DEFAULT 'UTC',
localeid VARCHAR(64) DEFAULT 'en-US-' localeid VARCHAR(64) DEFAULT 'en_US'
); );
# Indicates what the top-level "sidebox" configuration is for any given user. # Indicates what the top-level "sidebox" configuration is for any given user.
@ -377,6 +377,7 @@ CREATE TABLE postattach (
datalen INT, datalen INT,
filename VARCHAR(255), filename VARCHAR(255),
mimetype VARCHAR(128), mimetype VARCHAR(128),
stgmethod SMALLINT DEFAULT 0,
data MEDIUMBLOB data MEDIUMBLOB
); );
@ -387,6 +388,15 @@ CREATE TABLE postdogear (
PRIMARY KEY (uid, postid) PRIMARY KEY (uid, postid)
); );
# "Front page" publishing table.
CREATE TABLE postpublish (
sigid INT NOT NULL,
postid BIGINT NOT NULL PRIMARY KEY,
by_uid INT NOT NULL,
on_date DATETIME NOT NULL,
INDEX display_order (on_date, postid)
);
############################################################################## ##############################################################################
# Set table access rights # Set table access rights
############################################################################## ##############################################################################
@ -409,6 +419,7 @@ GRANT INSERT, DELETE, UPDATE, SELECT ON venice.*
# Types of audit records. This MUST be kept in sync with the constant definitions in # Types of audit records. This MUST be kept in sync with the constant definitions in
# com.silverwrist.venice.security.Audit!!!! # com.silverwrist.venice.security.Audit!!!!
INSERT INTO refaudit (type, descr) VALUES INSERT INTO refaudit (type, descr) VALUES
(1, 'Publish Message to Front Page'),
(101, 'Login OK'), (101, 'Login OK'),
(102, 'Login Failure'), (102, 'Login Failure'),
(103, 'Account Created'), (103, 'Account Created'),
@ -1312,8 +1323,9 @@ INSERT INTO refsigftr (ftr_code, is_default, is_locked, is_hidden, require_read,
############################################################################## ##############################################################################
# Initialize the system globals table. # Initialize the system globals table.
INSERT INTO globals (posts_per_page, old_posts_at_top, max_search_page, max_sig_mbr_page, max_conf_mbr_page) INSERT INTO globals (posts_per_page, old_posts_at_top, max_search_page, max_sig_mbr_page, max_conf_mbr_page,
VALUES (20, 2, 20, 50, 50); fp_posts)
VALUES (20, 2, 20, 50, 50, 10);
# Add the 'Anonymous Honyak' user to the users table. # Add the 'Anonymous Honyak' user to the users table.
# (Do 'SELECT * FROM users WHERE is_anon = 1' to retrieve the AC user details.) # (Do 'SELECT * FROM users WHERE is_anon = 1' to retrieve the AC user details.)

View File

@ -0,0 +1,62 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util;
import java.util.*;
public class LocaleFactory
{
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
private LocaleFactory()
{ // this object cannot be instantiated
} // end constructor
/*--------------------------------------------------------------------------------
* External static operations
*--------------------------------------------------------------------------------
*/
public static Locale createLocale(String streq)
{
if ((streq==null) || (streq.length()==0))
return Locale.getDefault();
int p1 = streq.indexOf('_');
if (p1<0)
return new Locale(streq,"");
String x_lang = streq.substring(0,p1);
int p2 = streq.indexOf('_',p1+1);
if (p2<0)
{ // there's only one underscore - figure out what part the last part is
String lastpart = streq.substring(p1+1);
if (lastpart.length()==2)
return new Locale(streq.substring(0,p1),lastpart);
else
return new Locale(streq.substring(0,p1),"",lastpart);
} // end if
// do all three variants
return new Locale(streq.substring(0,p1),streq.substring(p1+1,p2),streq.substring(p2+1));
} // end createLocale
} // end class LocaleFactory

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -73,4 +73,8 @@ public interface TopicMessageContext
public abstract void attachData(String m_type, String file, int length, InputStream data) public abstract void attachData(String m_type, String file, int length, InputStream data)
throws AccessError, DataException; throws AccessError, DataException;
public abstract boolean canPublish();
public abstract void publish() throws DataException, AccessError;
} // end interface TopicMessageContext } // end interface TopicMessageContext

View File

@ -18,6 +18,8 @@
package com.silverwrist.venice.core; package com.silverwrist.venice.core;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
public interface UserContext extends SearchMode public interface UserContext extends SearchMode
{ {
@ -93,4 +95,12 @@ public interface UserContext extends SearchMode
public abstract AdminOperations getAdminInterface() throws AccessError; public abstract AdminOperations getAdminInterface() throws AccessError;
public abstract Locale getLocale() throws DataException;
public abstract void setLocale(Locale locale) throws DataException;
public abstract TimeZone getTimeZone() throws DataException;
public abstract void setTimeZone(TimeZone timezone) throws DataException;
} // end interface UserContext } // end interface UserContext

View File

@ -73,4 +73,6 @@ public interface VeniceEngine extends SearchMode
public abstract List getMasterSideBoxList(); public abstract List getMasterSideBoxList();
public abstract List getPublishedMessages(boolean all) throws DataException;
} // end interface VeniceEngine } // end interface VeniceEngine

View File

@ -37,6 +37,7 @@ class BackgroundConferencePurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
private EngineBackend engine;
private DataPool datapool; private DataPool datapool;
private int confid; private int confid;
private int num_topics; private int num_topics;
@ -47,8 +48,10 @@ class BackgroundConferencePurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
BackgroundConferencePurge(DataPool datapool, int confid, int num_topics, int max_topicid) BackgroundConferencePurge(EngineBackend engine, DataPool datapool, int confid, int num_topics,
int max_topicid)
{ {
this.engine = engine;
this.datapool = datapool; this.datapool = datapool;
this.confid = confid; this.confid = confid;
this.num_topics = num_topics; this.num_topics = num_topics;
@ -100,7 +103,7 @@ class BackgroundConferencePurge implements Runnable
rs = stmt.executeQuery(sql.toString()); rs = stmt.executeQuery(sql.toString());
if (!(rs.next())) if (!(rs.next()))
throw new InternalStateError("BackgroundConferencePurge.run screwup on post SELECT"); throw new InternalStateError("BackgroundConferencePurge.run screwup on post SELECT");
rq.queue(new BackgroundTopicPurge(datapool,topicids[i],rs.getInt(1),rs.getLong(2))); rq.queue(new BackgroundTopicPurge(engine,datapool,topicids[i],rs.getInt(1),rs.getLong(2)));
} // end for } // end for

View File

@ -39,6 +39,7 @@ class BackgroundSIGPurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
private EngineBackend engine;
private DataPool datapool; private DataPool datapool;
private UserBackend user; private UserBackend user;
private int sigid; private int sigid;
@ -51,9 +52,10 @@ class BackgroundSIGPurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
BackgroundSIGPurge(DataPool datapool, UserBackend user, int sigid, int num_confs, int max_confid, BackgroundSIGPurge(EngineBackend engine, DataPool datapool, UserBackend user, int sigid, int num_confs,
Hashtable conf_objects) int max_confid, Hashtable conf_objects)
{ {
this.engine = engine;
this.datapool = datapool; this.datapool = datapool;
this.user = user; this.user = user;
this.sigid = sigid; this.sigid = sigid;
@ -137,7 +139,7 @@ class BackgroundSIGPurge implements Runnable
rs = stmt.executeQuery(sql.toString()); rs = stmt.executeQuery(sql.toString());
if (!(rs.next())) if (!(rs.next()))
throw new InternalStateError("BackgroundSIGPurge.run screwup on conference SELECT"); throw new InternalStateError("BackgroundSIGPurge.run screwup on conference SELECT");
rq.queue(new BackgroundConferencePurge(datapool,key.intValue(),rs.getInt(1),rs.getInt(2))); rq.queue(new BackgroundConferencePurge(engine,datapool,key.intValue(),rs.getInt(1),rs.getInt(2)));
} // end if (have to delete conference data) } // end if (have to delete conference data)

View File

@ -35,6 +35,7 @@ class BackgroundTopicPurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
private EngineBackend engine;
private DataPool datapool; private DataPool datapool;
private int topicid; private int topicid;
private int num_posts; private int num_posts;
@ -45,8 +46,9 @@ class BackgroundTopicPurge implements Runnable
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
BackgroundTopicPurge(DataPool datapool, int topicid, int num_posts, long max_postid) BackgroundTopicPurge(EngineBackend engine, DataPool datapool, int topicid, int num_posts, long max_postid)
{ {
this.engine = engine;
this.datapool = datapool; this.datapool = datapool;
this.topicid = topicid; this.topicid = topicid;
this.num_posts = num_posts; this.num_posts = num_posts;
@ -62,7 +64,7 @@ class BackgroundTopicPurge implements Runnable
public void run() public void run()
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("BackgroundTopicPurge running on topic #" + String.valueOf(topicid)); logger.debug("BackgroundTopicPurge running on topic #" + topicid);
long[] postids = new long[num_posts]; // stores the post IDs long[] postids = new long[num_posts]; // stores the post IDs
Connection conn = null; // pooled database connection Connection conn = null; // pooled database connection
@ -82,22 +84,23 @@ class BackgroundTopicPurge implements Runnable
for (int i=0; i<posts; i++) for (int i=0; i<posts; i++)
{ // remove all references to the posts in question { // remove all references to the posts in question
stmt.executeUpdate("DELETE FROM posts WHERE postid = " + String.valueOf(postids[i]) + ";"); stmt.executeUpdate("DELETE FROM posts WHERE postid = " + postids[i] + ";");
stmt.executeUpdate("DELETE FROM postdata WHERE postid = " + String.valueOf(postids[i]) + ";"); stmt.executeUpdate("DELETE FROM postdata WHERE postid = " + postids[i] + ";");
stmt.executeUpdate("DELETE FROM postattach WHERE postid = " + String.valueOf(postids[i]) + ";"); stmt.executeUpdate("DELETE FROM postattach WHERE postid = " + postids[i] + ";");
stmt.executeUpdate("DELETE FROM postdogear WHERE postid = " + String.valueOf(postids[i]) + ";"); stmt.executeUpdate("DELETE FROM postdogear WHERE postid = " + postids[i] + ";");
if (stmt.executeUpdate("DELETE FROM postpublish WHERE postid = " + postids[i] + ";")>0)
engine.unpublish(postids[i]);
} // end for } // end for
// all done, Bunky! // all done, Bunky!
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("BackgroundTopicPurge complete for topic #" + String.valueOf(topicid)); logger.debug("BackgroundTopicPurge complete for topic #" + topicid);
} // end try } // end try
catch (SQLException e) catch (SQLException e)
{ // on an error, just die { // on an error, just die
logger.error("BackgroundTopicPurge FATAL EXCEPTION purging #" + String.valueOf(topicid) + ": " logger.error("BackgroundTopicPurge FATAL EXCEPTION purging #" + topicid + ": " + e.getMessage(),e);
+ e.getMessage(),e);
} // end catch } // end catch
finally finally

View File

@ -1238,7 +1238,8 @@ class ConferenceCoreData implements ConferenceData
} // end finally } // end finally
// Delete the rest of the gunk in the background; spin off another thread to handle it. // Delete the rest of the gunk in the background; spin off another thread to handle it.
BackgroundConferencePurge purger = new BackgroundConferencePurge(datapool,confid,topic_count,topic_max); BackgroundConferencePurge purger = new BackgroundConferencePurge(engine,datapool,confid,topic_count,
topic_max);
Thread thrd = new Thread(purger); Thread thrd = new Thread(purger);
thrd.setPriority(Thread.NORM_PRIORITY-1); thrd.setPriority(Thread.NORM_PRIORITY-1);
thrd.start(); thrd.start();

View File

@ -789,7 +789,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
else else
{ // need to insert a confsettings row { // need to insert a confsettings row
sql.append("INSERT INTO confsettings (confid, uid, default_pseud) VALUES (").append(confid); sql.append("INSERT INTO confsettings (confid, uid, default_pseud) VALUES (").append(confid);
sql.append(", ").append(sig.realUID()).append(", '").append(SQLUtil.encodeString(val)).append("';"); sql.append(", ").append(sig.realUID()).append(", '").append(SQLUtil.encodeString(val)).append("');");
} // end else } // end else

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -19,12 +19,24 @@ package com.silverwrist.venice.core.impl;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import org.apache.log4j.*;
import com.silverwrist.venice.core.*; import com.silverwrist.venice.core.*;
import com.silverwrist.venice.db.*; import com.silverwrist.venice.db.*;
class ContactInfoImpl implements ContactInfo, Stashable class ContactInfoImpl implements ContactInfo, Stashable
{ {
// Attributes /*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Category logger = Category.getInstance(ContactInfoImpl.class.getName());
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private int contactid; // ID of this contact record (-1 = new) private int contactid; // ID of this contact record (-1 = new)
private String given_name; // given name ("first name") private String given_name; // given name ("first name")
private String family_name; // family name ("last name") private String family_name; // family name ("last name")
@ -53,6 +65,11 @@ class ContactInfoImpl implements ContactInfo, Stashable
private java.util.Date last_update; // date of last update private java.util.Date last_update; // date of last update
private boolean is_modified = false; // have we modified this ContactInfo? private boolean is_modified = false; // have we modified this ContactInfo?
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
/** /**
* Constructs a new blank <CODE>ContactInfoImpl</CODE> object. * Constructs a new blank <CODE>ContactInfoImpl</CODE> object.
* *
@ -60,6 +77,8 @@ class ContactInfoImpl implements ContactInfo, Stashable
*/ */
ContactInfoImpl(int owner_uid) ContactInfoImpl(int owner_uid)
{ {
if (logger.isDebugEnabled())
logger.debug("new ContactInfoImpl (empty) for UID = " + owner_uid);
makeEmpty(owner_uid,-1); makeEmpty(owner_uid,-1);
} // end constructor } // end constructor
@ -72,6 +91,8 @@ class ContactInfoImpl implements ContactInfo, Stashable
*/ */
ContactInfoImpl(int owner_uid, int owner_sigid) ContactInfoImpl(int owner_uid, int owner_sigid)
{ {
if (logger.isDebugEnabled())
logger.debug("new ContactInfoImpl (empty) for UID = " + owner_uid + ", SIGID = " + owner_sigid);
makeEmpty(owner_uid,owner_sigid); makeEmpty(owner_uid,owner_sigid);
} // end constructor } // end constructor
@ -85,6 +106,8 @@ class ContactInfoImpl implements ContactInfo, Stashable
*/ */
ContactInfoImpl(DataPool dp, int contactid) throws DataException ContactInfoImpl(DataPool dp, int contactid) throws DataException
{ {
if (logger.isDebugEnabled())
logger.debug("new ContactInfoImpl (loading CID " + contactid + ")");
Connection conn = null; Connection conn = null;
try try
@ -95,6 +118,7 @@ class ContactInfoImpl implements ContactInfo, Stashable
} // end try } // end try
catch (SQLException e) catch (SQLException e)
{ // turn SQLExceptions at this level into DataExceptions { // turn SQLExceptions at this level into DataExceptions
logger.error("DB error loading contact ID " + contactid + ": " + e.getMessage(),e);
throw new DataException("Unable to look up contact info: " + e.getMessage(),e); throw new DataException("Unable to look up contact info: " + e.getMessage(),e);
} // end catch } // end catch
@ -107,6 +131,11 @@ class ContactInfoImpl implements ContactInfo, Stashable
} // end constructor } // end constructor
/*--------------------------------------------------------------------------------
* Internal functions
*--------------------------------------------------------------------------------
*/
private void makeEmpty(int owner_uid, int owner_sigid) private void makeEmpty(int owner_uid, int owner_sigid)
{ {
this.contactid = -1; this.contactid = -1;
@ -180,18 +209,28 @@ class ContactInfoImpl implements ContactInfo, Stashable
last_update = SQLUtil.getFullDateTime(rs,"lastupdate"); last_update = SQLUtil.getFullDateTime(rs,"lastupdate");
} // end if } // end if
else // contact was not found else
{ // contact was not found
logger.error("contact ID " + contactid + " not found in database");
throw new DataException("Contact was not found."); throw new DataException("Contact was not found.");
} // end else
} // end try } // end try
catch (SQLException e) catch (SQLException e)
{ // map all SQLExceptions into DataExceptions { // map all SQLExceptions into DataExceptions
logger.error("DB error loading contact ID " + contactid + ": " + e.getMessage(),e);
throw new DataException("Unable to look up contact info: " + e.getMessage(),e); throw new DataException("Unable to look up contact info: " + e.getMessage(),e);
} // end catch } // end catch
} // end loadData } // end loadData
/*--------------------------------------------------------------------------------
* Implementations from interface ContactInfo
*--------------------------------------------------------------------------------
*/
public int getContactID() public int getContactID()
{ {
return contactid; return contactid;
@ -559,6 +598,11 @@ class ContactInfoImpl implements ContactInfo, Stashable
} // end getModified } // end getModified
/*--------------------------------------------------------------------------------
* Implementations from interface Stashable
*--------------------------------------------------------------------------------
*/
public int getStashableUID() public int getStashableUID()
{ {
return getOwnerUID(); return getOwnerUID();
@ -567,6 +611,8 @@ class ContactInfoImpl implements ContactInfo, Stashable
public void stash(Connection conn) throws DataException, SQLException public void stash(Connection conn) throws DataException, SQLException
{ {
if (logger.isDebugEnabled())
logger.debug("stashing contact ID " + contactid);
java.util.Date update = null; java.util.Date update = null;
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
StringBuffer buf; StringBuffer buf;
@ -653,10 +699,19 @@ class ContactInfoImpl implements ContactInfo, Stashable
int new_contactid; int new_contactid;
ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID();"); ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID();");
if (rs.next()) if (rs.next())
{ // found the contact ID...
new_contactid = rs.getInt(1); new_contactid = rs.getInt(1);
if (logger.isDebugEnabled())
logger.debug("created new contact ID " + new_contactid);
} // end if
else else
{ // error reading back the contact ID
logger.error("unable to read back contact ID");
throw new DataException("unable to read back new contact ID"); throw new DataException("unable to read back new contact ID");
} // end else
// and patch the database table so we know what our contact ID is // and patch the database table so we know what our contact ID is
buf.setLength(0); buf.setLength(0);
if (owner_sigid>=0) if (owner_sigid>=0)

View File

@ -36,6 +36,7 @@ public interface EngineBackend
public static final int IP_MAXSEARCHRETURN = 2; public static final int IP_MAXSEARCHRETURN = 2;
public static final int IP_MAXSIGMEMBERDISPLAY = 3; public static final int IP_MAXSIGMEMBERDISPLAY = 3;
public static final int IP_MAXCONFMEMBERDISPLAY = 4; public static final int IP_MAXCONFMEMBERDISPLAY = 4;
public static final int IP_NUMFRONTPAGEPOSTS = 5;
public abstract SimpleEmailer createEmailer(); public abstract SimpleEmailer createEmailer();
@ -83,4 +84,10 @@ public interface EngineBackend
public abstract SideBoxDescriptor getMasterSideBoxDescriptor(int id); public abstract SideBoxDescriptor getMasterSideBoxDescriptor(int id);
public abstract void startPublish();
public abstract void publishNew(PublishedMessageImpl pubmsg);
public abstract void unpublish(long postid);
} // end interface EngineBackend } // end interface EngineBackend

View File

@ -0,0 +1,426 @@
/*
* 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.io.*;
import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.db.*;
import com.silverwrist.venice.core.*;
class PublishedMessageImpl implements TopicMessageContext
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Category logger = Category.getInstance(PublishedMessageImpl.class.getName());
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private DataPool datapool;
private long postid;
private long parent;
private int num;
private int linecount;
private int creator_uid;
private java.util.Date posted;
private String pseud;
private String creator_cache = null;
private String text_cache = null;
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
PublishedMessageImpl(DataPool datapool, long postid, long parent, int num, int linecount, int creator_uid,
java.util.Date posted, String pseud, String creator_cache, String text_cache)
{
this.datapool = datapool;
this.postid = postid;
this.parent = parent;
this.num = num;
this.linecount = linecount;
this.creator_uid = creator_uid;
this.posted = posted;
this.pseud = pseud;
this.creator_cache = creator_cache;
this.text_cache = text_cache;
} // end constructor
protected PublishedMessageImpl(DataPool datapool, long postid, long parent, int num, int linecount,
int creator_uid, java.util.Date posted, String pseud)
{
this.datapool = datapool;
this.postid = postid;
this.parent = parent;
this.num = num;
this.linecount = linecount;
this.creator_uid = creator_uid;
this.posted = posted;
this.pseud = pseud;
} // end constructor
/*--------------------------------------------------------------------------------
* Internal functions
*--------------------------------------------------------------------------------
*/
private static String quickGetUserName(Connection conn, int uid) throws SQLException
{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT username FROM users WHERE uid = " + String.valueOf(uid) + ";");
if (rs.next())
return rs.getString(1);
else
return "(unknown)";
} // end quickGetUserName
/*--------------------------------------------------------------------------------
* Implementations from interface TopicMessageContext
*--------------------------------------------------------------------------------
*/
public long getPostID()
{
return postid;
} // end getPostID
public long getParentPostID()
{
return parent;
} // end getParentPostID
public int getPostNumber()
{
return num;
} // end getPostNumber
public int getNumLines()
{
return linecount;
} // end getNumLines
public int getCreatorUID()
{
return creator_uid;
} // end getCreatorUID
public String getCreatorName() throws DataException
{
if (creator_cache==null)
{ // we don't have the user name yet, get it out of the database
Connection conn = null;
try
{ // use a database connection to get the user name
conn = datapool.getConnection();
creator_cache = quickGetUserName(conn,creator_uid);
} // end try
catch (SQLException e)
{ // turn this into a DataException
logger.error("DB error reading user name: " + e.getMessage(),e);
throw new DataException("unable to retrieve user name: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end if
return creator_cache;
} // end getCreatorName
public java.util.Date getPostDate()
{
return posted;
} // end getPostDate
public boolean isHidden()
{
return false;
} // end isHidden
public boolean isScribbled()
{
return false;
} // end isScribbled
public boolean isNuked()
{
return false;
} // end isNuked
public java.util.Date getScribbleDate()
{
return null;
} // end getScribbleDate
public String getPseud()
{
return pseud;
} // end getPseud
public String getBodyText() throws DataException
{
if (text_cache==null)
{ // we don't have the body text yet, go get it
Connection conn = null;
try
{ // use a database connection to get the body text
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT data FROM postdata WHERE postid = "
+ String.valueOf(postid) + ";");
if (rs.next())
text_cache = rs.getString(1);
else
return "Data Missing"; // FUTURE: throw an exception?
} // end try
catch (SQLException e)
{ // turn this into a DataException
logger.error("DB error reading post data: " + e.getMessage(),e);
throw new DataException("unable to retrieve post data: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end if
return text_cache;
} // end getBodyCache
public boolean hasAttachment()
{
return false; // FUTURE: allow publishing paperclips?
} // end hasAttachment
public String getAttachmentType()
{
return null; // FUTURE: allow publishing paperclips?
} // end getAttachmentType
public String getAttachmentFilename()
{
return null; // FUTURE: allow publishing paperclips?
} // end getAttachmentFilename
public int getAttachmentLength()
{
return 0; // FUTURE: allow publishing paperclips?
} // end getAttachmentLength
public InputStream getAttachmentData() throws AccessError, DataException
{
// FUTURE: allow publishing paperclips?
throw new AccessError("There is no attachment data for this message.");
} // end getAttachmentData
public boolean canHide()
{
return false;
} // end canHide
public boolean canScribble()
{
return false;
} // end canScribble
public boolean canNuke()
{
return false;
} // end canNuke
public void setHidden(boolean flag) throws DataException, AccessError
{
throw new AccessError("You are not permitted to change the hidden status of this message.");
} // end setHidden
public void scribble() throws DataException, AccessError
{
throw new AccessError("You are not permitted to scribble this message.");
} // end scribble
public void nuke() throws DataException, AccessError
{
throw new AccessError("You are not permitted to nuke this message.");
} // end nuke
public void attachData(String m_type, String file, int length, InputStream data)
throws AccessError, DataException
{
throw new AccessError("You are not permitted to add an attachment to this message.");
} // end attachData
public boolean canPublish()
{
return false;
} // end canPublish
public void publish() throws DataException, AccessError
{
throw new DataException("Cannot publish a message that has already been published.");
} // end publish
/*--------------------------------------------------------------------------------
* Static operations usable only within package
*--------------------------------------------------------------------------------
*/
static void backfillCache(List cache_list, int desired_size, DataPool datapool) throws DataException
{
Connection conn = null;
try
{ // get a database connection
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// create the statement to retrieve the post information
StringBuffer sql =
new StringBuffer("SELECT p.postid, q.parent, q.num, q.linecount, q.creator_uid, q.posted, "
+ "q.pseud FROM postpublish p, posts q WHERE p.postid = q.postid "
+ "ORDER BY p.on_date DESC, p.postid ASC LIMIT ");
sql.append(cache_list.size()).append(", ").append(desired_size-cache_list.size()).append(';');
// execute the statement!
ResultSet rs = stmt.executeQuery(sql.toString());
while (rs.next())
cache_list.add(new PublishedMessageImpl(datapool,rs.getLong(1),rs.getLong(2),rs.getInt(3),rs.getInt(4),
rs.getInt(5),SQLUtil.getFullDateTime(rs,6),rs.getString(7)));
} // end try
catch (SQLException e)
{ // error retrieving post information
logger.error("DB error reading post information: " + e.getMessage(),e);
throw new DataException("unable to retrieve post information: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end backfillCache
static void backfillReturn(List return_list, DataPool datapool) throws DataException
{
Connection conn = null;
try
{ // get a database connection
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// How many posts have been published anyway?
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM postpublish;");
if (!(rs.next()))
throw new InternalStateError("Count query screwup in PublishedMessageImpl.backfillReturn");
if (rs.getInt(1)<=return_list.size())
return; // nothing to do here!
// execute the statement to retrieve the post information
final String sql = "SELECT p.postid, q.parent, q.num, q.linecount, q.creator_uid, q.posted, q.pseud "
+ "FROM postpublish p, posts q WHERE p.postid = q.postid ORDER BY p.on_date DESC, "
+ "p.postid ASC;";
rs = stmt.executeQuery(sql);
// append to the output list
int ctr = return_list.size();
while (rs.next())
{ // we need to skip the first batch of output, because it's cached
if ((ctr--)<=0)
{ // append context, please
TopicMessageContext ctxt =
new PublishedMessageImpl(datapool,rs.getLong(1),rs.getLong(2),rs.getInt(3),rs.getInt(4),
rs.getInt(5),SQLUtil.getFullDateTime(rs,6),rs.getString(7));
return_list.add(ctxt);
} // end if
} // end while
} // end try
catch (SQLException e)
{ // error retrieving post information
logger.error("DB error reading post information: " + e.getMessage(),e);
throw new DataException("unable to retrieve post information: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end backfillReturn
} // end class PublishedMessageImpl

View File

@ -1852,7 +1852,8 @@ class SIGCoreData implements SIGData, SIGDataBackend
} // end finally } // end finally
// Delete the rest of the gunk in the background; use another thread to do it. // Delete the rest of the gunk in the background; use another thread to do it.
BackgroundSIGPurge purger = new BackgroundSIGPurge(datapool,user,sigid,conf_count,conf_max,conf_objects); BackgroundSIGPurge purger = new BackgroundSIGPurge(engine,datapool,user,sigid,conf_count,conf_max,
conf_objects);
Thread thrd = new Thread(purger); Thread thrd = new Thread(purger);
thrd.setPriority(Thread.NORM_PRIORITY-1); thrd.setPriority(Thread.NORM_PRIORITY-1);
thrd.start(); thrd.start();

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -24,6 +24,7 @@ import org.apache.log4j.*;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.db.*; import com.silverwrist.venice.db.*;
import com.silverwrist.venice.security.AuditRecord; import com.silverwrist.venice.security.AuditRecord;
import com.silverwrist.venice.security.Capability;
import com.silverwrist.venice.core.*; import com.silverwrist.venice.core.*;
class TopicMessageUserContextImpl implements TopicMessageContext class TopicMessageUserContextImpl implements TopicMessageContext
@ -123,7 +124,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
private static String quickGetUserName(Connection conn, int uid) throws SQLException private static String quickGetUserName(Connection conn, int uid) throws SQLException
{ {
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT username FROM users WHERE uid = " + String.valueOf(uid) + ";"); ResultSet rs = stmt.executeQuery("SELECT username FROM users WHERE uid = " + uid + ";");
if (rs.next()) if (rs.next())
return rs.getString(1); return rs.getString(1);
else else
@ -297,8 +298,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
if (scribble_date==null) if (scribble_date==null)
{ // let's go get the body text! { // let's go get the body text!
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT data FROM postdata WHERE postid = " ResultSet rs = stmt.executeQuery("SELECT data FROM postdata WHERE postid = " + postid + ";");
+ String.valueOf(postid) + ";");
if (rs.next()) if (rs.next())
text_cache = rs.getString(1); text_cache = rs.getString(1);
else else
@ -508,8 +508,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
// record what we did in an audit record // record what we did in an audit record
ar = new AuditRecord(AuditRecord.HIDE_MESSAGE,conf.realUID(),conf.userRemoteAddress(), ar = new AuditRecord(AuditRecord.HIDE_MESSAGE,conf.realUID(),conf.userRemoteAddress(),
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",post=" conf.realSIGID(),"conf=" + conf.realConfID() + ",post=" + postid,
+ String.valueOf(postid),flag ? "hide" : "unhide"); flag ? "hide" : "unhide");
} // end try } // end try
catch (SQLException e) catch (SQLException e)
@ -562,7 +562,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
// lock the tables we reference // lock the tables we reference
stmt.executeUpdate("LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE;"); stmt.executeUpdate("LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE, postpublish WRITE;");
try try
{ // first, make sure we have the right status for our post { // first, make sure we have the right status for our post
refresh(conn); refresh(conn);
@ -581,8 +581,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
stmt.executeUpdate(sql.toString()); stmt.executeUpdate(sql.toString());
// Determine if we need to "rub out" the post before we delete it. // Determine if we need to "rub out" the post before we delete it.
ResultSet rs = stmt.executeQuery("SELECT LENGTH(data) FROM postdata WHERE postid = " ResultSet rs = stmt.executeQuery("SELECT LENGTH(data) FROM postdata WHERE postid = " + postid + ";");
+ String.valueOf(postid) + ";");
if (rs.next()) if (rs.next())
{ // use this data to overwrite the post with X's { // use this data to overwrite the post with X's
int len = rs.getInt(1); int len = rs.getInt(1);
@ -617,6 +616,12 @@ class TopicMessageUserContextImpl implements TopicMessageContext
sql.append("DELETE FROM postattach WHERE postid = ").append(postid).append(';'); sql.append("DELETE FROM postattach WHERE postid = ").append(postid).append(';');
stmt.executeUpdate(sql.toString()); stmt.executeUpdate(sql.toString());
// Un-publish the posting.
sql.setLength(0);
sql.append("DELETE FROM postpublish WHERE postid = ").append(postid).append(';');
if (stmt.executeUpdate(sql.toString())>0)
engine.unpublish(postid);
// Update our internal data fields. // Update our internal data fields.
linecount = 0; linecount = 0;
hidden = false; hidden = false;
@ -635,8 +640,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
// record what we did in an audit record // record what we did in an audit record
ar = new AuditRecord(AuditRecord.SCRIBBLE_MESSAGE,conf.realUID(),conf.userRemoteAddress(), ar = new AuditRecord(AuditRecord.SCRIBBLE_MESSAGE,conf.realUID(),conf.userRemoteAddress(),
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",post=" conf.realSIGID(),"conf=" + conf.realConfID() + ",post=" + postid);
+ String.valueOf(postid));
} // end try } // end try
catch (SQLException e) catch (SQLException e)
@ -687,7 +691,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
// lock the tables we reference // lock the tables we reference
stmt.executeUpdate("LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE, postdogear WRITE;"); stmt.executeUpdate("LOCK TABLES posts WRITE, postdata WRITE, postattach WRITE, postdogear WRITE, "
+ "postpublish WRITE;");
try try
{ // first, make sure we have the right status for our post { // first, make sure we have the right status for our post
@ -696,10 +701,12 @@ class TopicMessageUserContextImpl implements TopicMessageContext
return; // nuking a nuked post is futile return; // nuking a nuked post is futile
// Delete any and all references to this post! // Delete any and all references to this post!
stmt.executeUpdate("DELETE FROM posts WHERE postid = " + String.valueOf(postid) + ";"); stmt.executeUpdate("DELETE FROM posts WHERE postid = " + postid + ";");
stmt.executeUpdate("DELETE FROM postdata WHERE postid = " + String.valueOf(postid) + ";"); stmt.executeUpdate("DELETE FROM postdata WHERE postid = " + postid + ";");
stmt.executeUpdate("DELETE FROM postattach WHERE postid = " + String.valueOf(postid) + ";"); stmt.executeUpdate("DELETE FROM postattach WHERE postid = " + postid + ";");
stmt.executeUpdate("DELETE FROM postdogear WHERE postid = " + String.valueOf(postid) + ";"); stmt.executeUpdate("DELETE FROM postdogear WHERE postid = " + postid + ";");
if (stmt.executeUpdate("DELETE FROM postpublish WHERE postid = " + postid + ";")>0)
engine.unpublish(postid);
// Update our internal variables. // Update our internal variables.
linecount = 0; linecount = 0;
@ -726,8 +733,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
// record what we did in an audit record // record what we did in an audit record
ar = new AuditRecord(AuditRecord.NUKE_MESSAGE,conf.realUID(),conf.userRemoteAddress(), ar = new AuditRecord(AuditRecord.NUKE_MESSAGE,conf.realUID(),conf.userRemoteAddress(),
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",post=" conf.realSIGID(),"conf=" + conf.realConfID() + ",post=" + postid);
+ String.valueOf(postid));
} // end try } // end try
catch (SQLException e) catch (SQLException e)
@ -803,9 +809,9 @@ class TopicMessageUserContextImpl implements TopicMessageContext
} // end if } // end if
else if (length>MAX_ATTACH) else if (length>MAX_ATTACH)
{ // the attachment is too damn long! { // the attachment is too damn long!
logger.error("attachment is too long (" + String.valueOf(length) + " bytes)"); logger.error("attachment is too long (" + length + " bytes)");
throw new AccessError("The attachment is too long to store. Maximum available length is " throw new AccessError("The attachment is too long to store. Maximum available length is " + MAX_ATTACH
+ String.valueOf(MAX_ATTACH) + " bytes."); + " bytes.");
} // end else if } // end else if
@ -844,9 +850,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
// Generate an audit record indicating what we did. // Generate an audit record indicating what we did.
ar = new AuditRecord(AuditRecord.UPLOAD_ATTACHMENT,conf.realUID(),conf.userRemoteAddress(), ar = new AuditRecord(AuditRecord.UPLOAD_ATTACHMENT,conf.realUID(),conf.userRemoteAddress(),
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",post=" conf.realSIGID(),"conf=" + conf.realConfID() + ",post=" + postid,
+ String.valueOf(postid),"len=" + String.valueOf(length) + ",type=" + m_type "len=" + length + ",type=" + m_type + ",name=" + file);
+ ",name=" + file);
} // end try } // end try
catch (SQLException e) catch (SQLException e)
@ -876,6 +881,136 @@ class TopicMessageUserContextImpl implements TopicMessageContext
} // end attachData } // end attachData
public boolean canPublish()
{
if (!(Capability.canPublishToFrontPage(conf.realBaseLevel())))
return false; // must be a sysadmin to publish
if ((scribble_date!=null) || nuked)
return false; // cannot publish a scribbled or nuked message
Connection conn = null;
try
{ // get a database connection
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// see if the post has already been published
ResultSet rs = stmt.executeQuery("SELECT by_uid FROM postpublish WHERE postid = " + postid
+ " LIMIT 1;");
return !(rs.next());
} // end try
catch (SQLException e)
{ // just trap SQL exceptions and log them
logger.error("SQL exception in TopicMessageUserContextImpl.canPublish: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
return false; // assume we can't
} // end canPublish
public void publish() throws DataException, AccessError
{
if (!(Capability.canPublishToFrontPage(conf.realBaseLevel())))
{ // you aren't allowed to publish - naughty naughty!
logger.error("unable to publish because we're not allowed");
throw new AccessError("You are not permitted to publish postings to the front page.");
} // end if
if (nuked)
{ // we can't publish a nuked message!
logger.error("unable to publish because message nuked");
throw new DataException("Cannot publish a message that has been nuked.");
} // end if
if (scribble_date!=null)
{ // we can't publish a scribbled message!
logger.error("unable to publish because message scribbled");
throw new DataException("Cannot publish a message that has been scribbled.");
} // end if
Connection conn = null;
AuditRecord ar = null;
try
{ // get a database connection
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// see if post has already been published
ResultSet rs = stmt.executeQuery("SELECT by_uid FROM postpublish WHERE postid = " + postid
+ " LIMIT 1;");
if (rs.next()) // can't do it, friend!
throw new DataException("This posting has already been published.");
boolean done = false;
engine.startPublish();
try
{ // insert the post reference into the database
StringBuffer sql =
new StringBuffer("INSERT INTO postpublish (sigid, postid, by_uid, on_date) VALUES (");
sql.append(conf.realSIGID()).append(", ").append(postid).append(", ").append(conf.realUID());
java.util.Date now = new java.util.Date();
sql.append(", '").append(SQLUtil.encodeDate(now)).append("');");
stmt.executeUpdate(sql.toString());
// generate an audit record indicating what we've done
ar = new AuditRecord(AuditRecord.PUBLISH_POST,conf.realUID(),conf.userRemoteAddress(),
conf.realSIGID(),"conf=" + conf.realConfID() + ",post=" + postid);
// establish cached data object for front page
engine.publishNew(new PublishedMessageImpl(datapool,postid,parent,num,linecount,creator_uid,
posted,pseud,creator_cache,text_cache));
done = true;
} // end try
finally
{ // make sure to release the lock if we goofed in here
if (!done)
engine.publishNew(null);
} // end finally
} // end try
catch (SQLException e)
{ // just trap SQL exceptions and log them
logger.error("unable to publish posting: " + e.getMessage(),e);
throw new DataException("unable to publish posting: " + 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
} // end publish
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* External static operations * External static operations
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
@ -885,9 +1020,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
int post_low, int post_high) throws DataException int post_low, int post_high) throws DataException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("loadMessageRange for conf # " + String.valueOf(conf.realConfID()) + ", topic #" logger.debug("loadMessageRange for conf # " + conf.realConfID() + ", topic #" + topicid + ", range ["
+ String.valueOf(topicid) + ", range [" + String.valueOf(post_low) + ", " + post_low + ", " + post_high + "]");
+ String.valueOf(post_high) + "]");
Vector rc = new Vector(); Vector rc = new Vector();
Connection conn = null; // pooled database connection Connection conn = null; // pooled database connection
@ -942,8 +1076,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
int topicid, int message_num) throws DataException int topicid, int message_num) throws DataException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("loadMessage for conf # " + String.valueOf(conf.realConfID()) + ", topic #" logger.debug("loadMessage for conf # " + conf.realConfID() + ", topic #" + topicid + ", message "
+ String.valueOf(topicid) + ", message " + String.valueOf(message_num)); + message_num);
Connection conn = null; // pooled database connection Connection conn = null; // pooled database connection
@ -993,8 +1127,7 @@ class TopicMessageUserContextImpl implements TopicMessageContext
long postid) throws DataException long postid) throws DataException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("getMessage for conf # " + String.valueOf(conf.realConfID()) + ", post #" logger.debug("getMessage for conf # " + conf.realConfID() + ", post #" + postid);
+ String.valueOf(postid));
Connection conn = null; // pooled database connection Connection conn = null; // pooled database connection

View File

@ -880,7 +880,7 @@ class TopicUserContextImpl implements TopicContext
} // end finally } // end finally
// Delete the rest of the gunk in the background; spin off another thread to handle it. // 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); BackgroundTopicPurge purger = new BackgroundTopicPurge(engine,datapool,topicid,post_count,post_max);
Thread thrd = new Thread(purger); Thread thrd = new Thread(purger);
thrd.setPriority(Thread.NORM_PRIORITY-1); thrd.setPriority(Thread.NORM_PRIORITY-1);
thrd.start(); thrd.start();

View File

@ -20,6 +20,7 @@ package com.silverwrist.venice.core.impl;
import java.util.*; import java.util.*;
import java.sql.*; import java.sql.*;
import org.apache.log4j.*; import org.apache.log4j.*;
import com.silverwrist.util.LocaleFactory;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.*; import com.silverwrist.venice.*;
import com.silverwrist.venice.core.*; import com.silverwrist.venice.core.*;
@ -59,6 +60,8 @@ class UserContextImpl implements UserContext, UserBackend
private String my_email = null; // my email address (cached) private String my_email = null; // my email address (cached)
private String my_pseud = null; // my pseud (cached) private String my_pseud = null; // my pseud (cached)
private String full_name = null; // my full name (cached) private String full_name = null; // my full name (cached)
private Locale my_locale = null; // my default locale (cached)
private TimeZone my_tz = null; // my default timezone (cached)
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Constructor * Constructor
@ -84,6 +87,12 @@ class UserContextImpl implements UserContext, UserBackend
username = null; username = null;
created = null; created = null;
last_access = null; last_access = null;
description = null;
my_email = null;
my_pseud = null;
full_name = null;
my_locale = null;
my_tz = null;
} // end finalize } // end finalize
@ -108,18 +117,64 @@ class UserContextImpl implements UserContext, UserBackend
// skip field "passreminder" // skip field "passreminder"
description = rs.getString("description"); description = rs.getString("description");
// purge any "cached" fields that may be left over
my_email = null;
my_pseud = null;
full_name = null;
my_locale = null;
my_tz = null;
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ // spit it all out to debug info { // spit it all out to debug info
logger.debug("Loaded: UID " + String.valueOf(uid) + ", username \"" + username + "\", contactid " logger.debug("Loaded: UID " + uid + ", username \"" + username + "\", contactid " + contactid);
+ String.valueOf(contactid)); logger.debug("...is_anon " + is_anon + ", email_verified " + email_verified);
logger.debug("...is_anon " + String.valueOf(is_anon) + ", email_verified " logger.debug("... level " + level);
+ String.valueOf(email_verified));
logger.debug("... level " + String.valueOf(level));
} // end if } // end if
} // end loadUserData } // end loadUserData
private void loadPrefs(Connection conn) throws SQLException, DataException
{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM userprefs WHERE uid = " + uid + ";");
if (!(rs.next()))
throw new DataException("cannot find preferences for user");
if (my_tz==null)
my_tz = TimeZone.getTimeZone(rs.getString("tzid"));
if (my_locale==null)
my_locale = LocaleFactory.createLocale(rs.getString("localeid"));
} // end loadPrefs
private void loadPrefs() throws DataException
{
Connection conn = null;
try
{ // call through to lower level function
conn = datapool.getConnection();
loadPrefs(conn);
} // end try
catch (SQLException e)
{ // translate into DataException, yadda yadda yadda
logger.error("SQL error reading preferences: " + e.getMessage(),e);
throw new DataException("Unable to read user preferences: " + e.getMessage(),e);
} // end catch
finally
{ // make sure we release the connection
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end loadPrefs
private void sendEmailConfirmation() throws DataException, EmailException private void sendEmailConfirmation() throws DataException, EmailException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@ -180,7 +235,7 @@ class UserContextImpl implements UserContext, UserBackend
public boolean isLoggedIn() public boolean isLoggedIn()
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("isLoggedIn(): uid = " + String.valueOf(uid) + ", is_anon = " + String.valueOf(is_anon)); logger.debug("isLoggedIn(): uid = " + uid + ", is_anon = " + is_anon);
return ((uid!=-1) && !is_anon); return ((uid!=-1) && !is_anon);
} // end is_logged_in } // end is_logged_in
@ -195,7 +250,7 @@ class UserContextImpl implements UserContext, UserBackend
{ {
if (isLoggedIn()) if (isLoggedIn())
{ // already authenticated, can't authenticate again { // already authenticated, can't authenticate again
logger.error("UserContext already authenticated (with uid " + String.valueOf(uid) + ")"); logger.error("UserContext already authenticated (with uid " + uid + ")");
throw new InternalStateError("context already authenticated"); throw new InternalStateError("context already authenticated");
} // end if } // end if
@ -302,7 +357,7 @@ class UserContextImpl implements UserContext, UserBackend
public void confirmEmail(int conf_num) throws AccessError, DataException public void confirmEmail(int conf_num) throws AccessError, DataException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("confirmEmail(): confirming for UID " + String.valueOf(uid)); logger.debug("confirmEmail(): confirming for UID " + uid);
if ((email_verified) || Capability.exemptFromEmailVerification(level)) if ((email_verified) || Capability.exemptFromEmailVerification(level))
{ // already confirmed { // already confirmed
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@ -368,7 +423,7 @@ class UserContextImpl implements UserContext, UserBackend
public void resendEmailConfirmation() throws DataException, EmailException public void resendEmailConfirmation() throws DataException, EmailException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("resendEmailConfirmation(): resending for UID " + String.valueOf(uid)); logger.debug("resendEmailConfirmation(): resending for UID " + uid);
if ((email_verified) || Capability.exemptFromEmailVerification(level)) if ((email_verified) || Capability.exemptFromEmailVerification(level))
{ // already confirmed, no need to resend { // already confirmed, no need to resend
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@ -433,6 +488,9 @@ class UserContextImpl implements UserContext, UserBackend
public ContactInfo getContactInfo() throws DataException public ContactInfo getContactInfo() throws DataException
{ {
if (logger.isDebugEnabled())
logger.debug("getContactInfo() for UID " + uid);
ContactInfoImpl rc; ContactInfoImpl rc;
if (contactid>=0) if (contactid>=0)
rc = new ContactInfoImpl(datapool,contactid); rc = new ContactInfoImpl(datapool,contactid);
@ -450,11 +508,14 @@ class UserContextImpl implements UserContext, UserBackend
public boolean putContactInfo(ContactInfo ci) throws DataException, EmailException public boolean putContactInfo(ContactInfo ci) throws DataException, EmailException
{ {
if (logger.isDebugEnabled())
logger.debug("putContactInfo() for UID " + uid);
boolean email_changed = false; boolean email_changed = false;
if ((ci.getOwnerUID()!=uid) || (ci.getOwnerSIGID()>=0)) if ((ci.getOwnerUID()!=uid) || (ci.getOwnerSIGID()>=0))
{ // the contact information is not owned correctly { // the contact information is not owned correctly
logger.error("ContactInfo ownership wrong (it's " + String.valueOf(ci.getOwnerUID()) + ", " logger.error("ContactInfo ownership wrong (it's " + ci.getOwnerUID() + ", " + ci.getOwnerSIGID()
+ String.valueOf(ci.getOwnerSIGID()) + "), should be (" + String.valueOf(uid) + ", -1)"); + "), should be (" + uid + ", -1)");
throw new DataException("invalid contact information record"); throw new DataException("invalid contact information record");
} // end if } // end if
@ -481,7 +542,7 @@ class UserContextImpl implements UserContext, UserBackend
{ // contact being established for the first time { // contact being established for the first time
contactid = ci.getContactID(); contactid = ci.getContactID();
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("...established initial contact (" + String.valueOf(contactid) + ") for user"); logger.debug("...established initial contact (" + contactid + ") for user");
my_email = ci.getEmail(); my_email = ci.getEmail();
sendEmailConfirmation(); sendEmailConfirmation();
email_changed = true; email_changed = true;
@ -524,8 +585,7 @@ class UserContextImpl implements UserContext, UserBackend
} // end else if } // end else if
ar = new AuditRecord(AuditRecord.USER_CONTACT_INFO,uid,remote_addr, ar = new AuditRecord(AuditRecord.USER_CONTACT_INFO,uid,remote_addr,"contactid=" + contactid);
"contactid=" + String.valueOf(contactid));
} // end try } // end try
catch (ClassCastException cce) catch (ClassCastException cce)
@ -597,7 +657,7 @@ class UserContextImpl implements UserContext, UserBackend
public UserProfile getProfile(int xuid) throws DataException public UserProfile getProfile(int xuid) throws DataException
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("getProfile(#" + String.valueOf(xuid) + ")..."); logger.debug("getProfile(#" + xuid + ")...");
Connection conn = null; Connection conn = null;
try try
@ -893,6 +953,94 @@ class UserContextImpl implements UserContext, UserBackend
} // end getAdminInterface } // end getAdminInterface
public Locale getLocale() throws DataException
{
if (my_locale==null)
loadPrefs();
return my_locale;
} // end getLocale
public void setLocale(Locale locale) throws DataException
{
Connection conn = null;
try
{ // retrieve a connection from the data pool
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// create the update statement
StringBuffer sql = new StringBuffer("UPDATE userprefs SET localeid = '");
sql.append(SQLUtil.encodeString(locale.toString())).append("' WHERE uid = ").append(uid).append(';');
// execute the statement
stmt.executeUpdate(sql.toString());
// replace the locale here
my_locale = locale;
} // end try
catch (SQLException e)
{ // turn SQLException into data exception
logger.error("DB error setting user locale: " + e.getMessage(),e);
throw new DataException("unable to set user locale: " + e.getMessage(),e);
} // end catch
finally
{ // make sure the connection is released before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end setLocale
public TimeZone getTimeZone() throws DataException
{
if (my_tz==null)
loadPrefs();
return my_tz;
} // end getTimeZone
public void setTimeZone(TimeZone timezone) throws DataException
{
Connection conn = null;
try
{ // retrieve a connection from the data pool
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
// create the update statement
StringBuffer sql = new StringBuffer("UPDATE userprefs SET tzid = '");
sql.append(SQLUtil.encodeString(timezone.getID())).append("' WHERE uid = ").append(uid).append(';');
// execute the statement
stmt.executeUpdate(sql.toString());
// replace the locale here
my_tz = timezone;
} // end try
catch (SQLException e)
{ // turn SQLException into data exception
logger.error("DB error setting user timezone: " + e.getMessage(),e);
throw new DataException("unable to set user timezone: " + e.getMessage(),e);
} // end catch
finally
{ // make sure the connection is released before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
} // end setTimeZone
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Implementations from interface UserBackend * Implementations from interface UserBackend
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
@ -918,6 +1066,8 @@ class UserContextImpl implements UserContext, UserBackend
public String userDefaultPseud() throws DataException public String userDefaultPseud() throws DataException
{ {
if (logger.isDebugEnabled())
logger.debug("userDefaultPseud() for UID " + uid);
if (my_pseud==null) if (my_pseud==null)
getContactInfo(); getContactInfo();
return my_pseud; return my_pseud;
@ -999,8 +1149,8 @@ class UserContextImpl implements UserContext, UserBackend
java.util.Date created, java.util.Date last_access) java.util.Date created, java.util.Date last_access)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("loadNewUser() on UserContext: addr " + remote_addr + ", uid " + String.valueOf(uid) logger.debug("loadNewUser() on UserContext: addr " + remote_addr + ", uid " + uid + ", level "
+ ", level " + String.valueOf(level) + ", username \"" + username + "\""); + level + ", username \"" + username + "\"");
this.remote_addr = remote_addr; this.remote_addr = remote_addr;
this.uid = uid; this.uid = uid;

View File

@ -304,6 +304,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
private int[] gp_ints; // global integer parameters private int[] gp_ints; // global integer parameters
private MasterSideBox[] sideboxes; // master sidebox table private MasterSideBox[] sideboxes; // master sidebox table
private Hashtable sidebox_ids = new Hashtable(); // maps sidebox IDs to MasterSideBox objects private Hashtable sidebox_ids = new Hashtable(); // maps sidebox IDs to MasterSideBox objects
private Vector cache_fp_posts = new Vector(); // all posts that have been published to front page
private boolean cache_fp_posts_busy = false; // busy flag for above vector
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Constructor * Constructor
@ -333,8 +335,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
private void loadDefaults(Statement stmt) throws SQLException, DataException private void loadDefaults(Statement stmt) throws SQLException, DataException
{ {
final String query = final String query =
"SELECT posts_per_page, old_posts_at_top, max_search_page, max_sig_mbr_page, max_conf_mbr_page " "SELECT posts_per_page, old_posts_at_top, max_search_page, max_sig_mbr_page, max_conf_mbr_page, "
+ "FROM globals;"; + "fp_posts FROM globals;";
ResultSet rs = stmt.executeQuery(query); ResultSet rs = stmt.executeQuery(query);
if (!(rs.next())) if (!(rs.next()))
throw new DataException("Globals table does not appear to be loaded!"); throw new DataException("Globals table does not appear to be loaded!");
@ -345,6 +347,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
gp_ints[IP_MAXSEARCHRETURN] = rs.getInt(3); gp_ints[IP_MAXSEARCHRETURN] = rs.getInt(3);
gp_ints[IP_MAXSIGMEMBERDISPLAY] = rs.getInt(4); gp_ints[IP_MAXSIGMEMBERDISPLAY] = rs.getInt(4);
gp_ints[IP_MAXCONFMEMBERDISPLAY] = rs.getInt(5); gp_ints[IP_MAXCONFMEMBERDISPLAY] = rs.getInt(5);
gp_ints[IP_NUMFRONTPAGEPOSTS] = rs.getInt(6);
} // end loadDefaults } // end loadDefaults
@ -489,7 +492,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end catch } // end catch
// Allocate the global parameter arrays. // Allocate the global parameter arrays.
gp_ints = new int[5]; gp_ints = new int[6];
// initialize anything that requires us to pull from the database // initialize anything that requires us to pull from the database
Connection conn = null; Connection conn = null;
@ -1391,6 +1394,48 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end getMasterSideBoxList } // end getMasterSideBoxList
public List getPublishedMessages(boolean all) throws DataException
{
Vector rc = new Vector();
synchronized (this)
{ // Make sure the cache is in condition.
while (cache_fp_posts_busy)
{ // the list is busy, don't fsck with it until we're done
try
{ // wait to see if they can be un-busy
wait();
} // end try
catch (InterruptedException e)
{ // do nothing
} // end catch
} // end while
// If the cache list contains too few items, backfill it from the database.
if (cache_fp_posts.size()<gp_ints[IP_NUMFRONTPAGEPOSTS])
PublishedMessageImpl.backfillCache(cache_fp_posts,gp_ints[IP_NUMFRONTPAGEPOSTS],datapool);
// Copy the contents to the return vector, casting them to TopicMessageContext.
Iterator it = cache_fp_posts.iterator();
while (it.hasNext())
{ // cast each element and add the casted object to the output
PublishedMessageImpl pmi = (PublishedMessageImpl)(it.next());
TopicMessageContext ctxt = (TopicMessageContext)pmi;
rc.add(ctxt);
} // end while
} // end synchronized block
if (all) // add the extra postings to the list
PublishedMessageImpl.backfillReturn(rc,datapool);
return new ReadOnlyVector(rc);
} // end getPublishedMessages
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Implementations from interface EngineBackend * Implementations from interface EngineBackend
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
@ -1805,4 +1850,42 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end getMasterSideBoxDescriptor } // end getMasterSideBoxDescriptor
public synchronized void startPublish()
{
cache_fp_posts_busy = true;
} // end startPublish
public synchronized void publishNew(PublishedMessageImpl pubmsg)
{
if (pubmsg!=null)
{ // add the new message
cache_fp_posts.add(0,pubmsg);
while (cache_fp_posts.size()>gp_ints[IP_NUMFRONTPAGEPOSTS])
cache_fp_posts.remove(cache_fp_posts.size()-1);
} // end pubmsg
cache_fp_posts_busy = false;
notifyAll();
} // end publishNew
public synchronized void unpublish(long postid)
{
Iterator it = cache_fp_posts.iterator();
while (it.hasNext())
{ // get each published message in the cache in turn, looking for the specified post ID
PublishedMessageImpl pmi = (PublishedMessageImpl)(it.next());
if (pmi.getPostID()==postid)
{ // drop the specified post ID like a hot rock
it.remove();
break;
} // end if
} // end while
} // end unpublish
} // end class VeniceEngineImpl } // end class VeniceEngineImpl

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -19,7 +19,8 @@ package com.silverwrist.venice.security;
public interface Audit public interface Audit
{ {
// Codes 0-100 - System events // Codes 1-100 - System events
public static final int PUBLISH_POST = 1;
// Codes 101-200 - Login/user events // Codes 101-200 - Login/user events
public static final int LOGIN_OK = 101; public static final int LOGIN_OK = 101;

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -103,4 +103,10 @@ public class Capability implements SecLevels
} // end canAdministerSystem } // end canAdministerSystem
public static boolean canPublishToFrontPage(int level)
{
return (level>=GLOBAL_ANYADMIN);
} // end canPublishToFrontPage
} // end class Capability } // end class Capability

View File

@ -172,6 +172,30 @@ public class PostOperations extends VeniceServlet
} // end if ("nuke") } // end if ("nuke")
if (cmd.equals("PU"))
{ // we want to publish the message to the front page
try
{ // attempt to publish the message
msg.publish();
// go back and display stuff
throw new RedirectResult(location);
} // end try
catch (DataException de)
{ // there was a database error
return new ErrorBox("Database Error","Database error publishing message: " + de.getMessage(),
location);
} // end catch
catch (AccessError ae)
{ // naughty naughty = you can't do this!
return new ErrorBox("Access Error",ae.getMessage(),location);
} // end catch
} // end if
// unrecognized command! // unrecognized command!
logger.error("invalid command to PostOperations.doGet: " + cmd); logger.error("invalid command to PostOperations.doGet: " + cmd);
return new ErrorBox("Internal Error","Invalid command to PostOperations.doGet",location); return new ErrorBox("Internal Error","Invalid command to PostOperations.doGet",location);

View File

@ -76,7 +76,7 @@ public class Top extends VeniceServlet
try try
{ // attempt to get the user content { // attempt to get the user content
return new TopDisplay(getServletContext(),user); return new TopDisplay(getServletContext(),engine,user);
} // end try } // end try
catch (DataException de) catch (DataException de)

View File

@ -565,7 +565,7 @@ public abstract class VeniceServlet extends HttpServlet
ServletContext ctxt = getServletContext(); ServletContext ctxt = getServletContext();
VeniceEngine engine = Variables.getVeniceEngine(ctxt); VeniceEngine engine = Variables.getVeniceEngine(ctxt);
UserContext user = Variables.getUserContext(ctxt,request,request.getSession(true)); UserContext user = Variables.getUserContext(ctxt,request,request.getSession(true));
RenderData rdat = RenderConfig.createRenderData(ctxt,request,response); RenderData rdat = RenderConfig.createRenderData(ctxt,user,request,response);
ServletMultipartHandler mphandler = null; ServletMultipartHandler mphandler = null;
VeniceContent content = null; VeniceContent content = null;

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -25,6 +25,11 @@ import com.silverwrist.venice.core.Country;
public class CDCountryListFormField extends CDPickListFormField public class CDCountryListFormField extends CDPickListFormField
{ {
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public CDCountryListFormField(String name, String caption, String caption2, boolean required, public CDCountryListFormField(String name, String caption, String caption2, boolean required,
List country_list) List country_list)
{ {
@ -38,6 +43,11 @@ public class CDCountryListFormField extends CDPickListFormField
} // end constructor } // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class CDPickListFormField
*--------------------------------------------------------------------------------
*/
protected void renderChoice(Writer out, RenderData rdat, Object obj, String my_value) throws IOException protected void renderChoice(Writer out, RenderData rdat, Object obj, String my_value) throws IOException
{ {
Country c = (Country)obj; Country c = (Country)obj;
@ -48,6 +58,11 @@ public class CDCountryListFormField extends CDPickListFormField
} // end renderChoice } // end renderChoice
/*--------------------------------------------------------------------------------
* Implementations from interface CDFormField
*--------------------------------------------------------------------------------
*/
public CDFormField duplicate() public CDFormField duplicate()
{ {
return new CDCountryListFormField(this); return new CDCountryListFormField(this);

View File

@ -0,0 +1,106 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.servlets.format;
import java.util.*;
import java.io.Writer;
import java.io.IOException;
import com.silverwrist.util.StringUtil;
public class CDLocaleListFormField extends CDPickListFormField
{
/*--------------------------------------------------------------------------------
* Private list implementation
*--------------------------------------------------------------------------------
*/
static class LocaleList extends AbstractList
{
private Locale[] array; // local array
LocaleList()
{
array = Locale.getAvailableLocales();
} // end constructor
protected void finalize() throws Throwable
{
array = null;
super.finalize();
} // end finalize
public Object get(int index)
{
return array[index];
} // end get
public int size()
{
return array.length;
} // end size
} // end class LocaleList
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public CDLocaleListFormField(String name, String caption, String caption2, boolean required)
{
super(name,caption,caption2,required,new LocaleList());
} // end constructor
protected CDLocaleListFormField(CDLocaleListFormField other)
{
super(other);
} // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class CDPickListFormField
*--------------------------------------------------------------------------------
*/
protected void renderChoice(Writer out, RenderData rdat, Object obj, String my_value) throws IOException
{
Locale l = (Locale)obj;
out.write("<OPTION VALUE=\"" + l.toString() + "\"");
if (l.toString().equals(my_value))
out.write(" SELECTED");
out.write(">" + StringUtil.encodeHTML(l.getDisplayName()) + "</OPTION>\n");
} // end renderChoice
/*--------------------------------------------------------------------------------
* Implementations from interface CDFormField
*--------------------------------------------------------------------------------
*/
public CDFormField duplicate()
{
return new CDLocaleListFormField(this);
} // end duplicate
} // end class CDLocaleListFormField

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -25,8 +25,18 @@ import com.silverwrist.util.StringUtil;
public abstract class CDPickListFormField extends CDBaseFormField public abstract class CDPickListFormField extends CDBaseFormField
{ {
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private List choices; private List choices;
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
protected CDPickListFormField(String name, String caption, String caption2, boolean required, protected CDPickListFormField(String name, String caption, String caption2, boolean required,
List choices) List choices)
{ {
@ -42,9 +52,19 @@ public abstract class CDPickListFormField extends CDBaseFormField
} // end constructor } // end constructor
/*--------------------------------------------------------------------------------
* Abstract method declarations
*--------------------------------------------------------------------------------
*/
protected abstract void renderChoice(Writer out, RenderData rdat, Object obj, String my_value) protected abstract void renderChoice(Writer out, RenderData rdat, Object obj, String my_value)
throws IOException; throws IOException;
/*--------------------------------------------------------------------------------
* Overrides from class CDBaseFormField
*--------------------------------------------------------------------------------
*/
protected void renderActualField(Writer out, RenderData rdat) throws IOException protected void renderActualField(Writer out, RenderData rdat) throws IOException
{ {
out.write("<SELECT NAME=\"" + getName() + "\" SIZE=1"); out.write("<SELECT NAME=\"" + getName() + "\" SIZE=1");

View File

@ -0,0 +1,106 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.servlets.format;
import java.util.*;
import java.io.Writer;
import java.io.IOException;
import com.silverwrist.util.StringUtil;
public class CDTimeZoneListFormField extends CDPickListFormField
{
/*--------------------------------------------------------------------------------
* Private list implementation
*--------------------------------------------------------------------------------
*/
static class TimeZoneList extends AbstractList
{
private String[] array; // local array
TimeZoneList()
{
array = TimeZone.getAvailableIDs();
} // end constructor
protected void finalize() throws Throwable
{
array = null;
super.finalize();
} // end finalize
public Object get(int index)
{
return array[index];
} // end get
public int size()
{
return array.length;
} // end size
} // end class TimeZoneList
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public CDTimeZoneListFormField(String name, String caption, String caption2, boolean required)
{
super(name,caption,caption2,required,new TimeZoneList());
} // end constructor
protected CDTimeZoneListFormField(CDTimeZoneListFormField other)
{
super(other);
} // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class CDPickListFormField
*--------------------------------------------------------------------------------
*/
protected void renderChoice(Writer out, RenderData rdat, Object obj, String my_value) throws IOException
{
String id = (String)obj;
out.write("<OPTION VALUE=\"" + id + "\"");
if (id.equals(my_value))
out.write(" SELECTED");
out.write(">" + StringUtil.encodeHTML(id) + "</OPTION>\n");
} // end renderChoice
/*--------------------------------------------------------------------------------
* Implementations from interface CDFormField
*--------------------------------------------------------------------------------
*/
public CDFormField duplicate()
{
return new CDTimeZoneListFormField(this);
} // end duplicate
} // end class CDTimeZoneListFormField

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -17,13 +17,19 @@
*/ */
package com.silverwrist.venice.servlets.format; package com.silverwrist.venice.servlets.format;
import java.util.List; import java.util.*;
import com.silverwrist.util.LocaleFactory;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.ValidationException; import com.silverwrist.venice.ValidationException;
import com.silverwrist.venice.core.*; import com.silverwrist.venice.core.*;
public class EditProfileDialog extends ContentDialog public class EditProfileDialog extends ContentDialog
{ {
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public EditProfileDialog(List country_list) public EditProfileDialog(List country_list)
{ {
super("Edit Your Profile",null,"profform","account"); super("Edit Your Profile",null,"profform","account");
@ -62,6 +68,9 @@ public class EditProfileDialog extends ContentDialog
addFormField(new CDFormCategoryHeader("Personal")); addFormField(new CDFormCategoryHeader("Personal"));
addFormField(new CDTextFormField("descr","Personal description",null,false,32,255)); addFormField(new CDTextFormField("descr","Personal description",null,false,32,255));
// TODO: add photo selection/uploading method here // TODO: add photo selection/uploading method here
addFormField(new CDFormCategoryHeader("User Preferences"));
addFormField(new CDLocaleListFormField("locale","Default locale","(for formatting dates/times)",true));
addFormField(new CDTimeZoneListFormField("tz","Default time zone",null,true));
addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24)); addCommandButton(new CDImageButton("update","bn_update.gif","Update",80,24));
addCommandButton(new CDImageButton("cancel","bn_cancel.gif","Cancel",80,24)); addCommandButton(new CDImageButton("cancel","bn_cancel.gif","Cancel",80,24));
@ -73,6 +82,22 @@ public class EditProfileDialog extends ContentDialog
} // end constructor } // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class Object
*--------------------------------------------------------------------------------
*/
public Object clone()
{
return new EditProfileDialog(this);
} // end clone
/*--------------------------------------------------------------------------------
* Overrides from class ContentDialog
*--------------------------------------------------------------------------------
*/
protected void validateWholeForm() throws ValidationException protected void validateWholeForm() throws ValidationException
{ {
String pass1 = getFieldValue("pass1"); String pass1 = getFieldValue("pass1");
@ -93,6 +118,11 @@ public class EditProfileDialog extends ContentDialog
} // end validateWholeForm } // end validateWholeForm
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public void setTarget(String target) public void setTarget(String target)
{ {
setHiddenField("tgt",target); setHiddenField("tgt",target);
@ -132,6 +162,8 @@ public class EditProfileDialog extends ContentDialog
setFieldValue("pvt_email","Y"); setFieldValue("pvt_email","Y");
setFieldValue("url",ci.getURL()); setFieldValue("url",ci.getURL());
setFieldValue("descr",uc.getDescription()); setFieldValue("descr",uc.getDescription());
setFieldValue("locale",uc.getLocale().toString());
setFieldValue("tz",uc.getTimeZone().getID());
} // end setupDialog } // end setupDialog
@ -172,8 +204,10 @@ public class EditProfileDialog extends ContentDialog
// Store the completed contact info. // Store the completed contact info.
boolean retval = uc.putContactInfo(ci); boolean retval = uc.putContactInfo(ci);
// Save off the user's description. // Save off the user's description and preferences.
uc.setDescription(getFieldValue("descr")); uc.setDescription(getFieldValue("descr"));
uc.setLocale(LocaleFactory.createLocale(getFieldValue("locale")));
uc.setTimeZone(TimeZone.getTimeZone(getFieldValue("tz")));
// Finally, change the password if applicable. // Finally, change the password if applicable.
foo = getFieldValue("pass1"); foo = getFieldValue("pass1");
@ -192,10 +226,4 @@ public class EditProfileDialog extends ContentDialog
} // end resetOnError } // end resetOnError
public Object clone()
{
return new EditProfileDialog(this);
} // end clone
} // end class EditProfileDialog } // end class EditProfileDialog

View File

@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
@ -29,6 +29,8 @@ import org.xml.sax.SAXParseException;
import com.silverwrist.util.DOMElementHelper; import com.silverwrist.util.DOMElementHelper;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.core.ConfigException; import com.silverwrist.venice.core.ConfigException;
import com.silverwrist.venice.core.UserContext;
import com.silverwrist.venice.servlets.Variables;
public class RenderConfig public class RenderConfig
{ {
@ -56,6 +58,7 @@ public class RenderConfig
private String image_url; private String image_url;
private String static_url; private String static_url;
private String site_logo; private String site_logo;
private Hashtable stock_messages;
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Constructor * Constructor
@ -171,6 +174,35 @@ public class RenderConfig
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Site logo: " + image_url); logger.debug("Site logo: " + image_url);
Element msg_sect = root_h.getSubElement("messages");
if (msg_sect==null)
{ // no <messages/> section - bail out now!
logger.fatal("config document has no <messages/> section");
throw new ConfigException("no <messages/> section found in config file",root);
} // end if
// Initialize the stock messages list.
stock_messages = new Hashtable();
NodeList msg_nodes = msg_sect.getChildNodes();
for (int i=0; i<msg_nodes.getLength(); i++)
{ // examine all subnodes to add them to the message text
Node msgn = msg_nodes.item(i);
if (msgn.getNodeType()==Node.ELEMENT_NODE)
{ // add it to the hash table by its tag name
Element msgel = (Element)msgn;
DOMElementHelper h = new DOMElementHelper(msgel);
String txt = h.getElementText();
if (txt!=null)
stock_messages.put(msgel.getTagName(),txt.trim());
} // end if
} // end for
if (logger.isDebugEnabled())
logger.debug(stock_messages.size() + " stock messages loaded from config");
} // end constructor } // end constructor
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
@ -335,6 +367,19 @@ public class RenderConfig
} // end writeContentHeader } // end writeContentHeader
String getStockMessage(String identifier)
{
return (String)(stock_messages.get(identifier));
} // end getStockMessage
void writeStockMessage(Writer out, String identifier) throws IOException
{
String text = (String)(stock_messages.get(identifier));
out.write(StringUtil.encodeHTML(text));
} // end writeStockMessage
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
* Static operations for use by VeniceServlet * Static operations for use by VeniceServlet
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
@ -370,7 +415,15 @@ public class RenderConfig
public static RenderData createRenderData(ServletContext ctxt, HttpServletRequest request, public static RenderData createRenderData(ServletContext ctxt, HttpServletRequest request,
HttpServletResponse response) throws ServletException HttpServletResponse response) throws ServletException
{ {
return new RenderData(getRenderConfig(ctxt),request,response); UserContext uc = Variables.getUserContext(ctxt,request,request.getSession(true));
return new RenderData(getRenderConfig(ctxt),uc,request,response);
} // end createRenderData
public static RenderData createRenderData(ServletContext ctxt, UserContext uc, HttpServletRequest request,
HttpServletResponse response) throws ServletException
{
return new RenderData(getRenderConfig(ctxt),uc,request,response);
} // end createRenderData } // end createRenderData

View File

@ -24,7 +24,9 @@ import javax.servlet.*;
import javax.servlet.http.*; import javax.servlet.http.*;
import org.apache.log4j.*; import org.apache.log4j.*;
import com.silverwrist.util.StringUtil; import com.silverwrist.util.StringUtil;
import com.silverwrist.venice.core.DataException;
import com.silverwrist.venice.core.IDUtils; import com.silverwrist.venice.core.IDUtils;
import com.silverwrist.venice.core.UserContext;
import com.silverwrist.venice.db.PostLinkRewriter; import com.silverwrist.venice.db.PostLinkRewriter;
import com.silverwrist.venice.db.UserNameRewriter; import com.silverwrist.venice.db.UserNameRewriter;
@ -56,7 +58,7 @@ public class RenderData
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
RenderData(RenderConfig rconf, HttpServletRequest request, HttpServletResponse response) RenderData(RenderConfig rconf, UserContext uc, HttpServletRequest request, HttpServletResponse response)
{ {
this.rconf = rconf; this.rconf = rconf;
this.request = request; this.request = request;
@ -67,10 +69,30 @@ public class RenderData
if ((encodings!=null) && (encodings.indexOf("gzip")>=0)) if ((encodings!=null) && (encodings.indexOf("gzip")>=0))
can_gzip = true; can_gzip = true;
// TODO: replace with reading user's preferences // read the user's preferred locale
try
{ // get the user default locale
my_locale = uc.getLocale();
} // end try
catch (DataException de)
{ // locale problems...
my_locale = Locale.getDefault(); my_locale = Locale.getDefault();
} // end catch
// read the user's preferred time zone
try
{ // get the user default timezone
my_timezone = uc.getTimeZone();
} // end try
catch (DataException de)
{ // time zone problems...
my_timezone = TimeZone.getDefault(); my_timezone = TimeZone.getDefault();
} // end catch
} // end constructor } // end constructor
/*-------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------
@ -206,6 +228,18 @@ public class RenderData
} // end writeContentSelectorHeader } // end writeContentSelectorHeader
public String getStockMessage(String identifier)
{
return rconf.getStockMessage(identifier);
} // end getStockMessage
public void writeStockMessage(Writer out, String identifier) throws IOException
{
rconf.writeStockMessage(out,identifier);
} // end writeStockMessage
public String formatDateForDisplay(Date date) public String formatDateForDisplay(Date date)
{ {
DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM,my_locale); DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM,my_locale);

View File

@ -40,7 +40,9 @@ public class TopDisplay implements ContentRender
*/ */
private ServletContext ctxt; private ServletContext ctxt;
private VeniceEngine engine;
private UserContext uc; private UserContext uc;
private List top_posts;
private List descrs; private List descrs;
private VeniceContent[] sideboxes; private VeniceContent[] sideboxes;
@ -49,11 +51,14 @@ public class TopDisplay implements ContentRender
*-------------------------------------------------------------------------------- *--------------------------------------------------------------------------------
*/ */
public TopDisplay(ServletContext ctxt, UserContext uc) throws DataException, AccessError, ErrorBox public TopDisplay(ServletContext ctxt, VeniceEngine engine, UserContext uc)
throws DataException, AccessError, ErrorBox
{ {
// Stash some basic information. // Stash some basic information.
this.ctxt = ctxt; this.ctxt = ctxt;
this.engine = engine;
this.uc = uc; this.uc = uc;
this.top_posts = engine.getPublishedMessages(false);
this.descrs = uc.getSideBoxList(); this.descrs = uc.getSideBoxList();
// Create the arrays used to construct sideboxes. // Create the arrays used to construct sideboxes.
@ -242,4 +247,57 @@ public class TopDisplay implements ContentRender
} // end renderHere } // end renderHere
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public static String getPosterName(TopicMessageContext msg)
{
try
{ // have to guard agains a DataException here
return msg.getCreatorName();
} // end try
catch (DataException de)
{ // just return "unknown" on failure
return "(unknown)";
} // end catch
} // end getPosterName
public static String getMessageBodyText(TopicMessageContext msg)
{
try
{ // have to guard against a DataException here
return msg.getBodyText();
} // end try
catch (DataException de)
{ // just return an error message
return "<EM>(Unable to retrieve message data: " + StringUtil.encodeHTML(de.getMessage()) + ")</EM>";
} // end catch
} // end getMessageBodyText
public int getNumTopPosts()
{
return top_posts.size();
} // end getNumTopPosts
public TopicMessageContext getTopPost(int index)
{
return (TopicMessageContext)(top_posts.get(index));
} // end getTopPost
public boolean displayWelcome()
{
return !(uc.isLoggedIn());
} // end displayWelcome
} // end class TopDisplay } // end class TopDisplay

View File

@ -220,6 +220,11 @@
SRC="<%= rdat.getFullImagePath("bn_nuke.gif") %>" ALT="Nuke" WIDTH=80 HEIGHT=24 SRC="<%= rdat.getFullImagePath("bn_nuke.gif") %>" ALT="Nuke" WIDTH=80 HEIGHT=24
BORDER=0></A><P> BORDER=0></A><P>
<% } // end if (can nuke) %> <% } // end if (can nuke) %>
<% if (msg.canPublish()) { %>
<A HREF="<%= rdat.getEncodedServletPath("postops?" + po_loc + "&cmd=PU") %>"><IMG
SRC="<%= rdat.getFullImagePath("bn_publish.gif") %>" ALT="Publish" WIDTH=80 HEIGHT=24
BORDER=0></A><P>
<% } // end if (can publish) %>
</TD></TR></TABLE><BR> </TD></TR></TABLE><BR>
<% } // end if (showing advanced controls) %> <% } // end if (showing advanced controls) %>
<% can_line = true; %> <% can_line = true; %>

View File

@ -26,5 +26,29 @@
RenderData rdat = RenderConfig.createRenderData(application,request,response); RenderData rdat = RenderConfig.createRenderData(application,request,response);
%> %>
<% if (rdat.useHTMLComments()) { %><!-- Top content panel --><% } %> <% if (rdat.useHTMLComments()) { %><!-- Top content panel --><% } %>
<% rdat.writeContentHeader(out,"Venice Currents",null); %> <% if (data.displayWelcome()) { %>
TODO: Something profound goes here. :-) <% rdat.writeContentHeader(out,rdat.getStockMessage("welcome-top"),null); %>
<%= rdat.getStdFontTag(null,1) %><% rdat.writeStockMessage(out,"welcome"); %></FONT><P>
<% } // end if %>
<% rdat.writeContentHeader(out,rdat.getStockMessage("currents-top"),null); %>
<% int ntp = data.getNumTopPosts(); %>
<% if (ntp>0) { %>
<% for (int i=0; i<ntp; i++) { %>
<% if (i>0) { %><HR WIDTH="70%"><% } %>
<%
TopicMessageContext msg = data.getTopPost(i);
String poster = data.getPosterName(msg);
%>
<%= rdat.getStdFontTag(null,1) %>
<B><%= msg.getPseud() %></B>
(<EM>
<A HREF="<%= rdat.getEncodedServletPath("user/" + poster) %>" TARGET="_blank"><%= poster %></A>,
<%= rdat.formatDateForDisplay(msg.getPostDate()) %>
</EM>)
<P>
<PRE><%= rdat.rewritePostData(data.getMessageBodyText(msg)) %></PRE>
</FONT>
<% } // end for %>
<% } else { %>
<%= rdat.getStdFontTag(null,1) %><EM>No front page postings found.</EM></FONT>
<% } // end if %>

BIN
web/images/bn_publish.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B