From 36f7c7f10f3527c9488853677cbae24519520dec Mon Sep 17 00:00:00 2001 From: "Eric J. Bowersox" Date: Thu, 15 Feb 2001 04:28:00 +0000 Subject: [PATCH] fully implemented conference membership management and delete conference - now almost all the conference functionality is in place --- TODO | 7 +- setup/database.sql | 10 +- .../silverwrist/util/ParallelRunQueue.java | 101 ++++++ .../venice/core/ConferenceContext.java | 24 +- .../silverwrist/venice/core/SIGContext.java | 11 +- .../silverwrist/venice/core/UserFound.java | 2 + .../silverwrist/venice/core/VeniceEngine.java | 4 + .../core/impl/BackgroundConferencePurge.java | 131 +++++++ .../venice/core/impl/ConferenceCoreData.java | 275 +++++++++++++- .../venice/core/impl/ConferenceData.java | 12 +- .../core/impl/ConferenceSIGContext.java | 10 +- .../core/impl/ConferenceSIGContextImpl.java | 114 ++++++ .../core/impl/ConferenceUserContextImpl.java | 181 ++++++++-- .../venice/core/impl/EngineBackend.java | 9 +- .../venice/core/impl/SIGBackend.java | 4 + .../venice/core/impl/SIGCoreData.java | 312 ++++++++++++++-- .../silverwrist/venice/core/impl/SIGData.java | 10 + .../venice/core/impl/SIGUserContextImpl.java | 31 ++ .../venice/core/impl/UserFoundImpl.java | 7 + .../venice/core/impl/VeniceEngineImpl.java | 146 +++++--- .../silverwrist/venice/security/Audit.java | 1 + src/com/silverwrist/venice/security/Role.java | 18 + .../venice/servlets/ConfOperations.java | 202 +++++++++++ .../servlets/format/ConferenceActivity.java | 3 +- .../servlets/format/ConferenceMembership.java | 337 ++++++++++++++++++ .../venice/servlets/format/ConfirmBox.java | 2 +- web/format/conf_member.jsp | 154 ++++++++ web/format/manage_conf.jsp | 6 +- 28 files changed, 1978 insertions(+), 146 deletions(-) create mode 100644 src/com/silverwrist/util/ParallelRunQueue.java create mode 100644 src/com/silverwrist/venice/core/impl/BackgroundConferencePurge.java create mode 100644 src/com/silverwrist/venice/servlets/format/ConferenceMembership.java create mode 100644 web/format/conf_member.jsp diff --git a/TODO b/TODO index eb7b93b..5bb3ef2 100644 --- a/TODO +++ b/TODO @@ -31,12 +31,9 @@ Lots! - Functions still to do on conferencing "topics" page: Add Conference To Hotlist -- Functions still to do on "manage conference" page: - Manage members - Delete conference - - We need a "manage" button at conference list level so we can use that to - manage the ordering of conferences. + manage the ordering of conferences. This operation should be accessible + only to users with "create" privilege on the SIG. - Implement conference hotlist for users. diff --git a/setup/database.sql b/setup/database.sql index 90950af..2305ba8 100644 --- a/setup/database.sql +++ b/setup/database.sql @@ -35,7 +35,10 @@ USE venice; # in the XML config file. This table has ONLY ONE ROW! CREATE TABLE globals ( posts_per_page INT NOT NULL, - old_posts_at_top INT NOT NULL + old_posts_at_top INT NOT NULL, + max_search_page INT NOT NULL, + max_sig_mbr_page INT NOT NULL, + max_conf_mbr_page INT NOT NULL ); # The audit records table. Most "major" events add a record to this table. @@ -429,6 +432,7 @@ INSERT INTO refaudit (type, descr) VALUES (312, 'Scribble Message'), (313, 'Nuke Message'), (314, 'Upload Message Attachment'), + (315, 'Delete Conference'), (9999999, 'DUMMY'); # The ISO 3166 two-letter country codes. Source is @@ -1291,8 +1295,8 @@ INSERT INTO refsigftr (ftr_code, is_default, is_locked, is_hidden, require_read, ############################################################################## # Initialize the system globals table. -INSERT INTO globals (posts_per_page, old_posts_at_top) - VALUES (20, 2); +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); # Add the 'Anonymous Honyak' user to the users table. # (Do 'SELECT * FROM users WHERE is_anon = 1' to retrieve the AC user details.) diff --git a/src/com/silverwrist/util/ParallelRunQueue.java b/src/com/silverwrist/util/ParallelRunQueue.java new file mode 100644 index 0000000..3baa597 --- /dev/null +++ b/src/com/silverwrist/util/ParallelRunQueue.java @@ -0,0 +1,101 @@ +/* + * 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 . + * + * 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 , + * 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.Vector; + +public class ParallelRunQueue implements Runnable +{ + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private Thread[] thrds; + private Vector queue; + private int priority; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + public ParallelRunQueue(int nthread) + { + thrds = new Thread[nthread]; + for (int i=0; i0) + { // unqueue a new Runnable + Runnable r = (Runnable)(queue.remove(0)); + for (int i=0; i, * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are @@ -21,7 +21,7 @@ import java.util.BitSet; import java.util.Date; import java.util.List; -public interface SIGContext +public interface SIGContext extends SearchMode { public static final int HIDE_NONE = 0; public static final int HIDE_DIRECTORY = 1; @@ -144,4 +144,11 @@ public interface SIGContext public abstract boolean canCreateConference(); + public abstract List searchForMembers(int field, int mode, String term, int offset, int count) + throws DataException; + + public abstract int getSearchMemberCount(int field, int mode, String term) throws DataException; + + public abstract List getMemberList() throws DataException; + } // end interface SIGContext diff --git a/src/com/silverwrist/venice/core/UserFound.java b/src/com/silverwrist/venice/core/UserFound.java index fb8c26d..ba3c2e6 100644 --- a/src/com/silverwrist/venice/core/UserFound.java +++ b/src/com/silverwrist/venice/core/UserFound.java @@ -37,4 +37,6 @@ public interface UserFound public abstract int getLevel(); + public abstract UserFound createNewLevel(int level); + } // end interface UserFound diff --git a/src/com/silverwrist/venice/core/VeniceEngine.java b/src/com/silverwrist/venice/core/VeniceEngine.java index f17bdb1..05df082 100644 --- a/src/com/silverwrist/venice/core/VeniceEngine.java +++ b/src/com/silverwrist/venice/core/VeniceEngine.java @@ -67,4 +67,8 @@ public interface VeniceEngine extends SearchMode public abstract int getNumOldPostsBeforeNew(); + public abstract int getMaxNumConferenceMembersDisplay(); + + public abstract int getMaxNumSIGMembersDisplay(); + } // end interface VeniceEngine diff --git a/src/com/silverwrist/venice/core/impl/BackgroundConferencePurge.java b/src/com/silverwrist/venice/core/impl/BackgroundConferencePurge.java new file mode 100644 index 0000000..08b379f --- /dev/null +++ b/src/com/silverwrist/venice/core/impl/BackgroundConferencePurge.java @@ -0,0 +1,131 @@ +/* + * 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 . + * + * 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 , + * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are + * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * + * Contributor(s): + */ +package com.silverwrist.venice.core.impl; + +import java.sql.*; +import org.apache.log4j.*; +import com.silverwrist.util.ParallelRunQueue; +import com.silverwrist.venice.db.*; +import com.silverwrist.venice.core.InternalStateError; + +class BackgroundConferencePurge implements Runnable +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + private static Category logger = Category.getInstance(BackgroundConferencePurge.class.getName()); + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private DataPool datapool; + private int confid; + private int num_topics; + private int max_topicid; + + /*-------------------------------------------------------------------------------- + * Constructor + *-------------------------------------------------------------------------------- + */ + + BackgroundConferencePurge(DataPool datapool, int confid, int num_topics, int max_topicid) + { + this.datapool = datapool; + this.confid = confid; + this.num_topics = num_topics; + this.max_topicid = max_topicid; + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Implementations from interface Runnable + *-------------------------------------------------------------------------------- + */ + + public void run() + { + if (logger.isDebugEnabled()) + logger.debug("BackgroundConferencePurge running on conference #" + confid); + + Connection conn = null; // pooled database connection + ParallelRunQueue rq = new ParallelRunQueue(2); + + try + { // get a database connection from the pool + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // purge out some auxiliary tables first + stmt.executeUpdate("DELETE FROM confmember WHERE confid = " + confid + ";"); + stmt.executeUpdate("DELETE FROM confsettings WHERE confid = " + confid + ";"); + stmt.executeUpdate("DELETE FROM confhotlist WHERE confid = " + confid + ";"); + stmt.executeUpdate("DELETE FROM confbozo WHERE confid = " + confid + ";"); + + // look up all the topic IDs that are present in this conference + int[] topicids = new int[num_topics]; + StringBuffer sql = new StringBuffer("SELECT topicid FROM topics WHERE confid = "); + sql.append(confid).append(" AND topicid <= ").append(max_topicid).append(" ORDER BY topicid;"); + ResultSet rs = stmt.executeQuery(sql.toString()); + int topics = 0; + while (rs.next()) + topicids[topics++] = rs.getInt(1); + + for (int i=0; i=read_level); } // end canReadConference public boolean canPostToConference(int level) { + if (deleted) + return false; return (level>=post_level); } // end canReadConference public boolean canCreateTopic(int level) { + if (deleted) + return false; return (level>=create_level); } // end canCreateTopic public boolean canChangeConference(int level) { + if (deleted) + return false; return (level>=change_level); } // end canChangeConference @@ -371,6 +386,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void setSecurityLevels(SIGBackend sig, int read, int post, int create, int hide, int nuke, int change, int delete) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -402,7 +420,7 @@ class ConferenceCoreData implements ConferenceData // create an audit record reflecting the change ar = new AuditRecord(AuditRecord.CONF_SECURITY,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "conf=" + String.valueOf(confid)); + "conf=" + confid); } // end try catch (SQLException e) @@ -434,6 +452,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void setName(SIGBackend sig, String val) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -457,7 +478,7 @@ class ConferenceCoreData implements ConferenceData // create an audit record reflecting the change ar = new AuditRecord(AuditRecord.CONF_SECURITY,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "conf=" + String.valueOf(confid)); + "conf=" + confid); } // end try catch (SQLException e) @@ -489,6 +510,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void setDescription(String val) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection try @@ -526,6 +550,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void addAlias(SIGBackend sig, String alias) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -566,7 +593,7 @@ class ConferenceCoreData implements ConferenceData // set the database's update date and generate a new audit record touchUpdate(conn); ar = new AuditRecord(AuditRecord.CONF_ALIAS,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "conf=" + String.valueOf(confid),"add=" + alias); + "conf=" + confid,"add=" + alias); } // end try catch (SQLException e) @@ -598,6 +625,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void removeAlias(SIGBackend sig, String alias) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -651,7 +681,7 @@ class ConferenceCoreData implements ConferenceData if ((cached_alias!=null) && cached_alias.equals(alias)) cached_alias = null; // also release the cached alias and force a re-get ar = new AuditRecord(AuditRecord.CONF_ALIAS,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "conf=" + String.valueOf(confid),"remove=" + alias); + "conf=" + confid,"remove=" + alias); } // end if @@ -685,6 +715,9 @@ class ConferenceCoreData implements ConferenceData public synchronized void setMembership(SIGBackend sig, int uid, int grant_level) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -742,8 +775,7 @@ class ConferenceCoreData implements ConferenceData { // set the database's update date and generate a new audit record touchUpdate(conn); ar = new AuditRecord(AuditRecord.CONF_MEMBERSHIP,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "conf=" + String.valueOf(confid),"uid=" + String.valueOf(uid), - "level=" + String.valueOf(grant_level)); + "conf=" + confid,"uid=" + uid,"level=" + grant_level); } // end if @@ -777,12 +809,17 @@ class ConferenceCoreData implements ConferenceData public boolean canHideTopics(int level) { + if (deleted) + return false; return (level>=hide_level); } // end canHideTopics public synchronized String getAnAlias() throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + if (cached_alias!=null) return cached_alias; @@ -821,6 +858,9 @@ class ConferenceCoreData implements ConferenceData public synchronized ReturnTopicInfo createNewTopic(SIGBackend sig, String title, String pseud, String body, int body_lines) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record short new_topic_num; // sequential number of the new topic @@ -891,8 +931,7 @@ class ConferenceCoreData implements ConferenceData // create an audit record indicating we were successful ar = new AuditRecord(AuditRecord.CREATE_TOPIC,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "confid=" + String.valueOf(confid),"num=" + String.valueOf(new_topic_num), - "title=" + title); + "confid=" + confid,"num=" + new_topic_num,"title=" + title); } // end try finally @@ -935,18 +974,25 @@ class ConferenceCoreData implements ConferenceData public boolean canScribblePosts(int level) { + if (deleted) + return false; return (level>=nuke_level); } // end canScribblePosts public boolean canNukePosts(int level) { + if (deleted) + return false; return (level>=nuke_level); } // end canNukePosts public synchronized void touchUpdate(Connection conn, java.util.Date date) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + try { // update the last update date Statement stmt = conn.createStatement(); @@ -998,6 +1044,207 @@ class ConferenceCoreData implements ConferenceData } // end getTopTopic + public List getMemberList() throws DataException + { + if (deleted) + throw new DataException("This conference has been deleted."); + + if (logger.isDebugEnabled()) + logger.debug("Member list: conference = " + confid); + + Vector rc = new Vector(); // return from this function + Connection conn = null; // pooled database connection + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // create a new SQL statement + StringBuffer sql = new StringBuffer("SELECT u.uid, u.username, u.description, c.given_name, " + + "c.family_name, c.locality, c.region, c.country, m.granted_lvl " + + "FROM users u, contacts c, confmember m WHERE " + + "u.contactid = c.contactid AND u.uid = m.uid AND m.confid = "); + sql.append(confid).append(" AND u.is_anon = 0 ORDER BY u.username;"); + + if (logger.isDebugEnabled()) + logger.debug("SQL: " + sql.toString()); + + // launch the search! + ResultSet rs = stmt.executeQuery(sql.toString()); + + while (rs.next()) + { // add all the found users to the list + UserFoundImpl ufi = new UserFoundImpl(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getString(4), + rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8), + rs.getInt(9)); + UserFound tmp = (UserFound)ufi; + rc.add(tmp); + + } // end while + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading member entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve member information: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + return new ReadOnlyVector(rc); + + } // end getMemberList + + public int getMemberLevel(int uid) throws DataException + { + if (deleted) + throw new DataException("This conference has been deleted."); + + Connection conn = null; // pooled database connection + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // create the statement + StringBuffer sql = new StringBuffer("SELECT granted_lvl FROM confmember WHERE confid = "); + sql.append(confid).append(" AND uid = ").append(uid).append(';'); + + // execute the statement and return the retrieved value + ResultSet rs = stmt.executeQuery(sql.toString()); + if (rs.next()) + return rs.getInt(1); + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading member entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve member information: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + return -1; // default return if no member level present + + } // end getMemberLevel + + public boolean isDeleted() + { + return deleted; + + } // end isDeleted + + public boolean canDeleteConference(int level) + { + if (deleted) + return false; + return (level>=delete_level); + + } // end canDeleteConference + + public synchronized void delete(SIGBackend sig) throws DataException + { + if (deleted) + throw new DataException("This conference has been deleted."); + + Connection conn = null; // database connection + AuditRecord ar = null; // audit record + int topic_count, topic_max; // count and maximum topic + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // lock tables on the critical stuff that MUST be deleted now + stmt.executeUpdate("LOCK TABLES confs WRITE, confalias WRITE, topics READ;"); + try + { // first delete the conference record itself + StringBuffer sql = new StringBuffer("DELETE FROM confs WHERE confid = "); + sql.append(confid).append(';'); + stmt.executeUpdate(sql.toString()); + + // now delete all its alias records + sql.setLength(0); + sql.append("DELETE FROM confalias WHERE confid = ").append(confid).append(';'); + stmt.executeUpdate(sql.toString()); + + // determine the number of topics in this conference, and the maximum topic ID + sql.setLength(0); + sql.append("SELECT COUNT(*), MAX(topicid) FROM topics WHERE confid = ").append(confid).append(';'); + ResultSet rs = stmt.executeQuery(sql.toString()); + if (!(rs.next())) + throw new InternalStateError("ConferenceCoreData.delete screwup on topic SELECT"); + topic_count = rs.getInt(1); + topic_max = rs.getInt(2); + + // record that we're now deleted + create_date = null; + last_update = null; + top_topic = -1; + name = null; + description = null; + cached_alias = null; + deleted = true; + + } // end try + finally + { // unlock the tables before we go + Statement ulk_stmt = conn.createStatement(); + ulk_stmt.executeUpdate("UNLOCK TABLES;"); + + } // end finally + + // create an audit record indicating we were successful + ar = new AuditRecord(AuditRecord.DELETE_CONF,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), + "confid=" + confid); + + } // end try + catch (SQLException e) + { // database error - this is a DataException + logger.error("DB error deleting conference: " + e.getMessage(),e); + throw new DataException("unable to delete conference: " + e.getMessage(),e); + + } // end catch + finally + { // make sure the connection is released before we go + try + { // save off the audit record before we go, though + if ((ar!=null) && (conn!=null)) + ar.store(conn); + + } // end try + catch (SQLException e) + { // we couldn't store the audit record! + logger.error("DB error saving audit record: " + e.getMessage(),e); + + } // end catch + + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + // Delete the rest of the gunk in the background; spin off another thread to handle it. + BackgroundConferencePurge purger = new BackgroundConferencePurge(datapool,confid,topic_count,topic_max); + Thread thrd = new Thread(purger); + thrd.setPriority(Thread.NORM_PRIORITY-1); + thrd.start(); + + } // end delete + /*-------------------------------------------------------------------------------- * External static operations (usable only from within package) *-------------------------------------------------------------------------------- @@ -1100,13 +1347,13 @@ class ConferenceCoreData implements ConferenceData // create an audit record indicating we were successful ar = new AuditRecord(AuditRecord.CREATE_CONF,sig.realUID(),sig.userRemoteAddress(),sig.realSIGID(), - "confid=" + String.valueOf(new_confid),"name=" + name,"alias=" + alias); + "confid=" + new_confid,"name=" + name,"alias=" + alias); } // end try catch (SQLException e) { // database error - this is a DataException - logger.error("DB error creating SIG: " + e.getMessage(),e); - throw new DataException("unable to create SIG: " + e.getMessage(),e); + logger.error("DB error creating conference: " + e.getMessage(),e); + throw new DataException("unable to create conference: " + e.getMessage(),e); } // end catch finally diff --git a/src/com/silverwrist/venice/core/impl/ConferenceData.java b/src/com/silverwrist/venice/core/impl/ConferenceData.java index 01cd76a..e860ea2 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceData.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceData.java @@ -7,7 +7,7 @@ * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * - * The Original Code is the Venice Web Community System. + * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are @@ -92,4 +92,14 @@ public interface ConferenceData extends ReferencedData public abstract short getTopTopic(); + public abstract List getMemberList() throws DataException; + + public abstract int getMemberLevel(int uid) throws DataException; + + public abstract boolean isDeleted(); + + public abstract boolean canDeleteConference(int level); + + public abstract void delete(SIGBackend sig) throws DataException; + } // end interface ConferenceData diff --git a/src/com/silverwrist/venice/core/impl/ConferenceSIGContext.java b/src/com/silverwrist/venice/core/impl/ConferenceSIGContext.java index 1d2f7c3..49075ed 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceSIGContext.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceSIGContext.java @@ -7,7 +7,7 @@ * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * - * The Original Code is the Venice Web Community System. + * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are @@ -100,4 +100,12 @@ public interface ConferenceSIGContext extends ReferencedData public abstract short getTopTopic(); + public abstract List getMemberList() throws DataException; + + public abstract int getMemberLevel(int uid) throws DataException; + + public abstract boolean canDeleteConference(int level); + + public abstract void delete(SIGBackend sig) throws DataException; + } // end interface ConferenceSIGContext diff --git a/src/com/silverwrist/venice/core/impl/ConferenceSIGContextImpl.java b/src/com/silverwrist/venice/core/impl/ConferenceSIGContextImpl.java index fde7b09..a689c43 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceSIGContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceSIGContextImpl.java @@ -88,6 +88,7 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext private boolean hide_list; // hide the conference in the list? private ConfCache cache; // cache of locally-important information private ConferenceData confdata = null; // the inner conference data object + private boolean deleted = false; // has this conference been deleted? /*-------------------------------------------------------------------------------- * Constructors @@ -170,6 +171,23 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext } // end constructor + /*-------------------------------------------------------------------------------- + * finalize() function + *-------------------------------------------------------------------------------- + */ + + protected void finalize() + { + if (confdata!=null) + confdata.rd_release(); + confdata = null; + engine = null; + sig = null; + datapool = null; + cache = null; + + } // end finalize + /*-------------------------------------------------------------------------------- * Internal functions *-------------------------------------------------------------------------------- @@ -179,6 +197,8 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext { if (confdata==null) { // attempt to load the ConferenceSIGContext + if (deleted) + throw new DataException("This conference has been deleted."); confdata = engine.getConferenceDataObject(confid); // clear cache when we get the real confdata @@ -194,6 +214,9 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext { if (confdata==null) { // we need to load the ConferenceSIGContext... + if (deleted) + return null; // no return on deletion + try { // attempt to load the ConferenceSIGContext confdata = engine.getConferenceDataObject(confid); @@ -442,6 +465,9 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext public synchronized void setSIGGrantedLevel(SIGBackend sig, int new_level) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -501,6 +527,9 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext public synchronized void setSequence(short seq) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection try @@ -543,6 +572,9 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext public void setHideList(SIGBackend sig, boolean flag) throws DataException { + if (deleted) + throw new DataException("This conference has been deleted."); + Connection conn = null; // database connection AuditRecord ar = null; // audit record @@ -697,4 +729,86 @@ class ConferenceSIGContextImpl implements ConferenceSIGContext } // end getTopTopic + public List getMemberList() throws DataException + { + return getConferenceData().getMemberList(); + + } // end getMemberList + + public int getMemberLevel(int uid) throws DataException + { + return getConferenceData().getMemberLevel(uid); + + } // end getMemberLevel + + public boolean canDeleteConference(int level) + { + ConferenceData c = getConferenceDataNE(); + if (c==null) + return false; + if (level ").append(this.sig.realSIGID()).append(" LIMIT 1;"); + ResultSet rs = stmt.executeQuery(sql.toString()); + if (rs.next()) + delete_core = false; // we don't delete the core yet + + // remove the row that links this conference to this SIG + sql.setLength(0); + sql.append("DELETE FROM sigtoconf WHERE confid = ").append(confid).append(" AND sigid = "); + sql.append(this.sig.realSIGID()).append(';'); + stmt.executeUpdate(sql.toString()); + + // record that we've been deleted + level = 0; + sequence = -1; + hide_list = true; + cache = null; + deleted = true; + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error deleting conference entry: " + e.getMessage(),e); + throw new DataException("unable to delete conference information: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + if (delete_core) + { // the conference is not linked to any other SIGs - we need to delete the core as well + c.delete(sig); + engine.detachConferenceDataObject(confid); + + } // end if + + // detach our own reference from the lower-level object + confdata = null; + c.rd_release(); + + } // end delete + } // end class ConferenceSIGContextImpl diff --git a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java index 3f62dd3..ae36dcc 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java @@ -139,6 +139,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend private String pseud; // default pseud to use in this conference private java.util.Date last_read; // last date we read this conference private java.util.Date last_post; // last date we posted to this conference + private boolean deleted = false; // has conference been deleted? /*-------------------------------------------------------------------------------- * Constructors @@ -202,6 +203,8 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend { if (confdata==null) { // attempt to load the ConferenceSIGContext + if (deleted) + throw new DataException("This conference has been deleted."); confdata = sig.getConferenceDataObject(confid); // clear cache when we get the real confdata @@ -217,6 +220,9 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend { if (confdata==null) { // we need to load the ConferenceSIGContext... + if (deleted) + return null; // no return on deletion + try { // attempt to load the ConferenceSIGContext confdata = sig.getConferenceDataObject(confid); @@ -262,6 +268,9 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend private void tryLoadSettings(Connection conn) throws DataException { + if (deleted) + return; // this is a no-op + try { // look up the conference settings for this user Statement stmt = conn.createStatement(); @@ -609,7 +618,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end removeAlias - public void addMember(int uid, boolean as_host) throws DataException, AccessError + public void setMembership(int uid, int grant_level) throws DataException, AccessError { if (!(getConferenceData().canChangeConference(level))) { // this user can't modify the conference security @@ -618,13 +627,6 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - // figure out which level to grant the user - int grant_level; - if (as_host) - grant_level = DefaultLevels.hostConference(); - else - grant_level = DefaultLevels.memberConference(); - // call down to set the level getConferenceData().setMembership(sig,uid,grant_level); @@ -632,28 +634,23 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (uid==sig.realUID()) recalcLevel(grant_level); + } // end setMembership + + public void addMember(int uid, boolean as_host) throws DataException, AccessError + { + setMembership(uid,(as_host ? DefaultLevels.hostConference() : DefaultLevels.memberConference())); + } // end addMember public void removeMember(int uid) throws DataException, AccessError { - if (!(getConferenceData().canChangeConference(level))) - { // this user can't modify the conference security - logger.error("user not permitted to change membership"); - throw new AccessError("You are not permitted to change the membership of this conference."); - - } // end if - - // call down to set the level - getConferenceData().setMembership(sig,uid,-1); - - // If we adjusted our OWN level, reflect that change. - if (uid==sig.realUID()) - recalcLevel(-1); + setMembership(uid,-1); } // end removeMember public int getSIGGrantedLevel() throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to retrieve security info"); @@ -661,12 +658,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - return getConferenceData().getSIGGrantedLevel(); + return c.getSIGGrantedLevel(); } // end getSIGGrantedLevel public void setSIGGrantedLevel(int new_level) throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to change security info"); @@ -674,12 +672,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - getConferenceData().setSIGGrantedLevel(sig,new_level); + c.setSIGGrantedLevel(sig,new_level); } // end setSIGGrantedLevel public short getSequence() throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to retrieve layout info"); @@ -687,12 +686,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - return getConferenceData().getSequence(); + return c.getSequence(); } // end getSequence public void setSequence(short seq) throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to set layout info"); @@ -700,12 +700,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - getConferenceData().setSequence(seq); + c.setSequence(seq); } // end setSequence public boolean getHideList() throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to retrieve security info"); @@ -713,12 +714,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - return getConferenceData().getHideList(); + return c.getHideList(); } // end getHideList public void setHideList(boolean flag) throws DataException, AccessError { + ConferenceSIGContext c = getConferenceData(); if (!(sig.userCanCreateSubobjects())) { // this user can't modify the conference security logger.error("user not permitted to change security info"); @@ -726,7 +728,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if - getConferenceData().setHideList(sig,flag); + c.setHideList(sig,flag); } // end setHideList @@ -740,6 +742,8 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend { if (sig.userIsAnonymous()) return; // anonymous user can't change pseud + if (deleted) + throw new DataException("This conference has been deleted."); Connection conn = null; // pooled database connection @@ -787,6 +791,8 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend public boolean anyUnread() { + if (deleted) + return false; Connection conn = null; // pooled database connection try @@ -832,7 +838,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend { if (!(getConferenceData().canReadConference(level))) { // the luser can't even read the conference... - logger.error("user not permitted to change membership"); + logger.error("user not permitted to get topics"); throw new AccessError("You are not permitted to read this conference."); } // end if @@ -929,7 +935,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend { if (!(getConferenceData().canReadConference(level))) { // the luser can't even read the conference... - logger.error("user not permitted to change membership"); + logger.error("user not permitted to get messages"); throw new AccessError("You are not permitted to read this conference."); } // end if @@ -953,8 +959,15 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end getNewTopicPreviewChecker - public void fixSeen() throws DataException + public void fixSeen() throws DataException, AccessError { + if (!(getConferenceData().canReadConference(level))) + { // the luser can't even read the conference... + logger.error("user not permitted to set unread messages"); + throw new AccessError("You are not permitted to read this conference."); + + } // end if + if (sig.userIsAnonymous()) return; // anonymous user can't fixseen @@ -1018,8 +1031,15 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end fixSeen - public List getActivePosters(int skip, int limit) throws DataException + public List getActivePosters(int skip, int limit) throws DataException, AccessError { + if (!(getConferenceData().canReadConference(level))) + { // the luser can't even read the conference... + logger.error("user not permitted to get posters list"); + throw new AccessError("You are not permitted to read this conference."); + + } // end if + Connection conn = null; Vector rc = new Vector(); @@ -1066,20 +1086,27 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end getActivePosters - public List getActivePosters(int limit) throws DataException + public List getActivePosters(int limit) throws DataException, AccessError { return getActivePosters(0,limit); } // end getActivePosters - public List getActivePosters() throws DataException + public List getActivePosters() throws DataException, AccessError { return getActivePosters(-1,-1); } // end getActivePosters - public List getActiveReaders(int skip, int limit) throws DataException + public List getActiveReaders(int skip, int limit) throws DataException, AccessError { + if (!(getConferenceData().canReadConference(level))) + { // the luser can't even read the conference... + logger.error("user not permitted to get readers list"); + throw new AccessError("You are not permitted to read this conference."); + + } // end if + Connection conn = null; Vector rc = new Vector(); @@ -1126,18 +1153,81 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end getActiveReaders - public List getActiveReaders(int limit) throws DataException + public List getActiveReaders(int limit) throws DataException, AccessError { return getActiveReaders(0,limit); } // end getActiveReaders - public List getActiveReaders() throws DataException + public List getActiveReaders() throws DataException, AccessError { return getActiveReaders(-1,-1); } // end getActiveReaders + public List getMemberList() throws DataException, AccessError + { + if (!(getConferenceData().canReadConference(level))) + { // the luser can't even read the conference... + logger.error("user not permitted to get member list"); + throw new AccessError("You are not permitted to read this conference."); + + } // end if + + return getConferenceData().getMemberList(); + + } // end getMemberList + + public int getMemberLevel(int uid) throws DataException, AccessError + { + if (!(getConferenceData().canReadConference(level))) + { // the luser can't even read the conference... + logger.error("user not permitted to get member data"); + throw new AccessError("You are not permitted to read this conference."); + + } // end if + + return getConferenceData().getMemberLevel(uid); + + } // end getMemberLevel + + public void delete() throws DataException, AccessError + { + ConferenceSIGContext ctxt = getConferenceData(); + if (!(ctxt.canDeleteConference(level)) || !(sig.userCanDeleteSubobjects())) + { // no way can we delete this conference, not NO way! + logger.error("user not permitted to delete conference"); + throw new AccessError("You are not permitted to delete this conference."); + + } // end if + + // call the methods required to delete the conference + ctxt.delete(sig); + sig.detachConferenceDataObject(confid); + + // flag that we've been deleted + cache = null; + settings_loaded = true; + pseud = null; + last_read = null; + last_post = null; + deleted = true; + + // detach our references from the lower-level object + confdata = null; + ctxt.rd_release(); + + } // end delete + + public boolean canDeleteConference() + { + ConferenceSIGContext c = getConferenceDataNE(); + if (c==null) + return false; + return (c.canDeleteConference(level) && sig.userCanDeleteSubobjects()); + + } // end canDeleteConference + /*-------------------------------------------------------------------------------- * Implementations from interface UserBackend *-------------------------------------------------------------------------------- @@ -1214,6 +1304,18 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end realSIGAlias + public void detachConferenceDataObject(int confid) throws DataException + { + sig.detachConferenceDataObject(confid); + + } // end detachConferenceDataObject + + public boolean userCanDeleteSubobjects() + { + return sig.userCanDeleteSubobjects(); + + } // end userCanDeleteSubobjects + /*-------------------------------------------------------------------------------- * Implementations from interface ConferenceBackend *-------------------------------------------------------------------------------- @@ -1236,7 +1338,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend public void touchRead(Connection conn) throws SQLException { - if (sig.userIsAnonymous()) + if (deleted || sig.userIsAnonymous()) return; // anonymous user can't update squat Statement stmt = conn.createStatement(); @@ -1268,7 +1370,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend public void touchPost(Connection conn, java.util.Date post_date) throws SQLException { - if (sig.userIsAnonymous()) + if (deleted || sig.userIsAnonymous()) return; // anonymous user can't update squat Statement stmt = conn.createStatement(); @@ -1299,6 +1401,9 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend public String realConfAlias() { + if (deleted) + return null; + try { // just pull it from the lower-level object return getConferenceData().getAnAlias(); diff --git a/src/com/silverwrist/venice/core/impl/EngineBackend.java b/src/com/silverwrist/venice/core/impl/EngineBackend.java index 056a3c0..d5747fc 100644 --- a/src/com/silverwrist/venice/core/impl/EngineBackend.java +++ b/src/com/silverwrist/venice/core/impl/EngineBackend.java @@ -7,7 +7,7 @@ * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * - * The Original Code is the Venice Web Community System. + * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are @@ -32,6 +32,9 @@ public interface EngineBackend public static final int IP_POSTSPERPAGE = 0; public static final int IP_POSTSATTOP = 1; + public static final int IP_MAXSEARCHRETURN = 2; + public static final int IP_MAXSIGMEMBERDISPLAY = 3; + public static final int IP_MAXCONFMEMBERDISPLAY = 4; public abstract SimpleEmailer createEmailer(); @@ -45,6 +48,8 @@ public interface EngineBackend public abstract SIGData getSIGDataObject(int sigid) throws DataException; + public abstract void detachSIGDataObject(int sigid); + public abstract BitSet getLockedFeaturesMask(); public abstract List getSIGFeatureSet(BitSet enabled_features, int level, boolean read_privs); @@ -63,6 +68,8 @@ public interface EngineBackend public abstract ConferenceData getConferenceDataObject(int confid) throws DataException; + public abstract void detachConferenceDataObject(int confid); + public abstract void saveAuditRecord(AuditRecord ar); public abstract void registerNewConference(ConferenceData conf); diff --git a/src/com/silverwrist/venice/core/impl/SIGBackend.java b/src/com/silverwrist/venice/core/impl/SIGBackend.java index bf0f5a3..efbced8 100644 --- a/src/com/silverwrist/venice/core/impl/SIGBackend.java +++ b/src/com/silverwrist/venice/core/impl/SIGBackend.java @@ -33,4 +33,8 @@ public interface SIGBackend extends UserBackend public abstract String realSIGAlias(); + public abstract void detachConferenceDataObject(int confid) throws DataException; + + public abstract boolean userCanDeleteSubobjects(); + } // end interface SIGBackend diff --git a/src/com/silverwrist/venice/core/impl/SIGCoreData.java b/src/com/silverwrist/venice/core/impl/SIGCoreData.java index 17bd064..69db218 100644 --- a/src/com/silverwrist/venice/core/impl/SIGCoreData.java +++ b/src/com/silverwrist/venice/core/impl/SIGCoreData.java @@ -78,7 +78,7 @@ class SIGCoreData implements SIGData, SIGDataBackend SIGCoreData(EngineBackend engine, DataPool datapool, int sigid) throws DataException { if (logger.isDebugEnabled()) - logger.debug("new SIGCoreData for SIG " + String.valueOf(sigid)); + logger.debug("new SIGCoreData for SIG " + sigid); this.engine = engine; this.datapool = datapool; this.sigid = sigid; @@ -95,7 +95,7 @@ class SIGCoreData implements SIGData, SIGDataBackend sql.append(sigid).append(';'); ResultSet rs = stmt.executeQuery(sql.toString()); if (!(rs.next())) - throw new DataException("SIG #" + String.valueOf(sigid) + " does not exist in the database."); + throw new DataException("SIG #" + sigid + " does not exist in the database."); loadData(rs); // load the SIG data @@ -129,7 +129,7 @@ class SIGCoreData implements SIGData, SIGDataBackend BitSet features) { if (logger.isDebugEnabled()) - logger.debug("new SIGCoreData for BRAND NEW SIG " + String.valueOf(sigid)); + logger.debug("new SIGCoreData for BRAND NEW SIG " + sigid); this.engine = engine; this.datapool = datapool; this.sigid = sigid; @@ -218,8 +218,8 @@ class SIGCoreData implements SIGData, SIGDataBackend alias = rs.getString("alias"); if (logger.isDebugEnabled()) - logger.debug("Loaded data for SIG \"" + name + "\" (ID " + String.valueOf(sigid) + ", alias '" - + alias + "') successfully"); + logger.debug("Loaded data for SIG \"" + name + "\" (ID " + sigid + ", alias '" + alias + + "') successfully"); } // end loadData @@ -438,13 +438,13 @@ class SIGCoreData implements SIGData, SIGDataBackend { // contact being established for the first time contactid = ci.getContactID(); if (logger.isDebugEnabled()) - logger.debug("established new contact ID (" + String.valueOf(contactid) + ") for this SIG"); + logger.debug("established new contact ID (" + contactid + ") for this SIG"); } // end if touchUpdate(conn); ar = new AuditRecord(AuditRecord.SIG_CONTACT_INFO,user.realUID(),user.userRemoteAddress(),sigid, - "contactid=" + String.valueOf(contactid)); + "contactid=" + contactid); } // end try catch (ClassCastException cce) @@ -691,7 +691,7 @@ class SIGCoreData implements SIGData, SIGDataBackend this.category_id = catid; last_update = now; ar = new AuditRecord(AuditRecord.SIG_CATEGORY,user.realUID(),user.userRemoteAddress(),sigid, - "catid=" + String.valueOf(catid)); + "catid=" + catid); } // end try catch (SQLException e) @@ -879,7 +879,7 @@ class SIGCoreData implements SIGData, SIGDataBackend hidden_search = search; last_update = now; ar = new AuditRecord(AuditRecord.SIG_HIDE_INFO,user.realUID(),user.userRemoteAddress(),sigid, - "dir=" + String.valueOf(directory) + ",search=" + String.valueOf(search)); + "dir=" + directory + ",search=" + search); } // end try catch (SQLException e) @@ -932,7 +932,7 @@ class SIGCoreData implements SIGData, SIGDataBackend members_only = flag; last_update = now; ar = new AuditRecord(AuditRecord.SIG_MEMBERS_ONLY,user.realUID(),user.userRemoteAddress(),sigid, - "flag=" + String.valueOf(flag)); + "flag=" + flag); } // end try catch (SQLException e) @@ -1013,7 +1013,7 @@ class SIGCoreData implements SIGData, SIGDataBackend ResultSet rs = stmt.executeQuery(sql.toString()); if (!(rs.next())) { // can't find the join key? - logger.error("SIG " + String.valueOf(sigid) + "appears to not be there"); + logger.error("SIG " + sigid + "appears to not be there"); throw new DataException("Unable to find join key for SIG"); } // end if @@ -1241,7 +1241,7 @@ class SIGCoreData implements SIGData, SIGDataBackend { // update the SIG data and generate an audit record touchUpdate(conn); ar = new AuditRecord(AuditRecord.SET_MEMBERSHIP,user.realUID(),user.userRemoteAddress(),sigid, - "uid=" + String.valueOf(uid),"level=" + String.valueOf(grant_level)); + "uid=" + uid,"level=" + grant_level); } // end if } // end try @@ -1319,10 +1319,10 @@ class SIGCoreData implements SIGData, SIGDataBackend } // end isFeaturePresent - public ConferenceSIGContext getConferenceDataObject(int confid) throws DataException + public synchronized ConferenceSIGContext getConferenceDataObject(int confid) throws DataException { if (logger.isDebugEnabled()) - logger.debug("getConferenceDataObject(" + String.valueOf(confid) + ")..."); + logger.debug("getConferenceDataObject(" + confid + ")..."); Integer the_confid = new Integer(confid); ConferenceSIGContext csc = (ConferenceSIGContext)(conf_objects.get(the_confid)); @@ -1346,6 +1346,24 @@ class SIGCoreData implements SIGData, SIGDataBackend } // end getConferenceDataObject + public synchronized void detachConferenceDataObject(int confid) + { + if (logger.isDebugEnabled()) + logger.debug("detachConferenceDataObject(" + confid + ")..."); + + Integer the_confid = new Integer(confid); + ConferenceSIGContext csc = (ConferenceSIGContext)(conf_objects.get(the_confid)); + if (csc!=null) + { // remove from the hashtable + conf_objects.remove(the_confid); + csc.rd_release(); + if (logger.isDebugEnabled()) + logger.debug("...reference released"); + + } // end if + + } // end detachConferenceDataObject + public ConferenceSIGContext createConference(SIGBackend sig, String name, String alias, String description, boolean pvt, boolean hide_list) throws DataException { @@ -1362,19 +1380,271 @@ class SIGCoreData implements SIGData, SIGDataBackend cdata.rd_release(); rcs = null; - // Register this object with our local cache of ConferenceSIGData objects. - Integer the_confid = new Integer(conf.getConfID()); - if (conf_objects.get(the_confid)!=null) - throw new InternalStateError("ConfID " + the_confid.toString() + " already exists...but it CAN'T HAVE!"); + synchronized (this) + { // Register this object with our local cache of ConferenceSIGData objects. + Integer the_confid = new Integer(conf.getConfID()); + if (conf_objects.get(the_confid)!=null) + throw new InternalStateError("ConfID " + the_confid + " already exists...but it CAN'T HAVE!"); - // throw an extra reference on it and dump it in the object cache - conf.rd_addRef(); - conf_objects.put(the_confid,conf); + // throw an extra reference on it and dump it in the object cache + conf.rd_addRef(); + conf_objects.put(the_confid,conf); + + } // end synchronized block return conf; // pass it up to the next level } // end createConference + public List searchForMembers(int field, int mode, String term, int offset, int count, + boolean include_hidden) throws DataException + { + if (logger.isDebugEnabled()) + logger.debug("Member search: SIG = " + sigid + ", field = " + field + ", mode = " + mode + ", term '" + + term + "', offset = " + offset + ", count = " + count); + + Vector rc = new Vector(); // return from this function + Connection conn = null; // pooled database connection + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // create a new SQL statement + StringBuffer sql = new StringBuffer("SELECT u.uid, u.username, u.description, c.given_name, " + + "c.family_name, c.locality, c.region, c.country, m.granted_lvl " + + "FROM users u, contacts c, sigmember m WHERE " + + "u.contactid = c.contactid AND u.uid = m.uid AND m.sigid = "); + sql.append(sigid).append(" AND "); + switch (field) + { // determine which field to search on + case SearchMode.FIELD_USER_NAME: + sql.append("u.username "); + break; + + case SearchMode.FIELD_USER_DESCRIPTION: + sql.append("u.description "); + break; + + case SearchMode.FIELD_USER_GIVEN_NAME: + sql.append("c.given_name "); + break; + + case SearchMode.FIELD_USER_FAMILY_NAME: + sql.append("c.family_name "); + break; + + default: + throw new DataException("invalid search field specified"); + + } // end switch + + switch (mode) + { // compose SQL in different ways depending on the search term + case SearchMode.SEARCH_PREFIX: + sql.append("LIKE '").append(SQLUtil.encodeStringWildcards(term)).append("%'"); + break; + + case SearchMode.SEARCH_SUBSTRING: + sql.append("LIKE '%").append(SQLUtil.encodeStringWildcards(term)).append("%'"); + break; + + case SearchMode.SEARCH_REGEXP: + sql.append("REGEXP '").append(SQLUtil.encodeString(term)).append('\''); + break; + + default: + throw new DataException("invalid search mode specified"); + + } // end switch + + if (!include_hidden) + sql.append(" AND m.hidden = 0"); + sql.append(" AND u.is_anon = 0 ORDER BY u.username LIMIT ").append(offset).append(", "); + sql.append(count+1).append(';'); + + if (logger.isDebugEnabled()) + logger.debug("SQL: " + sql.toString()); + + // launch the search! + ResultSet rs = stmt.executeQuery(sql.toString()); + + while (rs.next()) + { // add all the found users to the list + UserFoundImpl ufi = new UserFoundImpl(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getString(4), + rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8), + rs.getInt(9)); + UserFound tmp = (UserFound)ufi; + rc.add(tmp); + + } // end while + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading member entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve member information: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + return new ReadOnlyVector(rc); + + } // end searchForMembers + + public int getSearchMemberCount(int field, int mode, String term, boolean include_hidden) + throws DataException + { + if (logger.isDebugEnabled()) + logger.debug("User search: SIG = " + sigid + ", field = " + field + ", mode = " + mode + ", term '" + + term + "'"); + + Connection conn = null; // pooled database connection + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + StringBuffer sql = new StringBuffer("SELECT COUNT(*) FROM users u, contacts c, sigmember m WHERE " + + "u.contactid = c.contactid AND u.uid = m.uid AND m.sigid = "); + sql.append(sigid).append(" AND "); + + switch (field) + { // determine which field to search on + case SearchMode.FIELD_USER_NAME: + sql.append("u.username "); + break; + + case SearchMode.FIELD_USER_DESCRIPTION: + sql.append("u.description "); + break; + + case SearchMode.FIELD_USER_GIVEN_NAME: + sql.append("c.given_name "); + break; + + case SearchMode.FIELD_USER_FAMILY_NAME: + sql.append("c.family_name "); + break; + + default: + throw new DataException("invalid search field specified"); + + } // end switch + + switch (mode) + { // compose SQL in different ways depending on the search term + case SearchMode.SEARCH_PREFIX: + sql.append("LIKE '").append(SQLUtil.encodeStringWildcards(term)).append("%'"); + break; + + case SearchMode.SEARCH_SUBSTRING: + sql.append("LIKE '%").append(SQLUtil.encodeStringWildcards(term)).append("%'"); + break; + + case SearchMode.SEARCH_REGEXP: + sql.append("REGEXP '").append(SQLUtil.encodeString(term)).append('\''); + break; + + default: + throw new DataException("invalid search mode specified"); + + } // end switch + + if (!include_hidden) + sql.append(" AND m.hidden = 0"); + sql.append(" AND u.is_anon = 0;"); + + if (logger.isDebugEnabled()) + logger.debug("SQL: " + sql.toString()); + + // launch the search! + ResultSet rs = stmt.executeQuery(sql.toString()); + + if (!(rs.next())) + throw new InternalStateError("getSearchMemberCount failure (MUST have 1 row!)"); + + return rs.getInt(1); + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading member entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve member 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 getSearchMemberCount + + public List getMemberList(boolean include_hidden) throws DataException + { + if (logger.isDebugEnabled()) + logger.debug("Member list: SIG = " + sigid); + + Vector rc = new Vector(); // return from this function + Connection conn = null; // pooled database connection + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // create a new SQL statement + StringBuffer sql = new StringBuffer("SELECT u.uid, u.username, u.description, c.given_name, " + + "c.family_name, c.locality, c.region, c.country, m.granted_lvl " + + "FROM users u, contacts c, sigmember m WHERE " + + "u.contactid = c.contactid AND u.uid = m.uid AND m.sigid = "); + sql.append(sigid); + if (!include_hidden) + sql.append(" AND m.hidden = 0"); + sql.append(" AND u.is_anon = 0 ORDER BY u.username;"); + + if (logger.isDebugEnabled()) + logger.debug("SQL: " + sql.toString()); + + // launch the search! + ResultSet rs = stmt.executeQuery(sql.toString()); + + while (rs.next()) + { // add all the found users to the list + UserFoundImpl ufi = new UserFoundImpl(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getString(4), + rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8), + rs.getInt(9)); + UserFound tmp = (UserFound)ufi; + rc.add(tmp); + + } // end while + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading member entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve member information: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + return new ReadOnlyVector(rc); + + } // end getMemberList + /*-------------------------------------------------------------------------------- * Implementations from interface SIGDataBackend *-------------------------------------------------------------------------------- diff --git a/src/com/silverwrist/venice/core/impl/SIGData.java b/src/com/silverwrist/venice/core/impl/SIGData.java index dd5a8cd..633ac3b 100644 --- a/src/com/silverwrist/venice/core/impl/SIGData.java +++ b/src/com/silverwrist/venice/core/impl/SIGData.java @@ -132,8 +132,18 @@ public interface SIGData extends ReferencedData public abstract ConferenceSIGContext getConferenceDataObject(int confid) throws DataException; + public abstract void detachConferenceDataObject(int confid); + public abstract ConferenceSIGContext createConference(SIGBackend sig, String name, String alias, String description, boolean pvt, boolean hide_list) throws DataException; + public abstract List searchForMembers(int field, int mode, String term, int offset, int count, + boolean include_hidden) throws DataException; + + public abstract int getSearchMemberCount(int field, int mode, String term, boolean include_hidden) + throws DataException; + + public abstract List getMemberList(boolean include_hidden) throws DataException; + } // end interface SIGData diff --git a/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java b/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java index 78a956a..243a38e 100644 --- a/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java @@ -1073,6 +1073,25 @@ class SIGUserContextImpl implements SIGContext, SIGBackend } // end canCreateConference + public List searchForMembers(int field, int mode, String term, int offset, int count) + throws DataException + { + return getSIGData().searchForMembers(field,mode,term,offset,count,Capability.showHiddenSIGMembers(level)); + + } // end searchForMembers + + public int getSearchMemberCount(int field, int mode, String term) throws DataException + { + return getSIGData().getSearchMemberCount(field,mode,term,Capability.showHiddenSIGMembers(level)); + + } // end getSearchMemberCount + + public List getMemberList() throws DataException + { + return getSIGData().getMemberList(Capability.showHiddenSIGMembers(level)); + + } // end getMemberList + /*-------------------------------------------------------------------------------- * Implementations from interface UserBackend *-------------------------------------------------------------------------------- @@ -1155,6 +1174,18 @@ class SIGUserContextImpl implements SIGContext, SIGBackend } // end realSIGAlias + public void detachConferenceDataObject(int confid) throws DataException + { + getSIGData().detachConferenceDataObject(confid); + + } // end detachConferenceDataObject + + public boolean userCanDeleteSubobjects() + { + return userCanCreateSubobjects(); + + } // end userCanDeleteSubobjects + /*-------------------------------------------------------------------------------- * Static operations for use within the implementation package *-------------------------------------------------------------------------------- diff --git a/src/com/silverwrist/venice/core/impl/UserFoundImpl.java b/src/com/silverwrist/venice/core/impl/UserFoundImpl.java index a1578f1..da63159 100644 --- a/src/com/silverwrist/venice/core/impl/UserFoundImpl.java +++ b/src/com/silverwrist/venice/core/impl/UserFoundImpl.java @@ -129,4 +129,11 @@ class UserFoundImpl implements UserFound } // end getLevel + public UserFound createNewLevel(int level) + { + return new UserFoundImpl(this.uid,this.name,this.description,this.given_name,this.family_name, + this.locality,this.region,this.country,level); + + } // end createNewLevel + } // end class UserFoundImpl diff --git a/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java b/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java index fe0b1f2..8be4278 100644 --- a/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java +++ b/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java @@ -242,7 +242,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend private void loadDefaults(Statement stmt) throws SQLException, DataException { - final String query = "SELECT posts_per_page, old_posts_at_top FROM globals;"; + final String query = + "SELECT posts_per_page, old_posts_at_top, max_search_page, max_sig_mbr_page, max_conf_mbr_page " + + "FROM globals;"; ResultSet rs = stmt.executeQuery(query); if (!(rs.next())) throw new DataException("Globals table does not appear to be loaded!"); @@ -250,6 +252,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend // stash the globals from the database gp_ints[IP_POSTSPERPAGE] = rs.getInt(1); gp_ints[IP_POSTSATTOP] = rs.getInt(2); + gp_ints[IP_MAXSEARCHRETURN] = rs.getInt(3); + gp_ints[IP_MAXSIGMEMBERDISPLAY] = rs.getInt(4); + gp_ints[IP_MAXCONFMEMBERDISPLAY] = rs.getInt(5); } // end loadDefaults @@ -381,7 +386,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end for if (logger.isDebugEnabled()) - logger.debug(String.valueOf(stock_messages.size()) + " stock messages loaded from config"); + logger.debug(stock_messages.size() + " stock messages loaded from config"); } // end try catch (ConfigException ce) @@ -393,7 +398,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end catch // Allocate the global parameter arrays. - gp_ints = new int[2]; + gp_ints = new int[5]; // initialize anything that requires us to pull from the database Connection conn = null; @@ -419,7 +424,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend features = new VeniceFeatureDef[++max_value]; System.arraycopy(tmp_array,0,features,0,max_value); if (logger.isDebugEnabled()) - logger.debug(String.valueOf(max_value) + " features loaded from database"); + logger.debug(max_value + " features loaded from database"); // load the global defaults loadDefaults(stmt); @@ -556,13 +561,13 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend while (rs.next()) { // load up a stack of memory objects with the country list - Country c = new CountryImpl(rs.getString("code"),rs.getString("name")); + Country c = new CountryImpl(rs.getString(1),rs.getString(2)); rc.add(c); } // end while if (logger.isDebugEnabled()) - logger.debug("getCountryList(): loaded " + String.valueOf(rc.size()) + " country names"); + logger.debug("getCountryList(): loaded " + rc.size() + " country names"); } // end try catch (SQLException e) @@ -596,13 +601,13 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend while (rs.next()) { // load up a stack of memory objects with the country list - Language l = new LanguageImpl(rs.getString("code"),rs.getString("name")); + Language l = new LanguageImpl(rs.getString(1),rs.getString(2)); rc.add(l); } // end while if (logger.isDebugEnabled()) - logger.debug("getLanguageList(): loaded " + String.valueOf(rc.size()) + " language names"); + logger.debug("getLanguageList(): loaded " + rc.size() + " language names"); } // end try catch (SQLException e) @@ -649,9 +654,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend { // look for a user name matching this user record conn = datapool.getConnection(); Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT c.email AS email FROM users u, contacts c " - + "WHERE u.contactid = c.contactid AND u.username = '" - + SQLUtil.encodeString(username) + "';"); + ResultSet rs = stmt.executeQuery("SELECT c.email FROM users u, contacts c WHERE u.contactid = " + + "c.contactid AND u.username = '" + SQLUtil.encodeString(username) + + "';"); if (!(rs.next())) { // could not find email address logger.warn("getEmailAddressForUser(\"" + username + "\") => not found!"); @@ -660,7 +665,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end if - String rc = rs.getString("email"); + String rc = rs.getString(1); if (logger.isDebugEnabled()) logger.debug("getEmailAddressForUser(\"" + username + "\") => \"" + rc + "\""); return rc; @@ -690,9 +695,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend { // look for a user name matching this user record conn = datapool.getConnection(); Statement stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("SELECT c.email AS email, u.passreminder AS passreminder " - + "FROM users u, contacts c WHERE u.contactid = c.contactid " - + "AND u.username = '"); + StringBuffer sql = new StringBuffer("SELECT c.email, u.passreminder FROM users u, contacts c WHERE " + + "u.contactid = c.contactid AND u.username = '"); sql.append(SQLUtil.encodeString(username)).append("';"); ResultSet rs = stmt.executeQuery(sql.toString()); if (!(rs.next())) @@ -703,7 +707,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end if - String email_addr = rs.getString("email"); + String email_addr = rs.getString(1); if (logger.isDebugEnabled()) logger.debug("sendPasswordReminder(\"" + username + "\") going out to \"" + email_addr + "\""); @@ -717,7 +721,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end if message = StringUtil.replaceAllInstances(message,"$USERNAME",username); - message = StringUtil.replaceAllInstances(message,"$REMINDER",rs.getString("passreminder")); + message = StringUtil.replaceAllInstances(message,"$REMINDER",rs.getString(2)); // Create the emailer and send the message. SimpleEmailer emailer = createEmailer(); @@ -796,7 +800,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend new_uid = rs.getInt(1); if (logger.isDebugEnabled()) - logger.debug("...created user \"" + username + "\" with UID " + String.valueOf(new_uid)); + logger.debug("...created user \"" + username + "\" with UID " + new_uid); // add a UserPrefs record for this user, too sql.setLength(0); @@ -974,9 +978,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend public List searchForUsers(int field, int mode, String term, int offset, int count) throws DataException { if (logger.isDebugEnabled()) - logger.debug("User search: field = " + String.valueOf(field) + ", mode = " + String.valueOf(mode) - + ", term '" + term + "', offset = " + String.valueOf(offset) + ", count = " - + String.valueOf(count)); + logger.debug("User search: field = " + field + ", mode = " + mode + ", term '" + term + "', offset = " + + offset + ", count = " + count); Vector rc = new Vector(); // return from this function Connection conn = null; // pooled database connection @@ -985,11 +988,9 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend { // get a database connection conn = datapool.getConnection(); Statement stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("SELECT u.uid AS uid, u.username AS username, u.description " - + "AS description, c.given_name AS given_name, c.family_name AS " - + "family_name, c.locality AS locality, c.region AS region, " - + "c.country AS country FROM users u, contacts c WHERE " - + "u.contactid = c.contactid AND "); + StringBuffer sql = new StringBuffer("SELECT u.uid, u.username, u.description, c.given_name, " + + "c.family_name, c.locality, c.region, c.country FROM users u, " + + "contacts c WHERE u.contactid = c.contactid AND "); switch (field) { // determine which field to search on @@ -1044,10 +1045,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend while (rs.next()) { // add all the found users to the list - UserFoundImpl ufi = new UserFoundImpl(rs.getInt("uid"),rs.getString("username"), - rs.getString("description"),rs.getString("given_name"), - rs.getString("family_name"),rs.getString("locality"), - rs.getString("region"),rs.getString("country")); + UserFoundImpl ufi = new UserFoundImpl(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getString(4), + rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8)); UserFound tmp = (UserFound)ufi; rc.add(tmp); @@ -1074,8 +1073,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend public int getSearchUserCount(int field, int mode, String term) throws DataException { if (logger.isDebugEnabled()) - logger.debug("User search: field = " + String.valueOf(field) + ", mode = " + String.valueOf(mode) - + ", term '" + term + "'"); + logger.debug("User search: field = " + field + ", mode = " + mode + ", term '" + term + "'"); Connection conn = null; // pooled database connection @@ -1083,8 +1081,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend { // get a database connection conn = datapool.getConnection(); Statement stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("SELECT COUNT(*) AS total FROM users u, contacts c WHERE " - + "u.contactid = c.contactid AND "); + StringBuffer sql = new StringBuffer("SELECT COUNT(*) FROM users u, contacts c WHERE u.contactid = " + + "c.contactid AND "); switch (field) { // determine which field to search on @@ -1140,7 +1138,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend if (!(rs.next())) throw new InternalStateError("getSearchUserCount search failure (MUST have 1 row!)"); - return rs.getInt("total"); + return rs.getInt(1); } // end try catch (SQLException e) @@ -1160,7 +1158,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend public int getStdNumSearchResults() { - return 20; // TODO: make this a config file option + return gp_ints[IP_MAXSEARCHRETURN]; } // end getStdNumSearchResults @@ -1245,6 +1243,18 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end getNumOldPostsBeforeNew + public int getMaxNumConferenceMembersDisplay() + { + return gp_ints[IP_MAXCONFMEMBERDISPLAY]; + + } // end getMaxNumConferenceMembersDisplay + + public int getMaxNumSIGMembersDisplay() + { + return gp_ints[IP_MAXSIGMEMBERDISPLAY]; + + } // end getMaxNumSIGMembersDisplay + /*-------------------------------------------------------------------------------- * Implementations from interface EngineBackend *-------------------------------------------------------------------------------- @@ -1357,11 +1367,11 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end getLanguageNameForCode - public SIGData getSIGDataObject(int sigid) throws DataException + public synchronized SIGData getSIGDataObject(int sigid) throws DataException { checkInitialized(); if (logger.isDebugEnabled()) - logger.debug("getSIGDataObject(" + String.valueOf(sigid) + ")..."); + logger.debug("getSIGDataObject(" + sigid + ")..."); Integer the_sigid = new Integer(sigid); SIGData sd = (SIGData)(sig_objects.get(the_sigid)); @@ -1385,6 +1395,25 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end getSIGDataObject + public synchronized void detachSIGDataObject(int sigid) + { + checkInitialized(); + if (logger.isDebugEnabled()) + logger.debug("detachSIGDataObject(" + sigid + ")..."); + + Integer the_sigid = new Integer(sigid); + SIGData sd = (SIGData)(sig_objects.get(the_sigid)); + if (sd!=null) + { // pull the reference out of our hashtable + sig_objects.remove(the_sigid); + sd.rd_release(); + if (logger.isDebugEnabled()) + logger.debug("...reference detached"); + + } // end if + + } // end detachSIGDataObject + public BitSet getLockedFeaturesMask() { checkInitialized(); @@ -1420,7 +1449,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end if and for if (logger.isDebugEnabled()) - logger.debug("getSIGFeatureSet() loaded " + String.valueOf(rc.size()) + " elements"); + logger.debug("getSIGFeatureSet() loaded " + rc.size() + " elements"); return new ReadOnlyVector(rc); // wrap the vector for return @@ -1431,14 +1460,14 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend checkInitialized(); if ((code<0) || (code>=features.length)) { // the index is out of bounds! - logger.error("getAppletForFeature(" + String.valueOf(code) + ") => out of range"); + logger.error("getAppletForFeature(" + code + ") => out of range"); throw new IndexOutOfBoundsException("invalid feature code"); } // end if String rc = features[code].getApplet(); if (logger.isDebugEnabled()) - logger.debug("getAppletForFeature(" + String.valueOf(code) + ") => \"" + rc + "\""); + logger.debug("getAppletForFeature(" + code + ") => \"" + rc + "\""); return rc; } // end getAppletForFeature @@ -1463,15 +1492,15 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end getDefaultFeaturesMask - public void registerNewSIG(SIGData sig) + public synchronized void registerNewSIG(SIGData sig) { checkInitialized(); if (logger.isDebugEnabled()) - logger.debug("registerNewSIG(" + String.valueOf(sig.getID()) + ")..."); + logger.debug("registerNewSIG(" + sig.getID() + ")..."); Integer the_sigid = new Integer(sig.getID()); if (sig_objects.get(the_sigid)!=null) - throw new InternalStateError("SIGID " + the_sigid.toString() + " already exists...but it CAN'T HAVE!"); + throw new InternalStateError("SIGID " + the_sigid + " already exists...but it CAN'T HAVE!"); // throw an extra reference on it and dump it in the object cache sig.rd_addRef(); @@ -1501,11 +1530,11 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end canAccessFeature - public ConferenceData getConferenceDataObject(int confid) throws DataException + public synchronized ConferenceData getConferenceDataObject(int confid) throws DataException { checkInitialized(); if (logger.isDebugEnabled()) - logger.debug("getConferenceDataObject(" + String.valueOf(confid) + ")..."); + logger.debug("getConferenceDataObject(" + confid + ")..."); Integer the_confid = new Integer(confid); ConferenceData cd = (ConferenceData)(conf_objects.get(the_confid)); @@ -1529,6 +1558,25 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end getConferenceDataObject + public synchronized void detachConferenceDataObject(int confid) + { + checkInitialized(); + if (logger.isDebugEnabled()) + logger.debug("detachConferenceDataObject(" + confid + ")..."); + + Integer the_confid = new Integer(confid); + ConferenceData cd = (ConferenceData)(conf_objects.get(the_confid)); + if (cd!=null) + { // remove it from our hashtable + conf_objects.remove(the_confid); + cd.rd_release(); + if (logger.isDebugEnabled()) + logger.debug("...detached reference"); + + } // end if + + } // end detachConferenceDataObject + public void saveAuditRecord(AuditRecord ar) { checkInitialized(); @@ -1557,15 +1605,15 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend } // end saveAuditRecord - public void registerNewConference(ConferenceData conf) + public synchronized void registerNewConference(ConferenceData conf) { checkInitialized(); if (logger.isDebugEnabled()) - logger.debug("registerNewConference(" + String.valueOf(conf.getID()) + ")..."); + logger.debug("registerNewConference(" + conf.getID() + ")..."); Integer the_confid = new Integer(conf.getID()); if (conf_objects.get(the_confid)!=null) - throw new InternalStateError("ConfID " + the_confid.toString() + " already exists...but it CAN'T HAVE!"); + throw new InternalStateError("ConfID " + the_confid + " already exists...but it CAN'T HAVE!"); // throw an extra reference on it and dump it in the object cache conf.rd_addRef(); diff --git a/src/com/silverwrist/venice/security/Audit.java b/src/com/silverwrist/venice/security/Audit.java index 282fe1e..728e501 100644 --- a/src/com/silverwrist/venice/security/Audit.java +++ b/src/com/silverwrist/venice/security/Audit.java @@ -59,5 +59,6 @@ public interface Audit public static final int SCRIBBLE_MESSAGE = 312; public static final int NUKE_MESSAGE = 313; public static final int UPLOAD_ATTACHMENT = 314; + public static final int DELETE_CONF = 315; } // end interface Audit diff --git a/src/com/silverwrist/venice/security/Role.java b/src/com/silverwrist/venice/security/Role.java index 8d88406..4cafcd1 100644 --- a/src/com/silverwrist/venice/security/Role.java +++ b/src/com/silverwrist/venice/security/Role.java @@ -63,6 +63,7 @@ public class Role implements Comparable, SecLevels *-------------------------------------------------------------------------------- */ + private static Role not_in_list = null; private static Role no_access = null; private static Role unrestricted_user = null; private static Vector global_low = null; @@ -99,6 +100,9 @@ public class Role implements Comparable, SecLevels private static void initAllSets() { + if (not_in_list==null) + not_in_list = new Role(0,"(not in list)"); + if (no_access==null) no_access = new Role(NO_ACCESS,"No Access"); @@ -343,4 +347,18 @@ public class Role implements Comparable, SecLevels } // end getConferenceDeleteList + public static List getConferenceMemberLevelChoices() + { + initAllSets(); + Vector rc = new Vector(); + rc.add(not_in_list); + rc.addAll(global_low); + rc.addAll(sig_low); + rc.addAll(conf_low); + rc.add(unrestricted_user); + rc.add(conf_high.lastElement()); + return new ReadOnlyVector(rc); + + } // end getConferenceMemberLevelChoices + } // end class Role diff --git a/src/com/silverwrist/venice/servlets/ConfOperations.java b/src/com/silverwrist/venice/servlets/ConfOperations.java index bded0b4..bc22bcf 100644 --- a/src/com/silverwrist/venice/servlets/ConfOperations.java +++ b/src/com/silverwrist/venice/servlets/ConfOperations.java @@ -18,6 +18,7 @@ package com.silverwrist.venice.servlets; import java.io.*; +import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.log4j.*; @@ -33,6 +34,9 @@ public class ConfOperations extends VeniceServlet *-------------------------------------------------------------------------------- */ + private static final String DELETE_CONFIRM_ATTR = "servlets.ConfOperations.delete.confirm"; + private static final String DELETE_CONFIRM_PARAM = "confirm"; + private static Category logger = Category.getInstance(ConfOperations.class.getName()); /*-------------------------------------------------------------------------------- @@ -174,6 +178,11 @@ public class ConfOperations extends VeniceServlet conf.fixSeen(); } // end try + catch (AccessError ae) + { // some sort of access error - display an error dialog + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch catch (DataException de) { // some sort of error in the database return new ErrorBox("Database Error","Database error catching up conference: " + de.getMessage(), @@ -282,9 +291,84 @@ public class ConfOperations extends VeniceServlet on_error); } // end catch + catch (AccessError ae) + { // some sort of access error - display an error dialog + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch } // end if ("RP" and "RR" commands) + if (cmd.equals("M")) + { // "M" - Manage Conference Membership (requires conference parameter) + ConferenceContext conf = getConferenceParameter(request,sig,true,on_error); + on_error = "confops?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID() + "&cmd=Q"; + + try + { // display the conference member list! + ConferenceMembership m = new ConferenceMembership(engine,sig,conf); + m.doConferenceMemberList(); + setMyLocation(request,"confops?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID() + "&cmd=M"); + return m; + + } // end try + catch (DataException de) + { // something wrong in the database + return new ErrorBox("Database Error","Database error listing conference members: " + de.getMessage(), + on_error); + + } // end catch + catch (AccessError ae) + { // some lack of access is causing problems + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch + + } // end if ("M" command) + + if (cmd.equals("DEL")) + { // "DEL" = "Delete Conference (requires conference parameter) + ConferenceContext conf = getConferenceParameter(request,sig,true,on_error); + on_error = "confops?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID() + "&cmd=Q"; + + if (!(conf.canDeleteConference())) + return new ErrorBox("Access Error","You do not have permission to delete this conference.",on_error); + + if (ConfirmBox.isConfirmed(request,DELETE_CONFIRM_ATTR,DELETE_CONFIRM_PARAM)) + { // we are confirmed - delete the conference! + try + { // tell it to go away + conf.delete(); + + } // end try + catch (DataException de) + { // something wrong in the database + return new ErrorBox("Database Error","Database error deleting conference: " + de.getMessage(), + on_error); + + } // end catch + catch (AccessError ae) + { // some lack of access is causing problems + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch + + // that's it - trap back to the main conference list + throw new RedirectResult("confops?sig=" + sig.getSIGID()); + + } // end if + else + { // generate a confirmation box and wait for confirmation + String message = "You are about to permanently delete the \"" + conf.getName() + "\" conference! " + + "Are you sure you want to do this?"; + return new ConfirmBox(request,DELETE_CONFIRM_ATTR,DELETE_CONFIRM_PARAM,"Delete Conference",message, + "confops?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID() + "&cmd=DEL", + on_error); + + } // end else + + } // end if ("DEL" command) + // Any unrecognized command shows us the conference list. on_error = "sigprofile?sig=" + sig.getSIGID(); try @@ -572,6 +656,124 @@ public class ConfOperations extends VeniceServlet } // end if ("A" command) + if (cmd.equals("M")) + { // "M" - Manage Conference Membership (requires conference parameter) + ConferenceContext conf = getConferenceParameter(request,sig,true,on_error); + on_error = "confops?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID() + "&cmd=M"; + + if (isImageButtonClicked(request,"update")) + { // the "update" command that changes all the security levels + HashMap org_vals = new HashMap(); + HashMap new_vals = new HashMap(); + try + { // retrieve all parameters and filter them for the levels + Enumeration p_names = request.getParameterNames(); + while (p_names.hasMoreElements()) + { // examine each parameter name in turn + String p_name = (String)(p_names.nextElement()); + if (p_name.startsWith("zxcur_")) + { // this is a current value (from a hidden field) + int uid = Integer.parseInt(p_name.substring(6)); + int level = Integer.parseInt(request.getParameter(p_name)); + org_vals.put(new Integer(uid),new Integer(level)); + + } // end if + else if (p_name.startsWith("zxnew_")) + { // this is a new value (from a dropdown list box) + int uid = Integer.parseInt(p_name.substring(6)); + int level = Integer.parseInt(request.getParameter(p_name)); + new_vals.put(new Integer(uid),new Integer(level)); + + } // end else if + + } // end while + + if (org_vals.size()!=new_vals.size()) + return new ErrorBox(null,"Invalid parameters.",on_error); + + } // end try + catch (NumberFormatException nfe) + { // error converting the parameters + return new ErrorBox(null,"Invalid parameter conversion.",on_error); + + } // end catch + + try + { // loop through the hashmaps and set the value + Iterator it = org_vals.keySet().iterator(); + while (it.hasNext()) + { // extract the UID, old level, and new level + Integer uid = (Integer)(it.next()); + Integer org_level = (Integer)(org_vals.get(uid)); + Integer new_level = (Integer)(new_vals.get(uid)); + if (new_level==null) // whoops + return new ErrorBox(null,"Invalid new level parameter.",on_error); + int new_level_x = new_level.intValue(); + if (new_level_x==0) + new_level_x = -1; + + // call down to set the membership level + if (org_level.intValue()!=new_level_x) + conf.setMembership(uid.intValue(),new_level_x); + + } // end while + + } // end try + catch (AccessError ae) + { // some sort of access error - display an error dialog + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch + catch (DataException de) + { // database error creating the conference + return new ErrorBox("Database Error","Database error setting memberships: " + de.getMessage(), + on_error); + + } // end catch + + // trap back to the conference membership display + throw new RedirectResult(on_error); + + } // end if ("update" clicked) + + if ( isImageButtonClicked(request,"search") || isImageButtonClicked(request,"previous") + || isImageButtonClicked(request,"next")) + { // create the new dialog box + ConferenceMembership m = new ConferenceMembership(engine,sig,conf); + + try + { // perform the search! + m.doSearch(request); + + } // end try + catch (ValidationException ve) + { // validation error - throw it back to the user + return new ErrorBox(null,ve.getMessage() + " Please try again.",on_error); + + } // end catch + catch (AccessError ae) + { // some sort of access error - display an error dialog + return new ErrorBox("Access Error",ae.getMessage(),on_error); + + } // end catch + catch (DataException de) + { // database error creating the conference + return new ErrorBox("Database Error","Database error updating conference: " + de.getMessage(), + on_error); + + } // end catch + + setMyLocation(request,on_error); + return m; + + } // end if (search function clicked) + + // we don't know what button was pressed + logger.error("no known button click on ConfOperations.doPost, cmd=M"); + return new ErrorBox("Internal Error","Unknown command button pressed",on_error); + + } // end if ("M" command) + // unrecognized command! logger.error("invalid command to ConfOperations.doPost: " + cmd); return new ErrorBox("Internal Error","Invalid command to ConfOperations.doPost",on_error); diff --git a/src/com/silverwrist/venice/servlets/format/ConferenceActivity.java b/src/com/silverwrist/venice/servlets/format/ConferenceActivity.java index 6807b0b..9745dc5 100644 --- a/src/com/silverwrist/venice/servlets/format/ConferenceActivity.java +++ b/src/com/silverwrist/venice/servlets/format/ConferenceActivity.java @@ -47,7 +47,8 @@ public class ConferenceActivity implements JSPRender *-------------------------------------------------------------------------------- */ - public ConferenceActivity(SIGContext sig, ConferenceContext conf, boolean posters) throws DataException + public ConferenceActivity(SIGContext sig, ConferenceContext conf, boolean posters) + throws DataException, AccessError { this.sig = sig; this.conf = conf; diff --git a/src/com/silverwrist/venice/servlets/format/ConferenceMembership.java b/src/com/silverwrist/venice/servlets/format/ConferenceMembership.java new file mode 100644 index 0000000..dac553f --- /dev/null +++ b/src/com/silverwrist/venice/servlets/format/ConferenceMembership.java @@ -0,0 +1,337 @@ +/* + * 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 . + * + * 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 , + * 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.io.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import com.silverwrist.venice.ValidationException; +import com.silverwrist.venice.security.Role; +import com.silverwrist.venice.core.*; + +public class ConferenceMembership implements JSPRender, SearchMode +{ + /*-------------------------------------------------------------------------------- + * Static data members + *-------------------------------------------------------------------------------- + */ + + // Attribute name for request attribute + protected static final String ATTR_NAME = "com.silverwrist.venice.content.ConferenceMembership"; + + /*-------------------------------------------------------------------------------- + * Attributes + *-------------------------------------------------------------------------------- + */ + + private VeniceEngine engine; // reference to the engine + private SIGContext sig; // the SIG we're in + private ConferenceContext conf; // the conference being listed + private List display_list = null; // list of members to display + private boolean conf_members = false; // is this a list of conference members? + private int field = -1; // search field + private int mode = -1; // search mode + private String term = null; // search term + private int offset = 0; // search result offset + private int find_count = -1; // search results count + private List role_choices; // the list of security roles + + /*-------------------------------------------------------------------------------- + * Constructors + *-------------------------------------------------------------------------------- + */ + + public ConferenceMembership(VeniceEngine engine, SIGContext sig, ConferenceContext conf) + { + this.engine = engine; + this.sig = sig; + this.conf = conf; + this.role_choices = Role.getConferenceMemberLevelChoices(); + + } // end constructor + + /*-------------------------------------------------------------------------------- + * Internal functions + *-------------------------------------------------------------------------------- + */ + + private static int getParamInt(ServletRequest request, String name, int default_val) + { + String str = request.getParameter(name); + if (str==null) + return -1; + + try + { // parse the integer value + return Integer.parseInt(str); + + } // end try + catch (NumberFormatException nfe) + { // in case of conversion error, return default + return default_val; + + } // end catch + + } // end getParamInt + + private static boolean isImageButtonClicked(ServletRequest request, String name) + { + String val = request.getParameter(name + ".x"); + return (val!=null); + + } // end isImageButtonClicked + + /*-------------------------------------------------------------------------------- + * External static functions + *-------------------------------------------------------------------------------- + */ + + public static ConferenceMembership retrieve(ServletRequest request) + { + return (ConferenceMembership)(request.getAttribute(ATTR_NAME)); + + } // end retrieve + + /*-------------------------------------------------------------------------------- + * Implementations from interface VeniceContent + *-------------------------------------------------------------------------------- + */ + + public String getPageTitle(RenderData rdat) + { + return "Membership in Conference " + conf.getName(); + + } // end getPageTitle + + /*-------------------------------------------------------------------------------- + * Implementations from interface JSPRender + *-------------------------------------------------------------------------------- + */ + + public void store(ServletRequest request) + { + request.setAttribute(ATTR_NAME,this); + + } // end store + + public String getTargetJSPName() + { + return "conf_member.jsp"; + + } // end getTargetJSPName + + /*-------------------------------------------------------------------------------- + * External operations + *-------------------------------------------------------------------------------- + */ + + public void doConferenceMemberList() throws DataException, AccessError + { + this.display_list = conf.getMemberList(); + this.conf_members = true; + this.term = ""; + + } // end doConferenceMemberList + + public void doSearch(ServletRequest request) throws ValidationException, DataException, AccessError + { + // Validate the search field parameter. + field = getParamInt(request,"field",FIELD_USER_NAME); + if ( (field!=FIELD_USER_NAME) && (field!=FIELD_USER_DESCRIPTION) && (field!=FIELD_USER_GIVEN_NAME) + && (field!=FIELD_USER_FAMILY_NAME)) + throw new ValidationException("The field search parameter is not valid."); + + // Validate the search mode parameter. + mode = getParamInt(request,"mode",SEARCH_PREFIX); + if ((mode!=SEARCH_PREFIX) && (mode!=SEARCH_SUBSTRING) && (mode!=SEARCH_REGEXP)) + throw new ValidationException("The search mode parameter is not valid."); + + // Retrieve the search term parameter. + term = request.getParameter("term"); + if (term==null) + term = ""; + + // Retrieve the offset and find count parameters. + offset = getParamInt(request,"ofs",0); + find_count = getParamInt(request,"fcount",-1); + + // Adjust the search return offset based on the command button click. + int count = getNumResultsDisplayed(); + if (isImageButtonClicked(request,"search")) + offset = 0; + else if (isImageButtonClicked(request,"previous")) + { // adjust the offset in the reverse direction + offset -= count; + if (offset<0) + offset = 0; + + } // end else if + else if (isImageButtonClicked(request,"next")) + offset += count; // go forwards instead + else + throw new ValidationException("Unable to determine what action triggered the form."); + + // Perform the search! + List intermediate = sig.searchForMembers(field,mode,term,offset,count); + if (find_count<0) + find_count = sig.getSearchMemberCount(field,mode,term); + + // Create the real display list by getting the conference security levels. + Iterator it = intermediate.iterator(); + Vector rc = new Vector(count+1); + while (it.hasNext()) + { // loop around and find the member level of every one + UserFound uf = (UserFound)(it.next()); + int new_level = conf.getMemberLevel(uf.getUID()); + if (new_level==-1) + new_level = 0; + rc.add(uf.createNewLevel(new_level)); + + } // end while + + display_list = rc; // save display list for display + + } // end doSearch + + public int getSIGID() + { + return sig.getSIGID(); + + } // end getSIGID + + public int getConfID() + { + return conf.getConfID(); + + } // end getConfID + + public String getSIGName() + { + return sig.getName(); + + } // end getSIGName + + public String getConfName() + { + return conf.getName(); + + } // end getConfName + + public String getLocator() + { + return "sig=" + sig.getSIGID() + "&conf=" + conf.getConfID(); + + } // end getLocator + + public boolean displayList() + { + if ((display_list==null) || (display_list.size()==0)) + return false; + if (conf_members && (display_list.size()>engine.getMaxNumConferenceMembersDisplay())) + return false; + return true; + + } // end displayList + + public boolean conferenceMemberList() + { + return conf_members; + + } // end conferenceMemberList + + public int getSearchField() + { + return field; + + } // end getSearchField + + public int getSearchMode() + { + return mode; + + } // end getSearchMode + + public boolean searchFieldIs(int value) + { + return (field==value); + + } // end searchFieldIs + + public boolean searchModeIs(int value) + { + return (mode==value); + + } // end searchModeIs + + public String getSearchTerm() + { + return term; + + } // end getSearchTerm + + public int getFindCount() + { + return find_count; + + } // end getFindCount + + public int getOffset() + { + return offset; + + } // end getOffset + + public int getSize() + { + return display_list.size(); + + } // end getSize + + public int getNumResultsDisplayed() + { + return engine.getStdNumSearchResults(); + + } // end getNumResultsDisplayed + + public UserFound getItem(int ndx) + { + return (UserFound)(display_list.get(ndx)); + + } // end getItem + + public void outputDropDown(Writer out, int uid, int cur_level) throws IOException + { + out.write("\n"); + out.write("\n"); + + } // end outputDropDown + +} // end class ConferenceMembership diff --git a/src/com/silverwrist/venice/servlets/format/ConfirmBox.java b/src/com/silverwrist/venice/servlets/format/ConfirmBox.java index 209a7fa..07bf881 100644 --- a/src/com/silverwrist/venice/servlets/format/ConfirmBox.java +++ b/src/com/silverwrist/venice/servlets/format/ConfirmBox.java @@ -66,7 +66,7 @@ public class ConfirmBox implements ContentRender this.conf_num = rng.nextInt(0x1000000); this.title = title; this.message = message; - this.confirm_url = confirm_url + "&" + param_name + "=" + String.valueOf(this.conf_num); + this.confirm_url = confirm_url + "&" + param_name + "=" + this.conf_num; this.deny_url = deny_url; // Stash this object in the HTTP session. diff --git a/web/format/conf_member.jsp b/web/format/conf_member.jsp new file mode 100644 index 0000000..ccc9814 --- /dev/null +++ b/web/format/conf_member.jsp @@ -0,0 +1,154 @@ +<%-- + 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 . + + 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 , + 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): +--%> +<%@ page import = "java.util.*" %> +<%@ page import = "com.silverwrist.util.StringUtil" %> +<%@ page import = "com.silverwrist.venice.core.*" %> +<%@ page import = "com.silverwrist.venice.servlets.Variables" %> +<%@ page import = "com.silverwrist.venice.servlets.format.*" %> +<% + ConferenceMembership data = ConferenceMembership.retrieve(request); + Variables.failIfNull(data); + RenderData rdat = RenderConfig.createRenderData(application,request,response); +%> +<% rdat.writeContentHeader(out,"Set Conference Membership:",data.getConfName()); %> +<%= rdat.getStdFontTag(null,2) %> + ">Return to + Manage Conference Menu +

