From 477aac51f0783b5133b2f5701bb6f695da6efb47 Mon Sep 17 00:00:00 2001 From: "Eric J. Bowersox" Date: Sun, 11 Jul 2004 08:08:27 +0000 Subject: [PATCH] added "sticky" topic facility to cause topics to always float at the top of the topic list when it's set --- etc/ui-config.xml | 4 + etc/venice-config.xml | 6 - scripts/conf/conf_reports.js | 6 +- scripts/conf/email.js | 6 +- scripts/conf/export.js | 2 +- scripts/conf/move_message.js | 6 +- scripts/conf/posts.js | 6 +- scripts/conf/read_new.js | 6 +- scripts/conf/stick_topic.js | 56 ++ scripts/conf/topics.js | 6 +- setup/database.sql | 2 + .../venice/core/ConferenceContext.java | 192 ++-- .../silverwrist/venice/core/TopicContext.java | 106 ++- .../impl/ConferenceCommunityContextImpl.java | 4 +- .../venice/core/impl/ConferenceCoreData.java | 119 +-- .../core/impl/ConferenceUserContextImpl.java | 24 +- .../core/impl/ConferencingExporter.java | 2 +- .../core/impl/PublishedMessageTopicImpl.java | 122 ++- .../core/impl/TopicUserContextImpl.java | 857 ++++++++++-------- .../silverwrist/venice/security/Audit.java | 1 + web/format/conf/posts.jsp | 204 +++-- web/format/conf/topics.jsp | 133 +-- web/images/classic/stick_topic.jpg | Bin 0 -> 1262 bytes web/images/classic/unstick_topic.jpg | Bin 0 -> 1331 bytes web/images/gelcap/stick_topic.jpg | Bin 0 -> 1575 bytes web/images/gelcap/unstick_topic.jpg | Bin 0 -> 1613 bytes 26 files changed, 1061 insertions(+), 809 deletions(-) create mode 100644 scripts/conf/stick_topic.js create mode 100644 web/images/classic/stick_topic.jpg create mode 100644 web/images/classic/unstick_topic.jpg create mode 100644 web/images/gelcap/stick_topic.jpg create mode 100644 web/images/gelcap/unstick_topic.jpg diff --git a/etc/ui-config.xml b/etc/ui-config.xml index 1ff474e..cfe6014 100644 --- a/etc/ui-config.xml +++ b/etc/ui-config.xml @@ -215,11 +215,13 @@ + + @@ -274,11 +276,13 @@ + + diff --git a/etc/venice-config.xml b/etc/venice-config.xml index b447699..44a353f 100644 --- a/etc/venice-config.xml +++ b/etc/venice-config.xml @@ -321,8 +321,6 @@ - - @@ -335,8 +333,6 @@ - - @@ -364,8 +360,6 @@ - - diff --git a/scripts/conf/conf_reports.js b/scripts/conf/conf_reports.js index 4ee7d0a..d15e263 100644 --- a/scripts/conf/conf_reports.js +++ b/scripts/conf/conf_reports.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// 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. +// Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -34,7 +34,7 @@ on_error = "conf/manage_conf.js.vs?cc=" + comm.communityID + "&conf=" + conf.con rc = null; try { // get a topic list from the conference - topics = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER); + topics = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER,true); rinput.setRequestAttribute("conference.reports.topiclist",topics); // create the result view diff --git a/scripts/conf/email.js b/scripts/conf/email.js index 4eb2c83..3739f31 100644 --- a/scripts/conf/email.js +++ b/scripts/conf/email.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// 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. +// Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -35,7 +35,7 @@ if ("GET"==rinput.verb) { // display the dialog try { // we need the topic list - tlist = conf.getTopicList(ConferenceContext.DISPLAY_ALL,ConferenceContext.SORT_NAME); + tlist = conf.getTopicList(ConferenceContext.DISPLAY_ALL,ConferenceContext.SORT_NAME,true); rinput.setRequestAttribute("topic.email.list",tlist); // create the dialog diff --git a/scripts/conf/export.js b/scripts/conf/export.js index 54ec8ef..7c5b8c3 100644 --- a/scripts/conf/export.js +++ b/scripts/conf/export.js @@ -45,7 +45,7 @@ try { // figure out what to do here if ("GET"==rinput.verb) { // load and display the JSP page for the form - l = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER); + l = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER,true); rinput.setRequestAttribute("topic.list",l); rc = new JSPView("Export Messages: " + conf.name,"conf/export.jsp"); diff --git a/scripts/conf/move_message.js b/scripts/conf/move_message.js index 9890663..fe945f4 100644 --- a/scripts/conf/move_message.js +++ b/scripts/conf/move_message.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// The Initial Developer of the Original Code is Eric J. Bowersox , // for Silverwrist Design Studios. Portions created by Eric J. Bowersox are -// Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. +// Copyright (C) 2002-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -58,7 +58,7 @@ if ("GET"==rinput.verb) rc = null; try { // get the list of topics in the conference - in_list = vlib.castList(conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NAME)); + in_list = vlib.castList(conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NAME,true)); out_list = vlib.createList(); it = in_list.iterator(); while (it.hasNext()) diff --git a/scripts/conf/posts.js b/scripts/conf/posts.js index 1d60f0e..4ff3e08 100644 --- a/scripts/conf/posts.js +++ b/scripts/conf/posts.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// 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. +// Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -113,7 +113,7 @@ try rc.pageQID = "go/" + comm.alias + "!" + tmp; if (conf.displayPostPictures() && rinput.user.displayPostPictures()) - { // set up the user p[hoto dimensions + { // set up the user photo dimensions old_psz = rinput.engine.getUserPhotoSize(); rc.photoDims = new Dimension((old_psz.width * SCALING_NUM) / SCALING_DENOM, (old_psz.height * SCALING_NUM) / SCALING_DENOM); diff --git a/scripts/conf/read_new.js b/scripts/conf/read_new.js index 104d36c..3859fd8 100644 --- a/scripts/conf/read_new.js +++ b/scripts/conf/read_new.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// 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. +// Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -32,7 +32,7 @@ conf = currc.getConference(true,"conf/conferences.js.vs?cc=" + comm.communityID) rc = null; try { // get the topic list, using the current view and sort options - topic_list = conf.getTopicList(currc.viewOption,currc.sortOption); + topic_list = conf.getTopicList(currc.viewOption,currc.sortOption,false); // initialize and return the topic visit order ord = currc.newTopicVisitOrder(topic_list); diff --git a/scripts/conf/stick_topic.js b/scripts/conf/stick_topic.js new file mode 100644 index 0000000..04b3322 --- /dev/null +++ b/scripts/conf/stick_topic.js @@ -0,0 +1,56 @@ +// 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) 2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. +// +// Contributor(s): + +importPackage(java.util); +importPackage(Packages.com.silverwrist.venice.core); +importPackage(Packages.com.silverwrist.venice.except); +importPackage(Packages.com.silverwrist.venice.ui); +importPackage(Packages.com.silverwrist.venice.ui.conf); +importPackage(Packages.com.silverwrist.venice.ui.helpers); + +// get the request object and the community +rinput = bsf.lookupBean("request"); +comm = rinput.getCommunity(true,"top.js.vs"); + +// get the current conference +currc = new CurrentConference(rinput); +conf = currc.getConference(true,"conf/conferences.js.vs?cc=" + comm.communityID); + +// get the current topic +topic = currc.getTopic(true,"conf/topics.js.vs?cc=" + comm.communityID + "&conf=" + conf.confID); +on_error = "conf/posts.js.vs?cc=" + comm.communityID + "&conf=" + conf.confID + "&top=" + topic.topicNumber; + +rc = null; +try +{ // get the flag and set the sticky status + flag = rinput.getParameterInt("flag",0); + topic.setSticky(flag==1); + rc = new Redirect(on_error,LinkTypes.SERVLET); + +} // end try +catch (e) +{ // error setting the hide topic + etype = vlib.exceptionType(e) + ""; + if (etype.match("DataException")) + rc = new ErrorBox("Database Error","Database error setting sticky status: " + e.message,on_error); + else if (etype.match("AccessError")) + rc = new ErrorBox("Access Error",e.message,on_error); + else + rc = e; + +} // end catch + +vlib.output(rc); // all done! diff --git a/scripts/conf/topics.js b/scripts/conf/topics.js index 38b711a..f4effaa 100644 --- a/scripts/conf/topics.js +++ b/scripts/conf/topics.js @@ -8,9 +8,9 @@ // // The Original Code is the Venice Web Communities System. // -// The Initial Developer of the Original Code is Eric J. Bowersox , +// 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. +// Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. // // Contributor(s): @@ -70,7 +70,7 @@ if (rinput.hasParameter("sort")) rc = null; try { // get the topic list - topic_list = conf.getTopicList(view_opt,sort_opt); + topic_list = conf.getTopicList(view_opt,sort_opt,false); // initialize the visit order ord = currc.newTopicVisitOrder(topic_list); diff --git a/setup/database.sql b/setup/database.sql index a88a462..c0446ea 100644 --- a/setup/database.sql +++ b/setup/database.sql @@ -328,6 +328,7 @@ CREATE TABLE topics ( top_message INT DEFAULT 0, frozen TINYINT DEFAULT 0, archived TINYINT DEFAULT 0, + sticky TINYINT DEFAULT 0, createdate DATETIME NOT NULL, lastupdate DATETIME NOT NULL, name VARCHAR(128) NOT NULL, @@ -508,6 +509,7 @@ INSERT INTO refaudit (type, descr) VALUES (314, 'Upload Message Attachment'), (315, 'Delete Conference'), (316, 'Move Message'), + (317, 'Set Topic Sticky'), (9999999, 'DUMMY'); # Populate the Category table. diff --git a/src/com/silverwrist/venice/core/ConferenceContext.java b/src/com/silverwrist/venice/core/ConferenceContext.java index 5e912f5..700f7cf 100644 --- a/src/com/silverwrist/venice/core/ConferenceContext.java +++ b/src/com/silverwrist/venice/core/ConferenceContext.java @@ -49,158 +49,158 @@ public interface ConferenceContext public static final int IMPORT_MATCH_NUM = 0; public static final int IMPORT_MATCH_NAME = 1; - public abstract int getConfID(); + public int getConfID(); - public abstract String getName(); + public String getName(); - public abstract String getDescription(); + public String getDescription(); - public abstract Date getCreationDate(); + public Date getCreationDate(); - public abstract Date getLastUpdateDate(); + public Date getLastUpdateDate(); - public abstract List getAliases() throws DataException; + public List getAliases() throws DataException; - public abstract List getHosts() throws DataException; + public List getHosts() throws DataException; - public abstract boolean canReadConference(); + public boolean canReadConference(); - public abstract boolean canPostToConference(); + public boolean canPostToConference(); - public abstract boolean canCreateTopic(); + public boolean canCreateTopic(); - public abstract boolean canChangeConference(); + public boolean canChangeConference(); - public abstract int getReadLevel() throws DataException, AccessError; + public int getReadLevel() throws DataException, AccessError; - public abstract int getPostLevel() throws DataException, AccessError; + public int getPostLevel() throws DataException, AccessError; - public abstract int getCreateLevel() throws DataException, AccessError; + public int getCreateLevel() throws DataException, AccessError; - public abstract int getHideLevel() throws DataException, AccessError; + public int getHideLevel() throws DataException, AccessError; - public abstract int getNukeLevel() throws DataException, AccessError; + public int getNukeLevel() throws DataException, AccessError; - public abstract int getChangeLevel() throws DataException, AccessError; + public int getChangeLevel() throws DataException, AccessError; - public abstract int getDeleteLevel() throws DataException, AccessError; + public int getDeleteLevel() throws DataException, AccessError; - public abstract void setSecurityLevels(int read, int post, int create, int hide, int nuke, - int change, int delete) throws DataException, AccessError; - - public abstract void setName(String val) throws DataException, AccessError; - - public abstract void setDescription(String val) throws DataException, AccessError; - - public abstract void addAlias(String alias) throws DataException, AccessError; - - public abstract void removeAlias(String alias) throws DataException, AccessError; - - public abstract void setMembership(int uid, int grant_level) throws DataException, AccessError; - - public abstract void addMember(int uid, boolean as_host) throws DataException, AccessError; - - public abstract void removeMember(int uid) throws DataException, AccessError; - - public abstract int getCommunityGrantedLevel() throws DataException, AccessError; - - public abstract void setCommunityGrantedLevel(int new_level) throws DataException, AccessError; - - public abstract short getSequence() throws DataException, AccessError; - - public abstract void setSequence(short seq) throws DataException, AccessError; - - public abstract boolean getHideList() throws DataException, AccessError; - - public abstract void setHideList(boolean flag) throws DataException, AccessError; - - public abstract boolean canSetHideList(); - - public abstract String getDefaultPseud(); - - public abstract void setDefaultPseud(String val) throws DataException; - - public abstract boolean anyUnread(); - - public abstract List getTopicList(int get_option, int sort_option) throws DataException, AccessError; - - public abstract TopicContext getTopic(short number) throws DataException, AccessError; - - public abstract TopicContext addTopic(String title, String zp_pseud, String zp_text) + public void setSecurityLevels(int read, int post, int create, int hide, int nuke, int change, int delete) throws DataException, AccessError; - public abstract TopicMessageContext getMessageByPostID(long postid) throws DataException, AccessError; + public void setName(String val) throws DataException, AccessError; - public abstract HTMLChecker getNewTopicPreviewChecker(); + public void setDescription(String val) throws DataException, AccessError; - public abstract void fixSeen() throws DataException, AccessError; + public void addAlias(String alias) throws DataException, AccessError; - public abstract List getActivePosters(int skip, int limit) throws DataException, AccessError; + public void removeAlias(String alias) throws DataException, AccessError; - public abstract List getActivePosters(int limit) throws DataException, AccessError; + public void setMembership(int uid, int grant_level) throws DataException, AccessError; - public abstract List getActivePosters() throws DataException, AccessError; + public void addMember(int uid, boolean as_host) throws DataException, AccessError; - public abstract List getActiveReaders(int skip, int limit) throws DataException, AccessError; + public void removeMember(int uid) throws DataException, AccessError; - public abstract List getActiveReaders(int limit) throws DataException, AccessError; + public int getCommunityGrantedLevel() throws DataException, AccessError; - public abstract List getActiveReaders() throws DataException, AccessError; + public void setCommunityGrantedLevel(int new_level) throws DataException, AccessError; - public abstract List getMemberList() throws DataException, AccessError; + public short getSequence() throws DataException, AccessError; - public abstract int getMemberLevel(int uid) throws DataException, AccessError; + public void setSequence(short seq) throws DataException, AccessError; - public abstract void delete() throws DataException, AccessError; + public boolean getHideList() throws DataException, AccessError; - public abstract void deleteConference() throws DataException, AccessError; + public void setHideList(boolean flag) throws DataException, AccessError; - public abstract boolean canDeleteConference(); + public boolean canSetHideList(); - public abstract boolean isInHotlist(); + public String getDefaultPseud(); - public abstract void addToHotlist() throws DataException; + public void setDefaultPseud(String val) throws DataException; - public abstract boolean canAddToHotlist(); + public boolean anyUnread(); - public abstract CommunityContext getEnclosingCommunity(); + public List getTopicList(int get_option, int sort_option, boolean ignore_sticky) throws DataException, AccessError; - public abstract void removeFromHotlist() throws DataException; + public List getTopicList(int get_option, int sort_option) throws DataException, AccessError; - public abstract void setHotlistSequence(int seq) throws DataException; + public TopicContext getTopic(short number) throws DataException, AccessError; - public abstract boolean displayPostPictures(); + public TopicContext addTopic(String title, String zp_pseud, String zp_text) throws DataException, AccessError; - public abstract ConferenceProperties getProperties() throws DataException, AccessError; + public TopicMessageContext getMessageByPostID(long postid) throws DataException, AccessError; - public abstract void setProperties(ConferenceProperties props) throws DataException, AccessError; + public HTMLChecker getNewTopicPreviewChecker(); - public abstract SecurityInfo getSecurityInfo(); + public void fixSeen() throws DataException, AccessError; - public abstract void sendInvitation(String address, String personal_message) + public List getActivePosters(int skip, int limit) throws DataException, AccessError; + + public List getActivePosters(int limit) throws DataException, AccessError; + + public List getActivePosters() throws DataException, AccessError; + + public List getActiveReaders(int skip, int limit) throws DataException, AccessError; + + public List getActiveReaders(int limit) throws DataException, AccessError; + + public List getActiveReaders() throws DataException, AccessError; + + public List getMemberList() throws DataException, AccessError; + + public int getMemberLevel(int uid) throws DataException, AccessError; + + public void delete() throws DataException, AccessError; + + public void deleteConference() throws DataException, AccessError; + + public boolean canDeleteConference(); + + public boolean isInHotlist(); + + public void addToHotlist() throws DataException; + + public boolean canAddToHotlist(); + + public CommunityContext getEnclosingCommunity(); + + public void removeFromHotlist() throws DataException; + + public void setHotlistSequence(int seq) throws DataException; + + public boolean displayPostPictures(); + + public ConferenceProperties getProperties() throws DataException, AccessError; + + public void setProperties(ConferenceProperties props) throws DataException, AccessError; + + public SecurityInfo getSecurityInfo(); + + public void sendInvitation(String address, String personal_message) throws AccessError, DataException, EmailException; - public abstract boolean canSendInvitation(); + public boolean canSendInvitation(); - public abstract void sendMailToParticipants(boolean posters, int day_limit, String subject, String text) + public void sendMailToParticipants(boolean posters, int day_limit, String subject, String text) throws AccessError, DataException; - public abstract String getCustomBlock(int selector) throws DataException; + public String getCustomBlock(int selector) throws DataException; - public abstract void setCustomBlock(int selector, String data) throws AccessError, DataException; + public void setCustomBlock(int selector, String data) throws AccessError, DataException; - public abstract void removeCustomBlocks() throws AccessError, DataException; + public void removeCustomBlocks() throws AccessError, DataException; - public abstract List searchPosts(String search_terms, int offset, int count) - throws AccessError, DataException; + public List searchPosts(String search_terms, int offset, int count) throws AccessError, DataException; - public abstract int getSearchPostCount(String search_terms) throws AccessError, DataException; + public int getSearchPostCount(String search_terms) throws AccessError, DataException; - public abstract String getPostLink() throws DataException; + public String getPostLink() throws DataException; - public abstract String exportTopics(Set select_topics) throws AccessError, DataException, IOException; + public String exportTopics(Set select_topics) throws AccessError, DataException, IOException; - public abstract List importMessages(InputStream xmlstream, int match_method, boolean create_new) + public List importMessages(InputStream xmlstream, int match_method, boolean create_new) throws AccessError, DataException; } // end interface ConferenceContext diff --git a/src/com/silverwrist/venice/core/TopicContext.java b/src/com/silverwrist/venice/core/TopicContext.java index 5a9a00b..924c61e 100644 --- a/src/com/silverwrist/venice/core/TopicContext.java +++ b/src/com/silverwrist/venice/core/TopicContext.java @@ -9,9 +9,9 @@ * * The Original Code is the Venice Web Communities System. * - * The Initial Developer of the Original Code is Eric J. Bowersox , + * 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -30,105 +30,111 @@ public interface TopicContext public static final int POST_MODE_NORMAL = 0; public static final int POST_MODE_EMAIL = 1; - public abstract void refresh() throws DataException; + public void refresh() throws DataException; - public abstract int getTopicID(); + public int getTopicID(); - public abstract short getTopicNumber(); + public short getTopicNumber(); - public abstract String getName(); + public String getName(); - public abstract int getUnreadMessages(); + public int getUnreadMessages(); - public abstract int getTotalMessages(); + public int getTotalMessages(); - public abstract Date getLastUpdateDate(); + public Date getLastUpdateDate(); - public abstract int getCreatorUID(); + public int getCreatorUID(); - public abstract boolean isFrozen(); + public boolean isFrozen(); - public abstract boolean isArchived(); + public boolean isArchived(); - public abstract Date getCreatedDate(); + public boolean isSticky(); - public abstract boolean isHidden(); + public Date getCreatedDate(); - public abstract boolean isDeleted(); + public boolean isHidden(); - public abstract boolean canFreeze(); + public boolean isDeleted(); - public abstract boolean canArchive(); + public boolean canFreeze(); - public abstract void setFrozen(boolean flag) throws DataException, AccessError; + public boolean canArchive(); - public abstract void setArchived(boolean flag) throws DataException, AccessError; + public boolean canStick(); - public abstract void setHidden(boolean flag) throws DataException; + public void setFrozen(boolean flag) throws DataException, AccessError; - public abstract int getFirstUnreadMessage(); + public void setArchived(boolean flag) throws DataException, AccessError; - public abstract void setUnreadMessages(int count) throws DataException; + public void setSticky(boolean flag) throws DataException, AccessError; - public abstract void fixSeen() throws DataException; + public void setHidden(boolean flag) throws DataException; - public abstract List getMessages(int low, int high) throws DataException, AccessError; + public int getFirstUnreadMessage(); - public abstract TopicMessageContext getMessage(int number) throws DataException, AccessError; + public void setUnreadMessages(int count) throws DataException; - public abstract TopicMessageContext postNewMessage(long parent, String pseud, String text, int mode) + public void fixSeen() throws DataException; + + public List getMessages(int low, int high) throws DataException, AccessError; + + public TopicMessageContext getMessage(int number) throws DataException, AccessError; + + public TopicMessageContext postNewMessage(long parent, String pseud, String text, int mode) throws DataException, AccessError; - public abstract TopicMessageContext postNewMessage(long parent, String pseud, String text) + public TopicMessageContext postNewMessage(long parent, String pseud, String text) throws DataException, AccessError; - public abstract HTMLChecker getPreviewChecker(); + public HTMLChecker getPreviewChecker(); - public abstract boolean canDelete(); + public boolean canDelete(); - public abstract void delete() throws DataException, AccessError; + public void delete() throws DataException, AccessError; - public abstract void deleteTopic() throws DataException, AccessError; + public void deleteTopic() throws DataException, AccessError; - public abstract List getActivePosters(int skip, int limit) throws DataException, AccessError; + public List getActivePosters(int skip, int limit) throws DataException, AccessError; - public abstract List getActivePosters(int limit) throws DataException, AccessError; + public List getActivePosters(int limit) throws DataException, AccessError; - public abstract List getActivePosters() throws DataException, AccessError; + public List getActivePosters() throws DataException, AccessError; - public abstract List getActiveReaders(int skip, int limit) throws DataException, AccessError; + public List getActiveReaders(int skip, int limit) throws DataException, AccessError; - public abstract List getActiveReaders(int limit) throws DataException, AccessError; + public List getActiveReaders(int limit) throws DataException, AccessError; - public abstract List getActiveReaders() throws DataException, AccessError; + public List getActiveReaders() throws DataException, AccessError; - public abstract boolean isBozo(int other_uid) throws DataException; + public boolean isBozo(int other_uid) throws DataException; - public abstract void setBozo(int other_uid, boolean bozo) throws DataException; + public void setBozo(int other_uid, boolean bozo) throws DataException; - public abstract boolean canSetBozo(int other_uid); + public boolean canSetBozo(int other_uid); - public abstract List getBozos() throws DataException; + public List getBozos() throws DataException; - public abstract boolean isSubscribed(); + public boolean isSubscribed(); - public abstract void setSubscribed(boolean flag) throws DataException; + public void setSubscribed(boolean flag) throws DataException; - public abstract void sendInvitation(String address, String personal_message) + public void sendInvitation(String address, String personal_message) throws AccessError, DataException, EmailException; - public abstract boolean canSendInvitation(); + public boolean canSendInvitation(); - public abstract void sendMailToParticipants(boolean posters, int day_limit, String subject, String text) + public void sendMailToParticipants(boolean posters, int day_limit, String subject, String text) throws AccessError, DataException; - public abstract List searchPosts(String search_terms, int offset, int count) + public List searchPosts(String search_terms, int offset, int count) throws AccessError, DataException; - public abstract int getSearchPostCount(String search_terms) throws AccessError, DataException; + public int getSearchPostCount(String search_terms) throws AccessError, DataException; - public abstract ConferenceContext getEnclosingConference(); + public ConferenceContext getEnclosingConference(); - public abstract String getPostLink() throws DataException; + public String getPostLink() throws DataException; } // end interface TopicContext diff --git a/src/com/silverwrist/venice/core/impl/ConferenceCommunityContextImpl.java b/src/com/silverwrist/venice/core/impl/ConferenceCommunityContextImpl.java index 124b459..dc6ba59 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceCommunityContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceCommunityContextImpl.java @@ -9,9 +9,9 @@ * * The Original Code is the Venice Web Communities System. * - * The Initial Developer of the Original Code is Eric J. Bowersox , + * 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ diff --git a/src/com/silverwrist/venice/core/impl/ConferenceCoreData.java b/src/com/silverwrist/venice/core/impl/ConferenceCoreData.java index 4834100..1db499e 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceCoreData.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceCoreData.java @@ -9,9 +9,9 @@ * * The Original Code is the Venice Web Communities System. * - * The Initial Developer of the Original Code is Eric J. Bowersox , + * 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -986,7 +986,9 @@ class ConferenceCoreData implements ConferenceData throw new DataException("This conference has been deleted."); Connection conn = null; // database connection - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; AuditRecord ar = null; // audit record short new_topic_num; // sequential number of the new topic int new_topic_id; // ID of the new topic @@ -995,63 +997,65 @@ class ConferenceCoreData implements ConferenceData try { // get a database connection conn = globalsite.getConnection(null); - stmt = conn.createStatement(); + stmt2 = conn.createStatement(); // lock the tables we need to use so we can update them - stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, posts WRITE, postdata WRITE;"); + stmt2.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, posts WRITE, postdata WRITE;"); try { // determine the data for the initial topic new_topic_num = (short)(top_topic + 1); // add the topic row to the database - StringBuffer sql = new StringBuffer("INSERT INTO topics (confid, num, creator_uid, createdate, " - + "lastupdate, name) VALUES ("); - sql.append(confid).append(", ").append(new_topic_num).append(", ").append(outer.getUserID()); + stmt = conn.prepareStatement("INSERT INTO topics (confid, num, creator_uid, createdate, lastupdate, name) " + + "VALUES (?, ?, ?, ?, ?, ?);"); + stmt.setInt(1,confid); + stmt.setShort(2,new_topic_num); + stmt.setInt(3,outer.getUserID()); creation = new java.util.Date(); - String now_str = SQLUtil.encodeDate(creation); - sql.append(", '").append(now_str).append("', '").append(now_str).append("', '").append(title); - sql.append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + SQLUtil.setFullDateTime(stmt,4,creation); + SQLUtil.setFullDateTime(stmt,5,creation); + stmt.setString(6,title); + stmt.executeUpdate(); // get the topic ID we just inserted - ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID();"); + rs = stmt2.executeQuery("SELECT LAST_INSERT_ID();"); if (!(rs.next())) throw new InternalStateError("createNewTopic() could not get back inserted Topic ID"); new_topic_id = rs.getInt(1); - SQLUtil.shutdown(rs); // insert the "header" for the "zero post" in the topic - sql.setLength(0); - sql.append("INSERT INTO posts (topicid, num, linecount, creator_uid, posted, pseud) VALUES ("); - sql.append(new_topic_id).append(", 0, ").append(body_lines).append(", ").append(outer.getUserID()); - sql.append(", '").append(now_str).append("', '").append(pseud).append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO posts (topicid, num, linecount, creator_uid, posted, pseud) " + + "VALUES (?, 0, ?, ?, ?, ?);"); + stmt.setInt(1,new_topic_id); + stmt.setInt(2,body_lines); + stmt.setInt(3,outer.getUserID()); + SQLUtil.setFullDateTime(stmt,4,creation); + stmt.setString(5,pseud); + stmt.executeUpdate(); // get the ID of the zero post - rs = stmt.executeQuery("SELECT LAST_INSERT_ID();"); + rs.close(); + rs = stmt2.executeQuery("SELECT LAST_INSERT_ID();"); if (!(rs.next())) throw new InternalStateError("createNewTopic() could not get back inserted zero post ID"); long zero_post_id = rs.getLong(1); - SQLUtil.shutdown(rs); // insert the post data - sql.setLength(0); - sql.append("INSERT INTO postdata (postid, data) VALUES (").append(zero_post_id).append(", '"); - sql.append(body).append("');"); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO postdata (postid, data) VALUES (?, ?);"); + stmt.setLong(1,zero_post_id); + stmt.setString(2,body); + stmt.executeUpdate(); // touch the "conference" entry to reflect the update - sql.setLength(0); - sql.append("UPDATE confs SET lastupdate = '").append(now_str).append("', top_topic = "); - sql.append(new_topic_num).append(" WHERE confid = ").append(confid).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("UPDATE confs SET lastupdate = ?, top_topic = ? WHERE confid = ?;"); + SQLUtil.setFullDateTime(stmt,1,creation); + stmt.setInt(2,new_topic_num); + stmt.setInt(3,confid); + stmt.executeUpdate(); // touch the local variables, too top_topic = new_topic_num; @@ -1077,7 +1081,9 @@ class ConferenceCoreData implements ConferenceData } // end catch finally { // make sure the connection is released before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); AuditRecord.store(conn,ar); SQLUtil.shutdown(conn); @@ -1109,14 +1115,14 @@ class ConferenceCoreData implements ConferenceData if (deleted) throw new DataException("This conference has been deleted."); - Statement stmt = null; + PreparedStatement stmt = null; try { // update the last update date - stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("UPDATE confs SET lastupdate = '"); - sql.append(SQLUtil.encodeDate(date)).append("' WHERE confid = ").append(confid).append(';'); - stmt.executeUpdate(sql.toString()); + stmt = conn.prepareStatement("UPDATE confs SET lastupdate = ? WHERE confid = ?;"); + SQLUtil.setFullDateTime(stmt,1,date); + stmt.setInt(2,confid); + stmt.executeUpdate(); last_update = date; } // end try @@ -1177,26 +1183,22 @@ class ConferenceCoreData implements ConferenceData ArrayList rc = new ArrayList(); // return from this function Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // get a database connection conn = globalsite.getConnection(null); - 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()); + stmt = conn.prepareStatement("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 = ? AND u.is_anon = 0 ORDER BY u.username;"); + stmt.setInt(1,confid); // launch the search! - ResultSet rs = stmt.executeQuery(sql.toString()); - + rs = stmt.executeQuery(); 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), @@ -1216,6 +1218,7 @@ class ConferenceCoreData implements ConferenceData } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -1231,19 +1234,20 @@ class ConferenceCoreData implements ConferenceData throw new DataException("This conference has been deleted."); Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // get a database connection conn = globalsite.getConnection(null); - 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(';'); + stmt = conn.prepareStatement("SELECT granted_lvl FROM confmember WHERE confid = ? AND uid = ?;"); + stmt.setInt(1,confid); + stmt.setInt(2,uid); // execute the statement and return the retrieved value - ResultSet rs = stmt.executeQuery(sql.toString()); + rs = stmt.executeQuery(); if (rs.next()) return rs.getInt(1); @@ -1256,6 +1260,7 @@ class ConferenceCoreData implements ConferenceData } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); diff --git a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java index 6a9395f..6f4551e 100644 --- a/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/ConferenceUserContextImpl.java @@ -866,7 +866,7 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end anyUnread - public List getTopicList(int get_option, int sort_option) throws DataException, AccessError + public List getTopicList(int get_option, int sort_option, boolean ignore_sticky) throws DataException, AccessError { if (!(getConferenceData().canReadConference(level))) { // the luser can't even read the conference... @@ -876,7 +876,13 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend } // end if // palm it all off on the big static function - return TopicUserContextImpl.getTopicList(env,get_option,sort_option); + return TopicUserContextImpl.getTopicList(env,get_option,sort_option,ignore_sticky); + + } // end getTopicList + + public List getTopicList(int get_option, int sort_option) throws DataException, AccessError + { + return getTopicList(get_option,sort_option,false); } // end getTopicList @@ -943,20 +949,18 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend // now we need to reset our last post date Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; try { // get a connection conn = env.getConnection(); // create a new record in topicsettings (we WERE the first to post in the topic after all!) - stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("INSERT INTO topicsettings (topicid, uid, last_post) VALUES ("); - sql.append(new_topic_inf.getTopicID()).append(", ").append(env.getUserID()).append(", '"); - sql.append(SQLUtil.encodeDate(new_topic_inf.getCreateDate())).append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + stmt = conn.prepareStatement("INSERT INTO topicsettings (topicid, uid, last_post) VALUES (?, ?, ?);"); + stmt.setInt(1,new_topic_inf.getTopicID()); + stmt.setInt(2,env.getUserID()); + SQLUtil.setFullDateTime(stmt,3,new_topic_inf.getCreateDate()); + stmt.executeUpdate(); // update the conference last-post information touchPost(conn,new_topic_inf.getCreateDate()); diff --git a/src/com/silverwrist/venice/core/impl/ConferencingExporter.java b/src/com/silverwrist/venice/core/impl/ConferencingExporter.java index dfa7608..0e08a49 100644 --- a/src/com/silverwrist/venice/core/impl/ConferencingExporter.java +++ b/src/com/silverwrist/venice/core/impl/ConferencingExporter.java @@ -188,7 +188,7 @@ class ConferencingExporter m_wr = new PrintWriter(m_buffer); m_wr.write("\n\n"); - List l = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER); + List l = conf.getTopicList(ConferenceContext.GET_ALL,ConferenceContext.SORT_NUMBER,true); for (Iterator it=l.iterator(); it.hasNext(); ) visit((TopicUserContextImpl)(it.next())); diff --git a/src/com/silverwrist/venice/core/impl/PublishedMessageTopicImpl.java b/src/com/silverwrist/venice/core/impl/PublishedMessageTopicImpl.java index a099f56..c3a10d3 100644 --- a/src/com/silverwrist/venice/core/impl/PublishedMessageTopicImpl.java +++ b/src/com/silverwrist/venice/core/impl/PublishedMessageTopicImpl.java @@ -9,9 +9,9 @@ * * The Original Code is the Venice Web Communities System. * - * The Initial Developer of the Original Code is Eric J. Bowersox , + * 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + * Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ @@ -40,18 +40,19 @@ class PublishedMessageTopicImpl implements TopicContext *-------------------------------------------------------------------------------- */ - private EnvEngine env; - private int cid; - private int topicid; - private short topicnum; - private int creator_uid; - private int total_msgs; - private boolean frozen; - private boolean archived; - private java.util.Date createdate; - private java.util.Date lastupdate; - private String name; - private String postlink; + private EnvEngine m_env; + private int m_cid; + private int m_topicid; + private short m_topicnum; + private int m_creator_uid; + private int m_total_msgs; + private boolean m_frozen; + private boolean m_archived; + private boolean m_sticky; + private java.util.Date m_createdate; + private java.util.Date m_lastupdate; + private String m_name; + private String m_postlink; /*-------------------------------------------------------------------------------- * Constructor @@ -61,47 +62,55 @@ class PublishedMessageTopicImpl implements TopicContext PublishedMessageTopicImpl(EnvEngine env, int cid, int topicid) throws DataException { Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // get a database connection conn = env.getConnection(); - stmt = conn.createStatement(); // query the topics table for information - StringBuffer sql = - new StringBuffer("SELECT confid, num, creator_uid, top_message, frozen, archived, createdate, " - + "lastupdate, name FROM topics WHERE topicid = "); - sql.append(topicid).append(";"); - ResultSet rs = stmt.executeQuery(sql.toString()); + stmt = conn.prepareStatement("SELECT confid, num, creator_uid, top_message, frozen, archived, sticky, " + + "createdate, lastupdate, name FROM topics WHERE topicid = ?;"); + stmt.setInt(1,topicid); + rs = stmt.executeQuery(); if (!(rs.next())) throw new DataException("Topic with ID " + topicid + " not found"); // fill internal attributes with data - this.env = env; - this.cid = cid; - this.topicid = topicid; + m_env = env; + m_cid = cid; + m_topicid = topicid; int confid = rs.getInt(1); - this.topicnum = rs.getShort(2); - this.creator_uid = rs.getInt(3); - this.total_msgs = rs.getInt(4) + 1; - this.frozen = rs.getBoolean(5); - this.archived = rs.getBoolean(6); - this.createdate = SQLUtil.getFullDateTime(rs,7); - this.lastupdate = SQLUtil.getFullDateTime(rs,8); - this.name = rs.getString(9); + m_topicnum = rs.getShort(2); + m_creator_uid = rs.getInt(3); + m_total_msgs = rs.getInt(4) + 1; + m_frozen = rs.getBoolean(5); + m_archived = rs.getBoolean(6); + m_sticky = rs.getBoolean(7); + m_createdate = SQLUtil.getFullDateTime(rs,8); + m_lastupdate = SQLUtil.getFullDateTime(rs,9); + m_name = rs.getString(10); + rs.close(); + stmt.close(); // retrieve the community alias - rs = stmt.executeQuery("SELECT alias FROM sigs WHERE sigid = " + cid + ";"); + stmt = conn.prepareStatement("SELECT alias FROM sigs WHERE sigid = ?;"); + stmt.setInt(1,cid); + rs = stmt.executeQuery(); if (!(rs.next())) throw new DataException("Community with ID " + cid + " not found"); - postlink = rs.getString(1) + "!"; + m_postlink = rs.getString(1) + "!"; + rs.close(); + stmt.close(); // retrieve a conference alias - rs = stmt.executeQuery("SELECT alias FROM confalias WHERE confid = " + confid + " LIMIT 1;"); + stmt = conn.prepareStatement("SELECT alias FROM confalias WHERE confid = ? LIMIT 1;"); + stmt.setInt(1,confid); + rs = stmt.executeQuery(); if (!(rs.next())) throw new DataException("Conference with ID " + confid + " not found"); - postlink += (rs.getString(1) + "." + topicnum); + m_postlink += (rs.getString(1) + "." + m_topicnum); } // end try catch (SQLException e) @@ -112,6 +121,7 @@ class PublishedMessageTopicImpl implements TopicContext } // end catch finally { // release the connection + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -130,19 +140,19 @@ class PublishedMessageTopicImpl implements TopicContext public int getTopicID() { - return topicid; + return m_topicid; } // end getTopicID public short getTopicNumber() { - return topicnum; + return m_topicnum; } // end getTopicNumber public String getName() { - return name; + return m_name; } // end getName @@ -154,39 +164,45 @@ class PublishedMessageTopicImpl implements TopicContext public int getTotalMessages() { - return total_msgs; + return m_total_msgs; } // end getTotalMessages public java.util.Date getLastUpdateDate() { - return lastupdate; + return m_lastupdate; } // end getLastUpdateDate public int getCreatorUID() { - return creator_uid; + return m_creator_uid; } // end getCreatorUID public boolean isFrozen() { - return frozen; + return m_frozen; } // end isFrozen public boolean isArchived() { - return archived; + return m_archived; } // end isArchived + public boolean isSticky() + { + return m_sticky; + + } // end isSticky + public java.util.Date getCreatedDate() { - return createdate; + return m_createdate; - } // end egtCreatedDate + } // end getCreatedDate public boolean isHidden() { @@ -212,6 +228,12 @@ class PublishedMessageTopicImpl implements TopicContext } // end canArchive + public boolean canStick() + { + return false; + + } // end canStick + public void setFrozen(boolean flag) throws AccessError { throw new AccessError("cannot perform this function from a read-only topic view"); @@ -224,6 +246,12 @@ class PublishedMessageTopicImpl implements TopicContext } // end setArchived + public void setSticky(boolean flag) throws AccessError + { + throw new AccessError("cannot perform this function from a read-only topic view"); + + } // end setSticky + public void setHidden(boolean flag) { // do nothing } // end setHidden @@ -399,7 +427,7 @@ class PublishedMessageTopicImpl implements TopicContext public String getPostLink() { - return postlink; + return m_postlink; } // end getPostLink diff --git a/src/com/silverwrist/venice/core/impl/TopicUserContextImpl.java b/src/com/silverwrist/venice/core/impl/TopicUserContextImpl.java index 647312d..1e15a0d 100644 --- a/src/com/silverwrist/venice/core/impl/TopicUserContextImpl.java +++ b/src/com/silverwrist/venice/core/impl/TopicUserContextImpl.java @@ -40,18 +40,26 @@ class TopicUserContextImpl implements TopicContext private static Category logger = Category.getInstance(TopicUserContextImpl.class); + private static final String BY_TOPIC_QUERY = + "SELECT topics.topicid, topics.num, topics.creator_uid, topics.top_message, topics.frozen, topics.archived, " + + "topics.sticky, topics.createdate, topics.lastupdate, topics.name, IFNULL(topicsettings.hidden,0) AS hidden, " + + "(topics.top_message - IFNULL(topicsettings.last_message,-1)) AS unread, " + + "IFNULL(topicsettings.subscribe,0) AS subscribe FROM topics LEFT JOIN topicsettings " + + "ON topics.topicid = topicsettings.topicid AND topicsettings.uid = ? WHERE topics.topicid = ?;"; + /*-------------------------------------------------------------------------------- * Attributes *-------------------------------------------------------------------------------- */ - private EnvConference env; // the enclosing environment - private int topicid; - private short topicnum; - private int creator_uid; - private int top_message; - private boolean frozen; - private boolean archived; + private EnvConference m_env; // the enclosing environment + private int m_topicid; // the ID of this topic + private short m_topicnum; // the topic's number + private int m_creator_uid; // the user that created the topic + private int m_top_message; // topmost message number in this topic + private boolean m_frozen; // is topic frozen? + private boolean m_archived; // is topic archived? + private boolean m_sticky; // is topic "sticky"? private java.util.Date created; private java.util.Date lastupdate; private String name; @@ -67,17 +75,18 @@ class TopicUserContextImpl implements TopicContext */ protected TopicUserContextImpl(EnvConference env, int topicid, short topicnum, int creator_uid, - int top_message, boolean frozen, boolean archived, java.util.Date created, - java.util.Date lastupdate, String name, boolean hidden, int unread, - boolean subscribed) + int top_message, boolean frozen, boolean archived, boolean sticky, + java.util.Date created, java.util.Date lastupdate, String name, boolean hidden, + int unread, boolean subscribed) { - this.env = env; - this.topicid = topicid; - this.topicnum = topicnum; - this.creator_uid = creator_uid; - this.top_message = top_message; - this.frozen = frozen; - this.archived = archived; + m_env = env; + m_topicid = topicid; + m_topicnum = topicnum; + m_creator_uid = creator_uid; + m_top_message = top_message; + m_frozen = frozen; + m_archived = archived; + m_sticky = sticky; this.created = created; this.lastupdate = lastupdate; this.name = name; @@ -89,13 +98,14 @@ class TopicUserContextImpl implements TopicContext TopicUserContextImpl(EnvConference env, ReturnTopicInfo inf, String name) { - this.env = env; - this.topicid = inf.getTopicID(); - this.topicnum = inf.getTopicNum(); - this.creator_uid = env.getUserID(); - this.top_message = 0; - this.frozen = false; - this.archived = false; + m_env = env; + m_topicid = inf.getTopicID(); + m_topicnum = inf.getTopicNum(); + m_creator_uid = env.getUserID(); + m_top_message = 0; + m_frozen = false; + m_archived = false; + m_sticky = false; this.created = inf.getCreateDate(); this.lastupdate = inf.getCreateDate(); this.name = name; @@ -111,28 +121,12 @@ class TopicUserContextImpl implements TopicContext *-------------------------------------------------------------------------------- */ - private static final ResultSet queryByTopic(Statement stmt, int topicid, int uid) throws SQLException - { - StringBuffer sql = - new StringBuffer("SELECT topics.topicid, topics.num, topics.creator_uid, topics.top_message, " - + "topics.frozen, topics.archived, topics.createdate, topics.lastupdate, " - + "topics.name, IFNULL(topicsettings.hidden,0) AS hidden, " - + "(topics.top_message - IFNULL(topicsettings.last_message,-1)) AS unread, " - + "IFNULL(topicsettings.subscribe,0) AS subscribe " - + "FROM topics LEFT JOIN topicsettings ON topics.topicid = topicsettings.topicid " - + "AND topicsettings.uid = "); - sql.append(uid).append(" WHERE topics.topicid = ").append(topicid).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - return stmt.executeQuery(sql.toString()); - - } // end queryByTopic - private final void makeDeleted() { - top_message = -1; - frozen = false; - archived = false; + m_top_message = -1; + m_frozen = false; + m_archived = false; + m_sticky = false; created = null; lastupdate = null; name = null; @@ -145,25 +139,30 @@ class TopicUserContextImpl implements TopicContext private final void refresh(Connection conn) throws SQLException { - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // use database to refresh object - stmt = conn.createStatement(); + stmt = conn.prepareStatement(BY_TOPIC_QUERY); + stmt.setInt(1,m_env.getUserID()); + stmt.setInt(2,m_topicid); // perform a requery of the database - ResultSet rs = queryByTopic(stmt,topicid,env.getUserID()); + rs = stmt.executeQuery(); if (rs.next()) { // update the fields that are capable of changing - top_message = rs.getInt(4); - frozen = rs.getBoolean(5); - archived = rs.getBoolean(6); - lastupdate = SQLUtil.getFullDateTime(rs,8); - hidden = rs.getBoolean(10); - unread = rs.getInt(11); + m_top_message = rs.getInt(4); + m_frozen = rs.getBoolean(5); + m_archived = rs.getBoolean(6); + m_sticky = rs.getBoolean(7); + lastupdate = SQLUtil.getFullDateTime(rs,9); + name = rs.getString(10); + hidden = rs.getBoolean(11); + unread = rs.getInt(12); if (unread<0) unread = 0; - subscribed = rs.getBoolean(12); + subscribed = rs.getBoolean(13); } // end if else // this topic must have been deleted - fsck it @@ -172,6 +171,7 @@ class TopicUserContextImpl implements TopicContext } // end try finally { // shut down the statement to conserve resources + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); } // end finally @@ -180,14 +180,15 @@ class TopicUserContextImpl implements TopicContext private final void loadBozo(Connection conn) throws SQLException { - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // load the bozo UIDs list - stmt = conn.createStatement(); - StringBuffer sql = new StringBuffer("SELECT bozo_uid FROM topicbozo WHERE topicid = "); - sql.append(topicid).append(" AND uid = ").append(env.getUserID()).append(';'); - ResultSet rs = stmt.executeQuery(sql.toString()); + stmt = conn.prepareStatement("SELECT bozo_uid FROM topicbozo WHERE topicid = ? AND uid = ?;"); + stmt.setInt(1,m_topicid); + stmt.setInt(2,m_env.getUserID()); + rs = stmt.executeQuery(); bozo_uids = new HashSet(); while (rs.next()) bozo_uids.add(new Integer(rs.getInt(1))); @@ -195,6 +196,7 @@ class TopicUserContextImpl implements TopicContext } // end try finally { // shut down the statement to conserve resources + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); } // end finally @@ -208,7 +210,7 @@ class TopicUserContextImpl implements TopicContext final int getTopMessage() { - return top_message; + return m_top_message; } // end getTopMessage @@ -220,12 +222,12 @@ class TopicUserContextImpl implements TopicContext public void refresh() throws DataException { if (logger.isDebugEnabled()) - logger.debug("refreshing topic ID " + String.valueOf(topicid)); + logger.debug("refreshing topic ID " + m_topicid); Connection conn = null; // pooled database connection try { // get a database connection - conn = env.getConnection(); + conn = m_env.getConnection(); refresh(conn); } // end try @@ -245,13 +247,13 @@ class TopicUserContextImpl implements TopicContext public int getTopicID() { - return topicid; + return m_topicid; } // end getTopicID public short getTopicNumber() { - return topicnum; + return m_topicnum; } // end getTopicNumber @@ -269,7 +271,7 @@ class TopicUserContextImpl implements TopicContext public int getTotalMessages() { - return top_message + 1; + return m_top_message + 1; } // end getTotalMessages @@ -281,22 +283,28 @@ class TopicUserContextImpl implements TopicContext public int getCreatorUID() { - return creator_uid; + return m_creator_uid; } // end getCreatorUID public boolean isFrozen() { - return frozen; + return m_frozen; } // end isFrozen public boolean isArchived() { - return archived; + return m_archived; } // end isArchived + public boolean isSticky() + { + return m_sticky; + + } // end isSticky + public java.util.Date getCreatedDate() { return created; @@ -317,21 +325,27 @@ class TopicUserContextImpl implements TopicContext public boolean canFreeze() { - return env.getConference().userCanHide(); + return m_env.getConference().userCanHide(); } // end canFreeze public boolean canArchive() { - return env.getConference().userCanHide(); + return m_env.getConference().userCanHide(); } // end canArchive + public boolean canStick() + { + return m_env.getConference().userCanHide(); + + } // end canStick + public void setFrozen(boolean flag) throws DataException, AccessError { - if ((frozen==flag) || deleted) + if ((m_frozen==flag) || deleted) return; // no-op - if (!(env.getConference().userCanHide())) + if (!(m_env.getConference().userCanHide())) { // you can't freeze the topic! logger.error("user cannot change frozen status of topic"); throw new AccessError("You are not permitted to freeze or unfreeze this topic."); @@ -339,22 +353,27 @@ class TopicUserContextImpl implements TopicContext } // end if Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; AuditRecord ar = null; // audit record indicating success try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES topics WRITE;"); - // create the SQL statement to freeze or unfreeze the topic - StringBuffer sql = new StringBuffer("UPDATE topics SET frozen = "); - sql.append(flag ? '1' : '0').append(" WHERE topicid = ").append(topicid).append(';'); - if (stmt.executeUpdate(sql.toString())>0) + // prepare the SQL statement to freeze or unfreeze the topic + stmt = conn.prepareStatement("UPDATE topics SET frozen = ? WHERE topicid = ?;"); + stmt.setInt(1,flag ? 1 : 0); + stmt.setInt(2,m_topicid); + + // execute the operation! + if (stmt.executeUpdate()>0) { // success! save the flag and generate an audit record - frozen = flag; - ar = env.newAudit(AuditRecord.TOPIC_FREEZE,"conf=" + env.getConfID() + ",topic=" + topicid, - flag ? "freeze" : "unfreeze"); + m_frozen = flag; + ar = m_env.newAudit(AuditRecord.TOPIC_FREEZE,"conf=" + m_env.getConfID() + ",topic=" + m_topicid, + flag ? "freeze" : "unfreeze"); } // end if else // somebody else must have deleted this topic @@ -369,6 +388,8 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.unlockTables(conn); + SQLUtil.shutdown(stmt2); SQLUtil.shutdown(stmt); AuditRecord.store(conn,ar); SQLUtil.shutdown(conn); @@ -379,32 +400,37 @@ class TopicUserContextImpl implements TopicContext public void setArchived(boolean flag) throws DataException, AccessError { - if ((archived==flag) || deleted) + if ((m_archived==flag) || deleted) return; // no-op - if (!(env.getConference().userCanHide())) + if (!(m_env.getConference().userCanHide())) { // you can't archive the topic! logger.error("user cannot change archived status of topic"); throw new AccessError("You are not permitted to archive or unarchive this topic."); } // end if - Connection conn = null; // pooled database connection - Statement stmt = null; - AuditRecord ar = null; // audit record indicating success + Connection conn = null; // pooled database connection + PreparedStatement stmt = null; // statement + Statement stmt2 = null; // used to lock the database + AuditRecord ar = null; // audit record indicating success try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES topics WRITE;"); - // create the SQL statement to freeze or unfreeze the topic - StringBuffer sql = new StringBuffer("UPDATE topics SET archived = "); - sql.append(flag ? '1' : '0').append(" WHERE topicid = ").append(topicid).append(';'); - if (stmt.executeUpdate(sql.toString())>0) + // prepare the SQL statement to archive or unarchive the topic + stmt = conn.prepareStatement("UPDATE topics SET archived = ? WHERE topicid = ?;"); + stmt.setInt(1,flag ? 1 : 0); + stmt.setInt(2,m_topicid); + + // execute the operation! + if (stmt.executeUpdate()>0) { // success! save the flag and generate an audit record - archived = flag; - ar = env.newAudit(AuditRecord.TOPIC_ARCHIVE,"conf=" + env.getConfID() + ",topic=" + topicid, - flag ? "archive" : "unarchive"); + m_archived = flag; + ar = m_env.newAudit(AuditRecord.TOPIC_ARCHIVE,"conf=" + m_env.getConfID() + ",topic=" + m_topicid, + flag ? "archive" : "unarchive"); } // end if else // somebody else must have deleted this topic @@ -419,7 +445,9 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.unlockTables(conn); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); AuditRecord.store(conn,ar); SQLUtil.shutdown(conn); @@ -427,36 +455,97 @@ class TopicUserContextImpl implements TopicContext } // end setArchived - public void setHidden(boolean flag) throws DataException + public void setSticky(boolean flag) throws DataException, AccessError { - if ((hidden==flag) || deleted || env.isAnonymous()) + if ((m_sticky==flag) || deleted) return; // no-op + if (!(m_env.getConference().userCanHide())) + { // you can't stick/unstick the topic! + logger.error("user cannot change sticky status of topic"); + throw new AccessError("You are not permitted to change the sticky setting of this topic."); - Connection conn = null; // pooled database connection - Statement stmt = null; + } // end if + + Connection conn = null; // pooled database connection + PreparedStatement stmt = null; // statement + Statement stmt2 = null; // used to lock the database + AuditRecord ar = null; // audit record indicating success try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); - stmt.executeUpdate("LOCK TABLES topicsettings WRITE, topics READ;"); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES topics WRITE;"); + + // prepare the SQL statement to stick or unstick the topic + stmt = conn.prepareStatement("UPDATE topics SET sticky = ? WHERE topicid = ?;"); + stmt.setInt(1,flag ? 1 : 0); + stmt.setInt(2,m_topicid); + + // execute the operation! + if (stmt.executeUpdate()>0) + { // success! save the flag and generate an audit record + m_sticky = flag; + ar = m_env.newAudit(AuditRecord.TOPIC_STICKY,"conf=" + m_env.getConfID() + ",topic=" + m_topicid, + flag ? "stick" : "unstick"); + + } // end if + else // somebody else must have deleted this topic + makeDeleted(); + + } // end try + catch (SQLException e) + { // turn SQLException into data exception + logger.error("DB error setting topic data: " + e.getMessage(),e); + throw new DataException("unable to set topic sticky status: " + e.getMessage(),e); + + } // end catch + finally + { // make sure we release the connection before we go + SQLUtil.unlockTables(conn); + SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); + AuditRecord.store(conn,ar); + SQLUtil.shutdown(conn); + + } // end finally + + } // end setSticky + + public void setHidden(boolean flag) throws DataException + { + if ((hidden==flag) || deleted || m_env.isAnonymous()) + return; // no-op + + Connection conn = null; // pooled database connection + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; + + try + { // get a database connection + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES topicsettings WRITE, topics READ;"); try { // start by trying to see if we can update topicsettings directly - StringBuffer sql = new StringBuffer("UPDATE topicsettings SET hidden = "); - sql.append(flag ? '1' : '0').append(" WHERE topicid = ").append(topicid).append(" AND uid = "); - sql.append(env.getUserID()).append(';'); - if (stmt.executeUpdate(sql.toString())>0) + stmt = conn.prepareStatement("UPDATE topicsettings SET hidden = ? WHERE topicid = ? AND uid = ?;"); + stmt.setInt(1,flag ? 1 : 0); + stmt.setInt(2,m_topicid); + stmt.setInt(3,m_env.getUserID()); + if (stmt.executeUpdate()>0) { // that was all we needed - just save the flag and exit hidden = flag; return; } // end if - // OK, check: Is the topic still there?!? - sql.setLength(0); - sql.append("SELECT topicid from topics WHERE topicid = ").append(topicid).append(';'); - ResultSet rs = stmt.executeQuery(sql.toString()); + // Sanity check: Is the topic still there?!? + stmt.close(); + stmt = conn.prepareStatement("SELECT topicid from topics WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + rs = stmt.executeQuery(); if (!(rs.next())) { // the topic's been deleted - bail out makeDeleted(); @@ -465,10 +554,12 @@ class TopicUserContextImpl implements TopicContext } // end if // OK, just insert a new row into topicsettings, why dontcha... - sql.setLength(0); - sql.append("INSERT INTO topicsettings (topicid, uid, hidden) VALUES (").append(topicid).append(", "); - sql.append(env.getUserID()).append(", ").append(flag ? '1' : '0').append(");"); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO topicsettings (topicid, uid, hidden) VALUES (?, ?, ?);"); + stmt.setInt(1,m_topicid); + stmt.setInt(2,m_env.getUserID()); + stmt.setInt(3,flag ? 1 : 0); + stmt.executeUpdate(); hidden = flag; // successful completion } // end try @@ -487,7 +578,9 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); SQLUtil.shutdown(conn); } // end finally @@ -499,7 +592,7 @@ class TopicUserContextImpl implements TopicContext if (unread==0) return -1; else - return top_message - (unread - 1); + return m_top_message - (unread - 1); } // end getFirstUnreadMessage @@ -508,14 +601,15 @@ class TopicUserContextImpl implements TopicContext if (logger.isDebugEnabled()) logger.debug("[raw] setUnreadMessages(" + count + ") entry"); - if (env.isAnonymous()) + if (m_env.isAnonymous()) { // this is effectively a no-op, but log it logger.debug("reject 1: anonymous user"); return; } // end if - if (count>(top_message+1)) // constrain count to [0, top_message+1] - count = top_message + 1; + + if (count>(m_top_message+1)) // constrain count to [0, top_message+1] + count = m_top_message + 1; else if (count<0) count = 0; if ((count==unread) || deleted) @@ -529,59 +623,59 @@ class TopicUserContextImpl implements TopicContext if (logger.isInfoEnabled()) logger.info("[cooked] setUnreadMessages(" + count + ") entry"); - int last_msg = top_message - count; + int last_msg = m_top_message - count; Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); - stmt.executeUpdate("LOCK TABLES confsettings WRITE, topicsettings WRITE, topics READ;"); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES confsettings WRITE, topicsettings WRITE, topics READ;"); try { // start by trying to see if we can update topicsettings directly - StringBuffer sql = new StringBuffer("UPDATE topicsettings SET last_message = "); - sql.append(last_msg).append(", last_read = '"); + stmt = conn.prepareStatement("UPDATE topicsettings SET last_message = ?, last_read = ? WHERE topicid = ? " + + "AND uid = ?;"); + stmt.setInt(1,last_msg); java.util.Date now = new java.util.Date(); - sql.append(SQLUtil.encodeDate(now)).append("' WHERE topicid = ").append(topicid).append(" AND uid = "); - sql.append(env.getUserID()).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - if (stmt.executeUpdate(sql.toString())>0) + SQLUtil.setFullDateTime(stmt,2,now); + stmt.setInt(3,m_topicid); + stmt.setInt(4,m_env.getUserID()); + if (stmt.executeUpdate()>0) { // that was all we needed - just save the flag and exit logger.debug("--> bailed out after update - done with setUnreadMessages{"); - env.getConference().touchRead(conn); + m_env.getConference().touchRead(conn); unread = count; return; } // end if - // OK, check: Is the topic still there?!? - sql.setLength(0); - sql.append("SELECT topicid from topics WHERE topicid = ").append(topicid).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - ResultSet rs = stmt.executeQuery(sql.toString()); + // Sanity check: Is the topic still there?!? + stmt.close(); + stmt = conn.prepareStatement("SELECT topicid from topics WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + rs = stmt.executeQuery(); if (!(rs.next())) { // the topic's been deleted - bail out - logger.debug("--> bailed out because topic is deleted - done with setUnreadMessages{"); + logger.debug("--> bailed out because topic is deleted - done with setUnreadMessages"); makeDeleted(); return; } // end if - SQLUtil.shutdown(rs); - // OK, just insert a new row into topicsettings, why dontcha... - sql.setLength(0); - sql.append("INSERT INTO topicsettings (topicid, uid, last_message, last_read) VALUES ("); - sql.append(topicid).append(", ").append(env.getUserID()).append(", ").append(last_msg).append(", '"); - sql.append(SQLUtil.encodeDate(now)).append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); - env.getConference().touchRead(conn); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO topicsettings (topicid, uid, last_message, last_read) " + + "VALUES (?, ?, ?, ?);"); + stmt.setInt(1,m_topicid); + stmt.setInt(2,m_env.getUserID()); + stmt.setInt(3,last_msg); + SQLUtil.setFullDateTime(stmt,4,now); + stmt.executeUpdate(); + m_env.getConference().touchRead(conn); unread = count; // successful completion } // end try @@ -600,6 +694,8 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); + SQLUtil.shutdown(stmt2); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -615,7 +711,7 @@ class TopicUserContextImpl implements TopicContext public List getMessages(int low, int high) throws DataException, AccessError { - if (!(env.getConference().userCanRead())) + if (!(m_env.getConference().userCanRead())) { // they can't read messages in this topic! logger.error("trying to read postings w/o permission!"); throw new AccessError("You do not have permission to read messages in this conference."); @@ -624,15 +720,15 @@ class TopicUserContextImpl implements TopicContext // reorder parameters so they come in the correct order! if (low<=high) - return TopicMessageUserContextImpl.loadMessageRange(env,topicid,low,high); + return TopicMessageUserContextImpl.loadMessageRange(m_env,m_topicid,low,high); else - return TopicMessageUserContextImpl.loadMessageRange(env,topicid,high,low); + return TopicMessageUserContextImpl.loadMessageRange(m_env,m_topicid,high,low); } // end getMessages public TopicMessageContext getMessage(int number) throws DataException, AccessError { - if (!(env.getConference().userCanRead())) + if (!(m_env.getConference().userCanRead())) { // they can't read messages in this topic! logger.error("trying to read postings w/o permission!"); throw new AccessError("You do not have permission to read messages in this conference."); @@ -640,7 +736,7 @@ class TopicUserContextImpl implements TopicContext } // end if // pass down to one of our static functiions to return this - return TopicMessageUserContextImpl.loadMessage(env,topicid,number); + return TopicMessageUserContextImpl.loadMessage(m_env,m_topicid,number); } // end getMessage @@ -653,7 +749,7 @@ class TopicUserContextImpl implements TopicContext if ((mode!=POST_MODE_NORMAL) && (mode!=POST_MODE_EMAIL)) throw new IllegalArgumentException("invalid mode parameter"); - if (!(env.getConference().userCanPost())) + if (!(m_env.getConference().userCanPost())) { // they can't post in this topic! logger.error("trying to post w/o permission!"); throw new AccessError("You do not have permission to post messages in this conference."); @@ -667,15 +763,15 @@ class TopicUserContextImpl implements TopicContext } // end if - if (frozen && !(env.getConference().userCanHide())) + if (m_frozen && !(m_env.getConference().userCanHide())) { // can't post to a frozen topic! logger.error("can't post to a frozen topic!"); throw new AccessError("The topic is frozen, and you do not have permission to post to it."); } // end if - if (archived && !(env.getConference().userCanHide())) - { // can't post to a frozen topic! + if (m_archived && !(m_env.getConference().userCanHide())) + { // can't post to an archived topic! logger.error("can't post to an archived topic!"); throw new AccessError("The topic is archived, and you do not have permission to post to it."); @@ -698,9 +794,9 @@ class TopicUserContextImpl implements TopicContext } // end else if // preprocess the two arguments through HTML checkers - HTMLChecker pseud_ch = env.getHTMLChecker(pseud_ch_name); - HTMLChecker text_ch = env.getHTMLChecker(body_ch_name); - text_ch.setContextValue("PostLinkDecoderContext",env.getConference().createDecoderContext(topicnum)); + HTMLChecker pseud_ch = m_env.getHTMLChecker(pseud_ch_name); + HTMLChecker text_ch = m_env.getHTMLChecker(body_ch_name); + text_ch.setContextValue("PostLinkDecoderContext",m_env.getConference().createDecoderContext(m_topicnum)); try { // run both arguments through the HTML checker pseud_ch.append(pseud); @@ -736,21 +832,21 @@ class TopicUserContextImpl implements TopicContext long new_post_id; java.util.Date posted_date; Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; AuditRecord ar = null; ArrayList mailto_addrs = null; + ResultSet rs = null; try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); ArrayList mailto_uids = null; - StringBuffer sql = new StringBuffer(); - ResultSet rs; // slap a lock on all the tables we need to touch - stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, posts WRITE, postdata WRITE, " - + "confsettings WRITE, topicsettings WRITE;"); + stmt2.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, posts WRITE, postdata WRITE, " + + "confsettings WRITE, topicsettings WRITE;"); try { // refresh our current status and recheck allowed status @@ -762,88 +858,88 @@ class TopicUserContextImpl implements TopicContext } // end if - if (frozen && !(env.getConference().userCanHide())) + if (m_frozen && !(m_env.getConference().userCanHide())) { // can't post to a frozen topic! logger.error("can't post to a frozen topic!"); throw new AccessError("The topic is frozen, and you do not have permission to post to it."); } // end if - if (archived && !(env.getConference().userCanHide())) - { // can't post to a frozen topic! + if (m_archived && !(m_env.getConference().userCanHide())) + { // can't post to an archived topic! logger.error("can't post to an archived topic!"); throw new AccessError("The topic is archived, and you do not have permission to post to it."); } // end if // Determine what the new post number is. - new_post_num = top_message + 1; + new_post_num = m_top_message + 1; if (logger.isDebugEnabled()) logger.debug("New post number: " + new_post_num); // Add the post "header" to the posts table. - sql.append("INSERT INTO posts (parent, topicid, num, linecount, creator_uid, posted, pseud) VALUES ("); - sql.append(parent).append(", ").append(topicid).append(", ").append(new_post_num).append(", "); - sql.append(text_linecount).append(", ").append(env.getUserID()).append(", '"); + stmt = conn.prepareStatement("INSERT INTO posts (parent, topicid, num, linecount, creator_uid, posted, pseud) " + + "VALUES (?, ?, ?, ?, ?, ?, ?);"); + stmt.setLong(1,parent); + stmt.setInt(2,m_topicid); + stmt.setInt(3,new_post_num); + stmt.setInt(4,text_linecount); + stmt.setInt(5,m_env.getUserID()); posted_date = new java.util.Date(); - sql.append(SQLUtil.encodeDate(posted_date)).append("', '").append(real_pseud).append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + SQLUtil.setFullDateTime(stmt,6,posted_date); + stmt.setString(7,real_pseud); + stmt.executeUpdate(); // Retrieve the new post ID. - rs = stmt.executeQuery("SELECT LAST_INSERT_ID();"); + rs = stmt2.executeQuery("SELECT LAST_INSERT_ID();"); if (!(rs.next())) throw new InternalStateError("postNewMessage(): Unable to get new post ID!"); new_post_id = rs.getLong(1); if (logger.isDebugEnabled()) logger.debug("New post ID: " + new_post_id); - SQLUtil.shutdown(rs); + rs.close(); // Touch the topic values to reflect the added post. - sql.setLength(0); - sql.append("UPDATE topics SET top_message = ").append(new_post_num).append(", lastupdate = '"); - sql.append(SQLUtil.encodeDate(posted_date)).append("' WHERE topicid = ").append(topicid).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("UPDATE topics SET top_message = ?, lastupdate = ? WHERE topicid = ?;"); + stmt.setInt(1,new_post_num); + SQLUtil.setFullDateTime(stmt,2,posted_date); + stmt.setInt(3,m_topicid); + stmt.executeUpdate(); // insert the post data - sql.setLength(0); - sql.append("INSERT INTO postdata (postid, data) VALUES (").append(new_post_id).append(", '"); - sql.append(real_text).append("');"); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO postdata (postid, data) VALUES (?, ?);"); + stmt.setLong(1,new_post_id); + stmt.setString(2,real_text); + stmt.executeUpdate(); // mark that we posted to the topic - sql.setLength(0); - sql.append("UPDATE topicsettings SET last_post = '").append(SQLUtil.encodeDate(posted_date)); - sql.append("' WHERE topicid = ").append(topicid).append(" AND uid = ").append(env.getUserID()); - sql.append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - if (stmt.executeUpdate(sql.toString())<1) + stmt.close(); + stmt = conn.prepareStatement("UPDATE topicsettings SET last_post = ? WHERE topicid = ? AND uid = ?;"); + SQLUtil.setFullDateTime(stmt,1,posted_date); + stmt.setInt(2,m_topicid); + stmt.setInt(3,m_env.getUserID()); + if (stmt.executeUpdate()<1) { // we had no topicsettings record, add one - sql.setLength(0); - sql.append("INSERT INTO topicsettings (topicid, uid, last_post) VALUES (").append(topicid); - sql.append(", ").append(env.getUserID()).append(", '").append(SQLUtil.encodeDate(posted_date)); - sql.append("');"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO topicsettings (topicid, uid, last_post) VALUES (?, ?, ?);"); + stmt.setInt(1,m_topicid); + stmt.setInt(2,m_env.getUserID()); + SQLUtil.setFullDateTime(stmt,3,posted_date); + stmt.executeUpdate(); } // end if // mark that we posted to the conference - env.getConference().touchUpdate(conn,posted_date); - env.getConference().touchPost(conn,posted_date); + m_env.getConference().touchUpdate(conn,posted_date); + m_env.getConference().touchPost(conn,posted_date); // Who's subscribed to this conference? Whoever it is, they need to get this post via E-mail. - sql.setLength(0); - sql.append("SELECT uid FROM topicsettings WHERE topicid = ").append(topicid); - sql.append(" AND subscribe = 1;"); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); - rs = stmt.executeQuery(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("SELECT uid FROM topicsettings WHERE topicid = ? AND subscribe = 1;"); + stmt.setInt(1,m_topicid); + rs = stmt.executeQuery(); while (rs.next()) { // load the UIDs here if (mailto_uids==null) @@ -852,14 +948,14 @@ class TopicUserContextImpl implements TopicContext } // end while - SQLUtil.shutdown(rs); + rs.close(); // Fill in our own local variables to reflect the update. This includes the recalculation // of "unread" based on the new value of "top_message". - int tmp_last_msg = top_message - unread; - top_message = new_post_num; + int tmp_last_msg = m_top_message - unread; + m_top_message = new_post_num; lastupdate = posted_date; - unread = top_message - tmp_last_msg; + unread = m_top_message - tmp_last_msg; logger.debug("message post completed successfully"); @@ -871,21 +967,21 @@ class TopicUserContextImpl implements TopicContext } // end finally // record what we did in an audit record - ar = env.newAudit(AuditRecord.POST_MESSAGE,"conf=" + env.getConfID() + ",topic=" + topicid + ",post=" - + new_post_id,"pseud=" + real_pseud); + ar = m_env.newAudit(AuditRecord.POST_MESSAGE,"conf=" + m_env.getConfID() + ",topic=" + m_topicid + ",post=" + + new_post_id,"pseud=" + real_pseud); if (mailto_uids!=null) { // We need to translate the "mailto" UIDs to E-mail addresses while we still have the database open! mailto_addrs = new ArrayList(mailto_uids.size()); - sql.setLength(0); - sql.append("SELECT c.email FROM users u, contacts c WHERE u.contactid = c.contactid AND u.uid "); + StringBuffer sql = new StringBuffer("SELECT c.email FROM users u, contacts c WHERE u.contactid = c.contactid " + + "AND u.uid "); if (mailto_uids.size()==1) sql.append("= ").append(mailto_uids.get(0)).append(';'); else sql.append("IN (").append(StringUtil.join(mailto_uids,", ")).append(");"); if (logger.isDebugEnabled()) logger.debug("SQL: " + sql.toString()); - rs = stmt.executeQuery(sql.toString()); + rs = stmt2.executeQuery(sql.toString()); while (rs.next()) mailto_addrs.add(rs.getString(1)); @@ -900,7 +996,9 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); AuditRecord.store(conn,ar); SQLUtil.shutdown(conn); @@ -909,14 +1007,14 @@ class TopicUserContextImpl implements TopicContext if (mailto_addrs!=null) { // a copy of the post needs to be delivered via E-mail to the specified addresses // use our PostDeliveryAgent to do it in the background - env.getGlobalSite().queueTask(new PostDeliveryAgent(env,text,pseud,name,topicnum,mailto_addrs)); + m_env.getGlobalSite().queueTask(new PostDeliveryAgent(m_env,text,pseud,name,m_topicnum,mailto_addrs)); } // end if // else don't bother - it would be a waste of time // return the new message context - return new TopicMessageUserContextImpl(env,new_post_id,parent,topicid,new_post_num,text_linecount, - env.getUserID(),posted_date,real_pseud); + return new TopicMessageUserContextImpl(m_env,new_post_id,parent,m_topicid,new_post_num,text_linecount, + m_env.getUserID(),posted_date,real_pseud); } // end postNewMessage @@ -929,21 +1027,21 @@ class TopicUserContextImpl implements TopicContext public HTMLChecker getPreviewChecker() { - HTMLChecker rc = env.getHTMLChecker("preview"); - rc.setContextValue("PostLinkDecoderContext",env.getConference().createDecoderContext(topicnum)); + HTMLChecker rc = m_env.getHTMLChecker("preview"); + rc.setContextValue("PostLinkDecoderContext",m_env.getConference().createDecoderContext(m_topicnum)); return rc; } // end getPreviewChecker public boolean canDelete() { - return env.getConference().userCanNuke(); + return m_env.getConference().userCanNuke(); } // end canDelete public void delete() throws DataException, AccessError { - if (!(env.getConference().userCanNuke())) + if (!(m_env.getConference().userCanNuke())) { // we can't delete the topic! logger.error("trying to delete w/o permission!"); throw new AccessError("You do not have permission to delete this topic."); @@ -954,42 +1052,47 @@ class TopicUserContextImpl implements TopicContext return; // an exercise in futility... Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; AuditRecord ar = null; int post_count; long post_max; try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); // lock some tables while we do the critical parts of the delete - stmt.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, topicbozo WRITE, " - + "posts READ;"); + stmt2.executeUpdate("LOCK TABLES confs WRITE, topics WRITE, topicsettings WRITE, topicbozo WRITE, " + + "posts READ;"); try { // first delete the topic record itself - StringBuffer sql = new StringBuffer("DELETE FROM topics WHERE topicid = "); - sql.append(topicid).append(';'); - stmt.executeUpdate(sql.toString()); + stmt = conn.prepareStatement("DELETE FROM topics WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + stmt.executeUpdate(); // now delete all topicsettings records - sql.setLength(0); - sql.append("DELETE FROM topicsettings WHERE topicid = ").append(topicid).append(';'); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("DELETE FROM topicsettings WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + stmt.executeUpdate(); // and all topicbozo records - sql.setLength(0); - sql.append("DELETE FROM topicbozo WHERE topicid = ").append(topicid).append(';'); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("DELETE FROM topicbozo WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + stmt.executeUpdate(); // and indicate that we updated the conference - env.getConference().touchUpdate(conn,new java.util.Date()); + m_env.getConference().touchUpdate(conn,new java.util.Date()); // determine the number of posts in this topic, and the maximum post ID - sql.setLength(0); - sql.append("SELECT COUNT(*), MAX(postid) FROM posts WHERE topicid = ").append(topicid).append(';'); - ResultSet rs = stmt.executeQuery(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("SELECT COUNT(*), MAX(postid) FROM posts WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + rs = stmt.executeQuery(); if (!(rs.next())) throw new InternalStateError("TopicContext.delete screwup on post SELECT"); post_count = rs.getInt(1); @@ -1006,7 +1109,7 @@ class TopicUserContextImpl implements TopicContext } // end finally // record what we did in an audit record - ar = env.newAudit(AuditRecord.DELETE_TOPIC,"conf=" + env.getConfID() + ",topic=" + topicid); + ar = m_env.newAudit(AuditRecord.DELETE_TOPIC,"conf=" + m_env.getConfID() + ",topic=" + m_topicid); } // end try catch (SQLException e) @@ -1017,16 +1120,18 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); AuditRecord.store(conn,ar); SQLUtil.shutdown(conn); } // end finally // Delete the rest of the gunk in the background; spin off another thread to handle it. - env.getGlobalSite().queueTask(new BackgroundTopicPurge(env.getGlobalSite(),env,topicid,post_count, - post_max), - GlobalSite.TASK_PRIO_NORMAL-1); + m_env.getGlobalSite().queueTask(new BackgroundTopicPurge(m_env.getGlobalSite(),m_env,m_topicid, + post_count,post_max), + GlobalSite.TASK_PRIO_NORMAL-1); } // end delete @@ -1044,14 +1149,14 @@ class TopicUserContextImpl implements TopicContext try { // retrieve a connection - conn = env.getConnection(); + conn = m_env.getConnection(); stmt = conn.createStatement(); // create the SQL statement to retrieve all posters StringBuffer sql = new StringBuffer("SELECT s.uid, u.username, s.last_read, s.last_post FROM topicsettings s, " + "users u WHERE u.uid = s.uid AND s.topicid = "); - sql.append(topicid).append(" AND u.is_anon = 0 AND ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC"); + sql.append(m_topicid).append(" AND u.is_anon = 0 AND ISNULL(s.last_post) = 0 ORDER BY s.last_post DESC"); if ((skip>=0) && (limit>0)) sql.append(" LIMIT ").append(skip).append(", ").append(limit); sql.append(';'); @@ -1105,14 +1210,14 @@ class TopicUserContextImpl implements TopicContext try { // retrieve a connection - conn = env.getConnection(); + conn = m_env.getConnection(); stmt = conn.createStatement(); // create the SQL statement to retrieve all readers StringBuffer sql = new StringBuffer("SELECT s.uid, u.username, s.last_read, s.last_post FROM topicsettings s, " + "users u WHERE u.uid = s.uid AND s.topicid = "); - sql.append(topicid).append(" AND u.is_anon = 0 AND ISNULL(s.last_read) = 0 ORDER BY s.last_read DESC"); + sql.append(m_topicid).append(" AND u.is_anon = 0 AND ISNULL(s.last_read) = 0 ORDER BY s.last_read DESC"); if ((skip>=0) && (limit>0)) sql.append(" LIMIT ").append(skip).append(", ").append(limit); sql.append(';'); @@ -1160,7 +1265,7 @@ class TopicUserContextImpl implements TopicContext public boolean isBozo(int other_uid) throws DataException { - if (deleted || env.isAnonymous() || (other_uid==env.getUserID())) + if (deleted || m_env.isAnonymous() || (other_uid==m_env.getUserID())) return false; // no-op if (bozo_uids==null) @@ -1168,7 +1273,7 @@ class TopicUserContextImpl implements TopicContext Connection conn = null; try { // load the bozo filter UIDs from the database - conn = env.getConnection(); + conn = m_env.getConnection(); loadBozo(conn); } // end try @@ -1192,30 +1297,32 @@ class TopicUserContextImpl implements TopicContext public void setBozo(int other_uid, boolean bozo) throws DataException { - if (deleted || env.isAnonymous() || (other_uid==env.getUserID())) + if (deleted || m_env.isAnonymous() || (other_uid==m_env.getUserID())) return; // no-op Connection conn = null; - Statement stmt = null; + PreparedStatement insert_stmt = null, remove_stmt = null; try { // figure out what to do here - conn = env.getConnection(); + conn = m_env.getConnection(); refresh(conn); if (deleted) return; // one more check to make sure we're not deleted if (bozo_uids==null) loadBozo(conn); // load the bozo filter if we don't already have it + insert_stmt = conn.prepareStatement("INSERT INTO topicbozo (topicid, uid, bozo_uid) VALUES (?, ?, ?);"); + remove_stmt = conn.prepareStatement("DELETE FROM topicbozo WHERE topicid = ? AND uid = ? AND bozo_uid = ?;"); + Integer uid_key = new Integer(other_uid); - StringBuffer sql; if (bozo) { // this user is a bozo... if (!(bozo_uids.contains(uid_key))) { // add them to the bozo list - sql = new StringBuffer("INSERT INTO topicbozo (topicid, uid, bozo_uid) VALUES ("); - sql.append(topicid).append(", ").append(env.getUserID()).append(", ").append(other_uid).append(");"); - stmt = conn.createStatement(); - stmt.executeUpdate(sql.toString()); + insert_stmt.setInt(1,m_topicid); + insert_stmt.setInt(2,m_env.getUserID()); + insert_stmt.setInt(3,other_uid); + insert_stmt.executeUpdate(); bozo_uids.add(uid_key); } // end if @@ -1226,11 +1333,10 @@ class TopicUserContextImpl implements TopicContext { // this user is no longer a bozo if (bozo_uids.contains(uid_key)) { // remove them from the bozo list - sql = new StringBuffer("DELETE FROM topicbozo WHERE topicid = "); - sql.append(topicid).append(" AND uid = ").append(env.getUserID()).append(" AND bozo_uid = "); - sql.append(other_uid).append(';'); - stmt = conn.createStatement(); - stmt.executeUpdate(sql.toString()); + remove_stmt.setInt(1,m_topicid); + remove_stmt.setInt(2,m_env.getUserID()); + remove_stmt.setInt(3,other_uid); + remove_stmt.executeUpdate(); bozo_uids.remove(uid_key); } // end if @@ -1247,7 +1353,8 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go - SQLUtil.shutdown(stmt); + SQLUtil.shutdown(insert_stmt); + SQLUtil.shutdown(remove_stmt); SQLUtil.shutdown(conn); } // end finally @@ -1259,13 +1366,13 @@ class TopicUserContextImpl implements TopicContext // 1. You can't set bozo filters on a deleted topic. // 2. You can't set bozo filters if you're the anonymous user. // 3. You can't bozo-filter yourself, silly. - return !(deleted || env.isAnonymous() || (other_uid==env.getUserID())); + return !(deleted || m_env.isAnonymous() || (other_uid==m_env.getUserID())); } // end canSetBozoFilter public List getBozos() throws DataException { - if (deleted || env.isAnonymous()) + if (deleted || m_env.isAnonymous()) return Collections.EMPTY_LIST; // no-op if (bozo_uids==null) @@ -1273,7 +1380,7 @@ class TopicUserContextImpl implements TopicContext Connection conn = null; try { // load the bozo filter UIDs from the database - conn = env.getConnection(); + conn = m_env.getConnection(); loadBozo(conn); } // end try @@ -1303,34 +1410,38 @@ class TopicUserContextImpl implements TopicContext public void setSubscribed(boolean flag) throws DataException { - if ((subscribed==flag) || deleted || env.isAnonymous()) + if ((subscribed==flag) || deleted || m_env.isAnonymous()) return; // no-op Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + Statement stmt2 = null; + ResultSet rs = null; try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); - stmt.executeUpdate("LOCK TABLES topicsettings WRITE, topics READ;"); + conn = m_env.getConnection(); + stmt2 = conn.createStatement(); + stmt2.executeUpdate("LOCK TABLES topicsettings WRITE, topics READ;"); try { // start by trying to see if we can update topicsettings directly - StringBuffer sql = new StringBuffer("UPDATE topicsettings SET subscribe = "); - sql.append(flag ? '1' : '0').append(" WHERE topicid = ").append(topicid).append(" AND uid = "); - sql.append(env.getUserID()).append(';'); - if (stmt.executeUpdate(sql.toString())>0) + stmt = conn.prepareStatement("UPDATE topicsettings SET subscribe = ? WHERE topicid = ? AND uid = ?;"); + stmt.setInt(1,flag ? 1 : 0); + stmt.setInt(2,m_topicid); + stmt.setInt(3,m_env.getUserID()); + if (stmt.executeUpdate()>0) { // that was all we needed - just save the flag and exit subscribed = flag; return; } // end if - // OK, check: Is the topic still there?!? - sql.setLength(0); - sql.append("SELECT topicid from topics WHERE topicid = ").append(topicid).append(';'); - ResultSet rs = stmt.executeQuery(sql.toString()); + // Sanity check: Is the topic still there?!? + stmt.close(); + stmt = conn.prepareStatement("SELECT topicid from topics WHERE topicid = ?;"); + stmt.setInt(1,m_topicid); + rs = stmt.executeQuery(); if (!(rs.next())) { // the topic's been deleted - bail out makeDeleted(); @@ -1338,13 +1449,13 @@ class TopicUserContextImpl implements TopicContext } // end if - SQLUtil.shutdown(rs); - // OK, just insert a new row into topicsettings, why dontcha... - sql.setLength(0); - sql.append("INSERT INTO topicsettings (topicid, uid, subscribe) VALUES (").append(topicid); - sql.append(", ").append(env.getUserID()).append(", ").append(flag ? '1' : '0').append(");"); - stmt.executeUpdate(sql.toString()); + stmt.close(); + stmt = conn.prepareStatement("INSERT INTO topicsettings (topicid, uid, subscribe) VALUES (?, ?, ?);"); + stmt.setInt(1,m_topicid); + stmt.setInt(2,m_env.getUserID()); + stmt.setInt(3,flag ? 1 : 0); + stmt.executeUpdate(); subscribed = flag; // successful completion } // end try @@ -1363,7 +1474,9 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); + SQLUtil.shutdown(stmt2); SQLUtil.shutdown(conn); } // end finally @@ -1373,27 +1486,27 @@ class TopicUserContextImpl implements TopicContext public void sendInvitation(String address, String personal_message) throws AccessError, DataException, EmailException { - if (!(env.getCommunity().selfCommunity().canSendInvitation())) + if (!(m_env.getCommunity().selfCommunity().canSendInvitation())) throw new AccessError("You are not permitted to send a topic invitation."); // Format the added "conference name" message. HashMap vars = new HashMap(); - vars.put("community.name",env.getCommunityName()); - vars.put("conference.name",env.getConferenceName()); + vars.put("community.name",m_env.getCommunityName()); + vars.put("conference.name",m_env.getConferenceName()); vars.put("topic.name",name); - String extra_msg = env.getStockMessage("add-topic-invite"); + String extra_msg = m_env.getStockMessage("add-topic-invite"); String msg = StringUtil.replaceAllVariables(extra_msg,vars); if (!StringUtil.isStringEmpty(personal_message)) msg += ("\n\n" + personal_message); // now send it as if it were a community invitation - env.getCommunity().selfCommunity().sendInvitation(address,msg); + m_env.getCommunity().selfCommunity().sendInvitation(address,msg); } // end sendInvitation public boolean canSendInvitation() { - return env.getCommunity().selfCommunity().canSendInvitation(); + return m_env.getCommunity().selfCommunity().canSendInvitation(); } // end canSendInvitation @@ -1402,7 +1515,7 @@ class TopicUserContextImpl implements TopicContext { if (logger.isDebugEnabled()) logger.debug("sendMailToParticipants(" + posters + "," + day_limit + ")"); - if (!(env.testPermission("Conference.EMailParticipants"))) + if (!(m_env.testPermission("Conference.EMailParticipants"))) throw new AccessError("You are not permitted to send E-mail to conference participants."); if (day_limit==0) @@ -1422,7 +1535,7 @@ class TopicUserContextImpl implements TopicContext try { // retrieve a connection - conn = env.getConnection(); + conn = m_env.getConnection(); stmt = conn.createStatement(); // Build the SQL statement. @@ -1432,7 +1545,7 @@ class TopicUserContextImpl implements TopicContext else sql.append("s.last_read"); sql.append(" FROM contacts c, users u, topicsettings s, propuser p WHERE c.contactid = u.contactid " - + "AND u.uid = s.uid AND s.topicid = ").append(topicid); + + "AND u.uid = s.uid AND s.topicid = ").append(m_topicid); sql.append(" AND u.is_anon = 0 AND u.uid = p.uid AND p.ndx = ").append(UserContextImpl.PROP_FLAGS); sql.append(" AND p.data NOT LIKE '%"); sql.append(OptionSet.getOptionChar(UserContextImpl.BF_MASSMAIL_OPTOUT)).append("%' AND "); @@ -1479,19 +1592,19 @@ class TopicUserContextImpl implements TopicContext if (rc.size()>0) { // prepare the E-mail message text; append the disKlaimer at the end HashMap vars = new HashMap(); - vars.put("community.name",env.getCommunityName()); - vars.put("conference.name",env.getConferenceName()); + vars.put("community.name",m_env.getCommunityName()); + vars.put("conference.name",m_env.getConferenceName()); vars.put("topic.name",name); String disklaimer = - env.getStockMessage(posters ? "mass-topic-notice-poster" : "mass-topic-notice-reader"); + m_env.getStockMessage(posters ? "mass-topic-notice-poster" : "mass-topic-notice-reader"); StringBuffer buf = new StringBuffer(text); buf.append("\n\n").append(StringUtil.replaceAllVariables(disklaimer,vars)); // send the actual E-mail messages in the background - MailSend msend = new PersonalMailSend(env.getMailSender(),env.getGlobalSite(),env.getUserProps()); + MailSend msend = new PersonalMailSend(m_env.getMailSender(),m_env.getGlobalSite(),m_env.getUserProps()); msend.setSubject(subject); msend.setText(buf.toString()); - env.getGlobalSite().queueTask(new MailerAgent(msend,rc)); + m_env.getGlobalSite().queueTask(new MailerAgent(msend,rc)); } // end if @@ -1507,32 +1620,32 @@ class TopicUserContextImpl implements TopicContext throw new IllegalArgumentException("invalid offset parameter"); if (count<=0) throw new IllegalArgumentException("invalid count parameter"); - if (!(env.getConference().userCanRead())) + if (!(m_env.getConference().userCanRead())) throw new AccessError("You are not permitted to search for posts within this topic."); Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; ArrayList rc = new ArrayList(); try { // get a database connection - conn = env.getConnection(); + conn = m_env.getConnection(); TopicMessageFoundHelper helper = new TopicMessageFoundHelper(conn); - stmt = conn.createStatement(); // create the SQL statement - StringBuffer sql = - new StringBuffer("SELECT p.postid, p.num, p.creator_uid, p.posted, p.linecount, d.data " - + "FROM posts p, postdata d WHERE p.topicid = "); - sql.append(topicid); - sql.append(" AND p.scribble_uid IS NULL AND d.postid = p.postid AND MATCH (d.data) AGAINST ("); - sql.append(SQLUtil.encodeStringArg(search_terms)).append(") LIMIT ").append(offset).append(", "); - sql.append(count+1).append(';'); + stmt = conn.prepareStatement("SELECT p.postid, p.num, p.creator_uid, p.posted, p.linecount, d.data " + + "FROM posts p, postdata d WHERE p.topicid = ? AND p.scribble_uid IS NULL " + + "AND d.postid = p.postid AND MATCH (d.data) AGAINST (?) LIMIT ?, ?;"); + stmt.setInt(1,m_topicid); + stmt.setString(2,search_terms); + stmt.setInt(3,offset); + stmt.setInt(4,count + 1); // execute the query and load the results into the return arraylist - ResultSet rs = stmt.executeQuery(sql.toString()); + rs = stmt.executeQuery(); while (rs.next()) - rc.add(new TopicMessageFoundImpl(helper,env.getCommunityID(),env.getConfID(),topicid,topicnum, + rc.add(new TopicMessageFoundImpl(helper,m_env.getCommunityID(),m_env.getConfID(),m_topicid,m_topicnum, rs.getLong(1),rs.getInt(2),rs.getInt(3), SQLUtil.getFullDateTime(rs,4),rs.getInt(5),rs.getString(6))); @@ -1545,6 +1658,7 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -1563,26 +1677,26 @@ class TopicUserContextImpl implements TopicContext logger.debug("getSearchPostCount('" + search_terms + ") entry"); if (search_terms==null) throw new NullPointerException("invalid search terms"); - if (!(env.getConference().userCanRead())) + if (!(m_env.getConference().userCanRead())) throw new AccessError("You are not permitted to search for posts within this topic."); Connection conn = null; - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // get a database connection - conn = env.getConnection(); - stmt = conn.createStatement(); + conn = m_env.getConnection(); // create the SQL statement - StringBuffer sql = - new StringBuffer("SELECT COUNT(*) FROM posts p, postdata d WHERE p.topicid = "); - sql.append(topicid); - sql.append(" AND p.scribble_uid IS NULL AND d.postid = p.postid AND MATCH (d.data) AGAINST ("); - sql.append(SQLUtil.encodeStringArg(search_terms)).append(");"); + stmt = conn.prepareStatement("SELECT COUNT(*) FROM posts p, postdata d WHERE p.topicid = ? " + + "AND p.scribble_uid IS NULL AND d.postid = p.postid " + + "AND MATCH (d.data) AGAINST (?);"); + stmt.setInt(1,m_topicid); + stmt.setString(2,search_terms); // execute the query and load the results into the return arraylist - ResultSet rs = stmt.executeQuery(sql.toString()); + rs = stmt.executeQuery(); if (!(rs.next())) throw new InternalStateError("query failure in TopicUserContextImpl.getSearchPostCount!"); return rs.getInt(1); @@ -1596,6 +1710,7 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -1605,7 +1720,7 @@ class TopicUserContextImpl implements TopicContext public ConferenceContext getEnclosingConference() { - return env.getConference().selfConference(); + return m_env.getConference().selfConference(); } // end getEnclosingConference @@ -1613,7 +1728,7 @@ class TopicUserContextImpl implements TopicContext { if (deleted) return null; - return env.getConference().selfConference().getPostLink() + "." + topicnum; + return m_env.getConference().selfConference().getPostLink() + "." + m_topicnum; } // end getPostLink @@ -1622,13 +1737,15 @@ class TopicUserContextImpl implements TopicContext *-------------------------------------------------------------------------------- */ - static final List getTopicList(EnvConference env, int get_option, int sort_option) throws DataException + static final List getTopicList(EnvConference env, int get_option, int sort_option, + boolean ignore_sticky) throws DataException { if (logger.isDebugEnabled()) logger.debug("getTopicList for conf # " + env.getConfID() + ", user #" + env.getUserID()); ArrayList rc = new ArrayList(); // return from this function Connection conn = null; // pooled database connection Statement stmt = null; + ResultSet rs = null; try { // get a database connection @@ -1646,8 +1763,11 @@ class TopicUserContextImpl implements TopicContext break; case ConferenceContext.DISPLAY_NEW: - // only non-hidden topics w/unread messages - where_clause = "IFNULL(s.hidden,0) = 0 AND t.top_message > IFNULL(s.last_message,-1)"; + // only non-hidden topics w/unread messages (and all sticky topics, if not ignoring) + where_clause = "t.top_message > IFNULL(s.last_message,-1)"; + if (!ignore_sticky) + where_clause = "(t.sticky = 1 OR " + where_clause + ")"; + where_clause = "t.archived = 0 AND IFNULL(s.hidden,0) = 0 AND " + where_clause; break; case ConferenceContext.DISPLAY_ACTIVE: @@ -1674,7 +1794,8 @@ class TopicUserContextImpl implements TopicContext // Figure out what the "order by" clause of the SQL statement will be. In the case of // DISPLAY_NEW mode, this will be in addition to an ordering clause that puts all topics - // with unread messages first. + // with unread messages first. Also, if ignore_sticky is not set, "sticky" topics will + // be placed above all others regardless of mode. boolean reverse = false; int real_sort_option = sort_option; if (sort_option<0) @@ -1736,7 +1857,7 @@ class TopicUserContextImpl implements TopicContext // Build the huge SQL statement to feed to the database. StringBuffer sql = new StringBuffer("SELECT t.topicid, t.num, t.creator_uid, t.top_message, t.frozen, t.archived, " - + "t.createdate, t.lastupdate, t.name, IFNULL(s.hidden,0) AS hidden, " + + "t.sticky, t.createdate, t.lastupdate, t.name, IFNULL(s.hidden,0) AS hidden, " + "(t.top_message - IFNULL(s.last_message,-1)) AS unread, " + "IFNULL(s.subscribe,0) AS subscribe"); if (get_option==ConferenceContext.DISPLAY_ACTIVE) @@ -1746,6 +1867,8 @@ class TopicUserContextImpl implements TopicContext if (where_clause!=null) sql.append(" AND ").append(where_clause); sql.append(" ORDER BY "); + if (!ignore_sticky) + sql.append("sticky DESC, "); if (get_option==ConferenceContext.DISPLAY_ACTIVE) sql.append("newflag DESC, "); sql.append(order_by_clause).append(';'); @@ -1753,15 +1876,15 @@ class TopicUserContextImpl implements TopicContext logger.debug("SQL: " + sql.toString()); // Now pass this query off to the database! - ResultSet rs = stmt.executeQuery(sql.toString()); + rs = stmt.executeQuery(sql.toString()); while (rs.next()) { // create the returned objects and add them to the vector TopicContext top = new TopicUserContextImpl(env,rs.getInt(1),rs.getShort(2),rs.getInt(3),rs.getInt(4), - rs.getBoolean(5),rs.getBoolean(6),SQLUtil.getFullDateTime(rs,7), - SQLUtil.getFullDateTime(rs,8),rs.getString(9),rs.getBoolean(10), - rs.getInt(11),rs.getBoolean(12)); + rs.getBoolean(5),rs.getBoolean(6),rs.getBoolean(7),SQLUtil.getFullDateTime(rs,8), + SQLUtil.getFullDateTime(rs,9),rs.getString(10),rs.getBoolean(11), + rs.getInt(12),rs.getBoolean(13)); rc.add(top); } // end while @@ -1775,11 +1898,13 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); } // end finally + rc.trimToSize(); return Collections.unmodifiableList(rc); } // end getTopicList @@ -1790,20 +1915,23 @@ class TopicUserContextImpl implements TopicContext logger.debug("getTopicByID for topic # " + topicid + ", user #" + env.getUserID()); Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; + ResultSet rs = null; try { // get a database connection conn = env.getConnection(); - stmt = conn.createStatement(); + stmt = conn.prepareStatement(BY_TOPIC_QUERY); + stmt.setInt(1,env.getUserID()); + stmt.setInt(2,topicid); - // Query the dtabase by topic ID. - ResultSet rs = queryByTopic(stmt,topicid,env.getUserID()); + // Query the database by topic ID. + rs = stmt.executeQuery(); if (rs.next()) // found it! return new TopicUserContextImpl(env,topicid,rs.getShort(2),rs.getInt(3),rs.getInt(4),rs.getBoolean(5), - rs.getBoolean(6),SQLUtil.getFullDateTime(rs,7), - SQLUtil.getFullDateTime(rs,8),rs.getString(9),rs.getBoolean(10), - rs.getInt(11),rs.getBoolean(12)); + rs.getBoolean(6),rs.getBoolean(7),SQLUtil.getFullDateTime(rs,8), + SQLUtil.getFullDateTime(rs,9),rs.getString(10),rs.getBoolean(11), + rs.getInt(12),rs.getBoolean(13)); // else fall out and return null } // end try @@ -1815,6 +1943,7 @@ class TopicUserContextImpl implements TopicContext } // end catch finally { // make sure we release the connection before we go + SQLUtil.shutdown(rs); SQLUtil.shutdown(stmt); SQLUtil.shutdown(conn); @@ -1831,32 +1960,30 @@ class TopicUserContextImpl implements TopicContext + env.getUserID()); Connection conn = null; // pooled database connection - Statement stmt = null; + PreparedStatement stmt = null; try { // get a database connection conn = env.getConnection(); - stmt = conn.createStatement(); - // Build the database query. - StringBuffer sql = - new StringBuffer("SELECT t.topicid, t.num, t.creator_uid, t.top_message, t.frozen, t.archived, " - + "t.createdate, t.lastupdate, t.name, IFNULL(s.hidden,0) AS hidden, " - + "(t.top_message - IFNULL(s.last_message,-1)) AS unread, " - + "IFNULL(s.subscribe,0) AS subscribe FROM topics t " - + "LEFT JOIN topicsettings s ON t.topicid = s.topicid AND s.uid = "); - sql.append(env.getUserID()).append(" WHERE t.confid = ").append(env.getConfID()); - sql.append(" AND t.num = ").append(topicnum).append(';'); - if (logger.isDebugEnabled()) - logger.debug("SQL: " + sql.toString()); + // prepare the statement + stmt = conn.prepareStatement("SELECT t.topicid, t.num, t.creator_uid, t.top_message, t.frozen, t.archived, " + + "t.sticky, t.createdate, t.lastupdate, t.name, IFNULL(s.hidden,0) AS hidden, " + + "(t.top_message - IFNULL(s.last_message,-1)) AS unread, " + + "IFNULL(s.subscribe,0) AS subscribe FROM topics t " + + "LEFT JOIN topicsettings s ON t.topicid = s.topicid AND s.uid = ? " + + "WHERE t.confid = ? AND t.num = ?;"); + stmt.setInt(1,env.getUserID()); + stmt.setInt(2,env.getConfID()); + stmt.setShort(3,topicnum); // Now pass this query off to the database! - ResultSet rs = stmt.executeQuery(sql.toString()); + ResultSet rs = stmt.executeQuery(); if (rs.next()) // found it! return new TopicUserContextImpl(env,rs.getInt(1),topicnum,rs.getInt(3),rs.getInt(4),rs.getBoolean(5), - rs.getBoolean(6),SQLUtil.getFullDateTime(rs,7), - SQLUtil.getFullDateTime(rs,8),rs.getString(9),rs.getBoolean(10), - rs.getInt(11),rs.getBoolean(12)); + rs.getBoolean(6),rs.getBoolean(7),SQLUtil.getFullDateTime(rs,8), + SQLUtil.getFullDateTime(rs,9),rs.getString(10),rs.getBoolean(11), + rs.getInt(12),rs.getBoolean(13)); // else fall out and return null } // end try diff --git a/src/com/silverwrist/venice/security/Audit.java b/src/com/silverwrist/venice/security/Audit.java index e476cfe..97785f7 100644 --- a/src/com/silverwrist/venice/security/Audit.java +++ b/src/com/silverwrist/venice/security/Audit.java @@ -68,5 +68,6 @@ public interface Audit public static final int UPLOAD_ATTACHMENT = 314; public static final int DELETE_CONF = 315; public static final int MOVE_MESSAGE = 316; + public static final int TOPIC_STICKY = 317; } // end interface Audit diff --git a/web/format/conf/posts.jsp b/web/format/conf/posts.jsp index 5bcac31..763a715 100644 --- a/web/format/conf/posts.jsp +++ b/web/format/conf/posts.jsp @@ -9,9 +9,9 @@ The Original Code is the Venice Web Communities System. - The Initial Developer of the Original Code is Eric J. Bowersox , + 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. Contributor(s): --%> @@ -45,6 +45,12 @@ <%= view.getTitle() %> + <% if (my_topic.isSticky()) { %> + (Sticky) + <% } // end if %> + <% if (my_topic.isHidden()) { %> + (Hidden) + <% } // end if %> <% if (my_topic.isArchived()) { %> (Archived) <% } else if (my_topic.isFrozen()) { %> @@ -55,19 +61,35 @@ <%= view.getTopCustom() %> - - - + +
+ + + - + + <% out.flush(); response.flushBuffer(); %> - - - + + - + + <% out.flush(); response.flushBuffer(); %> - - + - + - - - + + + - -
-
  +
  Topic admin controls section - <% if (my_topic.canFreeze()) { %> + <% if (my_topic.canStick()) { %> +   + <% if (my_topic.isSticky()) { %> + + conf/stick_topic.js.vs?<%= topic_locator %>&flag=0 + + + <% } else { %> + + conf/stick_topic.js.vs?<%= topic_locator %>&flag=1 + + +<% + } // end if + } // end if + if (my_topic.canFreeze()) { +%>   <% if (my_topic.isFrozen()) { %> @@ -106,25 +128,25 @@ <% } // end if %> -
+
Go box -
- - - -   +
+ + + +   -
-
+ + Upper navigation linkset - [  + [  conf/posts.js.vs?<%= topic_locator %>&p1=0&p2=-1 View All @@ -157,12 +179,12 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <% } // end if %>  |  - Bottom + Bottom  ] -
+
<%= view.getPageQID() %> [Permalink to this topic] @@ -172,27 +194,27 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <%= view.getPageQID() %>.<%= my_first %>-<%= my_last %> [Permalink to these posts] -
+
<% out.flush(); response.flushBuffer(); %> Begin Actual Messages <% - Iterator it = view.getMessages().iterator(); String last_post = "shac=1&p1=" + String.valueOf(my_total_msg - 1); boolean can_line = false; - while (it.hasNext()) { + for (Iterator it=view.getMessages().iterator(); it.hasNext(); ) { TopicMessageContext msg = (TopicMessageContext)(it.next()); String poster = view.getPosterName(msg); if (can_line && (msg.getPostNumber()==(my_total_msg-my_unread))) { - out.write("
\n"); + out.write("
\n"); } // end if if (view.getShowAdvanced() && (view.getMessages().size()==1)) { %> -
-
+
+ +
<% } // end if %> <% @@ -222,32 +244,32 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <% if (view.getShowAdvanced() && (view.getMessages().size()==1)) { if (msg.isHidden()) { - out.write("(Hidden)\n"); + out.write("(Hidden)\n"); } // end if if (view.showBozoFilteredIndicator(msg.getCreatorUID())) { %> - (User filtered; + (User filtered; conf/message_bozo.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %>&flag=0 remove filter ) - + <% } // end if } // end if if (!(view.bozoFilterUser(msg.getCreatorUID()))) { %> -
- <%= msg.getPseud() %> - ( +
+ <%= msg.getPseud() %> + ( user/<%= poster %> <%= poster %> , <%= view.formatDate(msg.getPostDate()) %> -
) + ) <% if (msg.hasAttachment()) { %> <% if (view.displayAttachmentInNewWindow(msg)) { %> @@ -272,15 +294,15 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l } // end if %>
-

+

<% if (msg.isScribbled()) { %> - + (Scribbled by <%= view.getMessageBodyText(msg) %> on <%= view.formatDate(msg.getScribbleDate()) %>) - - <% if (view.getPhotoDims()!=null) { %>
<% } %>

+ + <% if (view.getPhotoDims()!=null) { %>
<% } %>

<% } else if (view.bozoFilterUser(msg.getCreatorUID())) { %> - + conf/posts.js.vs?<%= topic_locator %>&shac=1&nbz=1&p1=<%= msg.getPostNumber() %> @@ -290,9 +312,9 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <%= msg.getNumLines() %> <% if (msg.getNumLines()==1) { %>Line<% } else { %>Lines<% } %>) -

+

<% } else if (msg.isHidden() && (!(view.getShowAdvanced()) || (view.getMessages().size()!=1))) { %> - + conf/posts.js.vs?<%= topic_locator %>&shac=1&p1=<%= msg.getPostNumber() %> @@ -302,16 +324,16 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <%= msg.getNumLines() %> <% if (msg.getNumLines()==1) { %>Line<% } else { %>Lines<% } %>) - - <% if (view.getPhotoDims()!=null) { %>
<% } %>

+ + <% if (view.getPhotoDims()!=null) { %>
<% } %>

<% } else { %> -

<%= view.getMessageBodyText(msg) %>
- <% if (view.getPhotoDims()!=null) { %>
<% } %>

+

<%= view.getMessageBodyText(msg) %>
+ <% if (view.getPhotoDims()!=null) { %>
<% } %>

<% } // end if if (view.getShowAdvanced() && (view.getMessages().size()==1)) { %> -

+ <% if (!(msg.isScribbled())) { if (msg.canHide()) { @@ -322,14 +344,14 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/hide_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %>&flag=0 -

+

<% } else { %> conf/hide_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %>&flag=1 -

+

<% } // end if } // end if (can hide) @@ -340,7 +362,7 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/scribble_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %> -

+

<% } // end if (can scribble) } // end if (not already scribbled) @@ -351,7 +373,7 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/message_bozo.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %>&flag=1 -

+

<% } // end if (can bozo filter) if (msg.canNuke()) { @@ -361,7 +383,7 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/nuke_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %> -

+

<% } // end if (can nuke) if (msg.canMove() && (my_topic.getTotalMessages()>1)) { @@ -371,7 +393,7 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/move_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %> -

+

<% } // end if (can move) if (msg.canPublish()) { @@ -381,21 +403,21 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l conf/publish_message.js.vs?<%= topic_locator %>&msg=<%= msg.getPostNumber() %> -

+

<% } // end if (can publish) %> -


+

<% } // end if (showing advanced controls) can_line = true; out.flush(); response.flushBuffer(); -} // end while +} // end for %> End Actual Messages - - - + +
+ + + - - - - + + + + - + + <% out.flush(); response.flushBuffer(); %> - - + - -
<%= view.getPageQID() %> [Permalink to this topic] @@ -405,13 +427,13 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <%= view.getPageQID() %>.<%= my_first %>-<%= my_last %> [Permalink to these posts] -
  +
  Lower navigation linkset - [  + [  conf/posts.js.vs?<%= topic_locator %>&p1=0&p2=-1 View All @@ -442,18 +464,18 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l <% } // end if %>  |  - Top + Top  ] -
+
-
+
<% out.flush(); response.flushBuffer(); %> <% @@ -462,9 +484,9 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l final boolean flag3 = (my_topic.isArchived() ? my_topic.canArchive() : true); if (flag1 && flag2 && flag3) { %> -
- Post Message in "<%= my_topic.getName() %>": -
+
+ Post Message in "<%= my_topic.getName() %>": +
<%= my_comm.getCommunityID() %> <%= my_conf.getConfID() %> @@ -486,15 +508,15 @@ conf/posts.js.vs?<%= topic_locator %>&p1=<%= my_last + 1 %>&p2=<%= Math.min(my_l } else if (my_conf.canPostToConference()) { if (my_topic.isArchived()) { %> -
This is an - Archived Topic
+
This is an + Archived Topic
<% } else if (my_topic.isFrozen()) { %> -
This is a - Frozen Topic
+
This is a + Frozen Topic
<% } // end if } // end if %> <%= view.getBottomCustom() %> <% out.flush(); response.flushBuffer(); %> - +<%-- EOF --%> diff --git a/web/format/conf/topics.jsp b/web/format/conf/topics.jsp index 6fd73fb..617d109 100644 --- a/web/format/conf/topics.jsp +++ b/web/format/conf/topics.jsp @@ -9,9 +9,9 @@ The Original Code is the Venice Web Communities System. - The Initial Developer of the Original Code is Eric J. Bowersox , + 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-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. + Copyright (C) 2001-2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. Contributor(s): --%> @@ -51,7 +51,7 @@ <%= view.getRequestAttribute("conference.custom.top").toString() %> -
+
conf/conferences.js.vs?<%= base_locator %> @@ -83,104 +83,106 @@   -
+
<%= view.getPageQID() %> [Permalink to this conference] -
+
<% out.flush(); response.flushBuffer(); %> <% final List topics = (List)(view.getRequestAttribute("topics.list")); %> <% if (topics.size()>0) { %> - - -
- + + + - + - + - + - + - + + + + <% out.flush(); response.flushBuffer(); %> - <% - Iterator it = topics.iterator(); - while (it.hasNext()) { + for (Iterator it=topics.iterator(); it.hasNext(); ) { TopicContext topic = (TopicContext)(it.next()); short num = topic.getTopicNumber(); String my_locator = base_locator + "&top=" + num; %> - - + - + - + - + - + - + + <% out.flush(); response.flushBuffer(); - } // end while (more topics in enumeration) + } // end for (all topics in enumeration) %> -
+ conf/topics.js.vs?<%= base_locator %>&sort=<%= ((sort_opt==SORT_NUMBER) ? -SORT_NUMBER : SORT_NUMBER) %> # -    - - +    + + conf/topics.js.vs?<%= base_locator %>&sort=<%= ((sort_opt==SORT_NAME) ? -SORT_NAME : SORT_NAME) %> Topic Name - - - + + + conf/topics.js.vs?<%= base_locator %>&sort=<%= ((sort_opt==SORT_UNREAD) ? -SORT_UNREAD : SORT_UNREAD) %> New - - - + + + conf/topics.js.vs?<%= base_locator %>&sort=<%= ((sort_opt==SORT_TOTAL) ? -SORT_TOTAL : SORT_TOTAL) %> Total - - - + + + conf/topics.js.vs?<%= base_locator %>&sort=<%= ((sort_opt==SORT_DATE) ? -SORT_DATE : SORT_DATE) %> Last Response - -
 
 
+
conf/posts.js.vs?<%= my_locator %>&rnm=1 <%= num %>    - + conf/posts.js.vs?<%= my_locator %>&rnm=1 <%= topic.getName() %> - <% if (topic.isArchived() && (view_opt!=DISPLAY_ARCHIVED)) { %> - (archived) - <% } else if (topic.isFrozen()) { %> - (frozen) + <% if (topic.isSticky()) { %> + (sticky) <% } // end if %> - + <% if (topic.isArchived() && (view_opt!=DISPLAY_ARCHIVED)) { %> + (archived) + <% } else if (topic.isFrozen()) { %> + (frozen) + <% } // end if %> + conf/posts.js.vs?<%= my_locator %>&rnm=1 <%= topic.getUnreadMessages() %> - + conf/posts.js.vs?<%= my_locator %>&p1=0&p2=-1 <%= topic.getTotalMessages() %> - + conf/posts.js.vs?<%= my_locator %>&rnm=1 <%= view.formatDate(topic.getLastUpdateDate()) %> -

+

<% } else { %> - <% + <% switch (view_opt) { case DISPLAY_NEW: @@ -200,58 +202,59 @@ out.write("Invalid display option selected."); break; } // end switch - %> -

+ %> +

<% } // end if %> <% out.flush(); response.flushBuffer(); %> -

- [ +
+ [ <% if (view_opt==DISPLAY_NEW) { %> - New + New <% } else { %> conf/topics.js.vs?<%= base_locator %>&view=<%= DISPLAY_NEW %> New <% } // end if %> - | + | <% if (view_opt==DISPLAY_ACTIVE) { %> - Active + Active <% } else { %> conf/topics.js.vs?<%= base_locator %>&view=<%= DISPLAY_ACTIVE %> Active <% } // end if %> - | + | <% if (view_opt==DISPLAY_ALL) { %> - All + All <% } else { %> conf/topics.js.vs?<%= base_locator %>&view=<%= DISPLAY_ALL %> All <% } // end if %> - | + | <% if (view_opt==DISPLAY_HIDDEN) { %> - Hidden + Hidden <% } else { %> conf/topics.js.vs?<%= base_locator %>&view=<%= DISPLAY_HIDDEN %> Hidden <% } // end if %> - | + | <% if (view_opt==DISPLAY_ARCHIVED) { %> - Archived + Archived <% } else { %> conf/topics.js.vs?<%= base_locator %>&view=<%= DISPLAY_ARCHIVED %> Archived <% } // end if %> - ] -
+ ] +
<%= view.getRequestAttribute("conference.custom.bottom").toString() %> +<%-- EOF --%> diff --git a/web/images/classic/stick_topic.jpg b/web/images/classic/stick_topic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bcdb777f034d75841c8202fa64ffa4b67c818c1 GIT binary patch literal 1262 zcmex=LJ%Z3brs zCZIY-Mi9va0xZlRl9h#pnT3s&jSY<1IXT$aIoa9RIJh}Dxj+EO;^F4v0dYWvK(sQk zGBdMsv9qy*m5@aIKfoZ!!63m9z|5$`z$D1XEXer(2!j;R4-Cve3#?j{P6!4 z0}oI;lORyWo*{qX#$m=8Xx+W$&#n~LG<|_m$sL?q zVih$m{B!c$^h&S$`EsAr{L^#t5<;%rzhHOhKZEVs+NhV?mPaZq&Iw-?YZrFg?w`V1)GJwbF}udWK;R`qolNt827^=g3ns|LZIs>5GymyXtCv|1ul)61r~Oqu zNUMzFtnHlbH{!$QD+{fhIH88=@{C;pPvp&Agk*1jG-u`EdY35Fkk}p=YrlB8ZSt$Q ztuMAUS6;bNH-Y7D=)u`~X{T=Te7!K&iKCx+or+M$^7p)Z%w)Jq-e|8j@HF_qw}ioQ z6RS`}?xISYt8zMFYMLFsr}llRUu|~ndvQ&%bg9tyzcF(+?5aBP)p^FDlK%`B{BADU zF1Kn|Lv~Wvn*G;S&(sn!e&Q(IJhekVYJlnv@*2pliH$JG>mDOH;|GaxY_ZH^e_we|1*G^Ubf$%ov!`x3E$#8Hv zDBO6wfA-|>?ho6elum^?P3Kp%S+vSF&XiSl#b$mp%PT?*Gkp4$D-{Lr7Zu4VKiu)Q zCvao5(@sJCtN!nPFP?Q})y9+C-(<^4ytzBm)-~#tUYD!7q=-Yy9iAr*_KW0YVpn-z zoo%ks+h@b#{I=!&w8+kfL5t_i)t-H3pVr9`4aW0n{S5s1r#bK2r7rs$ZXm&(n)pDP z?Y!rGoehiqS{^bB6`Z?WvsQZAH8bVE53L`nzWNz&FoV{l^6~cPuCm3QBHsg8G#%1rwtp@1`_V107-wTWX-j_J@gwOw*07$Ui#{d8T literal 0 HcmV?d00001 diff --git a/web/images/classic/unstick_topic.jpg b/web/images/classic/unstick_topic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..871caddd5a8ef5059c7a943ff3e86c9e8e191c26 GIT binary patch literal 1331 zcmex=LJ%Z3brs zCZIY-Mi9va0xZlRl9h#pnT3s&jSY<1IXT$aIoa9RIJh}Dxj+EO;^F4v0dYWvK(sQk zGBdMsv9qy*m5@aIKfoZ!!63m9z|5$`z$D1XEXer(2!kX80~0eN12SM|vW!ph9f0hG}Z1O^B*6Ehn-OqP*Jkbzl|#gLUvNGWmR#)}_>jU0oL3L8KE zzs0}#L-~V()NMZ)7FQSWUt#)l<$LgD|C@7cgdgmk@5Xm!?;*n{l1zK- z5~}T1g@*6CwN=2>U+d*NGxq5_C)}@EaQsuXbx*`o5p^A(DdO^zUwYVaY|}Wr!f8qO z{%QA0AMIu5jZ-_b*Rje$UAU8B?lA_V>eWkLZDl(kF>|foF%|!QnR@5ve^%7qnij2o z#^KpR(@pC0j~?Ed+WR`%o^zXQ&$3`?i&LRR*>Ta2wiaG~E|V;)A>Ogp!Qe~9vKQJH zHHOh1w+*vK=$SOIP@xO8@h9t=}o5 zod;SPa+PZ5i2n;Zt$#+3`}9M}+i%YPy>-6U_3FAcrotXut$mB7uNBIDn4$WKCDy8Q zx!x3!rn_6$J5D%rQBa}waM0Jl*kDz)AN;&8`!Dle5BxfR`I>frt9^%`@m}2Bb^F~k z&JVpi9C@WOW^kM<6s_ILr{$M_`pC2HF%+;``!7jtlOV5ImSrU>_5W+*;SJtMx67%Ja6)CnWH-8 zf8^|(=iOiY%u;r>Tvh798G-jFZM)zW!yJ;aGpDU#Urca)bXC`*zdm2{r={lJ{4~4w z;hxr+W@agm1V1i`SZAzcuDQANY*6&&o?^4;e=U>3X8*%m4s>ee+%C0R;)_utK#B#$asoC%Cek!af7T+#=<*%R8 z9PatkI&SAiN2aXmzvzGSYuM7lI*E#~6_IJYUnd&M2|n#;v$2TRC&!E)KO zfad8ZoK`UI5}Du%Ow^alMRq^BxVUSbd%kPPKLhKFu3ptzA!*&EXRhqKIw`5CBYkr8 zMd7DE9+a<33!b0!q@{V%flt1ZGZ)_L(pc=*a*v=G$6ghb9{J49 z%R~G{_NPCSn)iwX<-WX>)!KY(Y3_dp-Hp2*ia%a4|4n~Y#|_;bIx+KVzg^k(Of^;} z_w4l{eMRQql=iBm+wUYk k-h9$=Ur}pKvWv?U>GiAj{nA(*vuWY>HTjmD@&9iE0GEdn2mk;8 literal 0 HcmV?d00001 diff --git a/web/images/gelcap/stick_topic.jpg b/web/images/gelcap/stick_topic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e6236e2aa45c07176af0ab23708fd7a764e4dfb GIT binary patch literal 1575 zcmb7AXHb(_6#c$@=^zl1;8G$bNQepxB1%AtASHr8XbL*JG=%^XgDyi+7e--MHY8LP zr6&;rL<2-nDMmsU3o0lOWg!+ulp?w)Vm9dPjDPpsd1vmMcka1op5lpO0??qkdAb20 z2m&6;0u)~XZ5L)#*s-WcgQS>a(FOt0Q3mdw-oA=4zy*LQbs)IPuvNgJRYt(!5FCj> zBEKCJ28~2vP)H z7~ph;gX>(fe8HjEfBO2Yc_cPl+*;2O3Th(?(RGgxgzq45d2ltyEr$+oPMLa|7kGS* z*HhF~E43v}fRZm_+q|PCSCZn37Df9SiNShxqm71N1SNi6wrf|W$UZmYKbUyN(_j5w ziI(TM>x`6}`1;Z&4%*!j1e6k&#@QR+m*FF3_WUU-mfbOWG<_@CwX!Y5KLjeOp|Z@W zVhYEacc$ec>?2qBn?qHnuq$kqxhRM~P8-T{tf0CGz+YUR(;i)V=zT@{=?qrlH4J6P zb*zoeF|H?@(UPgXa*~F71w7`bs<&h2gWNvrOWMb_Cp=70QDanJkLj!kmT!cQoG#L% zV>|tE`sXN}D`-C&Ti+>BcqX&{t!y-zuBuu~m%m;-$}n5DttABPn0pfP=KX>5H!6es z@k5hjGap~#HN58Sdz898BWI1RDc4JfZBHT4)1%on147nj-*+9ormX4EC%#bkogvy* zZ%T)1K(r0^P|qeBG{3QBl9E?hXj-$$nBxpj(Qqq|Z<9@`^fz2&-p@^VOy7hhrF&ne zE%#&I2{p3LvI%WBV=ty|j+6C=sj`yBQrV4UQnM*P?k3KQQgEAZbEBz;z&0$edTerk zO5NnyMDyQs1*O$-tme?kTfMrR-mw%3j+DPCVYEynwqxe2*}rg(=ke=`nM;HhA8dGP zY4&w&$DNM#=6Q22rQ5W&UA@9DtJlrPm~o4_!k0i&q!A; zx7*K$Du9ov3Lqsr(c*zQK2ikhJ3571kn)@a_5q#cFkfMoJy|cOr{$H$JI}V}SZyQM z?yJ0)-8F%BCl@ZVNE~{#cS7dZeZ{e2gxP_bCTi&Ov^?E?DstwwYj*TmK`yf|DCnA% z#Q(T6eb(bOzb)?4G{4?Zv5I%$gI{PXUH2I(#7JY#Iv%UjGC6z?fZS!&+g|_X{lyga__yUay!F)e}1Op zFOF0Eo9N}Ox4Y)EcdaWV%VB1{8N*Ul0UImImnwj>O=%kg2>ZGez)-!8_3qZmlOr-w zVn(F+{(`%NeY(Fa)8cDk^paQ2Qn&(`4r1wq-Zg!DVyukYm#R)o)72kHHE^WS8$NEp zo*$sbT%fZDSQV~XCgk@(0heP(KrIYAUyeGQhVD*)of3yw$0U$)7nd6|vH7ImWBWEB zJG>;x?VmYCh}t<;zKrTT4 literal 0 HcmV?d00001 diff --git a/web/images/gelcap/unstick_topic.jpg b/web/images/gelcap/unstick_topic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a10f2e1df9c9445b270de2b28b58dbd1cf1605b2 GIT binary patch literal 1613 zcmb7Bc{J2p9KXNWhn$S8*=87PG+9Q{WN(aJ4C2i*$=D02BwHv&USY;a%g8p0VI(`1 z>Qt5%yNG%YEhwZ?(W`l*&O816KKI#(^DxiG2{X#;`RY;A@OTAm9iT5{3G?(O3)$jYXqS z7)cCPVh!TcI!TFjYnQc>Ur`tm4o6C$QRttR|3#wP0EYpJzyl6x02mH};~>#Jpdy|D zz+iCj8yFZIfkmRwV%1n0KyU;EheIgTFAF3V#TpJ^WC$B%jWn=w^2Ro7P2w)!v^?9u z*tJFoKnOVWyAPm&I3f;W#Oh`ofW$)pEaJZ>As7ybJ7rJ=BlHG2n_Yo<{R8p`(%x&( z>qO7MI&l*W2gd;`@b0OQ*>GBrxu8==mCI7?sdxO5Qj0&rPq!xMy5F(bJ~k=>LYizq zWwgtA?}!?X2|21k+m*4~qjW;6KrOdu;j?GK2&`bccf)$khQ;Zk=xsqy)gG}0wHcc! zjeMrZ7&UdH)m!$6)SZ5}kqNKd3|DjAUi!U|&;@gogu}S7R;63_%-=7ew+E?nEI}@?-#$D#@ z+|pTVV!9)9bZ4zwH;lq+dO#{DPg}WEu$m#%*=#KFvv|f?PKQw3#;7yCqX%EdgpY6d~fSM>ox_jCi_Wq@u z)muG^J|a*b(IlktQe4>MoHHqmP{S*%<`~mYzIc-f6|BAeyVVHW*EIIJ3_zcgk`Jpi~eRVBJpKG2|A(8o#t6{c1SOQVT;b4DOaCXZ$cy| zo*fJ;cC^1GQ_aY`7B{}2G}YwpxzfCG*so^l2Jhg`%wqY%gL6(?mGTwUlDoy84u+N| zZuM=o$S$Zp$kwa2YZ;BadEV&8RwK=qpGDxl-ST(JN5Mbjy`l8i3d&DR4Ng27Q83(W zwNREF=Cz|9rX0R+KH!?iZp%UmNlASzEy|Sy!+PyM#zx2!13o9G=cP3LH!WCE4#zb2 zGYlgOTX!35SCh>7@=@Bt%6D!*K{z`zD`;B{&)8P3!k;R&+4GWk*2dX#+$c~tt6%#eP7vFtJo(Q~RB)VL+G|Co%M#h1M3gJUPI&L7JWL@t-_p4(PT`IrV z9s4ZE3Flfhk$wyx==@~}nz=|y`{Zy}ZBSnwtz`Ah`w2xkh+s|9=45&)b{}=?GH}pc zW>{_VIW<&Pay@BD9HWbS_wnRHrsFJWUmYyZr+-XdCKyQiJ~MOY>Y;Co0Hrh`ZWgDw w;wYF{k0$bD$nWE)x!I3jx9;hQfsS9M-c$}xIGR