diff --git a/TODO b/TODO index bf439b0..499083a 100644 --- a/TODO +++ b/TODO @@ -12,6 +12,16 @@ Lots! - There's no system admin functionality AT ALL. We need to have this stuff before we go live. (It plugs into the Administrative SIG features.) +- Unimplemented functions on the Top page: + Manage SIG list (SIG sidebox) + Manage Conference Hotlist (Conference sidebox) + Customize Sideboxes + +- The plan for the "main" part of the Top page is to let a sysadmin put + notices there by "publishing" selected conference messages to the front page. + We may include a welcome message up top to be displayed if the user's not + logged in. + - Implement quick e-mail from the user profile display (engine support and UI). @@ -23,14 +33,12 @@ Lots! - Slippage during posting is still untested. -- Functions still to do on conferencing "topics" page: - Add Conference To Hotlist - - We need a "manage" button at conference list level so we can use that to manage the ordering of conferences. This operation should be accessible only to users with "create" privilege on the SIG. -- Implement conference hotlist for users. +- Conference hotlist is now partially implemented, but we need some more work + at engine level. - Not everybody likes purple. Provide a way to change the default colors. Probably via entries in render-config.xml. Of course, if we go to a diff --git a/doc/tag_new.png b/doc/tag_new.png deleted file mode 100644 index 70a7626..0000000 Binary files a/doc/tag_new.png and /dev/null differ diff --git a/setup/database.sql b/setup/database.sql index c3bd195..9245bdf 100644 --- a/setup/database.sql +++ b/setup/database.sql @@ -1325,6 +1325,8 @@ INSERT INTO contacts (contactid, given_name, family_name, locality, region, pcod # new users. INSERT INTO sideboxes (uid, boxid, sequence, param) VALUES (1, 1, 100, NULL), (1, 2, 200, NULL); +INSERT INTO confhotlist (uid, sequence, sigid, confid) + VALUES (1, 100, 2, 2); # Add the 'Administrator' user to the users table. # (UID = 2, CONTACTID = 2) @@ -1337,6 +1339,8 @@ INSERT INTO contacts (contactid, given_name, family_name, locality, region, pcod # Create the default view for Administrator. INSERT INTO sideboxes (uid, boxid, sequence, param) VALUES (2, 1, 100, NULL), (2, 2, 200, NULL); +INSERT INTO confhotlist (uid, sequence, sigid, confid) + VALUES (2, 100, 2, 2); # Add the administration SIG to the SIGs table. # (SIGID = 1, CONTACTID = 3) @@ -1432,6 +1436,8 @@ INSERT INTO contacts (contactid, given_name, family_name, locality, region, pcod VALUES (5, 'Test', 'User', 'Denver', 'CO', '80231', 'US', 'testuser@example.com', 3); INSERT INTO sideboxes (uid, boxid, sequence, param) VALUES (3, 1, 100, NULL), (3, 2, 200, NULL); +INSERT INTO confhotlist (uid, sequence, sigid, confid) + VALUES (3, 100, 2, 2); INSERT INTO sigmember (sigid, uid, granted_lvl, locked) VALUES (2, 3, 6500, 1); diff --git a/src/com/silverwrist/venice/core/ConferenceContext.java b/src/com/silverwrist/venice/core/ConferenceContext.java index 94fc04d..e07ed44 100644 --- a/src/com/silverwrist/venice/core/ConferenceContext.java +++ b/src/com/silverwrist/venice/core/ConferenceContext.java @@ -141,4 +141,12 @@ public interface ConferenceContext public abstract boolean canDeleteConference(); + public abstract boolean isInHotlist(); + + public abstract void addToHotlist() throws DataException; + + public abstract boolean canAddToHotlist(); + + public abstract SIGContext getEnclosingSIG(); + } // end interface ConferenceContext diff --git a/src/com/silverwrist/venice/core/ConferenceHotlistEntry.java b/src/com/silverwrist/venice/core/ConferenceHotlistEntry.java new file mode 100644 index 0000000..226e1be --- /dev/null +++ b/src/com/silverwrist/venice/core/ConferenceHotlistEntry.java @@ -0,0 +1,26 @@ +/* + * 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; + +public interface ConferenceHotlistEntry +{ + public abstract ConferenceContext getConference(); + + public abstract int getSequence(); + +} // end interface ConferenceHotlistEntry diff --git a/src/com/silverwrist/venice/core/UserContext.java b/src/com/silverwrist/venice/core/UserContext.java index 297877b..a768d01 100644 --- a/src/com/silverwrist/venice/core/UserContext.java +++ b/src/com/silverwrist/venice/core/UserContext.java @@ -87,4 +87,6 @@ public interface UserContext extends SearchMode public abstract List getSideBoxList() throws DataException; + public abstract List getConferenceHotlist() throws DataException; + } // end interface UserContext diff --git a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java index ae36dcc..0057dd4 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java @@ -116,6 +116,37 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end class FixSeenHelper + /*-------------------------------------------------------------------------------- + * Static class used to return hot list entries + *-------------------------------------------------------------------------------- + */ + + static class MyHotlist implements ConferenceHotlistEntry + { + private ConferenceContext conf; + private int seq; + + MyHotlist(ConferenceContext conf, int seq) + { + this.conf = conf; + this.seq = seq; + + } // end constructor + + public ConferenceContext getConference() + { + return conf; + + } // end getConference + + public int getSequence() + { + return seq; + + } // end getSequence + + } // end class MyHotlist + /*-------------------------------------------------------------------------------- * Static data members *-------------------------------------------------------------------------------- @@ -515,8 +546,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (post>create) { // Post level should be no greater than Create if (logger.isDebugEnabled()) - logger.debug("Post level (" + String.valueOf(post) + ") was greater than create level (" - + String.valueOf(create) + "), correcting"); + logger.debug("Post level (" + post + ") was greater than create level (" + create + "), correcting"); post = create; } // end if @@ -524,8 +554,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (read>post) { // Read level should be no greater than Post if (logger.isDebugEnabled()) - logger.debug("Read level (" + String.valueOf(read) + ") was greater than post level (" - + String.valueOf(post) + "), correcting"); + logger.debug("Read level (" + read + ") was greater than post level (" + post + "), correcting"); read = post; } // end if @@ -533,8 +562,8 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (change>delete) { // Change level should be no greater than Delete if (logger.isDebugEnabled()) - logger.debug("Change level (" + String.valueOf(change) + ") was greater than delete level (" - + String.valueOf(delete) + "), correcting"); + logger.debug("Change level (" + change + ") was greater than delete level (" + delete + + "), correcting"); change = delete; } // end if @@ -542,8 +571,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (nuke>delete) { // Nuke level should be no greater than Delete if (logger.isDebugEnabled()) - logger.debug("Nuke level (" + String.valueOf(nuke) + ") was greater than delete level (" - + String.valueOf(delete) + "), correcting"); + logger.debug("Nuke level (" + nuke + ") was greater than delete level (" + delete + "), correcting"); nuke = delete; } // end if @@ -551,8 +579,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend if (hide>nuke) { // Hide level should be no greater than Nuke if (logger.isDebugEnabled()) - logger.debug("Hide level (" + String.valueOf(hide) + ") was greater than nuke level (" - + String.valueOf(nuke) + "), correcting"); + logger.debug("Hide level (" + hide + ") was greater than nuke level (" + nuke + "), correcting"); hide = nuke; } // end if @@ -791,7 +818,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend public boolean anyUnread() { - if (deleted) + if (deleted || sig.userIsAnonymous()) return false; Connection conn = null; // pooled database connection @@ -1228,6 +1255,110 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end canDeleteConference + public boolean isInHotlist() + { + Connection conn = null; + + try + { // retrieve a connection from the datapool + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // do a quickie query + StringBuffer sql = new StringBuffer("SELECT sequence FROM confhotlist WHERE uid = "); + sql.append(sig.realUID()).append(" AND sigid = ").append(sig.realSIGID()).append(" AND confid = "); + sql.append(confid).append(';'); + ResultSet rs = stmt.executeQuery(sql.toString()); + return rs.next(); + + } // end try + catch (SQLException e) + { // this becomes a DataException + logger.error("DB error checking hotlist: " + e.getMessage(),e); + return false; + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + } // end isInHotlist + + public void addToHotlist() throws DataException + { + Connection conn = null; + + try + { // retrieve a connection from the datapool + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + stmt.executeUpdate("LOCK TABLES confhotlist WRITE;"); + try + { // do a quickie query to see if we're already in the hotlist + StringBuffer sql = new StringBuffer("SELECT sequence FROM confhotlist WHERE uid = "); + sql.append(sig.realUID()).append(" AND sigid = ").append(sig.realSIGID()).append(" AND confid = "); + sql.append(confid).append(';'); + ResultSet rs = stmt.executeQuery(sql.toString()); + if (rs.next()) + return; // already in hotlist - this is a no-op + + // find a sequence number for the new entry + sql.setLength(0); + sql.append("SELECT MAX(sequence) FROM confhotlist WHERE uid = ").append(sig.realUID()).append(';'); + rs = stmt.executeQuery(sql.toString()); + if (!(rs.next())) + throw new InternalStateError("bogus query result on addToHotlist"); + int new_sequence = rs.getInt(1) + 100; + + // add the new record + sql.setLength(0); + sql.append("INSERT INTO confhotlist (uid, sequence, sigid, confid) VALUES (").append(sig.realUID()); + sql.append(", ").append(new_sequence).append(", ").append(sig.realSIGID()).append(", "); + sql.append(confid).append(");"); + stmt.executeUpdate(sql.toString()); + + } // end try + finally + { // make sure the table is unlocked before we go + Statement ulk_stmt = conn.createStatement(); + ulk_stmt.executeUpdate("UNLOCK TABLES;"); + + } // end finally + + } // end try + catch (SQLException e) + { // this becomes a DataException + logger.error("DB error adding to hotlist: " + e.getMessage(),e); + throw new DataException("error adding to hotlist: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + if (conn!=null) + datapool.releaseConnection(conn); + + } // end finally + + } // end addToHotList + + public boolean canAddToHotlist() + { + if (sig.userIsAnonymous()) + return false; + return !(isInHotlist()); + + } // end canAddToHotlist + + public SIGContext getEnclosingSIG() + { + return sig.selfSIG(); + + } // end getEnclosingSIG + /*-------------------------------------------------------------------------------- * Implementations from interface UserBackend *-------------------------------------------------------------------------------- @@ -1268,6 +1399,12 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend *-------------------------------------------------------------------------------- */ + public SIGContext selfSIG() + { + return sig.selfSIG(); + + } // end selfsig; + public int realSIGID() { return sig.realSIGID(); @@ -1468,8 +1605,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend static List getSIGConferences(EngineBackend engine, SIGBackend sig, DataPool datapool) throws DataException { if (logger.isDebugEnabled()) - logger.debug("getSIGConferences for SIG # " + String.valueOf(sig.realSIGID()) + ", user #" - + String.valueOf(sig.realUID())); + logger.debug("getSIGConferences for SIG # " + sig.realSIGID() + ", user #" + sig.realUID()); Vector rc = new Vector(); // return from this function Connection conn = null; // pooled database connection @@ -1529,8 +1665,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend int confid) throws DataException { if (logger.isDebugEnabled()) - logger.debug("getConference(#" + String.valueOf(confid) + ") for SIG # " - + String.valueOf(sig.realSIGID()) + ", user #" + String.valueOf(sig.realUID())); + logger.debug("getConference(#" + confid + ") for SIG # " + sig.realSIGID() + ", user #" + sig.realUID()); Connection conn = null; // pooled database connection @@ -1553,8 +1688,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend // Run that monster query! ResultSet rs = stmt.executeQuery(sql.toString()); if (!(rs.next())) - throw new DataException("conference ID#" + String.valueOf(confid) + " not found in SIG#" - + String.valueOf(sig.realSIGID())); + throw new DataException("conference ID#" + confid + " not found in SIG#" + sig.realSIGID()); // pass back the new object return new ConferenceUserContextImpl(engine,sig,datapool,confid,rs.getString(2), @@ -1581,8 +1715,8 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend String alias) throws DataException { if (logger.isDebugEnabled()) - logger.debug("getConference(\"" + alias + "\") for SIG # " + String.valueOf(sig.realSIGID()) - + ", user #" + String.valueOf(sig.realUID())); + logger.debug("getConference(\"" + alias + "\") for SIG # " + sig.realSIGID() + ", user #" + + sig.realUID()); Connection conn = null; // pooled database connection @@ -1607,8 +1741,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend // Run that monster query! ResultSet rs = stmt.executeQuery(sql.toString()); if (!(rs.next())) - throw new DataException("conference \"" + alias + "\" not found in SIG#" - + String.valueOf(sig.realSIGID())); + throw new DataException("conference \"" + alias + "\" not found in SIG#" + sig.realSIGID()); // pass back the new object return new ConferenceUserContextImpl(engine,sig,datapool,rs.getInt(1),rs.getString(3),rs.getString(4), @@ -1630,4 +1763,77 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end getConference + static List getUserHotlist(EngineBackend engine, UserBackend user, DataPool datapool) throws DataException + { + if (logger.isDebugEnabled()) + logger.debug("getUserHotlist for user #" + user.realUID()); + + Connection conn = null; // pooled database connection + Vector rc = new Vector(); // return from this function + + try + { // get a database connection + conn = datapool.getConnection(); + Statement stmt = conn.createStatement(); + + // Build a monster query! We pull the SIGID and ConfID entries from the confhotlist table, + // but we need to pull in "confs" and "confmember" (left joined) to get enough data to create + // a ConferenceUserContextImpl object. + StringBuffer sql = + new StringBuffer("SELECT h.sigid, h.confid, c.name, c.descr, c.createdate, s.granted_lvl, " + + "f.granted_lvl, h.sequence FROM confhotlist h, sigtoconf s, confs c " + + "LEFT JOIN confmember f ON h.confid = f.confid AND h.uid = f.uid " + + "WHERE h.confid = s.confid AND c.confid = h.confid AND h.uid = "); + sql.append(user.realUID()).append(" ORDER BY h.sequence ASC;"); + if (logger.isDebugEnabled()) + logger.debug("SQL: " + sql.toString()); + + // Run that puppy! + ResultSet rs = stmt.executeQuery(sql.toString()); + + // Create some temporary data structures to assist us in building the return list. + HashMap sig_backend_cache = new HashMap(); + + while (rs.next()) + { // retrieve the sigid from the resultset first + Integer sigid = new Integer(rs.getInt(1)); + + // we need a SIG backend for our conference, so make sure we have one + SIGBackend sig = (SIGBackend)(sig_backend_cache.get(sigid)); + if (sig==null) + { // get it and make sure it's in the cache for next time + sig = SIGUserContextImpl.getSIGBackend(engine,user,datapool,conn,sigid.intValue()); + sig_backend_cache.put(sigid,sig); + + } // end if + + // make the new ConferenceContext + ConferenceContext conf = + new ConferenceUserContextImpl(engine,sig,datapool,rs.getInt(2),rs.getString(3),rs.getString(4), + SQLUtil.getFullDateTime(rs,5),rs.getInt(6),rs.getInt(7),conn); + + // and create the actual return value + ConferenceHotlistEntry hle = new MyHotlist(conf,rs.getInt(8)); + rc.add(hle); + + } // end while + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading hotlist entries: " + e.getMessage(),e); + throw new DataException("unable to retrieve hotlist 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 getUserHotlist + } // end class ConferenceUserContextImpl diff --git a/src/com/silverwrist/venice/core/impl/SIGBackend.java b/src/com/silverwrist/venice/core/impl/SIGBackend.java index efbced8..96f5f02 100644 --- a/src/com/silverwrist/venice/core/impl/SIGBackend.java +++ b/src/com/silverwrist/venice/core/impl/SIGBackend.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 @@ -18,9 +18,12 @@ package com.silverwrist.venice.core.impl; import com.silverwrist.venice.core.DataException; +import com.silverwrist.venice.core.SIGContext; public interface SIGBackend extends UserBackend { + public abstract SIGContext selfSIG(); + public abstract int realSIGID(); public abstract boolean userHideHiddenConferences(); diff --git a/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java b/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java index 243a38e..0454bf6 100644 --- a/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/SIGUserContextImpl.java @@ -229,6 +229,38 @@ class SIGUserContextImpl implements SIGContext, SIGBackend } // end testConferenceAccess + private static SIGUserContextImpl getSIGPrivate(EngineBackend engine, UserBackend user, DataPool datapool, + Connection conn, int sigid) throws DataException + { + try + { // create the query to find the SIG in the table + Statement stmt = conn.createStatement(); + StringBuffer sql = new StringBuffer("SELECT signame, alias FROM sigs WHERE sigid = "); + sql.append(sigid).append(';'); + ResultSet rs = stmt.executeQuery(sql.toString()); + if (!(rs.next())) + { // the SIG entry was not found + logger.error("SIG " + String.valueOf(sigid) + " not found in database"); + throw new DataException("SIG #" + String.valueOf(sigid) + " was not found in the database."); + + } // end if + + // initialize the object and check membership info + SIGUserContextImpl sc = new SIGUserContextImpl(engine,user,datapool,sigid,rs.getString("signame"), + rs.getString("alias")); + sc.checkMembership(conn); + return sc; + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error reading SIG entry: " + e.getMessage(),e); + throw new DataException("unable to retrieve SIG information: " + e.getMessage(),e); + + } // end catch + + } // end getSIGPrivate + /*-------------------------------------------------------------------------------- * Implementations from class SIGContext *-------------------------------------------------------------------------------- @@ -1132,6 +1164,12 @@ class SIGUserContextImpl implements SIGContext, SIGBackend *-------------------------------------------------------------------------------- */ + public SIGContext selfSIG() + { + return this; + + } // end selfsig; + public int realSIGID() { return sigid; @@ -1248,23 +1286,8 @@ class SIGUserContextImpl implements SIGContext, SIGBackend { // get a database connection conn = datapool.getConnection(); - // create the query to find the SIG in the table - Statement stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("SELECT signame, alias FROM sigs WHERE sigid = "); - sql.append(sigid).append(';'); - ResultSet rs = stmt.executeQuery(sql.toString()); - if (!(rs.next())) - { // the SIG entry was not found - logger.error("SIG " + String.valueOf(sigid) + " not found in database"); - throw new DataException("SIG #" + String.valueOf(sigid) + " was not found in the database."); - - } // end if - - // initialize the object and check membership info - SIGUserContextImpl sc = new SIGUserContextImpl(engine,user,datapool,sigid,rs.getString("signame"), - rs.getString("alias")); - sc.checkMembership(conn); - return sc; + // return the SIG we want + return getSIGPrivate(engine,user,datapool,conn,sigid); } // end try catch (SQLException e) @@ -1325,6 +1348,13 @@ class SIGUserContextImpl implements SIGContext, SIGBackend } // end getSIGContext + static SIGBackend getSIGBackend(EngineBackend engine, UserBackend user, DataPool datapool, Connection conn, + int sigid) throws DataException + { + return getSIGPrivate(engine,user,datapool,conn,sigid); + + } // end getSIGBackend + static List searchForSIGs(EngineBackend engine, UserBackend user, DataPool datapool, int field, int mode, String term, int offset, int count) throws DataException { diff --git a/src/com/silverwrist/venice/core/impl/UserContextImpl.java b/src/com/silverwrist/venice/core/impl/UserContextImpl.java index a05be7d..7c9da46 100644 --- a/src/com/silverwrist/venice/core/impl/UserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/UserContextImpl.java @@ -862,6 +862,12 @@ class UserContextImpl implements UserContext, UserBackend } // end getSideBoxList + public List getConferenceHotlist() throws DataException + { + return ConferenceUserContextImpl.getUserHotlist(engine,this,datapool); + + } // end getConferenceHotlist + /*-------------------------------------------------------------------------------- * Implementations from interface UserBackend *-------------------------------------------------------------------------------- diff --git a/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java b/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java index 201a99b..88d0102 100644 --- a/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java +++ b/src/com/silverwrist/venice/core/impl/VeniceEngineImpl.java @@ -874,7 +874,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend { // look to see if the user name is already present conn = datapool.getConnection(); Statement stmt = conn.createStatement(); - stmt.executeUpdate("LOCK TABLES users WRITE, userprefs WRITE, sigmember WRITE, sideboxes WRITE;"); + stmt.executeUpdate("LOCK TABLES users WRITE, userprefs WRITE, sigmember WRITE, sideboxes WRITE, " + + "confhotlist WRITE;"); try { // make sure the user name isn't there already ResultSet rs = stmt.executeQuery("SELECT uid FROM users WHERE username = '" + encode_username + "';"); @@ -967,6 +968,31 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend if (logger.isDebugEnabled()) logger.debug("...loaded default sidebox config"); + // get the hotlist configuration for this user + rs = stmt.executeQuery("SELECT confhotlist.sequence, confhotlist.sigid, confhotlist.confid FROM " + + "confhotlist, users WHERE confhotlist.uid = users.uid AND users.is_anon = 1;"); + sql.setLength(0); + while (rs.next()) + { // set up to insert into the confhotlist table + if (sql.length()==0) + sql.append("INSERT INTO confhotlist (uid, sequence, sigid, confid) VALUES "); + else + sql.append(", "); + sql.append('(').append(new_uid).append(", ").append(rs.getInt(1)).append(", ").append(rs.getInt(2)); + sql.append(", ").append(rs.getInt(3)).append(')'); + + } // end while + + if (sql.length()>0) + { // execute the big update + sql.append(';'); + stmt.executeUpdate(sql.toString()); + + } // end if + + if (logger.isDebugEnabled()) + logger.debug("...loaded default hotlist config"); + } // end try finally { // make sure the tables get unlocked before we go diff --git a/src/com/silverwrist/venice/servlets/ConfOperations.java b/src/com/silverwrist/venice/servlets/ConfOperations.java index bc22bcf..ac8dfd1 100644 --- a/src/com/silverwrist/venice/servlets/ConfOperations.java +++ b/src/com/silverwrist/venice/servlets/ConfOperations.java @@ -326,6 +326,28 @@ public class ConfOperations extends VeniceServlet } // end if ("M" command) + if (cmd.equals("H")) + { // "H" = "Add Conference To Hotlist" (requires conference parameter) + ConferenceContext conf = getConferenceParameter(request,sig,true,on_error); + on_error = "confdisp?sig=" + sig.getSIGID() + "&conf=" + conf.getConfID(); + + try + { // add to the hotlist + conf.addToHotlist(); + + // and trap back to the conference display + throw new RedirectResult(on_error); + + } // end try + catch (DataException de) + { // something wrong in the database + return new ErrorBox("Database Error","Database error adding to hotlist: " + de.getMessage(), + on_error); + + } // end catch + + } // end if ("H" command) + if (cmd.equals("DEL")) { // "DEL" = "Delete Conference (requires conference parameter) ConferenceContext conf = getConferenceParameter(request,sig,true,on_error); diff --git a/src/com/silverwrist/venice/servlets/format/SideBoxConferences.java b/src/com/silverwrist/venice/servlets/format/SideBoxConferences.java index f027339..44d69ea 100644 --- a/src/com/silverwrist/venice/servlets/format/SideBoxConferences.java +++ b/src/com/silverwrist/venice/servlets/format/SideBoxConferences.java @@ -19,6 +19,7 @@ package com.silverwrist.venice.servlets.format; import java.io.*; import java.util.*; +import com.silverwrist.util.StringUtil; import com.silverwrist.venice.core.*; public class SideBoxConferences implements ContentRender @@ -29,15 +30,17 @@ public class SideBoxConferences implements ContentRender */ private UserContext uc; + private List hotlist; /*-------------------------------------------------------------------------------- * Constructor *-------------------------------------------------------------------------------- */ - public SideBoxConferences(UserContext uc, String parameter) + public SideBoxConferences(UserContext uc, String parameter) throws DataException { this.uc = uc; + this.hotlist = uc.getConferenceHotlist(); } // end constructor @@ -62,14 +65,34 @@ public class SideBoxConferences implements ContentRender public void renderHere(Writer out, RenderData rdat) throws IOException { - /* BEGIN TEMP */ - out.write("
    \n"); - out.write("
  • BOFH (Benevolent Dictators)
  • \n"); - out.write("
  • Playground (Electric Minds)
  • \n"); - out.write("
  • Commons (Electric Minds)
  • \n"); - out.write("
  • Top Ten Lists (Pamela's Lounge)
  • \n"); - out.write("
\n"); - /* END TEMP */ + out.write(rdat.getStdFontTag(null,2) + "\n"); + if (hotlist.size()>0) + { // display the list of conferences + out.write("\n"); + Iterator it = hotlist.iterator(); + while (it.hasNext()) + { // display the names of the conferences and SIGs one by one + ConferenceHotlistEntry hle = (ConferenceHotlistEntry)(it.next()); + ConferenceContext conf = hle.getConference(); + String href = "confdisp?sig=" + conf.getEnclosingSIG().getSIGID() + "&conf=" + conf.getConfID(); + out.write("\n\n"); + out.write("\n\n"); + + } // end while + + out.write("
\"*\"\n" + rdat.getStdFontTag(null,2) + "" + StringUtil.encodeHTML(conf.getName()) + + " (" + StringUtil.encodeHTML(conf.getEnclosingSIG().getName()) + ")\n"); + if (conf.anyUnread()) + out.write(" \"New!\"\n"); + out.write("
\n"); + + } // end if + else + out.write(rdat.getStdFontTag(null,2) + "You have no conferences in your hotlist.\n"); // write the link at the end out.write("

" + rdat.getStdFontTag(null,1) + "[ " ALT="Read New" WIDTH=80 HEIGHT=24 BORDER=0>  <% } // end if %> - ">">" ALT="Manage" WIDTH=80 HEIGHT=24 BORDER=0>  <% if (data.canAddToHotlist()) { %> - " - ALT="Add to HotList" WIDTH=80 HEIGHT=24 BORDER=0>  + ">" ALT="Add to HotList" WIDTH=80 + HEIGHT=24 BORDER=0>  <% } // end if %> <% if (data.anyTopics()) { %> diff --git a/web/images/tag_new.gif b/web/images/tag_new.gif new file mode 100644 index 0000000..26ba084 Binary files /dev/null and b/web/images/tag_new.gif differ