+ +<%= rdat.getStdFontTag(null,3) %>Find users in SIG "<%= data.getSIGName() %>":

+

"> + + + + + <%= rdat.getStdFontTag(null,2) %> + Display all SIG members whose   +
+ + +
+ " + ALT="Search" WIDTH=80 HEIGHT=24 BORDER=0>
+ +
+ +<% if (data.displayList()) { %> + <% int dcount = data.getSize(); %> +
+ <% if (data.conferenceMemberList()) { %> + <%-- The conference list header --%> + <%= rdat.getStdFontTag(null,3) %> + Members of Conference "<%= StringUtil.encodeHTML(data.getConfName()) %>": +
+ <% } else { %> + <% + // Determine the number of results to display and whether to display a "next" button + boolean go_next = false; + if (dcount>data.getNumResultsDisplayed()) + { // there's a "next" + dcount = data.getNumResultsDisplayed(); + go_next = true; + + } // end if + %> + + + +
<%= rdat.getStdFontTag(null,2) %> + <%-- The search results header --%> + Search Results: + <% if (data.getFindCount()>0) { %> + (Displaying <%= data.getOffset() + 1 %>-<%= data.getOffset() + dcount %> of + <%= data.getFindCount() %>) + <% } else { %>(None)<% } %> + + <% if (go_next || (data.getOffset()>0)) { %> + <%-- The navigational form that allows us to page through the results --%> + <% if (rdat.useHTMLComments()) { %><% } %> +
"> + + + + + + + + + <% if (data.getOffset()>0) { %> + " + ALT="Previous" WIDTH=80 HEIGHT=24 BORDER=0> + <% } else { %> + " WIDTH=80 HEIGHT=24 BORDER=0> + <% } // end if %> +   + <% if (go_next) { %> + " + ALT="Next" WIDTH=80 HEIGHT=24 BORDER=0> + <% } else { %> + " WIDTH=80 HEIGHT=24 BORDER=0> + <% } // end if %> + +
+ <% } else { %> <% } %> +

+ <% } // end if %> + + <%-- Display the results of the search --%> +
"> + + + + + <% for (int i=0; i + <% UserFound uf = data.getItem(i); %> + + + + + + <% } // end for %> +
+ " ALT="*" WIDTH=14 HEIGHT=14 BORDER=0> + <%= rdat.getStdFontTag(null,2) %> + "><%= uf.getName() %> + <%= rdat.getStdFontTag(null,2) %> + <% data.outputDropDown(out,uf.getUID(),uf.getLevel()); %> +

+ " NAME="update" ALT="Update" + WIDTH=80 HEIGHT=24 BORDER=0> +

+<% } // end if %> +<% rdat.writeFooter(out); %> diff --git a/web/format/manage_conf.jsp b/web/format/manage_conf.jsp index 63ebff6..3fccf1e 100644 --- a/web/format/manage_conf.jsp +++ b/web/format/manage_conf.jsp @@ -59,12 +59,14 @@ Conference Information

">Manage Conference Aliases

- Manage Conference Members

+ ">Manage + Conference Members

">Conference Posters Report

">Conference Readers/Lurkers Report

- Delete Conference

+ ">Delete + Conference

<% } // end if (displaying admin section) %>