From ffa005c6859358732489f5884a51693e38390431 Mon Sep 17 00:00:00 2001
From: pb
Date: Fri, 15 Feb 2008 08:41:21 +0000
Subject: [PATCH] incorporating r1628 | chrisg23 | 2007-09-17 10:10:40 +0200
(Mo, 17 Sep 2007) | 1 line
Sourceforge patch 1689988 - rather a large commit, but in fact causes very little visible change. Large single commit is necessary because all these changes are essentially atomic.
git-svn-id: https://svn.libreccm.org/ccm/trunk@8 8810af33-2d31-482b-a856-94f89814c4df
---
ccm-forum/application.xml | 7 +-
ccm-forum/doc/new-features.txt | 86 ++++
ccm-forum/etc/enterprise.init.in | 25 --
ccm-forum/pdl/com/arsdigita/forum/Forum.pdl | 15 +-
.../com/arsdigita/forum/MyForumsPortlet.pdl | 30 ++
ccm-forum/pdl/com/arsdigita/forum/Post.pdl | 45 ++
.../6.5.0-6.5.1/add_anonymous_option.sql | 3 +
.../6.5.0-6.5.1/add_file_attachments.sql | 21 +
.../6.5.0-6.5.1/add_forum_introduction.sql | 2 +
.../add_forum_no_category_posts.sql | 3 +
.../upgrade/6.5.0-6.5.1/add_groups.sql | 20 +
.../upgrade/6.5.0-6.5.1/add_image_uploads.sql | 21 +
.../upgrade/6.5.0-6.5.1/add_privileges.sql | 18 +
.../6.5.0-6.5.1/add_thread_subscriber.sql | 5 +
.../upgrade/oracle-se-6.5.0-6.5.1.sql | 8 +
.../upgrade/postgres-6.5.0-6.5.1.sql | 10 +
.../src/WEB-INF/resources/forum-adapters.xml | 75 ++++
ccm-forum/src/ccm-forum.upgrade | 7 +
.../com/arsdigita/forum/BboardDispatcher.java | 125 ------
.../arsdigita/forum/DailySubscription.java | 12 +-
ccm-forum/src/com/arsdigita/forum/Forum.java | 391 ++++++++++++++++-
.../src/com/arsdigita/forum/ForumConfig.java | 197 ++++++++-
.../forum/ForumConfig_parameter.properties | 54 +++
.../src/com/arsdigita/forum/ForumContext.java | 12 +
.../com/arsdigita/forum/ForumPageBuilder.java | 88 ++++
.../com/arsdigita/forum/ForumPageFactory.java | 70 +++
.../src/com/arsdigita/forum/ForumServlet.java | 47 ++-
.../arsdigita/forum/ForumSubscription.java | 33 +-
.../src/com/arsdigita/forum/Initializer.java | 153 ++++---
ccm-forum/src/com/arsdigita/forum/Loader.java | 43 +-
.../src/com/arsdigita/forum/PageBuilder.java | 35 ++
ccm-forum/src/com/arsdigita/forum/Post.java | 398 +++++++++++++-----
.../arsdigita/forum/PostFileAttachment.java | 130 ++++++
.../forum/PostFileAttachmentURLFinder.java | 67 +++
.../src/com/arsdigita/forum/PostFinder.java | 63 +++
.../arsdigita/forum/PostImageAttachment.java | 131 ++++++
.../RemoveUnattachedAssetsScheduler.java | 115 +++++
.../forum/RemoveUnattachedAssetsTask.java | 41 ++
.../src/com/arsdigita/forum/Subscription.java | 44 +-
.../arsdigita/forum/ThreadPageBuilder.java | 85 ++++
.../arsdigita/forum/ThreadSubscription.java | 93 +++-
.../forum/portlet/MyForumsPortlet.java | 123 ++++++
.../forum/portlet/RecentPostingsPortlet.java | 3 +-
.../FileAttachmentMetadataProvider.java | 98 +++++
.../forum/search/PostMetadataProvider.java | 126 ++++++
.../forum/search/TextContentProvider.java | 58 +++
.../forum/search/XMLContentProvider.java | 79 ++++
.../arsdigita/forum/ui/AttachedFilesStep.java | 376 +++++++++++++++++
.../forum/ui/AttachedFilesTable.java | 179 ++++++++
.../arsdigita/forum/ui/CategoryAddForm.java | 27 +-
.../com/arsdigita/forum/ui/CategoryView.java | 2 +-
.../arsdigita/forum/ui/CategoryWidget.java | 11 +-
.../com/arsdigita/forum/ui/ConfirmStep.java | 75 ++++
.../src/com/arsdigita/forum/ui/Constants.java | 3 +-
.../com/arsdigita/forum/ui/EditPostForm.java | 15 +-
.../arsdigita/forum/ui/ForumAlertsView.java | 4 +-
.../arsdigita/forum/ui/ForumComponent.java | 135 ++++--
.../forum/ui/ForumResources.properties | 26 +-
.../com/arsdigita/forum/ui/ForumUserView.java | 31 +-
.../com/arsdigita/forum/ui/ImagesStep.java | 349 +++++++++++++++
.../com/arsdigita/forum/ui/ImagesTable.java | 184 ++++++++
.../com/arsdigita/forum/ui/MessageView.java | 15 +-
.../com/arsdigita/forum/ui/NewPostForm.java | 110 -----
.../src/com/arsdigita/forum/ui/PostForm.java | 292 ++++++++-----
.../com/arsdigita/forum/ui/PostTextStep.java | 228 ++++++++++
.../arsdigita/forum/ui/ReplyToPostForm.java | 85 ++--
.../forum/ui/ReplyToPostTextStep.java | 74 ++++
.../arsdigita/forum/ui/RootPostTextStep.java | 82 ++++
.../arsdigita/forum/ui/ThreadAlertsList.java | 6 +-
.../arsdigita/forum/ui/ThreadComponent.java | 37 +-
.../com/arsdigita/forum/ui/ThreadDisplay.java | 72 ++--
.../com/arsdigita/forum/ui/ThreadList.java | 6 +-
.../src/com/arsdigita/forum/ui/TopicList.java | 6 +-
.../com/arsdigita/forum/ui/TopicSelector.java | 4 +-
.../forum/ui/admin/AdminEditPane.java | 66 +++
.../forum/ui/admin/GroupMemberDisplay.java | 12 +-
.../forum/ui/admin/GroupMemberPicker.java | 13 +
.../forum/ui/admin/ModeratorEditPane.java | 2 +-
.../forum/ui/admin/PermissionsView.java | 63 +++
.../forum/ui/admin/ReaderEditPane.java | 66 +++
.../forum/ui/admin/RejectionForm.java | 144 ++++++-
.../arsdigita/forum/ui/admin/SetupView.java | 212 ++++++++++
.../forum/ui/admin/ThreadCreatorEditPane.java | 63 +++
.../ui/admin/ThreadResponderEditPane.java | 64 +++
.../arsdigita/forum/ui/admin/UserPicker.java | 19 +-
.../forum/upgrade/CreateContainerGroups.java | 155 +++++++
.../upgrade/CreateGroupsAndPortletType.java | 97 +++++
ccm-forum/web/WEB-INF/bebop-define.tld | 395 -----------------
ccm-forum/web/WEB-INF/bebop-show.tld | 117 -----
ccm-forum/web/WEB-INF/web.xml | 11 -
ccm-forum/web/packages/forum/xsl/forum.xsl | 4 +-
91 files changed, 5889 insertions(+), 1363 deletions(-)
create mode 100644 ccm-forum/doc/new-features.txt
create mode 100644 ccm-forum/pdl/com/arsdigita/forum/MyForumsPortlet.pdl
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_file_attachments.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_groups.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_image_uploads.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_privileges.sql
create mode 100644 ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql
create mode 100644 ccm-forum/sql/ccm-forum/upgrade/oracle-se-6.5.0-6.5.1.sql
create mode 100644 ccm-forum/sql/ccm-forum/upgrade/postgres-6.5.0-6.5.1.sql
delete mode 100755 ccm-forum/src/com/arsdigita/forum/BboardDispatcher.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ForumPageBuilder.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ForumPageFactory.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/PageBuilder.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/PostFileAttachment.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/PostFileAttachmentURLFinder.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/PostFinder.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/PostImageAttachment.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsScheduler.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsTask.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ThreadPageBuilder.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/portlet/MyForumsPortlet.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/search/FileAttachmentMetadataProvider.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/search/PostMetadataProvider.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/search/TextContentProvider.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/search/XMLContentProvider.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesTable.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/ConfirmStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/ImagesStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/ImagesTable.java
delete mode 100755 ccm-forum/src/com/arsdigita/forum/ui/NewPostForm.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/PostTextStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostTextStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/RootPostTextStep.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/AdminEditPane.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/PermissionsView.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/ReaderEditPane.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/SetupView.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadCreatorEditPane.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadResponderEditPane.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/upgrade/CreateContainerGroups.java
create mode 100644 ccm-forum/src/com/arsdigita/forum/upgrade/CreateGroupsAndPortletType.java
diff --git a/ccm-forum/application.xml b/ccm-forum/application.xml
index 3d1c1eee1..778729927 100755
--- a/ccm-forum/application.xml
+++ b/ccm-forum/application.xml
@@ -2,11 +2,12 @@
-
-
+
+
+
diff --git a/ccm-forum/doc/new-features.txt b/ccm-forum/doc/new-features.txt
new file mode 100644
index 000000000..a6b86d341
--- /dev/null
+++ b/ccm-forum/doc/new-features.txt
@@ -0,0 +1,86 @@
+Main new features included in this release are:
+
+Fine grained forum permissions
+Allow file attachments and images in posts
+Contents of posts are searchable
+New portlet type lising links to all forums user has read access to
+Allow automatic thread subscription for thread starter (useful for noticeboard type forums)
+Forum admin can prevent posts with no topic
+Expiry can be specified for all types of forum
+Reply count calculation fixed
+HTML Editor can be used for posts
+Subscription emails can (and should) be sent as html emails)
+
+Other minor changes, fixes and configurable features are also included.
+Check new config parameter descriptions in com.arsdigita.forum.ForumConfig_parameter.properties
+
+After deployment, to install new features, either get rid of existing forum app, and load new version, OR
+
+ccm upgrade ccm-forum --from-version 6.5.0 --to-version 6.5.1
+ccm upgrade ccm-forum --from-version 6.5.1 --to-version 6.5.2
+ccm-run com.arsdigita.london.search.Reindexer --object-type com.arsdigita.forum.Post
+
+
+
+When developing this, I tried to ensure that a basic deployment will not affect the XML
+that is produced by the current forum application.
+
+I have tested the new implementation with Coventry's theme. There is one theme amendment required (because of a bug fix).
+In current release, the drop down list for filtering threads by category has the same name as the drop down list for selecting a category when making a new post. This means that the selected value carries through . ie if you have filtered the threads then make a new post, the new post has the filter category selected as default. More importantly, if you make a post and assign a category, then the thread list is filtered after you complete the post.
+
+To fix the bug, I renamed the drop down list in the post form from topic to PostTopic. This means the category drop down is not visible until the two references to @name='topic' in the forum:postForm template are changed to @name='postTopic'
+
+Only other visible changes if the patch is applied without changing config
+are:
+
+Reply count only includes posts that have been approved
+
+Posts are searchable from the main site search. This is a change from the current behaviour . if not desired then it could be made configurable.
+
+Moderation form and emails are formatted slightly differently
+
+recent forum postings portlet prevents users creating new forum application .
+only site admin can do this. Also filters forums to those that the user has
+read access on.
+
+New portlet . my forums. Lists links to forums that user has read access to.
+
+The other non-visble effect is that the wizard uses java session rather than
+hidden fields. This approach makes it much easier to include links in form
+steps (eg remove an uploaded file etc). The impact is that users in a load
+balanced environment need to consider session affinity. In our production
+environment, this is accomplished by the server that sprays requests to the
+various back end servers. It identifies each browser session and routes all
+their requests to the same back end server. Hence there is no replication of
+session - the user is guaranteed to end up at the server that holds their java
+session. As a result, when a backend server is stopped, there is a risk that a
+user with session on that server in the middle of creating a post will lose
+information entered up to that point. On our site we live with this small risk
+but mitigate it by restarting servers at unsociable hours where possible.
+
+I have put examle theme files in
+ccm-ldn-aplaws/web/__ccm__/themes/aplaws/forum-example: forum-index.xsl,
+forum-index.css and the contents of images/forum
+
+To have a look at a forum using these files, copy the xsl and css to the top
+level of your theme and make a new forum directory in images and copy the
+images there. I.m afraid these files have continued the existing format of
+putting all the templates in a single file, so they are not the most easily
+maintained, and I make no guarantees about the content, but they do work. and
+if required they may be used as a basis for your own look and feel.
+
+
+There is a separate application - ccm-categorised-forum that adds category path and menu components to the front end,
+and adds a categorisation tab for admin users. Load this application if you would like this functionality.
+
+When a forum is created, only site admin can access the admin tabs,
+until you assign users/groups to the forum admin group under the permissions tab.
+
+Next things I plan to do are:
+
+list pending and reapprove posts under the moderation tab
+create a user info page so users can write a bit about themselves
+allow thread branching so administrators can split long threads or threads that have strayed from the point.
+Allow different thread views - paginated full details, or tree of titles with one post visible (a la sourceforge)
+
+chris.gilbert@westsussex.gov.uk
diff --git a/ccm-forum/etc/enterprise.init.in b/ccm-forum/etc/enterprise.init.in
index 14d22c5ed..e69de29bb 100755
--- a/ccm-forum/etc/enterprise.init.in
+++ b/ccm-forum/etc/enterprise.init.in
@@ -1,25 +0,0 @@
-// Forum initialization file
-//
-// ::replyHostName:: -> example.com
-// ::digestUserEmail:: -> digests
-// ::adminCanEditPosts:: -> true
-// ::authorCanEditPosts:: -> true
-// ::forums:: -> {}
-
-init com.arsdigita.forum.LegacyInitializer {
- // All outbound bboard message will have return address as the
- // following format: forumID.bboard@hostname
- replyHostName = "::replyHostName::";
- // The email address that daily digests come from
- digestUserEmail = "::digests::";
- // whether administrators can edit posts
- adminCanEditPosts = ::adminCanEditPosts::;
- // whether the author of a post can edit it later
- authorCanEditPosts = ::authorCanEditPosts::;
-
- forums = ::forums::;
-}
-
-init com.arsdigita.domain.installer.DomainObjectTraversalInitializer {
- adapters = { "/WEB-INF/resources/forum-adapters.xml" };
-}
diff --git a/ccm-forum/pdl/com/arsdigita/forum/Forum.pdl b/ccm-forum/pdl/com/arsdigita/forum/Forum.pdl
index b96e10436..9181a49cd 100755
--- a/ccm-forum/pdl/com/arsdigita/forum/Forum.pdl
+++ b/ccm-forum/pdl/com/arsdigita/forum/Forum.pdl
@@ -32,8 +32,16 @@ object type Forum extends Application {
Boolean [1..1] isModerated = forum_forums.is_moderated;
Boolean [1..1] isNoticeboard = forum_forums.is_noticeboard;
+ component Group [0..1] adminGroup =
+ join forum_forums.admin_group_id to groups.group_id;
component Group [0..1] moderationGroup =
join forum_forums.mod_group_id to groups.group_id;
+ component Group [0..1] threadCreateGroup =
+ join forum_forums.create_group_id to groups.group_id;
+ component Group [0..1] threadRespondGroup =
+ join forum_forums.respond_group_id to groups.group_id;
+ component Group [0..1] readGroup =
+ join forum_forums.read_group_id to groups.group_id;
component ForumSubscription[0..n] subscriptions =
join forum_forums.forum_id to forum_subscriptions.forum_id;
@@ -44,7 +52,12 @@ object type Forum extends Application {
join forum_forums.lifecycle_definition_id to lifecycle_definitions.definition_id;
BigDecimal [0..1] expireAfter = forum_forums.expire_after;
-
+ Boolean [1..1] fileAttachmentsAllowed = forum_forums.file_attachments_allowed;
+ Boolean [1..1] imageUploadsAllowed = forum_forums.image_uploads_allowed;
+ Boolean [1..1] autoSubscribeThreadStarter = forum_forums.subscribe_thread_starter;
+ Boolean [1..1] noCategoryPostsAllowed = forum_forums.no_category_posts_allowed;
+ Boolean [1..1] anonymousPostsAllowed = forum_forums.anonymous_posts_allowed;
+ String [0..1] introduction = forum_forums.introduction VARCHAR(4000);
reference key (forum_forums.forum_id);
}
diff --git a/ccm-forum/pdl/com/arsdigita/forum/MyForumsPortlet.pdl b/ccm-forum/pdl/com/arsdigita/forum/MyForumsPortlet.pdl
new file mode 100644
index 000000000..e40f68632
--- /dev/null
+++ b/ccm-forum/pdl/com/arsdigita/forum/MyForumsPortlet.pdl
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// $Id: RecentPostingsPortlet.pdl 285 2005-02-22 00:29:02Z sskracic $
+// $DateTime: 2004/08/17 23:26:27 $
+model com.arsdigita.forum;
+
+import com.arsdigita.portal.Portlet;
+
+// lists links to forums for which user has read access
+
+object type MyForumsPortlet extends Portlet {
+
+// no attributes for this one
+
+}
diff --git a/ccm-forum/pdl/com/arsdigita/forum/Post.pdl b/ccm-forum/pdl/com/arsdigita/forum/Post.pdl
index bd22571c1..f18fbde31 100755
--- a/ccm-forum/pdl/com/arsdigita/forum/Post.pdl
+++ b/ccm-forum/pdl/com/arsdigita/forum/Post.pdl
@@ -21,6 +21,9 @@ model com.arsdigita.forum;
import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.kernel.Party;
+import com.arsdigita.cms.FileAsset;
+import com.arsdigita.cms.ImageAsset;
+
object type Post extends com.arsdigita.messaging.ThreadedMessage {
@@ -29,6 +32,31 @@ object type Post extends com.arsdigita.messaging.ThreadedMessage {
aggressive load(moderator.id);
}
+object type PostFileAttachment extends FileAsset {
+ Integer[0..1] fileOrder = forum_post_files.file_order INTEGER;
+ reference key (forum_post_files.file_id);
+}
+
+object type PostImageAttachment extends ImageAsset {
+ Integer[0..1] imageOrder = forum_post_images.image_order INTEGER;
+ reference key (forum_post_images.image_id);
+}
+
+association {
+
+ composite Post[0..1] fileMessage = join forum_post_files.post_id to forum_posts.post_id;
+ component PostFileAttachment[0..n] files = join forum_posts.post_id to forum_post_files.post_id;
+
+}
+
+association {
+
+ composite Post[0..1] imageMessage = join forum_post_images.post_id to forum_posts.post_id;
+ component PostImageAttachment[0..n] images = join forum_posts.post_id to forum_post_images.post_id;
+
+}
+
+
association {
Party [0..1] moderator = join forum_posts.moderator to parties.party_id;
Post [0..1] moderatedMessage = join parties.party_id to forum_posts.moderator;
@@ -53,3 +81,20 @@ query threadModerationStatus {
id = message_threads.thread_id;
}
}
+
+// Subquery for filtering out threads where root post is of a
+// particular status (eg unconfirmed)
+//
+//query threadStatus {
+ // BigDecimal id;
+//
+ // do {
+ // select m.thread_id
+ // from forum_posts f,
+ // message_threads m
+ // where m.root_id = f.post_id
+ // and f.status <> :status2
+ // } map {
+ // id = message_threads.thread_id;
+ // }
+// }
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql
new file mode 100644
index 000000000..2baf2087e
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql
@@ -0,0 +1,3 @@
+alter table forum_forums add (anonymous_posts_allowed CHAR(1));
+
+update forum_forums set anonymous_posts_allowed = 0;
\ No newline at end of file
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_file_attachments.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_file_attachments.sql
new file mode 100644
index 000000000..0437bca96
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_file_attachments.sql
@@ -0,0 +1,21 @@
+create table forum_post_files
+ (post_id NUMBER,
+ file_id NUMBER not null,
+ file_order NUMBER);
+
+
+
+alter table forum_post_files add
+ constraint FORU_POS_FILES_FILE_ID_F_XBKED foreign key (file_id)
+ references cms_files(file_id);
+
+alter table forum_post_files add
+ constraint FORU_POS_FILES_POST_ID_F_K0XJQ foreign key (post_id)
+ references forum_posts(post_id);
+
+alter table forum_forums add (file_attachments_allowed CHAR(1));
+
+update forum_forums set file_attachments_allowed = 0;
+
+
+
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql
new file mode 100644
index 000000000..2a6037d74
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql
@@ -0,0 +1,2 @@
+ALTER TABLE FORUM_FORUMS ADD (
+ INTRODUCTION VARCHAR2(4000) );
\ No newline at end of file
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql
new file mode 100644
index 000000000..0b11148cb
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql
@@ -0,0 +1,3 @@
+alter table forum_forums add (no_category_posts_allowed CHAR(1));
+
+update forum_forums set no_category_posts_allowed = 1;
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_groups.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_groups.sql
new file mode 100644
index 000000000..f05d54834
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_groups.sql
@@ -0,0 +1,20 @@
+alter table forum_forums
+add (admin_group_id NUMBER,
+ create_group_id NUMBER,
+ respond_group_id NUMBER,
+ read_group_id NUMBER);
+
+
+alter table forum_forums add
+ constraint foru_foru_admi_grou_id_f_k0nw6 foreign key (admin_group_id)
+ references groups(group_id);
+alter table forum_forums add
+ constraint foru_foru_crea_grou_id_f_f7x57 foreign key (create_group_id)
+ references groups(group_id);
+alter table forum_forums add
+ constraint foru_foru_respo_gro_id_f_rnofz foreign key (respond_group_id)
+ references groups(group_id);
+alter table forum_forums add
+ constraint foru_forum_rea_grou_id_f_itati foreign key (read_group_id)
+ references groups(group_id);
+
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_image_uploads.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_image_uploads.sql
new file mode 100644
index 000000000..da6af6394
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_image_uploads.sql
@@ -0,0 +1,21 @@
+create table forum_post_images
+ (post_id NUMBER,
+ image_id NUMBER not null,
+ image_order NUMBER);
+
+
+
+alter table forum_post_images add
+ constraint FORU_POS_IMAGE_IMAG_ID_F_WYRXA foreign key (image_id)
+ references cms_images(image_id);
+
+alter table forum_post_images add
+ constraint FORU_POS_IMAGE_POST_ID_F_1HH02 foreign key (post_id)
+ references forum_posts(post_id);
+
+alter table forum_forums add (image_uploads_allowed CHAR(1));
+
+update forum_forums set image_uploads_allowed = 0;
+
+
+
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_privileges.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_privileges.sql
new file mode 100644
index 000000000..499b270c5
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_privileges.sql
@@ -0,0 +1,18 @@
+insert into acs_privileges (privilege)
+values ('forum_read');
+
+insert into acs_privileges (privilege)
+values ('forum_create_thread');
+
+insert into acs_privileges (privilege)
+values ('forum_respond');
+
+insert into acs_privilege_hierarchy (privilege, child_privilege)
+values ('forum_moderation', 'forum_create_thread');
+
+insert into acs_privilege_hierarchy (privilege, child_privilege)
+values ('forum_create_thread', 'forum_respond');
+
+insert into acs_privilege_hierarchy (privilege, child_privilege)
+values ('forum_respond', 'forum_read');
+
diff --git a/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql
new file mode 100644
index 000000000..51f326be1
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql
@@ -0,0 +1,5 @@
+alter table forum_forums add (subscribe_thread_starter CHAR(1));
+
+update forum_forums set subscribe_thread_starter = 0;
+
+
diff --git a/ccm-forum/sql/ccm-forum/upgrade/oracle-se-6.5.0-6.5.1.sql b/ccm-forum/sql/ccm-forum/upgrade/oracle-se-6.5.0-6.5.1.sql
new file mode 100644
index 000000000..4155005c2
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/upgrade/oracle-se-6.5.0-6.5.1.sql
@@ -0,0 +1,8 @@
+@@ ../default/upgrade/6.5.0-6.5.1/add_privileges.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_groups.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_file_attachments.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_image_uploads.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql
+@@ ../default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql
diff --git a/ccm-forum/sql/ccm-forum/upgrade/postgres-6.5.0-6.5.1.sql b/ccm-forum/sql/ccm-forum/upgrade/postgres-6.5.0-6.5.1.sql
new file mode 100644
index 000000000..1be788736
--- /dev/null
+++ b/ccm-forum/sql/ccm-forum/upgrade/postgres-6.5.0-6.5.1.sql
@@ -0,0 +1,10 @@
+\i ../default/upgrade/6.5.0-6.5.1/add_thread_subscriber.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_privileges.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_groups.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_privileges.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_file_attachments.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_forum_introduction.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_image_uploads.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_forum_no_category_posts.sql
+\i ../default/upgrade/6.5.0-6.5.1/add_anonymous_option.sql
+
diff --git a/ccm-forum/src/WEB-INF/resources/forum-adapters.xml b/ccm-forum/src/WEB-INF/resources/forum-adapters.xml
index 337d603a7..0951e26ab 100755
--- a/ccm-forum/src/WEB-INF/resources/forum-adapters.xml
+++ b/ccm-forum/src/WEB-INF/resources/forum-adapters.xml
@@ -79,6 +79,8 @@
+
+
@@ -132,4 +134,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ccm-forum/src/ccm-forum.upgrade b/ccm-forum/src/ccm-forum.upgrade
index 9af6f4619..3fcacaaac 100755
--- a/ccm-forum/src/ccm-forum.upgrade
+++ b/ccm-forum/src/ccm-forum.upgrade
@@ -5,4 +5,11 @@
+
+
+
+
+
+
+
diff --git a/ccm-forum/src/com/arsdigita/forum/BboardDispatcher.java b/ccm-forum/src/com/arsdigita/forum/BboardDispatcher.java
deleted file mode 100755
index aa0d68ec8..000000000
--- a/ccm-forum/src/com/arsdigita/forum/BboardDispatcher.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-package com.arsdigita.forum;
-
-import com.arsdigita.bebop.Page;
-import com.arsdigita.bebop.PageFactory;
-import com.arsdigita.bebop.PageState;
-import com.arsdigita.bebop.page.BebopMapDispatcher;
-import com.arsdigita.bebop.event.RequestEvent;
-import com.arsdigita.bebop.event.RequestListener;
-import com.arsdigita.bebop.parameters.BigDecimalParameter;
-import com.arsdigita.forum.ui.Constants;
-import com.arsdigita.forum.ui.ForumComponent;
-import com.arsdigita.forum.ui.ThreadComponent;
-
-import java.math.BigDecimal;
-
-import org.apache.log4j.Logger;
-
-/**
- * Maps the bboard user interface onto "index.jsp" and "thread.jsp".
- *
- * @author Kevin Scaldeferri
- * @author Vadim Nasardinov (vadimn@redhat.com)
- *
- * @version $Revision: #18 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
- */
-public class BboardDispatcher extends BebopMapDispatcher
- implements Constants {
- public static final String versionId =
- "$Id: BboardDispatcher.java 287 2005-02-22 00:29:02Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
-
- private static final String XSL_HOOK = "forum";
-
- private static final Logger s_log = Logger.getLogger
- (BboardDispatcher.class);
-
- /**
- * Constructor. Instantiates the subsite url/page mapping.
- */
- public BboardDispatcher() {
- s_log.warn("BboardDispatcher created!");
-
- Page index = buildForumPage(new BigDecimalParameter(TOPIC_PARAM));
- addPage("", index);
- addPage("index.jsp", index);
- addPage("thread.jsp", buildThreadPage(
- new BigDecimalParameter(THREAD_PARAM)));
- }
-
- static Page buildThreadPage(BigDecimalParameter stateParam) {
- Page threadPage = PageFactory.buildPage(XSL_HOOK, "Threads", "forumThreadPage");
- threadPage.add(new ThreadComponent());
- // Register the thread id parameter as a global state parameter.
- threadPage.addGlobalStateParam(stateParam);
- threadPage.addRequestListener
- (new ThreadPageRequestListener(stateParam));
- threadPage.lock();
- return threadPage;
- }
-
- static Page buildForumPage(BigDecimalParameter stateParam) {
- Page page = PageFactory.buildPage(XSL_HOOK, "Forum", "forumPage");
- ForumComponent forumComp = new ForumComponent();
- page.add(forumComp);
- page.addGlobalStateParam(stateParam);
- page.addRequestListener(new ForumPageRequestListener(stateParam, forumComp));
- page.lock();
- return page;
- }
-
- private static class ThreadPageRequestListener implements RequestListener {
- private BigDecimalParameter m_threadID;
-
- public ThreadPageRequestListener(BigDecimalParameter threadID) {
- m_threadID = threadID;
- }
-
-
- public void pageRequested(RequestEvent event) {
- PageState state = event.getPageState();
- ForumContext context = ForumContext.getContext(state);
- context.setThreadID
- ((BigDecimal) event.getPageState().getValue(m_threadID));
- }
- }
-
- private static class ForumPageRequestListener implements RequestListener {
- private BigDecimalParameter m_categorySelection;
- private ForumComponent m_forumComp;
-
- public ForumPageRequestListener(BigDecimalParameter categorySelection,
- ForumComponent forumComp) {
- m_categorySelection = categorySelection;
- m_forumComp = forumComp;
- }
-
- public void pageRequested(RequestEvent event) {
-
- PageState state = event.getPageState();
- ForumContext context = ForumContext.getContext(state);
-
- context.setCategorySelection
- ((BigDecimal) event.getPageState().getValue(m_categorySelection));
- }
- }
-}
diff --git a/ccm-forum/src/com/arsdigita/forum/DailySubscription.java b/ccm-forum/src/com/arsdigita/forum/DailySubscription.java
index 7b61634e0..5213f12d1 100755
--- a/ccm-forum/src/com/arsdigita/forum/DailySubscription.java
+++ b/ccm-forum/src/com/arsdigita/forum/DailySubscription.java
@@ -36,7 +36,7 @@ import java.math.BigDecimal;
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
*
- * @version $Revision: #8 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
+ * @version $Revision: 1.1 $ $Author: chrisg23 $ $DateTime: 2004/08/17 23:26:27 $
*/
public class DailySubscription extends ForumSubscription {
@@ -94,6 +94,11 @@ public class DailySubscription extends ForumSubscription {
return BASE_DATA_OBJECT_TYPE;
}
+
+ public String getSubscriptionGroupName() {
+ return "Daily Digest Subscription Group";
+ }
+
private Digest getDigest() {
if (m_digest == null) {
DataObject digestData = (DataObject) get(DIGEST);
@@ -115,6 +120,11 @@ public class DailySubscription extends ForumSubscription {
public void sendNotification(Post post) {
Notification notification = new Notification(getGroup(), post);
notification.setDigest(getDigest());
+ if (Forum.getConfig().deleteNotifications()) {
+// make sure we don't delete the post itself!!!
+ notification.setMessageDelete(Boolean.FALSE);
+ notification.setIsPermanent(Boolean.FALSE);
+ }
notification.save();
}
diff --git a/ccm-forum/src/com/arsdigita/forum/Forum.java b/ccm-forum/src/com/arsdigita/forum/Forum.java
index cc027e6d8..f05d9ea3d 100755
--- a/ccm-forum/src/com/arsdigita/forum/Forum.java
+++ b/ccm-forum/src/com/arsdigita/forum/Forum.java
@@ -18,6 +18,10 @@
*/
package com.arsdigita.forum;
+import java.math.BigDecimal;
+
+import org.apache.log4j.Logger;
+
import com.arsdigita.categorization.Category;
import com.arsdigita.cms.lifecycle.LifecycleDefinition;
import com.arsdigita.domain.DataObjectNotFoundException;
@@ -37,27 +41,27 @@ import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.DataQuery;
import com.arsdigita.persistence.Filter;
+import com.arsdigita.persistence.FilterFactory;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.Session;
import com.arsdigita.persistence.SessionManager;
import com.arsdigita.util.Assert;
import com.arsdigita.web.Application;
-import java.math.BigDecimal;
-import org.apache.log4j.Logger;
/**
* The Forum class represents a discussion forum.
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
*
- * @version $Revision: #25 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
+ * @version $Revision: 1.7 $ $Author: chrisg23 $ $DateTime: 2004/08/17 23:26:27 $
*/
public class Forum extends Application {
+ public static final String THREAD_SUBSCRIPTION_GROUPS_NAME = "Thread Subscription Groups";
public static final String versionId =
- "$Id: Forum.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
+ "$Id: Forum.java 1628 2007-09-17 08:10:40Z chrisg23 $"
+ + "$Author: chrisg23 $"
+ + "$DateTime: 2004/08/17 23:26:27 $";
private static ForumConfig s_config = new ForumConfig();
@@ -76,18 +80,48 @@ public class Forum extends Application {
"com.arsdigita.forum.Forum";
public static final String PACKAGE_TYPE = "forum";
-
- public static final String FORUM_MODERATION_PRIVILEGE
- = "forum_moderation";
-
+ //////
+ //Forum specific privileges
+ /////
+ public static final String FORUM_MODERATION_PRIVILEGE = "forum_moderation";
+ public static final String CREATE_THREAD_PRIVILEGE = "forum_create_thread";
+ public static final String RESPOND_TO_THREAD_PRIVILEGE = "forum_respond";
+ // separate read privilege required because all public users
+ // have READ on homepage, which is parent of forum, hence
+ // everyone inherits READ cg
+ //
+ // note in hindsight, I have stopped homepage being set as
+ // permission context for forum, because site search checks
+ // for READ privilege anyway, and so search results were being
+ // returned for non public posts. This means there is no longer
+ // any need for a separate forum_read privilege, though it
+ // does no harm. Now removed
+ // public static final String FORUM_READ_PRIVILEGE = "forum_read";
+
+ ///////
+ // pdl forum attribute/association names
+ ///////
private static final String POSTS = "posts";
private static final String SUBSCRIPTIONS = "subscriptions";
private static final String MODERATION = "isModerated";
private static final String NOTICEBOARD = "isNoticeboard";
+ private static final String ADMIN_GROUP = "adminGroup";
private static final String MODERATION_GROUP = "moderationGroup";
+ private static final String THREAD_CREATE_GROUP = "threadCreateGroup";
+ private static final String THREAD_RESPONDER_GROUP = "threadRespondGroup";
+ private static final String READ_GROUP = "readGroup";
private static final String CATEGORY = "category";
private static final String EXPIRE_AFTER = "expireAfter";
private static final String LIFECYCLE_DEFINITION = "lifecycleDefinition";
+ // additional attributes added chris.gilbert@westsussex.gov.uk
+ private static final String ALLOW_FILE_ATTACHMENTS =
+ "fileAttachmentsAllowed";
+ private static final String ALLOW_IMAGE_UPLOADS = "imageUploadsAllowed";
+ private static final String AUTOSUBSCRIBE_THREAD_STARTER =
+ "autoSubscribeThreadStarter";
+ private static final String INTRODUCTION = "introduction";
+ private static final String NO_CATEGORY_POSTS = "noCategoryPostsAllowed";
+ private static final String ANONYMOUS_POSTS = "anonymousPostsAllowed";
public Forum(DataObject data) {
super(data);
@@ -113,16 +147,26 @@ public class Forum extends Application {
* category for the Forum in the event that the Forum should be
* categorized.
* This also sets up instant and daily subscriptions on the Forum.
- * The default for moderation is false
+ * The default for moderation is false.
+ *
+ * Also sets default values for other forum settings. These can be
+ * amended under the setup tab in the ui
*/
public static Forum create(String urlName, String title,
Application parent, boolean moderated) {
s_log.debug("creating forum " + title);
Forum forum = (Forum) Application.createApplication
- (BASE_DATA_OBJECT_TYPE, urlName, title, parent);
+ (BASE_DATA_OBJECT_TYPE, urlName, title, parent, true);
forum.setModerated(moderated);
+ // default settings ensure legacy forum users do not
+ // see any change chris.gilbert@westsussex.gov.uk
+ forum.setAllowFileAttachments(false);
+ forum.setAllowImageUploads(false);
+ forum.setAutoSubscribeThreadCreator(false);
+ forum.setNoCategoryPostsAllowed(true);
+ forum.setAnonymousPostsAllowed(false);
return forum;
}
@@ -151,6 +195,22 @@ public class Forum extends Application {
}
/**
+ * Set introduction
+ */
+ public void setIntroduction(String introduction) {
+ set(INTRODUCTION, introduction);
+ }
+
+ /**
+ * @return introduction
+ */
+
+ public String getIntroduction() {
+ return (String) get(INTRODUCTION);
+
+ }
+
+ /**
* creates a Root Category for the forum.
*/
private Category createRootCategory() {
@@ -162,7 +222,11 @@ public class Forum extends Application {
return category;
}
- private void createModerationGroup() {
+ private void createGroups() {
+ Group administrators = new Group();
+ administrators.setName(getTitle() + " Administrators");
+ setAssociation(ADMIN_GROUP, administrators);
+
Group moderators = new Group();
moderators.setName(getTitle() + " Moderators");
setAssociation( MODERATION_GROUP, moderators );
@@ -176,6 +240,37 @@ public class Forum extends Application {
// Actually, the only hack involved is making the email address unique.
String email = "forum-moderator-" + getID() + "-" + moderators.getID() + "@" + s_config.getReplyHostName();
moderators.setPrimaryEmail(new EmailAddress(email));
+
+ // chris.gilbert@westsussex.gov.uk create additional groups for privilege
+ // assignment - could have assigned privileges directly without having associated
+ // groups, but this reduces rows in the (already enormous) dnm_permissions
+ // table
+ Group threadCreators = new Group();
+ threadCreators.setName(getTitle() + " Thread Creators");
+ setAssociation(THREAD_CREATE_GROUP, threadCreators);
+
+ Group threadResponders = new Group();
+ threadResponders.setName(getTitle() + " Thread Responders");
+ setAssociation(THREAD_RESPONDER_GROUP, threadResponders);
+
+ Group forumReaders = new Group();
+ forumReaders.setName(getTitle() + " Readers");
+ setAssociation(READ_GROUP, forumReaders);
+
+ Group container = getGroup();
+
+ container.addSubgroup(administrators);
+ container.addSubgroup(moderators);
+ container.addSubgroup(threadCreators);
+ container.addSubgroup(threadResponders);
+ container.addSubgroup(forumReaders);
+ Group threadSubscriptions = new Group();
+ threadSubscriptions.setName(THREAD_SUBSCRIPTION_GROUPS_NAME);
+ container.addSubgroup(threadSubscriptions);
+ container.save();
+
+
+
}
public void initialize() {
@@ -184,8 +279,13 @@ public class Forum extends Application {
if (isNew()) {
setModerated(false);
setNoticeboard(false);
+ setAllowFileAttachments(false);
+ setAllowImageUploads(false);
+ setAutoSubscribeThreadCreator(false);
+ setNoCategoryPostsAllowed(true);
+ setAnonymousPostsAllowed(false);
createRootCategory();
- createModerationGroup();
+
}
}
@@ -199,14 +299,71 @@ public class Forum extends Application {
protected void afterSave() {
if (m_wasNew) {
PermissionService.setContext(getRootCategory(), this);
+ createGroups();
+ if (getAdminGroup() != null) {
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.ADMIN,
+ this,
+ getAdminGroup()));
+ s_log.debug(
+ "Current user : "
+ + Kernel.getContext().getParty().getPrimaryEmail()
+ + " class is "
+ + Kernel.getContext().getParty().getClass());
+ //
+ // chris.gilbert@westsussex.gov.uk Original plan was that creator of forum
+ // is administrator by default, but party from Kernel at this point in code is
+ // acs-system-party - creation must happen in a KernelExcersion somewhere
+ // though I can't immediately see where.
+ // as a consequence, code below justs causes a classcast exception,
+ //
+ // revisit, but in meantime, only site admin can administer new forum
+ // until forum admin permissions set in UI
+ //
+ // User creator = (User) Kernel.getContext().getParty();
+ // can't be null but let's be supercautious
+ // if (creator != null) {
+ // getAdminGroup().addMember(creator);
+ // }
+ ///
+ }
if (getModerationGroup() != null ) {
PermissionService.grantPermission(
new PermissionDescriptor(
PrivilegeDescriptor.get(FORUM_MODERATION_PRIVILEGE),
this,
- getModerationGroup())
- );
+ getModerationGroup()));
+ }
+ if (getThreadCreateGroup() != null) {
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.get(CREATE_THREAD_PRIVILEGE),
+ this,
+ getThreadCreateGroup()));
+ // chris.gilbert@westsussex.gov.uk
+ // wouldn't do this normally, but this enables legacy implementations
+ // to use new version without any side effects
+ // public can view forum by default and see create thread link - existing
+ // code forces login if link is selected
+ getThreadCreateGroup().addMember(Kernel.getPublicUser());
+ }
+
+ if (getThreadResponderGroup() != null) {
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.get(RESPOND_TO_THREAD_PRIVILEGE),
+ this,
+ getThreadResponderGroup()));
+ }
+
+ if (getReadGroup() != null) {
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.READ,
+ this,
+ getReadGroup()));
}
KernelExcursion excursion = new KernelExcursion() {
protected void excurse() {
@@ -243,7 +400,15 @@ public class Forum extends Application {
}
- super.afterSave();
+ // chris.gilbert@westsussex.gov.uk line removed.
+ // afterSave in Application sets permission
+ // context of forum to parent app (portal homepage)
+ // don't want to inherit permissions of portal,
+ // as public users have 'READ' privilege on this
+ // and so get shown postings in search results.
+ //
+ //
+ // super.afterSave();
}
protected String getBaseDataObjectType() {
@@ -287,6 +452,38 @@ public class Forum extends Application {
}
/**
+ * gets all pending messages and messages for reapproval - allows
+ * moderators to see which messages require their attention
+ * @return
+ */
+ public DataAssociation getPendingPosts() {
+ // doesn't use getPosts in view of the warning that it
+ // may disappear
+ DataAssociation posts = (DataAssociation) get(POSTS);
+ FilterFactory factory = posts.getFilterFactory();
+ Filter pending = factory.equals(Post.STATUS, Post.PENDING);
+ Filter reapprove = factory.equals(Post.STATUS, Post.REAPPROVE);
+ ;
+
+ posts.addFilter(factory.or().addFilter(pending).addFilter(reapprove));
+
+ return posts;
+ }
+
+ /**
+ * gets all suppressed messages - allows moderators to see which messages
+ * heve been rejectedrequire their attention
+ * @return
+ */
+ public DataAssociation getSuppressedPosts() {
+ // doesn't use getPosts in view of the warning that it
+ // may disappear
+ DataAssociation posts = (DataAssociation) get(POSTS);
+ posts.addEqualsFilter(Post.STATUS, Post.SUPPRESSED);
+ return posts;
+ }
+
+ /**
* Gets a ThreadCollection of the threads in this forum. I.e. the
* top-level posts which are not replies to any other post.
*/
@@ -358,9 +555,9 @@ public class Forum extends Application {
}
return threads;
- }
+ }
/**
* Sets up instant and daily subscriptions for the forum. Daily
@@ -527,6 +724,12 @@ public class Forum extends Application {
return Boolean.TRUE.equals(get(NOTICEBOARD));
}
+ /** Returns the administrator group. Null if it doesn't exist */
+ public Group getAdminGroup() {
+ DataObject dObj = (DataObject) get(ADMIN_GROUP);
+ Assert.exists(dObj, DataObject.class);
+ return (Group) DomainObjectFactory.newInstance(dObj);
+ }
/** Returns the moderator group. Null if it doesn't exist */
public Group getModerationGroup() {
DataObject dObj = (DataObject) get( MODERATION_GROUP );
@@ -534,6 +737,27 @@ public class Forum extends Application {
return (Group)DomainObjectFactory.newInstance(dObj);
}
+ /** Returns the thread create group. Null if it doesn't exist */
+ public Group getThreadCreateGroup() {
+ DataObject dObj = (DataObject) get(THREAD_CREATE_GROUP);
+ Assert.exists(dObj, DataObject.class);
+ return (Group) DomainObjectFactory.newInstance(dObj);
+ }
+
+ /** Returns the thread reply group. Null if it doesn't exist */
+ public Group getThreadResponderGroup() {
+ DataObject dObj = (DataObject) get(THREAD_RESPONDER_GROUP);
+ Assert.exists(dObj, DataObject.class);
+ return (Group) DomainObjectFactory.newInstance(dObj);
+ }
+
+ /** Returns the read group. Null if it doesn't exist */
+ public Group getReadGroup() {
+ DataObject dObj = (DataObject) get(READ_GROUP);
+ Assert.exists(dObj, DataObject.class);
+ return (Group) DomainObjectFactory.newInstance(dObj);
+ }
+
public String getContextPath() {
return "/ccm-forum";
}
@@ -555,7 +779,7 @@ public class Forum extends Application {
}
LifecycleDefinition newLife = new LifecycleDefinition();
newLife.setLabel("Delete expired noticeboard postings");
- newLife.addPhaseDefinition("Noticeboard posting lifespan",
+ newLife.addPhaseDefinition("Forum posting lifespan",
null,
new Integer(0),
new Integer(1440 * value), // in minutes
@@ -565,13 +789,20 @@ public class Forum extends Application {
// have the same expiration policy.
DataAssociationCursor posts = getPosts().cursor();
while (posts.next()) {
- Post post
- = (Post)DomainObjectFactory.newInstance(
- posts.getDataObject());
- s_log.debug("Resetting expiration lifecycle for " + post.getOID());
+ Post post =
+ (Post) DomainObjectFactory.newInstance(posts.getDataObject());
+ if (post
+ .getThread()
+ .getRootMessage()
+ .getID()
+ .equals(post.getID())) {
+
+ s_log.debug(
+ "Resetting expiration lifecycle for " + post.getOID());
post.setLifecycle(newLife);
}
}
+ }
public int getExpireAfter() {
BigDecimal expire = (BigDecimal) get(EXPIRE_AFTER);
@@ -594,5 +825,119 @@ public class Forum extends Application {
set(LIFECYCLE_DEFINITION, life);
}
+ /**
+ * method required for upgrade - normally groups are set during forum creation and so
+ * there is no need to invoke a setter
+ * @author cgyg9330
+ *
+ */
+ public void setAdminGroup(Group group) {
+ setAssociation(ADMIN_GROUP, group);
+ PermissionService.grantPermission(
+ new PermissionDescriptor(PrivilegeDescriptor.ADMIN, this, group));
+ }
+ /**
+ * method required for upgrade - normally groups are set during forum creation and so
+ * there is no need to invoke a setter
+ * @author cgyg9330
+ *
+ */
+ public void setThreadCreatorGroup(Group group) {
+ setAssociation(THREAD_CREATE_GROUP, group);
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.get(CREATE_THREAD_PRIVILEGE),
+ this,
+ group));
+ }
+ /**
+ * method required for upgrade - normally groups are set during forum creation and so
+ * there is no need to invoke a setter
+ * @author cgyg9330
+ *
+ */
+ public void setThreadResponderGroup(Group group) {
+ setAssociation(THREAD_RESPONDER_GROUP, group);
+ PermissionService.grantPermission(
+ new PermissionDescriptor(
+ PrivilegeDescriptor.get(RESPOND_TO_THREAD_PRIVILEGE),
+ this,
+ group));
+ }
+ /**
+ * method required for upgrade - normally groups are set during forum creation and so
+ * there is no need to invoke a setter
+ * @author cgyg9330
+ *
+ */
+ public void setReaderGroup(Group group) {
+ setAssociation(READ_GROUP, group);
+ PermissionService.grantPermission(
+ new PermissionDescriptor(PrivilegeDescriptor.READ, this, group));
+ }
+
+ /**
+ * @return
+ */
+ public boolean allowFileAttachments() {
+ return ((Boolean) get(ALLOW_FILE_ATTACHMENTS)).booleanValue();
+ }
+ public boolean allowImageUploads() {
+ return ((Boolean) get(ALLOW_IMAGE_UPLOADS)).booleanValue();
+ }
+
+ public boolean autoSubscribeThreadStarter() {
+ return ((Boolean) get(AUTOSUBSCRIBE_THREAD_STARTER)).booleanValue();
+ }
+
+ public boolean noCategoryPostsAllowed() {
+ return ((Boolean) get(NO_CATEGORY_POSTS)).booleanValue();
+ }
+ public boolean anonymousPostsAllowed() {
+ return ((Boolean) get(ANONYMOUS_POSTS)).booleanValue();
+ }
+
+ public void setAllowFileAttachments(boolean allow) {
+ set(ALLOW_FILE_ATTACHMENTS, new Boolean(allow));
+ }
+ public void setAllowImageUploads(boolean allow) {
+ set(ALLOW_IMAGE_UPLOADS, new Boolean(allow));
+ }
+ public void setAutoSubscribeThreadCreator(boolean subscribe) {
+ set(AUTOSUBSCRIBE_THREAD_STARTER, new Boolean(subscribe));
+ }
+
+ public void setNoCategoryPostsAllowed(boolean allow) {
+ set(NO_CATEGORY_POSTS, new Boolean(allow));
+ }
+
+ public void setAnonymousPostsAllowed(boolean allow) {
+ set(ANONYMOUS_POSTS, new Boolean(allow));
+ }
+
+ public void setTitle (String title) {
+ String oldTitle = getTitle();
+ super.setTitle(title);
+ if (!oldTitle.equals(title)) {
+ // 1. rename permission groups
+ getAdminGroup().setName(title + " Administrators");
+ getModerationGroup().setName(title + " Moderators");
+ getThreadCreateGroup().setName(title + " Thread Creators");
+ getThreadResponderGroup().setName(title + " Thread Responders");
+ getReadGroup().setName(title + " Readers");
+ DataCollection subscriptions = getSubscriptions();
+ while (subscriptions.next()) {
+ ForumSubscription subscription = (ForumSubscription)DomainObjectFactory.newInstance(subscriptions.getDataObject());
+ subscription.getGroup().setName(subscription.getGroupName(this));
+ }
+ ThreadCollection threads = getThreads();
+ while (threads.next()) {
+ ThreadSubscription threadSub = ThreadSubscription.getThreadSubscription(threads.getMessageThread());
+ threadSub.getGroup().setName(threadSub.getSubscriptionGroupName(this));
+
+ }
+
+ }
}
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumConfig.java b/ccm-forum/src/com/arsdigita/forum/ForumConfig.java
index 51f5bb202..95a5150fa 100755
--- a/ccm-forum/src/com/arsdigita/forum/ForumConfig.java
+++ b/ccm-forum/src/com/arsdigita/forum/ForumConfig.java
@@ -18,33 +18,34 @@
*/
package com.arsdigita.forum;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.kernel.User;
+import com.arsdigita.kernel.UserCollection;
import com.arsdigita.runtime.AbstractConfig;
+import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.util.parameter.BooleanParameter;
+import com.arsdigita.util.parameter.IntegerParameter;
import com.arsdigita.util.parameter.Parameter;
-import com.arsdigita.util.parameter.URLParameter;
import com.arsdigita.util.parameter.StringParameter;
-import com.arsdigita.util.UncheckedWrapperException;
-
-import com.arsdigita.kernel.UserCollection;
-import com.arsdigita.kernel.User;
+import com.arsdigita.util.parameter.URLParameter;
import com.arsdigita.web.Web;
-import java.io.InputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.net.MalformedURLException;
-import org.apache.log4j.Logger;
-
/**
* A set of configuration parameters for forums.
*
* @author Justin Ross <jross@redhat.com>
- * @version $Id: ForumConfig.java 1377 2006-11-17 10:39:41Z sskracic $
+ * @version $Id: ForumConfig.java 1628 2007-09-17 08:10:40Z chrisg23 $
*/
public class ForumConfig extends AbstractConfig {
public final static String versionId =
- "$Id: ForumConfig.java 1377 2006-11-17 10:39:41Z sskracic $" +
- "$Author: sskracic $" +
+ "$Id: ForumConfig.java 1628 2007-09-17 08:10:40Z chrisg23 $" +
+ "$Author: chrisg23 $" +
"$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(ForumConfig.class);
@@ -53,7 +54,18 @@ public class ForumConfig extends AbstractConfig {
private Parameter m_authorEditPosts;
private Parameter m_digestUserEmail;
private Parameter m_replyHostName;
+ private Parameter m_disablePageCaching;
+ private Parameter m_adminOnlyCreateTopics;
+ private Parameter m_maxImageSize;
+ private Parameter m_maxFileSize;
private final Parameter m_adapters;
+ private Parameter m_showAllThreadAlerts;
+ private Parameter m_showNewTabs;
+ private Parameter m_useWysiwygEditor;
+ private Parameter m_rejectionMessage;
+ private Parameter m_threadPageSize;
+ private Parameter m_quickFinish;
+ private Parameter m_deleteSentSubscriptionNotifications;
public ForumConfig() {
m_adminEditPosts = new BooleanParameter(
@@ -72,6 +84,49 @@ public class ForumConfig extends AbstractConfig {
"com.arsdigita.forum.digest_user_email",
Parameter.OPTIONAL,
null);
+ m_disablePageCaching = new BooleanParameter (
+ "com.arsdigita.forum.disable_page_caching",
+ Parameter.REQUIRED,
+ Boolean.FALSE);
+
+ m_adminOnlyCreateTopics = new BooleanParameter (
+ "com.arsdigita.forum.admin_only_to_create_topics",
+ Parameter.REQUIRED,
+ Boolean.FALSE);
+ m_maxImageSize = new IntegerParameter (
+ "com.arsdigita.forum.maximum_image_size",
+ Parameter.OPTIONAL, null);
+ m_maxFileSize = new IntegerParameter (
+ "com.arsdigita.forum.maximum_file_size",
+ Parameter.OPTIONAL, null);
+
+ m_showNewTabs = new BooleanParameter(
+ "com.arsdigita.forum.show_new_tabs",
+ Parameter.OPTIONAL,
+ Boolean.FALSE);
+ m_showAllThreadAlerts = new BooleanParameter(
+ "com.arsdigita.forum.show_all_forum_thread_alerts",
+ Parameter.OPTIONAL,
+ Boolean.TRUE);
+ m_useWysiwygEditor = new BooleanParameter(
+ "com.arsdigita.forum.use_wysiwyg_editor",
+ Parameter.OPTIONAL,
+ Boolean.FALSE);
+ m_rejectionMessage = new StringParameter(
+ "com.arsdigita.forum.rejection_form_message.example",
+ Parameter.OPTIONAL,
+ null);
+ m_threadPageSize = new IntegerParameter (
+ "com.arsdigita.forum.thread_page_size",
+ Parameter.REQUIRED, new Integer(10));
+ m_quickFinish = new BooleanParameter(
+ "com.arsdigita.forum.allow_quick_finish",
+ Parameter.OPTIONAL,
+ Boolean.FALSE);
+ m_deleteSentSubscriptionNotifications = new BooleanParameter(
+ "com.arsdigita.forum.delete_sent_subscription_notifications",
+ Parameter.OPTIONAL,
+ Boolean.FALSE);
try {
m_adapters = new URLParameter
@@ -88,6 +143,17 @@ public class ForumConfig extends AbstractConfig {
register(m_authorEditPosts);
register(m_replyHostName);
register(m_adapters);
+ register(m_disablePageCaching);
+ register(m_adminOnlyCreateTopics);
+ register(m_maxImageSize);
+ register(m_maxFileSize);
+ register(m_showAllThreadAlerts);
+ register(m_showNewTabs);
+ register(m_useWysiwygEditor);
+ register(m_rejectionMessage);
+ register(m_threadPageSize);
+ register(m_quickFinish);
+ register(m_deleteSentSubscriptionNotifications);
loadInfo();
}
@@ -123,6 +189,28 @@ public class ForumConfig extends AbstractConfig {
return hostName;
}
+ /**
+ * Supports prevention of client and middleware caching -
+ * use in situations where users with different
+ * permissions share machines
+ * @return
+ */
+ public boolean disableClientPageCaching () {
+ return ((Boolean)get(m_disablePageCaching)).booleanValue();
+ }
+
+ /**
+ * if true, disables topic tab for non admin users. Topic
+ * tab does not access control topic creation, so set this
+ * to true to maintain control of the topics on the forum.
+ *
+ *
+ *
+ * @return
+ */
+ public boolean topicCreationByAdminOnly () {
+ return ((Boolean)get(m_adminOnlyCreateTopics)).booleanValue();
+ }
public User getDigestUser() {
String email = getDigestUserEmail();
@@ -138,4 +226,85 @@ public class ForumConfig extends AbstractConfig {
users.close();
return user;
}
+ /**
+ * returns the maximum allowed size (in bytes) of
+ * image files attached to posts. Any larger
+ * files are rejected by UI validation
+ * @return
+ */
+ public long getMaxImageSize() {
+ Integer size = (Integer)get(m_maxImageSize);
+ long longSize = Long.MAX_VALUE;
+ if (size != null) {
+ longSize = size.longValue();
+ }
+ return longSize;
+ }
+ /**
+ * returns the maximum allowed size (in bytes) of
+ * files attached to posts. Any larger
+ * files are rejected by UI validation
+ * @return
+ */
+ public long getMaxFileSize() {
+ Integer size = (Integer)get(m_maxFileSize);
+ long longSize = Long.MAX_VALUE;
+ if (size != null) {
+ longSize = size.longValue();
+ }
+ return longSize;
+ }
+
+
+ /**
+ * if true, alerts tab displays thread alerts for this and all other
+ * forums. If false, only display thread subscriptions for current
+ * forum.
+ * @return
+ */
+ /*
+ * If true, the thread alert page lists thread alerts from
+ * all forums - alerts not from the current forum have
+ * links to the thread displayed within the context of
+ * the current forum. Looks weird and needs to be sorted out
+ * presumably the correct forum needs to be set in the ForumContext
+ * when a link is selected
+ */
+ public boolean showThreadAlertsForAllForums () {
+ return ((Boolean)get(m_showAllThreadAlerts)).booleanValue();
+ }
+ /**
+ * if true, displays setup and permissions tabs
+ * @return
+ */
+ public boolean showNewTabs () {
+ return ((Boolean)get(m_showNewTabs)).booleanValue();
+ }
+
+ public boolean useWysiwygEditor () {
+ return ((Boolean)get(m_useWysiwygEditor)).booleanValue();
+ }
+
+ /**
+ * message added to the bottom of the moderation reection email.
+ * May give details about what the poster can do if not happy
+ * with rejection
+ * @return
+ */
+ public String getRejectionMessage () {
+ return (String)get(m_rejectionMessage);
+ }
+
+ public int getThreadPageSize () {
+ return ((Integer)get(m_threadPageSize)).intValue();
+ }
+
+ public boolean quickFinishAllowed () {
+ return ((Boolean)get(m_quickFinish)).booleanValue();
+ }
+
+ public boolean deleteNotifications () {
+ return ((Boolean)get(m_deleteSentSubscriptionNotifications)).booleanValue();
+ }
+
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumConfig_parameter.properties b/ccm-forum/src/com/arsdigita/forum/ForumConfig_parameter.properties
index 8e259d76d..e6ecda2c6 100755
--- a/ccm-forum/src/com/arsdigita/forum/ForumConfig_parameter.properties
+++ b/ccm-forum/src/com/arsdigita/forum/ForumConfig_parameter.properties
@@ -18,8 +18,62 @@ com.arsdigita.forum.admin_can_edit_posts.purpose=Whether administrators can edit
com.arsdigita.forum.admin_can_edit_posts.format=[boolean]
com.arsdigita.forum.admin_can_edit_posts.example=true|false
+com.arsdigita.forum.admin_only_to_create_topics.title=Prevent other users creating new topics
+com.arsdigita.forum.admin_only_to_create_topics.purpose=Whether only admin can create (true) topics or all users (false)
+com.arsdigita.forum.admin_only_to_create_topics.format=[boolean]
+com.arsdigita.forum.admin_only_to_create_topics.example=true|false
+
com.arsdigita.forum.author_can_edit_posts.title=Authors can edit posts
com.arsdigita.forum.author_can_edit_posts.purpose=Whether authors can edijt their posts
com.arsdigita.forum.author_can_edit_posts.format=[boolean]
com.arsdigita.forum.author_can_edit_posts.example=true|false
+com.arsdigita.forum.disable_page_caching.title=Disable client & middleware page caching
+com.arsdigita.forum.disable_page_caching.purpose=Disable caching, particularly for situations where users share PCs
+com.arsdigita.forum.disable_page_caching.format=[boolean]
+com.arsdigita.forum.disable_page_caching.example=true|false
+
+com.arsdigita.forum.maximum_image_size.title=Maximum size of image uploads in bytes
+com.arsdigita.forum.maximum_image_size.purpose=Prevent huge images from being uploaded
+com.arsdigita.forum.maximum_image_size.format=[integer]
+com.arsdigita.forum.maximum_image_size.example=1048576
+
+com.arsdigita.forum.maximum_file_size.title=Maximum size of file uploads in bytes
+com.arsdigita.forum.maximum_file_size.purpose=prevent huge files from being uploaded
+com.arsdigita.forum.maximum_file_size.format=[integer]
+com.arsdigita.forum.maximum_file_size.example=1048576
+
+com.arsdigita.forum.show_all_forum_thread_alerts.title=Display thread alerts from all forums
+com.arsdigita.forum.show_all_forum_thread_alerts.purpose=decide whether to display thread alerts for this forum only or all alerts for user
+com.arsdigita.forum.show_all_forum_thread_alerts.format=[boolean]
+com.arsdigita.forum.show_all_forum_thread_alerts.example=true|false
+
+com.arsdigita.forum.show_new_tabs.title=Display permissions and setup tabs
+com.arsdigita.forum.show_new_tabs.purpose=to allow forum users to completely hide new functionality
+com.arsdigita.forum.show_new_tabs.format=[boolean]
+com.arsdigita.forum.show_new_tabs.example=true|false
+
+com.arsdigita.forum.use_wysiwyg_editor.title=Use HTML Editor, or stick with legacy version
+com.arsdigita.forum.use_wysiwyg_editor.purpose=to allow legacy implementations to stick with existing stylesheets
+com.arsdigita.forum.use_wysiwyg_editor.format=[boolean]
+com.arsdigita.forum.use_wysiwyg_editor.example=true|false
+
+com.arsdigita.forum.rejection_form_message.title=Instructions to poster added to bottom of email
+com.arsdigita.forum.rejection_form_message.purpose=tail of email that may contain site specific information - who to contact etc
+com.arsdigita.forum.rejection_form_message.format=[string]
+com.arsdigita.forum.rejection_form_message.example=Please do not reply to this email. If you have any comments, please email webmaster@example.com
+
+com.arsdigita.forum.thread_page_size.title=Number of threads displayed per page
+com.arsdigita.forum.thread_page_size.purpose=balance page loading time against number of key preses
+com.arsdigita.forum.thread_page_size.format=[integer]
+com.arsdigita.forum.thread_page_size.example=10
+
+com.arsdigita.forum.allow_quick_finish.title=Allow quick finish on posts
+com.arsdigita.forum.allow_quick_finish.purpose=To give users the option of omitting post steps if they have a quick text post
+com.arsdigita.forum.allow_quick_finish.format=[boolean]
+com.arsdigita.forum.allow_quick_finish.example=true|false
+
+com.arsdigita.forum.delete_sent_subscription_notifications.title=Delete Sent Subscription Notifications
+com.arsdigita.forum.delete_sent_subscription_notifications.purpose=Enable deletion of successfully sent notifications to save space in DB
+com.arsdigita.forum.delete_sent_subscription_notifications.format=[boolean]
+com.arsdigita.forum.delete_sent_subscription_notifications.example=true|false
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumContext.java b/ccm-forum/src/com/arsdigita/forum/ForumContext.java
index 080e3ac2c..408f93ee7 100755
--- a/ccm-forum/src/com/arsdigita/forum/ForumContext.java
+++ b/ccm-forum/src/com/arsdigita/forum/ForumContext.java
@@ -27,8 +27,11 @@ import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.Party;
import com.arsdigita.util.Assert;
+import java.io.IOException;
import java.math.BigDecimal;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.log4j.Logger;
/**
@@ -103,6 +106,15 @@ public final class ForumContext {
// thread.assertPrivilege(PrivilegeDescriptor.READ);
m_thread = thread;
} catch (DataObjectNotFoundException ex) {
+ PageState state = PageState.getPageState();
+ if (state != null) {
+ try {
+ state.getResponse().sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ } catch (IOException e) {
+ s_log.warn("Thread not found, but failed to send a response to user");
+ }
+ }
throw new UncheckedWrapperException(
"Couldn't find a MessageThread for " + threadID, ex);
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumPageBuilder.java b/ccm-forum/src/com/arsdigita/forum/ForumPageBuilder.java
new file mode 100644
index 000000000..be3e334d5
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ForumPageBuilder.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import java.math.BigDecimal;
+
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageFactory;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleComponent;
+import com.arsdigita.bebop.event.RequestEvent;
+import com.arsdigita.bebop.event.RequestListener;
+import com.arsdigita.bebop.parameters.BigDecimalParameter;
+import com.arsdigita.bebop.parameters.ParameterModel;
+import com.arsdigita.forum.ui.Constants;
+import com.arsdigita.forum.ui.ForumComponent;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.toolbox.ui.ApplicationAuthenticationListener;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Implementation of com.arsdigita.forum.PageBuilder that creates a basic forum page with read access check
+ */
+public class ForumPageBuilder implements PageBuilder, Constants {
+
+
+ public Page buildPage() {
+ Page page = PageFactory.buildPage(Constants.FORUM_XML_PREFIX, "Forum", "forumPage");
+ //Output the title in an easy to find place
+ page.add(new SimpleComponent(){
+ public void generateXML(PageState state, Element parent) {
+ Element nameElement = parent.newChildElement(Constants.FORUM_XML_PREFIX + ":name", Constants.FORUM_XML_NS);
+ nameElement.setText(ForumContext.getContext(state).getForum().getTitle());
+ Element introductionElement = parent.newChildElement(Constants.FORUM_XML_PREFIX + ":introduction", Constants.FORUM_XML_NS);
+ introductionElement.setText(ForumContext.getContext(state).getForum().getIntroduction());
+ }
+ });
+ ForumComponent forumComp = getForumComponent();
+ page.add(forumComp);
+ BigDecimalParameter topic = new BigDecimalParameter(TOPIC_PARAM);
+ page.addGlobalStateParam(topic);
+ page.addRequestListener(new ApplicationAuthenticationListener(PrivilegeDescriptor.READ));
+ page.addRequestListener(new ForumPageRequestListener(topic, forumComp));
+ return page;
+ }
+
+
+ protected ForumComponent getForumComponent() {
+ return new ForumComponent();
+ }
+
+ private static class ForumPageRequestListener implements RequestListener {
+ private BigDecimalParameter m_categorySelection;
+ private ForumComponent m_forumComp;
+
+ public ForumPageRequestListener(BigDecimalParameter topicSelection, ForumComponent forumComp) {
+ m_categorySelection = topicSelection;
+ m_forumComp = forumComp;
+ }
+
+ public void pageRequested(RequestEvent event) {
+
+ PageState state = event.getPageState();
+ ForumContext context = ForumContext.getContext(state);
+
+ context.setCategorySelection
+ ((BigDecimal) event.getPageState().getValue(m_categorySelection));
+ }
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumPageFactory.java b/ccm-forum/src/com/arsdigita/forum/ForumPageFactory.java
new file mode 100644
index 000000000..1fab84d4c
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ForumPageFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.parameters.ParameterModel;
+import com.arsdigita.util.Assert;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Factory class that enables projects to provide their own page creators.
+ * A reason for doing this is that a particular forum project may wish to
+ * include components on the page that introduce dependencies on other projects
+ */
+public class ForumPageFactory {
+
+ public static final String THREAD_PAGE = "thread";
+ public static final String FORUM_PAGE = "forum";
+
+ private static Map pageBuilders = new HashMap();
+
+ static {
+ // default pageBuilders are those provided with this project
+ pageBuilders.put(THREAD_PAGE, new ThreadPageBuilder());
+ pageBuilders.put(FORUM_PAGE, new ForumPageBuilder());
+ }
+
+ public static Page getPage(String pageType) {
+ Assert.truth(pageBuilders.containsKey(pageType), "Requested page type (" + pageType + ") does not have a builder registered" );
+ PageBuilder builder = (PageBuilder)pageBuilders.get(pageType);
+ Page page = builder.buildPage();
+ page.lock();
+ return page;
+
+
+ }
+
+ public static Iterator getPages () {
+ return pageBuilders.keySet().iterator();
+ }
+
+
+ public static void registerPageBuilder (String pageType, PageBuilder builder) {
+ pageBuilders.put(pageType, builder);
+
+ }
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumServlet.java b/ccm-forum/src/com/arsdigita/forum/ForumServlet.java
index 8e80fe8f8..39a22afb5 100755
--- a/ccm-forum/src/com/arsdigita/forum/ForumServlet.java
+++ b/ccm-forum/src/com/arsdigita/forum/ForumServlet.java
@@ -18,36 +18,67 @@
*/
package com.arsdigita.forum;
+import java.util.Iterator;
+import java.util.Map;
+
import com.arsdigita.forum.ui.Constants;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.page.BebopApplicationServlet;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import javax.servlet.ServletException;
+
import org.apache.log4j.Logger;
/**
* @author Justin Ross <jross@redhat.com>
- * @version $Id: ForumServlet.java 287 2005-02-22 00:29:02Z sskracic $
+ * @version $Id: ForumServlet.java 1628 2007-09-17 08:10:40Z chrisg23 $
+ *
+ * Updated chris.gilbert@westsussex.gov.uk to make use of PageFactory and to enable
+ * disablement of client/middleware caching
*/
public class ForumServlet extends BebopApplicationServlet
implements Constants {
public static final String versionId =
- "$Id: ForumServlet.java 287 2005-02-22 00:29:02Z sskracic $" +
- "$Author: sskracic $" +
+ "$Id: ForumServlet.java 1628 2007-09-17 08:10:40Z chrisg23 $" +
+ "$Author: chrisg23 $" +
"$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(ForumServlet.class);
public void init() throws ServletException {
super.init();
-
- final Page forum = BboardDispatcher.buildForumPage
- (new BigDecimalParameter(TOPIC_PARAM));
- final Page thread = BboardDispatcher.buildThreadPage
- (new BigDecimalParameter(THREAD_PARAM));
+ s_log.debug("creating forum page");
+ final Page forum = ForumPageFactory.getPage(ForumPageFactory.FORUM_PAGE);
+ s_log.debug("creating thread page");
+ final Page thread = ForumPageFactory.getPage(ForumPageFactory.THREAD_PAGE);
put("/", forum);
put("/index.jsp", forum);
put("/thread.jsp", thread);
+ if (Forum.getConfig().disableClientPageCaching()) {
+ s_log.debug("caching disabled");
+ disableClientCaching("/");
+ disableClientCaching("/index.jsp");
+ disableClientCaching("/thread.jsp");
+ }
+
+ // allow other pages to be added
+ // eg - allows categorised forum to add load-category page
+ // for AJAX category asignment
+ Iterator it = ForumPageFactory.getPages();
+ while (it.hasNext()) {
+ Object key = (Object)it.next();
+ if (!key.equals(ForumPageFactory.FORUM_PAGE) && !key.equals(ForumPageFactory.THREAD_PAGE)) {
+ put("/" + key, ForumPageFactory.getPage((String)key));
+ if (Forum.getConfig().disableClientPageCaching()) {
+ disableClientCaching("/" + key);
+
}
}
+ }
+
+ }
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ForumSubscription.java b/ccm-forum/src/com/arsdigita/forum/ForumSubscription.java
index a3ae16c70..fb21dc331 100755
--- a/ccm-forum/src/com/arsdigita/forum/ForumSubscription.java
+++ b/ccm-forum/src/com/arsdigita/forum/ForumSubscription.java
@@ -22,6 +22,7 @@ import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.mail.Mail;
import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject;
@@ -40,7 +41,7 @@ import org.apache.log4j.Logger;
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
*
- * @version $Revision: #8 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
+ * @version $Revision: 1.3 $ $Author: chrisg23 $ $DateTime: 2004/08/17 23:26:27 $
*/
public class ForumSubscription extends Subscription {
@@ -89,6 +90,10 @@ public class ForumSubscription extends Subscription {
return BASE_DATA_OBJECT_TYPE;
}
+ public String getSubscriptionGroupName() {
+ return "Instant Alert Subscription Group";
+ }
+
public Forum getForum() {
if (m_forum == null) {
DataObject forumData = (DataObject) get(FORUM);
@@ -106,6 +111,17 @@ public class ForumSubscription extends Subscription {
private void setForum(Forum forum) {
m_forum = forum;
setAssociation(FORUM, m_forum);
+ if (getGroup() != null) {
+ // in the case of moderation alert this is null - good, because
+ // mod group has already been placed in the group hierarchy
+
+ getGroup().setName(getGroupName(forum));
+ forum.getGroup().addSubgroup(getGroup());
+ }
+ }
+
+ public String getGroupName(Forum forum) {
+ return forum.getTitle() + " " + getSubscriptionGroupName();
}
protected void afterSave() {
@@ -120,15 +136,18 @@ public class ForumSubscription extends Subscription {
public String getSignature(ThreadedMessage post) {
StringBuffer sb = new StringBuffer();
- // XXX
- /*
- sb.append(SEPARATOR);
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+
+ sb.append(HTML_SEPARATOR);
+ sb.append(getReturnURLMessage((Post)post));
+ sb.append(HTML_SEPARATOR);
sb.append(ALERT_BLURB);
sb.append("You are receiving this email because you subscribed to ");
- sb.append("alerts on this forum.\n\n");
- sb.append(REPLY_BLURB);
- */
+ sb.append("alerts on this forum. To unsubscribe, follow the link above, return to the thread list and change the settings under the alerts tab.\n");
+ sb.append("");
+ } else {
sb.append(getReturnURLMessage((Post)post));
+ }
return sb.toString();
}
diff --git a/ccm-forum/src/com/arsdigita/forum/Initializer.java b/ccm-forum/src/com/arsdigita/forum/Initializer.java
index 08bd159df..a5ef509c3 100755
--- a/ccm-forum/src/com/arsdigita/forum/Initializer.java
+++ b/ccm-forum/src/com/arsdigita/forum/Initializer.java
@@ -18,55 +18,47 @@
*/
package com.arsdigita.forum;
-import com.arsdigita.db.DbHelper;
-import com.arsdigita.bebop.RequestLocal;
+import org.apache.log4j.Logger;
+import com.arsdigita.bebop.RequestLocal;
+import com.arsdigita.db.DbHelper;
+import com.arsdigita.domain.DomainObject;
import com.arsdigita.domain.xml.TraversalHandler;
-
-import com.arsdigita.persistence.pdl.ManifestSource;
-import com.arsdigita.persistence.pdl.NameFilter;
-
-import com.arsdigita.runtime.CompoundInitializer;
-import com.arsdigita.runtime.RuntimeConfig;
-import com.arsdigita.runtime.PDLInitializer;
-import com.arsdigita.runtime.DomainInitEvent;
-
-import com.arsdigita.xml.XML;
-
-import com.arsdigita.kernel.URLFinder;
-import com.arsdigita.kernel.URLService;
-import com.arsdigita.kernel.NoValidURLException;
+import com.arsdigita.forum.portlet.MyForumsPortlet;
+import com.arsdigita.forum.portlet.RecentPostingsPortlet;
+import com.arsdigita.forum.search.FileAttachmentMetadataProvider;
+import com.arsdigita.forum.search.PostMetadataProvider;
+import com.arsdigita.forum.ui.portlet.RecentPostingsPortletEditor;
import com.arsdigita.kernel.ACSObjectInstantiator;
-import com.arsdigita.kernel.ResourceTypeConfig;
import com.arsdigita.kernel.ResourceType;
+import com.arsdigita.kernel.ResourceTypeConfig;
+import com.arsdigita.kernel.URLService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
import com.arsdigita.kernel.ui.ResourceConfigFormSection;
-
-import com.arsdigita.domain.DomainObject;
-import com.arsdigita.domain.DataObjectNotFoundException;
-
-import com.arsdigita.persistence.DataObject;
-import com.arsdigita.persistence.OID;
-import com.arsdigita.persistence.SessionManager;
-import com.arsdigita.web.Application;
import com.arsdigita.messaging.ThreadedMessage;
-
-import com.arsdigita.forum.portlet.RecentPostingsPortlet;
-import com.arsdigita.forum.ui.portlet.RecentPostingsPortletEditor;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.pdl.ManifestSource;
+import com.arsdigita.persistence.pdl.NameFilter;
+import com.arsdigita.runtime.CompoundInitializer;
+import com.arsdigita.runtime.DomainInitEvent;
+import com.arsdigita.runtime.LegacyInitEvent;
+import com.arsdigita.runtime.PDLInitializer;
+import com.arsdigita.runtime.RuntimeConfig;
+import com.arsdigita.search.MetadataProviderRegistry;
import com.arsdigita.web.ui.ApplicationConfigFormSection;
-
-import org.apache.log4j.Logger;
+import com.arsdigita.xml.XML;
/**
* The forum initializer.
*
* @author Justin Ross <jross@redhat.com>
- * @version $Id: Initializer.java 755 2005-09-02 13:42:47Z sskracic $
+ * @version $Id: Initializer.java 1628 2007-09-17 08:10:40Z chrisg23 $
*/
public class Initializer extends CompoundInitializer {
public final static String versionId =
- "$Id: Initializer.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
+ "$Id: Initializer.java 1628 2007-09-17 08:10:40Z chrisg23 $"
+ + "$Author: chrisg23 $"
+ + "$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(Initializer.class);
@@ -91,6 +83,29 @@ public class Initializer extends CompoundInitializer {
}
});
e.getFactory().registerInstantiator(
+ Post.BASE_DATA_OBJECT_TYPE,
+ new ACSObjectInstantiator() {
+ public DomainObject doNewInstance(DataObject dataObject) {
+ return new Post(dataObject);
+ }
+ });
+
+ e.getFactory().registerInstantiator(
+ PostFileAttachment.BASE_DATA_OBJECT_TYPE,
+ new ACSObjectInstantiator() {
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new PostFileAttachment(dataObject);
+ }
+ });
+
+ e.getFactory().registerInstantiator(
+ PostImageAttachment.BASE_DATA_OBJECT_TYPE,
+ new ACSObjectInstantiator() {
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new PostImageAttachment(dataObject);
+ }
+ });
+ e.getFactory().registerInstantiator(
"com.arsdigita.forum.Inbox",
new ACSObjectInstantiator() {
public DomainObject doNewInstance(DataObject dataObject) {
@@ -107,6 +122,14 @@ public class Initializer extends CompoundInitializer {
});
e.getFactory().registerInstantiator(
+ MyForumsPortlet.BASE_DATA_OBJECT_TYPE,
+ new ACSObjectInstantiator() {
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new MyForumsPortlet(dataObject);
+ }
+ });
+
+ e.getFactory().registerInstantiator(
ForumSubscription.BASE_DATA_OBJECT_TYPE,
new ACSObjectInstantiator() {
public DomainObject doNewInstance(DataObject dataObject) {
@@ -128,42 +151,12 @@ public class Initializer extends CompoundInitializer {
XML.parse(Forum.getConfig().getTraversalAdapters(),
new TraversalHandler());
- URLFinder messageFinder = new URLFinder() {
- public String find(OID oid, String context)
- throws NoValidURLException {
- return find(oid);
- }
- public String find(OID oid) throws NoValidURLException {
- DataObject dobj = SessionManager.getSession().retrieve(oid);
- if (dobj == null) {
- throw new NoValidURLException("No such data object " + oid);
- }
-
- Application app = Application.retrieveApplication(dobj);
-
- if (app == null) {
- throw new NoValidURLException
- ("Could not find application instance for " + dobj);
- }
-
- try {
- ThreadedMessage message = new ThreadedMessage(oid);
-
- String url = app.getPath() +
- "/thread.jsp?threadID=" +
- message.getThread().getID().toString();
-
- return url;
- } catch(DataObjectNotFoundException e) {
- throw new NoValidURLException
- ("Could not find application instance for " + dobj);
- }
- }
- };
URLService.registerFinder(
- ThreadedMessage.BASE_DATA_OBJECT_TYPE, messageFinder);
+ ThreadedMessage.BASE_DATA_OBJECT_TYPE,
+ new PostFinder());
+ URLService.registerFinder(PostFileAttachment.BASE_DATA_OBJECT_TYPE, new PostFileAttachmentURLFinder());
new ResourceTypeConfig(RecentPostingsPortlet.BASE_DATA_OBJECT_TYPE) {
public ResourceConfigFormSection getCreateFormSection
@@ -183,15 +176,20 @@ public class Initializer extends CompoundInitializer {
}
};
- new ResourceTypeConfig(Forum.BASE_DATA_OBJECT_TYPE) {
+ // chris.gilbert@westsussex.gov.uk use new constructor that allows create form to be hidden from users other than those
+ // with admin rights on parent app. Particularly appropriate for portlet where users
+ // customising their own homepage should NOT be allowed to create new forums
+ new ResourceTypeConfig(Forum.BASE_DATA_OBJECT_TYPE, PrivilegeDescriptor.ADMIN, PrivilegeDescriptor.READ) {
public ResourceConfigFormSection getCreateFormSection
- (final ResourceType resType, final RequestLocal parentAppRL) {
+ (final ResourceType resType,
+ final RequestLocal parentAppRL) {
final ResourceConfigFormSection config =
- new ApplicationConfigFormSection(resType, parentAppRL);
+ new ApplicationConfigFormSection(resType, parentAppRL, true);
return config;
}
+
public ResourceConfigFormSection getModifyFormSection
(final RequestLocal application) {
final ResourceConfigFormSection config =
@@ -201,5 +199,20 @@ public class Initializer extends CompoundInitializer {
}
};
+
+ MetadataProviderRegistry.registerAdapter(Post.BASE_DATA_OBJECT_TYPE, new PostMetadataProvider());
+ MetadataProviderRegistry.registerAdapter(PostFileAttachment.BASE_DATA_OBJECT_TYPE, new FileAttachmentMetadataProvider());
+
+ }
+
+ public void init(LegacyInitEvent e) {
+ super.init(e);
+
+ if (RuntimeConfig.getConfig().runBackGroundTasks()) {
+ RemoveUnattachedAssetsScheduler.startTimer();
}
+
+
+ }
+
}
diff --git a/ccm-forum/src/com/arsdigita/forum/Loader.java b/ccm-forum/src/com/arsdigita/forum/Loader.java
index 2887c9066..81e2c89c3 100755
--- a/ccm-forum/src/com/arsdigita/forum/Loader.java
+++ b/ccm-forum/src/com/arsdigita/forum/Loader.java
@@ -22,8 +22,10 @@ import com.arsdigita.loader.PackageLoader;
import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.KernelExcursion;
+import com.arsdigita.kernel.Party;
import com.arsdigita.kernel.User;
import com.arsdigita.kernel.EmailAddress;
+import com.arsdigita.kernel.UserCollection;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
import com.arsdigita.persistence.SessionManager;
@@ -33,6 +35,7 @@ import com.arsdigita.web.ApplicationType;
import com.arsdigita.portal.apportlet.AppPortletType;
import com.arsdigita.portal.PortletType;
+import com.arsdigita.forum.portlet.MyForumsPortlet;
import com.arsdigita.forum.portlet.RecentPostingsPortlet;
import org.apache.log4j.Logger;
@@ -42,12 +45,12 @@ import org.apache.log4j.Logger;
* Loader.
*
* @author Justin Ross <jross@redhat.com>
- * @version $Id: Loader.java 755 2005-09-02 13:42:47Z sskracic $
+ * @version $Id: Loader.java 1628 2007-09-17 08:10:40Z chrisg23 $
*/
public class Loader extends PackageLoader {
public final static String versionId =
- "$Id: Loader.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
+ "$Id: Loader.java 1628 2007-09-17 08:10:40Z chrisg23 $" +
+ "$Author: chrisg23 $" +
"$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(Loader.class);
@@ -60,6 +63,7 @@ public class Loader extends PackageLoader {
setupForumAppType();
//setupInboxAppType();
setupRecentPostingsPortletType();
+ setupMyForumsPortletType();
setupDigestUser();
SessionManager.getSession().flushAll();
}
@@ -97,6 +101,17 @@ public class Loader extends PackageLoader {
return type;
}
+ public static PortletType setupMyForumsPortletType() {
+
+ PortletType type = PortletType
+ .createPortletType("My Forums",
+ PortletType.WIDE_PROFILE,
+ MyForumsPortlet.BASE_DATA_OBJECT_TYPE);
+ type.setDescription("Lists forums that user has access to, with last posting date");
+
+ return type;
+ }
+
private static void setupDigestUser() {
s_log.debug("Setting up the digest user");
@@ -104,20 +119,36 @@ public class Loader extends PackageLoader {
// specified in the configuration file.
String email = Forum.getConfig().getDigestUserEmail();
+ UserCollection users = User.retrieveAll();
+ users.addEqualsFilter("primaryEmail", email);
+ if (users.next()) {
+ s_log.debug("user exists");
+ } else {
- if (s_log.isDebugEnabled()) {
s_log.debug("Creating a user with the email " + email);
- }
-
User user = new User();
user.setPrimaryEmail(new EmailAddress(email));
user.getPersonName().setGivenName("Forum");
user.getPersonName().setFamilyName("Digest Sender");
+ users.close();
+ }
+
+
}
public static void setupPrivileges() {
PrivilegeDescriptor.createPrivilege(
Forum.FORUM_MODERATION_PRIVILEGE);
+ PrivilegeDescriptor.createPrivilege(
+ Forum.CREATE_THREAD_PRIVILEGE);
+ PrivilegeDescriptor.createPrivilege(
+ Forum.RESPOND_TO_THREAD_PRIVILEGE);
+ PrivilegeDescriptor.addChildPrivilege(Forum.FORUM_MODERATION_PRIVILEGE, Forum.CREATE_THREAD_PRIVILEGE);
+ PrivilegeDescriptor.addChildPrivilege(Forum.CREATE_THREAD_PRIVILEGE, Forum.RESPOND_TO_THREAD_PRIVILEGE);
+ PrivilegeDescriptor.addChildPrivilege(Forum.RESPOND_TO_THREAD_PRIVILEGE, PrivilegeDescriptor.READ.getName());
+
+
+
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/PageBuilder.java b/ccm-forum/src/com/arsdigita/forum/PageBuilder.java
new file mode 100644
index 000000000..e0ba02e8d
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/PageBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.parameters.ParameterModel;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Interface for classes that create forum pages. To build a page different
+ * from the default, provide new implemention and register it with the
+ * com.arsdigita.forum.ForumPageFactory
+ */
+public interface PageBuilder {
+
+ public Page buildPage();
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/Post.java b/ccm-forum/src/com/arsdigita/forum/Post.java
index 4d6d95245..3241454aa 100755
--- a/ccm-forum/src/com/arsdigita/forum/Post.java
+++ b/ccm-forum/src/com/arsdigita/forum/Post.java
@@ -18,6 +18,11 @@
*/
package com.arsdigita.forum;
+import java.math.BigDecimal;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.PageState;
import com.arsdigita.categorization.CategorizedObject;
import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryCollection;
@@ -26,6 +31,8 @@ import com.arsdigita.cms.lifecycle.LifecycleDefinition;
import com.arsdigita.cms.lifecycle.LifecycleService;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.ui.PostForm;
+import com.arsdigita.kernel.ACSObject;
import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.KernelExcursion;
import com.arsdigita.kernel.Party;
@@ -33,18 +40,14 @@ import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.messaging.MessageThread;
import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.notification.Notification;
+import com.arsdigita.persistence.DataAssociation;
+import com.arsdigita.persistence.DataAssociationCursor;
import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject;
-import com.arsdigita.persistence.DataOperation;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.PersistenceException;
import com.arsdigita.persistence.SessionManager;
import com.arsdigita.util.Assert;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.log4j.Logger;
/**
* A Post represents a single posting to a discussion forum.
@@ -105,7 +108,8 @@ import org.apache.log4j.Logger;
*
*
*
-
+ *
+ *
* @author Kevin Scaldeferri (kevin@arsdigita.com)
* @author Nobuko Asakai (nasakai@redhat.com)
*/
@@ -121,6 +125,16 @@ public class Post extends ThreadedMessage {
* message */
public static final String MODERATOR = "moderator";
+ /**
+ * 0..n association with PostImageAttachments
+ */
+ public static final String IMAGE_ATTACHMENTS = "images";
+
+ /**
+ * 0..n association with PostFileAttachments
+ */
+ public static final String FILE_ATTACHMENTS = "files";
+
/** The status strings */
public static final String PENDING = "pending";
public static final String APPROVED = "approved";
@@ -134,6 +148,8 @@ public class Post extends ThreadedMessage {
private Party m_moderator;
+ // referred to afterSave method
+ private boolean m_wasNew;
/*
* The base DomainObject is Post which extends ThreadedMessage. In
@@ -147,7 +163,7 @@ public class Post extends ThreadedMessage {
this(BASE_DATA_OBJECT_TYPE);
}
- protected Post(String typeName) {
+ public Post(String typeName) {
super(typeName);
}
@@ -155,52 +171,35 @@ public class Post extends ThreadedMessage {
super(oid);
}
+ public Post(BigDecimal id) {
+ this(new OID(BASE_DATA_OBJECT_TYPE, id));
+ }
+
public Post(DataObject obj) {
super(obj);
}
/**
- * Creates a new Posting in a form. If the forum
- * is moderated, then the post's status will be
- * set to PENDING, otherwise it will be set to
- * APPROVED
+ * Creates a new Posting in a forum. The post is
+ * not yet in a fit state to be saved as it needs
+ * it's status to be set, and the subject and message
+ *
* @param forum the owner forum
*/
public static Post create(Forum forum) {
- return create(forum,
- forum.isModerated() ? PENDING : APPROVED);
- }
-
- /**
- * Creates a new Posting in a form. The approval
- * status will be set as specified.
- * @param forum the owner forum
- * @param status the approval status
- */
- public static Post create(Forum forum,
- String status) {
Post post = new Post();
- post.setup(forum, status);
+ post.setForum(forum);
return post;
}
- protected void setup(Forum forum,
- String status) {
- setForum(forum);
- setStatus(status);
- }
-
protected String getBaseDataObjectType() {
return BASE_DATA_OBJECT_TYPE;
}
/**
- * @deprecated use replyTo() instead
+ * overridden version of method in ThreadedMessage
+ * used to create a reply to an existing post
*/
- public Post replyToPost() {
- return (Post)replyTo();
- }
-
public ThreadedMessage newInstance() {
return create(getForum());
}
@@ -210,6 +209,7 @@ public class Post extends ThreadedMessage {
* before saving.
*/
protected void beforeSave() {
+ m_wasNew = isNew();
Forum forum = getForum();
Assert.exists(forum, Forum.class);
@@ -222,14 +222,14 @@ public class Post extends ThreadedMessage {
super.beforeSave();
- if (isNew()) {
- if (forum.isNoticeboard() && forum.getExpireAfter() > 0) {
- s_log.info("Creating expiration lifecycle for " + getOID());
- setLifecycle(forum.getLifecycleDefinition());
- }
- }
}
+ /**
+ * set permission contexts for this post to the root post, and for the root
+ * post to the forum. Additionally create a lifecycle if required for a new
+ * root post
+ */
+
protected void afterSave() {
super.afterSave();
Forum forum = getForum();
@@ -238,22 +238,51 @@ public class Post extends ThreadedMessage {
s_log.info("Setting context for " + getOID() + " to " + root.getOID());
PermissionService.setContext(this, root);
- s_log.info("Setting context for " + root.getOID() + " to " +
+ s_log.info(
+ "Setting context for " + root.getOID() + " to " +
forum.getOID());
PermissionService.setContext(root, forum);
+ // originally this was created in beforeSave, but this was when only noticeboard
+ // (reply disabled) forums could have a lifecycle. Now that all forums may
+ // have a lifecycle on root posts, the method needs to be here in order
+ // for persistence to work when users are replying to posts chris.gilbert@westsussex.gov.uk
+
+ if (m_wasNew) {
+ if (getRoot() == null && forum.getExpireAfter() > 0) {
+ s_log.info("Creating expiration lifecycle for " + getOID());
+ setLifecycle(forum.getLifecycleDefinition());
+ }
+ }
+ m_wasNew = false;
+
+ DataAssociationCursor files = getFiles();
+
+ // allow attached files to be returned in search results
+ // by setting their status as live
+ while (files.next()) {
+ PostFileAttachment file =
+ (PostFileAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ if (getStatus().equals(APPROVED)) {
+ file.setLive();
+ } else {
+ file.setDraft();
+ }
+
+ }
}
/**
* Sends out the notifications for any subscriptions to the forum
* or thread to which this message belongs. Only sends
- * notificatios if the post is approved.
+ * notifications if the post is approved.
*/
- public void sendNotifications() {
+ public void sendNotifications(final String context) {
KernelExcursion ex = new KernelExcursion() {
protected void excurse() {
setEffectiveParty(Kernel.getSystemParty());
- doSendNotifications();
+ doSendNotifications(context);
}
};
ex.run();
@@ -264,6 +293,9 @@ public class Post extends ThreadedMessage {
* on for the forum.
*/
public void sendModeratorAlerts() {
+
+ if (!getStatus().equals(APPROVED)) {
+ // don't send if pre-approved (ie posted by a moderator)
KernelExcursion ex = new KernelExcursion() {
protected void excurse() {
setEffectiveParty(Kernel.getSystemParty());
@@ -271,17 +303,17 @@ public class Post extends ThreadedMessage {
}
};
ex.run();
+ } else {
+ s_log.debug("not sending moderator alerts because the post " +
+ "was pre-approved (created by an approver)");
+ }
}
- private void doSendNotifications() {
- if (s_log.isDebugEnabled()) {
+ private void doSendNotifications(String context) {
s_log.debug("sending user notifications");
- }
Forum forum = getForum();
if (getStatus().equals(APPROVED)) {
- if (s_log.isDebugEnabled()) {
s_log.debug("Sending forum level subsriptions");
- }
DataCollection subscriptions = forum.getSubscriptions();
while (subscriptions.next()) {
@@ -290,28 +322,30 @@ public class Post extends ThreadedMessage {
subscriptions.getDataObject());
s_log.debug("notification to " + subscription.getOID());
- subscription.sendNotification(Post.this);
+ subscription.sendNotification(Post.this, Forum.getConfig().deleteNotifications());
}
- if (s_log.isDebugEnabled()) {
s_log.debug("Sending thread level subsriptions");
- }
+ if (context == null || !context.equals(PostForm.NEW_CONTEXT)) {
+
ThreadSubscription sub =
ThreadSubscription.getThreadSubscription(getThread());
-
- if (sub != null ) {
- sub.sendNotification(this);
+ if (sub == null) {
+ s_log.error(
+ "Got a null ThreadSubscription from "
+ + "Post # "
+ + getID());
} else {
- s_log.error("Got a null ThreadSubscription from " +
- "Post # " + getID());
+ sub.sendNotification(this, Forum.getConfig().deleteNotifications());
+ }
+
}
+
} else {
- if (s_log.isDebugEnabled()) {
s_log.debug("Not sending notifications because the " +
"message is not approved");
}
}
- }
private void doSendModeratorAlerts() {
if (s_log.isDebugEnabled()) {
@@ -327,19 +361,16 @@ public class Post extends ThreadedMessage {
while (alerts.next()) {
ModerationAlert alert
= (ModerationAlert)
- DomainObjectFactory.newInstance(alerts.getDataObject());
- if (s_log.isDebugEnabled()) {
+ DomainObjectFactory.newInstance(
+ alerts.getDataObject());
s_log.debug("Processing moderation alert " + alert.getOID());
- }
- alert.sendNotification(this);
+ alert.sendNotification(this, Forum.getConfig().deleteNotifications());
}
} else {
- if (s_log.isDebugEnabled()) {
s_log.debug("Not sending moderator alerts because the " +
"forum is not moderated");
}
}
- }
/**
* Set the Forum that contains this post. Just a wrapper for the
@@ -382,11 +413,32 @@ public class Post extends ThreadedMessage {
*/
public void clearCategories() {
- DataOperation clearCategories = SessionManager.getSession()
- .retrieveDataOperation("com.arsdigita.forum.clearCategories");
+ DataCollection categories =
+ SessionManager.getSession().retrieve(
+ Category.BASE_DATA_OBJECT_TYPE);
+ categories.addEqualsFilter(
+ Category.CHILD_OBJECTS + "." + ACSObject.ID,
+ getID());
+ while (categories.next()) {
+ Category cat =
+ (Category) DomainObjectFactory.newInstance(
+ categories.getDataObject());
+ cat.removeChild(this);
+ }
+
+ // above is slower than data operation implementation below,
+ // but data op caused problems in persistence. If edited post
+ // had topic unchanged, then attempt was made to assign topic
+ // category before data op had cleared existing. Hence exception
+ // - attempt to map object to same cat twice
+
+ /*
+ DataOperation clearCategories =
+ SessionManager.getSession().retrieveDataOperation(
+ "com.arsdigita.forum.clearCategories");
clearCategories.setParameter("postID", this.getID());
clearCategories.execute();
- return;
+ return;*/
}
/**
@@ -397,15 +449,41 @@ public class Post extends ThreadedMessage {
}
/**
- * creates a ThreadSubscription, but only if this is a root
+ * creates a ThreadSubscription, and returns it but only if this is a root,
+ * else return null
* Note, you must save() the Post before calling this method.
*/
- public void createThreadSubscription() {
+ public ThreadSubscription createThreadSubscription() {
+ ThreadSubscription sub = null;
if (getRoot() == null) {
- ThreadSubscription sub = new ThreadSubscription();
+ sub = new ThreadSubscription();
sub.setThread(getThread());
sub.save();
}
+ return sub;
+ }
+
+ public ThreadSubscription getSubscription() {
+ MessageThread thread;
+ if (getRoot() != null) {
+ thread = getRootMsg().getThread();
+ } else {
+ thread = getThread();
+ }
+ DataCollection subscriptions =
+ SessionManager.getSession().retrieve(
+ ThreadSubscription.BASE_DATA_OBJECT_TYPE);
+ subscriptions.addEqualsFilter(
+ ThreadSubscription.THREAD,
+ thread.getID());
+ ThreadSubscription subscription = null;
+ while (subscriptions.next()) {
+ subscription =
+ (ThreadSubscription) DomainObjectFactory.newInstance(
+ subscriptions.getDataObject());
+
+ }
+ return subscription;
}
/**
@@ -416,7 +494,10 @@ public class Post extends ThreadedMessage {
*/
public boolean canEdit(Party party) {
Party author = getFrom();
- return (Forum.getConfig().canAuthorEditPosts()
+ // cg added - for anonymous posts, don't allow editing, else everyone could edit everyone else's posts
+ return (
+ !author.equals(Kernel.getPublicUser())
+ && Forum.getConfig().canAuthorEditPosts()
&& author.equals(party))
|| getForum().canEdit(party);
}
@@ -439,6 +520,38 @@ public class Post extends ThreadedMessage {
set(STATUS, status);
}
+ /**
+ * set the status of a new post according to the priviliges of
+ * the current user - used by UI when creating new post or reply
+ * @param state
+ */
+ public void setStatus(PageState state) {
+ setStatus(state, null);
+ }
+
+ /**
+ * set the status of an edited post according to the privileges
+ * of the current user and the status of the post that is being
+ * edited - used by the edit post UI
+ * @param state
+ * @param previousStatus
+ */
+ public void setStatus(PageState state, String previousStatus) {
+ ForumContext ctx = ForumContext.getContext(state);
+ Forum forum = ctx.getForum();
+ // set status of edited post
+ if (forum.isModerated() && !ctx.canModerate()) {
+ if (Post.APPROVED.equals(previousStatus)) {
+ setStatus(Post.REAPPROVE);
+ } else {
+ setStatus(Post.PENDING);
+ }
+ } else {
+ setStatus(Post.APPROVED);
+ }
+
+ }
+
public String getStatus() {
return (String)get(STATUS);
}
@@ -458,24 +571,19 @@ public class Post extends ThreadedMessage {
return m_moderator;
}
+ // note that the replies to this post are deleted in beforeDelete() of
+ // ThreadedMessage (and hence beforeDelete is called recursively on their replies)
+
protected void beforeDelete() {
- // First delete associated entries in nt_requests this entry and
- // all of its replies (in case of a root message) have
- List replies = new ArrayList();
- List msgIdList = new ArrayList();
- msgIdList.add(getID());
- if (getRoot() == null) {
- DataCollection msgs = SessionManager.getSession()
- .retrieve(BASE_DATA_OBJECT_TYPE);
- msgs.addEqualsFilter("root", getID());
- while (msgs.next()) {
- replies.add(msgs.getDataObject());
- msgIdList.add( msgs.getDataObject().getOID().get("id"));
- }
- }
- DataCollection requests = SessionManager.getSession()
- .retrieve(Notification.BASE_DATA_OBJECT_TYPE);
- requests.addFilter("messageID in :msgIdList").set("msgIdList", msgIdList);
+ s_log.debug("Post - before delete " + getID());
+
+ // threaded message recursively deletes children
+ super.beforeDelete();
+ // remove any nt_requests
+ DataCollection requests =
+ SessionManager.getSession().retrieve(
+ Notification.BASE_DATA_OBJECT_TYPE);
+ requests.addEqualsFilter(Notification.MESSAGE_ID, this.getID());
while (requests.next()) {
Notification no = new Notification(requests.getDataObject().getOID());
no.setMessageDelete(Boolean.FALSE);
@@ -483,21 +591,23 @@ public class Post extends ThreadedMessage {
}
if (getRoot() == null) {
- // This posting is the root of the thread. Make sure all postings
- // in this thread are deleted before this very one. Also
- // take care of thread subscription.
- ThreadSubscription sub = ThreadSubscription.getThreadSubscription(this.getThread());
+ s_log.debug(
+ "Root post - get rid of thread subscription and thread");
+ // This posting is the root of the thread. Remove the thread subscription and thread
+ MessageThread thread = getThread();
+ ThreadSubscription sub =
+ ThreadSubscription.getThreadSubscription(thread);
+ if (sub != null) {
+ // if unconfirmed post, then threadsubscription has not been created
sub.delete();
- MessageThread thread = MessageThread.getFromRootMessage(this);
- thread.delete();
- for (Iterator it = replies.iterator(); it.hasNext(); ) {
- Post reply = new Post( (DataObject) it.next());
- reply.delete();
+
}
+ if (thread != null) {
+ thread.delete();
}
- super.beforeDelete();
}
+ }
// package access only
void setLifecycle(LifecycleDefinition life) {
@@ -507,5 +617,91 @@ public class Post extends ThreadedMessage {
cycle.save();
}
+ public void addImage(PostImageAttachment image) {
+ DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS);
+ image.addToAssociation(images);
+ long currentImageCount = images.getDataAssociationCursor().size();
+ image.setImageOrder((int) currentImageCount);
+ }
+
+ public void removeImage(PostImageAttachment image) {
+ DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS);
+ image.removeFromAssociation(images);
+ renumberImages();
+ }
+
+ // image order for a new image is based on the count of existing
+ // images, hence necessary to fill in any gaps when images are deleted
+ private void renumberImages() {
+ int count = 1;
+ DataAssociationCursor images = getImages();
+ while (images.next()) {
+ PostImageAttachment image =
+ (PostImageAttachment) DomainObjectFactory.newInstance(
+ images.getDataObject());
+ image.setImageOrder(count);
+ count++;
+ }
+ }
+
+ public DataAssociationCursor getImages() {
+ DataAssociationCursor images =
+ ((DataAssociation) get(Post.IMAGE_ATTACHMENTS))
+ .getDataAssociationCursor();
+ images.addOrder(PostImageAttachment.IMAGE_ORDER);
+ return images;
+ }
+
+ public void addFile(PostFileAttachment file) {
+ DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS);
+ file.addToAssociation(files);
+ PermissionService.setContext(file, this);
+ long currentFileCount = files.getDataAssociationCursor().size();
+ file.setFileOrder((int) currentFileCount);
+ }
+
+ public void removeFile(PostFileAttachment file) {
+ DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS);
+ file.removeFromAssociation(files);
+ renumberFiles();
+
+ }
+
+ // file order for a new file is based on the count of existing
+ // files, hence necessary to fill in any gaps when images are deleted
+
+ private void renumberFiles() {
+ int count = 1;
+ DataAssociationCursor files = getFiles();
+ while (files.next()) {
+ PostFileAttachment file =
+ (PostFileAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ file.setFileOrder(count);
+ count++;
+ }
+
+ }
+
+ public DataAssociationCursor getFiles() {
+ DataAssociationCursor files =
+ ((DataAssociation) get(Post.FILE_ATTACHMENTS))
+ .getDataAssociationCursor();
+ files.addOrder(PostFileAttachment.FILE_ORDER);
+ return files;
+
+ }
+
+
+ /**
+ * used by thread to prevent counting unapproved posts in the
+ * reply count.
+ *
+ */
+ // should really be static - revisit this - refer to MessageThread for use
+ protected void addReplyFilter(DataCollection replies) {
+ replies.addEqualsFilter(STATUS, APPROVED);
+
+ }
}
diff --git a/ccm-forum/src/com/arsdigita/forum/PostFileAttachment.java b/ccm-forum/src/com/arsdigita/forum/PostFileAttachment.java
new file mode 100644
index 000000000..ee269a64e
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/PostFileAttachment.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.auditing.BasicAuditTrail;
+import com.arsdigita.cms.FileAsset;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Domain object for a file attached to a post. Modelled as domain object
+ * rather than simple association with link attribute because cloning
+ * seems to struggle with link attributes and also this allows files
+ * to be indexed separately for searching
+ */
+public class PostFileAttachment extends FileAsset {
+
+ private static final Logger s_log = Logger.getLogger(PostFileAttachment.class);
+
+ public static final String BASE_DATA_OBJECT_TYPE =
+ "com.arsdigita.forum.PostFileAttachment";
+ public static final String FILE_OWNER = "fileMessage";
+ public static final String FILE_ORDER = "fileOrder";
+
+ public PostFileAttachment() {
+ super(BASE_DATA_OBJECT_TYPE);
+ setVersion(DRAFT);
+
+ }
+
+ public PostFileAttachment(OID oid) {
+ super(oid);
+ }
+
+ public PostFileAttachment(BigDecimal id) {
+ this(new OID(BASE_DATA_OBJECT_TYPE, id));
+ }
+
+ public PostFileAttachment(DataObject obj) {
+ super(obj);
+ }
+
+ public PostFileAttachment(String type) {
+ super(type);
+ }
+
+ public String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+ public void setFileOrder(Integer order) {
+ set(FILE_ORDER, order);
+ }
+
+ public void setFileOrder(int order) {
+ set(FILE_ORDER, new Integer(order));
+ }
+
+ /*
+ * forums don't have a full publishing cycle,
+ * so we won't apply a heavyweight publishing to attached files
+ * just switch version tag
+ */
+ public void setLive () {
+ setVersion(LIVE);
+ }
+
+ /*
+ * prevent files from being returned in search results -
+ * used after save of post, so that for example if post is unapproved,
+ * files are removed from search results
+ */
+ public void setDraft () {
+ setVersion(DRAFT);
+ }
+
+
+ public Post getOwner() {
+ return (Post)DomainObjectFactory.newInstance((DataObject)get(FILE_OWNER));
+ }
+
+ protected static void removeUnattachedFiles() {
+ s_log.debug("removing orphaned files created more than a day ago");
+
+ DataCollection files = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
+ Calendar yesterday = Calendar.getInstance();
+ yesterday.add(Calendar.DATE, -1);
+ files.addFilter(files.getFilterFactory().lessThan(AUDITING + "." + BasicAuditTrail.CREATION_DATE,
+ yesterday.getTime(),
+ false));
+
+ files.addEqualsFilter(FILE_OWNER, null);
+ while (files.next()) {
+ s_log.debug("deleting one");
+
+ DomainObjectFactory.newInstance(files.getDataObject()).delete();
+ }
+
+ }
+
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/PostFileAttachmentURLFinder.java b/ccm-forum/src/com/arsdigita/forum/PostFileAttachmentURLFinder.java
new file mode 100644
index 000000000..ca82640a9
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/PostFileAttachmentURLFinder.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import com.arsdigita.cms.ContentItem;
+import com.arsdigita.cms.dispatcher.AssetURLFinder;
+
+import com.arsdigita.kernel.NoValidURLException;
+import com.arsdigita.kernel.URLFinder;
+import com.arsdigita.kernel.URLService;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.Assert;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * A URLFinder for PostFileAttachments.
+ */
+public class PostFileAttachmentURLFinder implements URLFinder {
+
+ private static final AssetURLFinder s_assetFinder = new AssetURLFinder();
+
+ /**
+ *
+ * find URL for a file attachment by finding its post
+ *
+ * @param oid the OID of the file attachment
+ * @param content the context of the search (ie draft/live)
+ */
+ public String find(OID oid, String context) throws NoValidURLException {
+ // a draft attachment is one where the post hasn't been saved yet
+ // the behaviour is the same as far as finding the url goes
+ return find(oid);
+
+
+ }
+
+ /**
+ *
+ * find URL for the context of a file attachment. Delegates to
+ * AssetURLFinder.
+ *
+ * @param oid the OID of the file attachment
+ *
+ */
+ public String find(OID oid) throws NoValidURLException {
+ return s_assetFinder.find(oid);
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/PostFinder.java b/ccm-forum/src/com/arsdigita/forum/PostFinder.java
new file mode 100644
index 000000000..e5757787f
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/PostFinder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.kernel.NoValidURLException;
+import com.arsdigita.kernel.URLFinder;
+import com.arsdigita.messaging.ThreadedMessage;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.web.Application;
+import com.arsdigita.web.ParameterMap;
+import com.arsdigita.web.URL;
+
+/**
+ * @author cgyg9330
+ * (copied from Matt Booth)
+ * A URLFinder for Posts
+ */
+public class PostFinder implements URLFinder {
+
+ public String find(OID oid, String context) throws NoValidURLException {
+ return find(oid);
+ }
+ public String find(OID oid) throws NoValidURLException {
+ DataObject dobj = SessionManager.getSession().retrieve(oid);
+ if (dobj == null) {
+ throw new NoValidURLException("No such data object " + oid);
+ }
+
+ Application app = Application.retrieveApplication(dobj);
+
+ if (app == null) {
+ throw new NoValidURLException("Could not find application instance for " + dobj);
+ }
+
+ try {
+ ThreadedMessage message = new ThreadedMessage(oid);
+ ParameterMap params = new ParameterMap();
+ params.setParameter("thread", message.getThread().getID().toString());
+ return URL.there("/" + app.getPath() + "/thread.jsp", params).toString();
+ } catch (DataObjectNotFoundException e) {
+ throw new NoValidURLException("Could not find application instance for " + dobj);
+ }
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/PostImageAttachment.java b/ccm-forum/src/com/arsdigita/forum/PostImageAttachment.java
new file mode 100644
index 000000000..d850e5d47
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/PostImageAttachment.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.auditing.BasicAuditTrail;
+import com.arsdigita.cms.ImageAsset;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Domain object for an image attached to a post. Modelled as domain object
+ * rather than simple association with link attribute because cloning
+ * seems to struggle with link attributes
+ */
+public class PostImageAttachment extends ImageAsset {
+
+ private static final Logger s_log = Logger.getLogger(PostImageAttachment.class);
+
+ public static final String BASE_DATA_OBJECT_TYPE =
+ "com.arsdigita.forum.PostImageAttachment";
+
+ public static final String IMAGE_OWNER = "imageMessage";
+ public static final String IMAGE_ORDER = "imageOrder";
+
+ /**
+ * Default constructor. ;
+ **/
+ public PostImageAttachment() {
+ super(BASE_DATA_OBJECT_TYPE);
+ setVersion(DRAFT);
+
+ }
+
+ /**
+ * Constructor. The contained DataObject is retrieved
+ * from the persistent storage mechanism with an OID
+ * specified by oid.
+ *
+ * @param oid The OID for the retrieved
+ * DataObject.
+ **/
+ public PostImageAttachment(OID oid) {
+ super(oid);
+ }
+
+ /**
+ * Constructor. The contained DataObject is retrieved
+ * from the persistent storage mechanism with an OID
+ * specified by id and ContentPage.BASE_DATA_OBJECT_TYPE.
+ *
+ * @param id The id for the retrieved
+ * DataObject.
+ **/
+ public PostImageAttachment(BigDecimal id) {
+ this(new OID(BASE_DATA_OBJECT_TYPE, id));
+ }
+
+ public PostImageAttachment(DataObject obj) {
+ super(obj);
+ }
+
+ public PostImageAttachment(String type) {
+ super(type);
+ }
+
+ public String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+ public void setImageOrder(Integer order) {
+ set(IMAGE_ORDER, order);
+ }
+
+ public void setImageOrder(int order) {
+ set(IMAGE_ORDER, new Integer(order));
+ }
+
+
+
+ public Post getOwner() {
+ return (Post)DomainObjectFactory.newInstance((DataObject)get(IMAGE_OWNER));
+ }
+
+
+ protected static void removeUnattachedImages() {
+ s_log.debug("removing orphaned images created more than a day ago");
+ DataCollection images = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
+ Calendar yesterday = Calendar.getInstance();
+ yesterday.add(Calendar.DATE, -1);
+ images.addFilter(images.getFilterFactory().lessThan(AUDITING + "." + BasicAuditTrail.CREATION_DATE,
+ yesterday.getTime(),
+ false));
+
+ images.addEqualsFilter(IMAGE_OWNER, null);
+ while (images.next()) {
+ s_log.debug("deleting one");
+ DomainObjectFactory.newInstance(images.getDataObject()).delete();
+ }
+
+ }
+
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsScheduler.java b/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsScheduler.java
new file mode 100644
index 000000000..1f48d9555
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsScheduler.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Timer;
+
+import org.apache.log4j.Logger;
+
+
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.KernelExcursion;
+import com.arsdigita.persistence.Session;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.persistence.TransactionContext;
+import com.arsdigita.util.UncheckedWrapperException;
+
+/**
+ * Scheduler thread to remove any files or images that are more than a day old
+ * and haven't been attached to a post.
+ * These posts arise if a user starts to create a post and closes their browser
+ * before completing the post. This
+ * process gets rid of them on a daily basis to keep them under control
+ *
+ * nb - We can't just delete all unattached assets, as some may be there because the user is
+ * halfway through making a new post
+ *
+ * @author Chris Gilbert(chris.gilbert@westsussex.gov.uk)
+ * @version $Revision: 1.1 $ $DateTime: 2004/08/17 23:15:09 $
+ */
+public class RemoveUnattachedAssetsScheduler {
+
+ public static final String versionId = "$Id: RemoveUnattachedAssetsScheduler.java,v 1.1 2006/07/13 10:19:28 cgyg9330 Exp $ by $Author: cgyg9330 $, $DateTime: 2004/08/17 23:15:09 $";
+
+ // For storing timer which runs a method periodically to fire
+ // begin and end events
+ private static Timer s_Timer;
+
+ // if process runs very very slowly, prevent duplicate attempt fro mrunning before the first one ends
+ private static boolean s_running = false;
+
+ private static Logger s_log =
+ Logger.getLogger( RemoveUnattachedAssetsScheduler.class);
+
+
+ /**
+ * startTimer - starts the timer
+ */
+ public static synchronized void startTimer() {
+ if ( s_Timer != null ) {
+ return; // Timer already exists
+ }
+
+ // Timer triggers straight away, and then every 24 hours
+ // don't run timer as a daemon - if server stops, kill this process too, as no one will be creating new posts
+ s_Timer = new Timer(false);
+
+ s_Timer.scheduleAtFixedRate(new RemoveUnattachedAssetsTask(), 0, 1000 * 60 * 60 * 24);
+ }
+
+
+ /**
+ * run - Run the task
+ */
+ public static synchronized void run() {
+ s_log.debug("Firing off scheduler");
+ Session ssn = SessionManager.getSession();
+ if ( !s_running ) {
+ new KernelExcursion() {
+ protected final void excurse() {
+ s_running = true;
+ try {
+ setEffectiveParty(Kernel.getSystemParty());
+ TransactionContext txn =SessionManager.getSession().getTransactionContext();
+ txn.beginTxn();
+
+ PostFileAttachment.removeUnattachedFiles();
+ PostImageAttachment.removeUnattachedImages();
+ txn.commitTxn();
+ } catch (Throwable t) {
+ s_log.error("Attempt to remove unconfirmed forum posts failed", t);
+ throw new UncheckedWrapperException(t);
+
+ } finally {
+ s_running = false;
+ }
+
+ }
+ }.run();
+ }
+ }
+
+
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsTask.java b/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsTask.java
new file mode 100644
index 000000000..b163fab7d
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/RemoveUnattachedAssetsTask.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import org.apache.log4j.Logger;
+
+import java.util.TimerTask;
+
+import com.arsdigita.util.UncheckedWrapperException;
+
+
+/**
+ *
+ * @version $Revision: 1.1 $ $DateTime: 2004/08/17 23:15:09 $
+ **/
+class RemoveUnattachedAssetsTask extends TimerTask {
+
+ public static final String versionId = "$Id: RemoveUnattachedAssetsTask.java,v 1.1 2006/07/13 10:19:28 cgyg9330 Exp $ by $Author: cgyg9330 $, $DateTime: 2004/08/17 23:15:09 $";
+ private static final Logger s_log = Logger.getLogger(RemoveUnattachedAssetsTask.class);
+ public void run() {
+ RemoveUnattachedAssetsScheduler.run();
+
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/Subscription.java b/ccm-forum/src/com/arsdigita/forum/Subscription.java
index e40d65d9e..1fb83439c 100755
--- a/ccm-forum/src/com/arsdigita/forum/Subscription.java
+++ b/ccm-forum/src/com/arsdigita/forum/Subscription.java
@@ -18,16 +18,17 @@
*/
package com.arsdigita.forum;
+import org.apache.log4j.Logger;
+
import com.arsdigita.domain.DataObjectNotFoundException;
-import com.arsdigita.web.URL;
-import com.arsdigita.web.ParameterMap;
+import com.arsdigita.mail.Mail;
import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.notification.BaseSubscription;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.Assert;
-import com.arsdigita.util.StringUtils;
-import org.apache.log4j.Logger;
+import com.arsdigita.web.ParameterMap;
+import com.arsdigita.web.URL;
/**
* The abstract Subscription class provides the ability for Users
@@ -41,12 +42,13 @@ import org.apache.log4j.Logger;
*/
public abstract class Subscription extends BaseSubscription {
public static final String versionId =
- "$Id: Subscription.java 287 2005-02-22 00:29:02Z sskracic $" +
- "$Author: sskracic $" +
+ "$Id: Subscription.java 1628 2007-09-17 08:10:40Z chrisg23 $" +
+ "$Author: chrisg23 $" +
"$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(Subscription.class);
+ protected static final String HTML_SEPARATOR = "
\n
\n
\n";
public Subscription(String objectType) {
super(objectType);
}
@@ -81,8 +83,17 @@ public abstract class Subscription extends BaseSubscription {
if (author == null) {
author = "Unknown";
}
-
StringBuffer sb = new StringBuffer();
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ sb.append("");
+ sb.append("Forum : ");
+ sb.append(post.getForum().getDisplayName()).append("\n
");
+ sb.append("Subject : ");
+ sb.append(post.getSubject()).append("\n
");
+ sb.append("Posted by: ");
+ sb.append(author).append("\n
");
+ } else {
+
sb.append("Forum : ");
sb.append(post.getForum().getDisplayName()).append("\n");
sb.append("Subject : ");
@@ -90,6 +101,9 @@ public abstract class Subscription extends BaseSubscription {
sb.append("Posted by: ");
sb.append(author).append("\n\n");
+ }
+
+
return sb.toString();
}
@@ -98,8 +112,12 @@ public abstract class Subscription extends BaseSubscription {
* implementation returns a separator and a generic messages.
*/
public String getSignature(ThreadedMessage post) {
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ return HTML_SEPARATOR + ALERT_BLURB + "";
+ } else {
return SEPARATOR + ALERT_BLURB;
}
+ }
/**
* @return an appropriate message to direct people back to the
@@ -115,15 +133,13 @@ public abstract class Subscription extends BaseSubscription {
StringBuffer sb = new StringBuffer();
sb.append("To reply to this message, go to:\n");
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ sb.append("
" + url.getURL() + "");
+ } else {
sb.append(url.getURL());
-
+ }
return sb.toString();
}
- /*
- * @return an appropriate separator for the body and signature of a post.
- */
- private static String getSeparator() {
- return "\n\n" + StringUtils.repeat('-', 20) + "\n\n";
- }
+
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ThreadPageBuilder.java b/ccm-forum/src/com/arsdigita/forum/ThreadPageBuilder.java
new file mode 100644
index 000000000..63585d73f
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ThreadPageBuilder.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum;
+
+import java.math.BigDecimal;
+
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageFactory;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleComponent;
+import com.arsdigita.bebop.event.RequestEvent;
+import com.arsdigita.bebop.event.RequestListener;
+import com.arsdigita.bebop.parameters.BigDecimalParameter;
+import com.arsdigita.bebop.parameters.ParameterModel;
+import com.arsdigita.forum.ui.Constants;
+import com.arsdigita.forum.ui.ThreadComponent;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.toolbox.ui.ApplicationAuthenticationListener;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Implementation of com.arsdigita.forum.PageBuilder that creates a basic thread page with read access check
+ */
+public class ThreadPageBuilder implements PageBuilder, Constants {
+
+ /* (non-Javadoc)
+ * @see com.arsdigita.forum.PageBuilder#buildPage(com.arsdigita.bebop.parameters.ParameterModel)
+ */
+ public Page buildPage() {
+ Page threadPage = PageFactory.buildPage(Constants.FORUM_XML_PREFIX, "Threads", "forumThreadPage");
+ //Output the title in an easy to find place
+ threadPage.add(new SimpleComponent(){
+ public void generateXML(PageState state, Element parent) {
+ Element nameElement = parent.newChildElement(Constants.FORUM_XML_PREFIX + ":name", Constants.FORUM_XML_NS);
+ nameElement.setText(ForumContext.getContext(state).getForum().getTitle());
+ Element introductionElement = parent.newChildElement(Constants.FORUM_XML_PREFIX + ":introduction", Constants.FORUM_XML_NS);
+ introductionElement.setText(ForumContext.getContext(state).getForum().getIntroduction());
+ }
+ });
+ threadPage.add(new ThreadComponent());
+ // Register the thread id parameter as a global state parameter.
+ BigDecimalParameter threadID = new BigDecimalParameter(THREAD_PARAM);
+ threadPage.addGlobalStateParam(threadID);
+ threadPage.addRequestListener(new ApplicationAuthenticationListener(PrivilegeDescriptor.READ));
+
+ threadPage.addRequestListener
+ (new ThreadPageRequestListener(threadID));
+ return threadPage;
+ }
+
+ private static class ThreadPageRequestListener implements RequestListener {
+ private BigDecimalParameter m_threadID;
+
+ public ThreadPageRequestListener(BigDecimalParameter threadID) {
+ m_threadID = threadID;
+ }
+
+
+ public void pageRequested(RequestEvent event) {
+ PageState state = event.getPageState();
+ ForumContext context = ForumContext.getContext(state);
+ context.setThreadID
+ ((BigDecimal) event.getPageState().getValue(m_threadID));
+ }
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ThreadSubscription.java b/ccm-forum/src/com/arsdigita/forum/ThreadSubscription.java
index 049e25e45..52b761b8b 100755
--- a/ccm-forum/src/com/arsdigita/forum/ThreadSubscription.java
+++ b/ccm-forum/src/com/arsdigita/forum/ThreadSubscription.java
@@ -18,25 +18,27 @@
*/
package com.arsdigita.forum;
+import java.math.BigDecimal;
+
+import com.arsdigita.bebop.PageState;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainCollection;
-import com.arsdigita.domain.DomainObject;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.kernel.GroupCollection;
+import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.Party;
import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.mail.Mail;
import com.arsdigita.messaging.MessageThread;
+import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.notification.Notification;
import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject;
-import com.arsdigita.persistence.DataQuery;
-import com.arsdigita.persistence.DataQueryDataCollectionAdapter;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager;
-import java.math.BigDecimal;
-
/**
- * Experimental
* Class for managing subscriptions to individual threads in a Forum.
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
@@ -46,7 +48,7 @@ public class ThreadSubscription extends Subscription {
public static final String BASE_DATA_OBJECT_TYPE =
"com.arsdigita.forum.ThreadSubscription";
- private static final String THREAD = "thread";
+ public static final String THREAD = "thread";
private MessageThread m_thread = null;
@@ -66,6 +68,29 @@ public class ThreadSubscription extends Subscription {
super(oid);
}
+ public String getSubscriptionGroupName() {
+ // not overridden because group should be based on
+ // thread root post name, but thread hasn't been set when
+ // this is called. Group name is updated in setThread method
+ return super.getSubscriptionGroupName();
+
+ }
+
+ public String getSubscriptionGroupName(Forum forum) {
+ return forum.getTitle() + ": " + getThreadReal().getRootMessage().getSubject() + " Subscription Group";
+ }
+
+ protected Group getParentGroup() {
+ GroupCollection forumGroups = ((Forum)Kernel.getContext().getResource()).getGroup().getSubgroups();
+ forumGroups.addEqualsFilter("name", Forum.THREAD_SUBSCRIPTION_GROUPS_NAME);
+ Group parent = null;
+ if (forumGroups.next()) {
+ parent = forumGroups.getGroup();
+ forumGroups.close();
+ }
+ return parent;
+ }
+
public ThreadSubscription(BigDecimal id)
throws DataObjectNotFoundException {
super(new OID(BASE_DATA_OBJECT_TYPE, id));
@@ -107,6 +132,7 @@ public class ThreadSubscription extends Subscription {
public void setThread(MessageThread thread) {
m_thread = thread;
setAssociation(THREAD, thread);
+ getGroup().setName(getSubscriptionGroupName((Forum)Kernel.getContext().getResource()));
}
protected void afterSave() {
@@ -158,30 +184,51 @@ public class ThreadSubscription extends Subscription {
return sub;
}
- public static DomainCollection getSubsForUser(Party party) {
- DataQuery subs = SessionManager.getSession()
- .retrieveQuery("com.arsdigita.forum.getUserThreadSubscriptions");
+ public static DomainCollection getSubsForUser(Party party, PageState state) {
+ // chris.gilbert@westsussex.gov.uk replace query with standard filtering
+ DataCollection subscriptions = SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE);
+ subscriptions.addEqualsFilter("group.allMembers.id", party.getID());
+
+ // currently specified in config, but could be selected from widget on screen
+ // ie show thread subscriptions for this forum/all forums
+ //
+ // Currently, if subscription for a different forum is selected, the thread is displayed within
+ // the context of this forum which is not good. I suspect there is a need to set the forum in the
+ // forum context when thread.jsp is reached. Have not implemented changes as we are only displaying
+ // subscriptions for current forum cg.
+ if (!Forum.getConfig().showThreadAlertsForAllForums()){
+ subscriptions.addEqualsFilter("thread.root.objectID", ForumContext.getContext(state).getForum().getID());
+ }
- subs.setParameter("userID", party.getID());
+ return new DomainCollection(subscriptions);
- return new DomainCollection(new DataQueryDataCollectionAdapter(subs, "subscription")) {
- public DomainObject getDomainObject() {
- return new ThreadSubscription(m_dataCollection.getDataObject());
- }
- };
}
/**
* Returns a signature with information about replying to the
* message
*/
- public String getSignature(Post post) {
+ public String getSignature(ThreadedMessage post) {
+ StringBuffer sb = new StringBuffer();
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ sb.append(HTML_SEPARATOR);
+ sb.append(getReturnURLMessage((Post)post));
+ sb.append(HTML_SEPARATOR);
+ sb.append(ALERT_BLURB);
+ sb.append("You are receiving this email because you subscribed to ");
+ sb.append("alerts on this thread. To unsubscribe, follow the link above and click the 'stop watching thread' link at the top of the page.\n");
+ sb.append("");
+ } else {
+ sb.append(SEPARATOR);
+ sb.append(ALERT_BLURB);
+ sb.append("You are receiving this email because you subscribed to ");
+ sb.append("alerts on this thread.\n\n");
+ sb.append(REPLY_BLURB);
+ sb.append(getReturnURLMessage((Post)post));
+ }
+ return sb.toString();
+
+
- return SEPARATOR
- + ALERT_BLURB
- + "You are receiving this email because you subscribed to "
- + "alerts on this thread.\n\n"
- + REPLY_BLURB
- + getReturnURLMessage(post);
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/portlet/MyForumsPortlet.java b/ccm-forum/src/com/arsdigita/forum/portlet/MyForumsPortlet.java
new file mode 100644
index 000000000..e73202e46
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/portlet/MyForumsPortlet.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.portlet;
+
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ThreadCollection;
+import com.arsdigita.forum.ui.Constants;
+import com.arsdigita.forum.ui.ThreadList;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.domain.DomainObjectXMLRenderer;
+import com.arsdigita.bebop.portal.AbstractPortletRenderer;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.messaging.MessageThread;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.xml.Element;
+import com.arsdigita.xml.formatters.DateFormatter;
+import com.arsdigita.web.URL;
+import com.arsdigita.web.ParameterMap;
+import com.arsdigita.portal.Portlet;
+import com.arsdigita.portal.apportlet.AppPortlet;
+
+/**
+ *
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * portlet with no attributes that displays links to all forums that user has read access to
+ *
+ */
+public class MyForumsPortlet extends Portlet {
+ public static final String versionId = "$Id: MyForumsPortlet.java,v 1.4 2006/07/13 10:19:28 cgyg9330 Exp $ by $Author: cgyg9330 $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public static final String BASE_DATA_OBJECT_TYPE =
+ "com.arsdigita.forum.MyForumsPortlet";
+
+
+ protected String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+ public MyForumsPortlet(DataObject dataObject) {
+ super(dataObject);
+ }
+
+
+
+ protected AbstractPortletRenderer doGetPortletRenderer() {
+ return new MyForumsPortletRenderer(this);
+ }
+
+
+}
+
+class MyForumsPortletRenderer
+ extends AbstractPortletRenderer
+ implements Constants {
+
+ private MyForumsPortlet m_portlet;
+
+ public MyForumsPortletRenderer(MyForumsPortlet
+ portlet) {
+ m_portlet = portlet;
+ }
+
+ protected void generateBodyXML(PageState pageState,
+ Element parent) {
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":myForumsPortlet",
+ FORUM_XML_NS);
+
+
+ Party party = Kernel.getContext().getParty();
+ if (party == null) {
+ party = Kernel.getPublicUser();
+ }
+
+ DataCollection forums = SessionManager.getSession().retrieve(Forum.BASE_DATA_OBJECT_TYPE);
+ forums.addOrder("lower(" + Forum.TITLE + ")");
+ PermissionService.filterObjects(forums, PrivilegeDescriptor.READ, party.getOID());
+
+
+ while (forums.next()) {
+ Forum forum = (Forum)DomainObjectFactory.newInstance(forums.getDataObject());
+ Element forumEl = content.newChildElement(FORUM_XML_PREFIX + ":forum", FORUM_XML_NS);
+ URL url = URL.there(forum, "/", null);
+ forumEl.addAttribute("url", url.toString());
+ forumEl.addAttribute("title", forum.getTitle());
+ // display last forum update info
+ ThreadCollection threads = forum.getThreads();
+ threads.addOrder(MessageThread.LAST_UPDATE);
+ if (threads.next()) {
+ MessageThread lastUpdatedThread = threads.getMessageThread();
+ forumEl.addAttribute("lastUpdated", new DateFormatter().format(lastUpdatedThread.getLatestUpdateDate()));
+ threads.close();
+ } else {
+ forumEl.addAttribute("lastUpdated", "");
+ }
+
+
+ }
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/portlet/RecentPostingsPortlet.java b/ccm-forum/src/com/arsdigita/forum/portlet/RecentPostingsPortlet.java
index 4ec501423..c551e5a6c 100755
--- a/ccm-forum/src/com/arsdigita/forum/portlet/RecentPostingsPortlet.java
+++ b/ccm-forum/src/com/arsdigita/forum/portlet/RecentPostingsPortlet.java
@@ -36,7 +36,7 @@ import com.arsdigita.portal.apportlet.AppPortlet;
public class RecentPostingsPortlet extends AppPortlet {
- public static final String versionId = "$Id: RecentPostingsPortlet.java 755 2005-09-02 13:42:47Z sskracic $ by $Author: sskracic $, $DateTime: 2004/08/17 23:26:27 $";
+ public static final String versionId = "$Id: RecentPostingsPortlet.java 1628 2007-09-17 08:10:40Z chrisg23 $ by $Author: chrisg23 $, $DateTime: 2004/08/17 23:26:27 $";
public static final String BASE_DATA_OBJECT_TYPE =
"com.arsdigita.forum.RecentPostingsPortlet";
@@ -93,6 +93,7 @@ class RecentPostingsPortletRenderer
Forum forum = (Forum)m_portlet.getParentApplication();
content.addAttribute("noticeboard", (new Boolean(forum.isNoticeboard())).toString());
+ content.addAttribute("forumName", forum.getTitle());
Party party = Kernel.getContext().getParty();
diff --git a/ccm-forum/src/com/arsdigita/forum/search/FileAttachmentMetadataProvider.java b/ccm-forum/src/com/arsdigita/forum/search/FileAttachmentMetadataProvider.java
new file mode 100644
index 000000000..cb9e35e4c
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/search/FileAttachmentMetadataProvider.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.search;
+
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.cms.search.AssetExtractor;
+import com.arsdigita.cms.search.AssetMetadataProvider;
+import com.arsdigita.domain.DomainObject;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.PostFileAttachment;
+import com.arsdigita.globalization.Globalization;
+import com.arsdigita.globalization.SystemLocaleProvider;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.kernel.URLService;
+import com.arsdigita.kernel.User;
+import com.arsdigita.search.ContentProvider;
+import com.arsdigita.search.ContentType;
+import com.arsdigita.search.MetadataProvider;
+import com.arsdigita.toolbox.util.GlobalizationUtil;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ *
+ */
+public class FileAttachmentMetadataProvider extends AssetMetadataProvider {
+
+ private static Logger s_log = Logger.getLogger(FileAttachmentMetadataProvider.class);
+
+ public String getSummary(DomainObject dobj) {
+ PostFileAttachment file = (PostFileAttachment)dobj;
+ s_log.debug("Getting Summary File " + file.getID());
+ Post owner = file.getOwner();
+ //s_log.debug("Owner " + (owner == null ? null : owner.getID()));
+ if (owner == null){
+ //until post is saved, the file doesn't have an owner
+ //file is saved as draft so result will not be returned at front end
+ return "File attached to forum post";
+ }
+ String url = URLService.locate(owner.getOID());
+ String fileDescription = file.getDescription();
+ StringBuffer summary = new StringBuffer();
+ if (fileDescription != null) {
+ summary.append(fileDescription + " - ");
+ }
+ summary.append("A file attached to " +
+ owner.getSubject() + " - a posting by " +
+ ((User)owner.getFrom()).getName() + " to forum " + owner.getForum().getTitle());
+ return summary.toString();
+
+ }
+
+ public boolean isIndexable (DomainObject dobj) {
+ PostFileAttachment file = (PostFileAttachment)dobj;
+ Post owner = file.getOwner();
+ Post root = null;
+ s_log.debug("start:isIndexable");
+ boolean indexable = false;
+ if (owner != null) {
+ // post has been saved
+ s_log.debug("owner = " + owner);
+ BigDecimal rootId = owner.getRoot();
+ if (rootId != null) {
+ root = new Post(owner.getRoot());
+ // else this is a root post
+ }
+ indexable = owner.getStatus().equals(Post.APPROVED) && (root == null ? true : root.getStatus().equals(Post.APPROVED));
+ }
+ return indexable;
+
+ }
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/search/PostMetadataProvider.java b/ccm-forum/src/com/arsdigita/forum/search/PostMetadataProvider.java
new file mode 100644
index 000000000..fd9450559
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/search/PostMetadataProvider.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.search;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.domain.DomainObject;
+import com.arsdigita.forum.Post;
+import com.arsdigita.globalization.Globalization;
+import com.arsdigita.globalization.SystemLocaleProvider;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.search.ContentProvider;
+import com.arsdigita.search.ContentType;
+import com.arsdigita.search.MetadataProvider;
+import com.arsdigita.toolbox.util.GlobalizationUtil;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ */
+public class PostMetadataProvider implements MetadataProvider {
+
+ private static Logger s_log = Logger.getLogger(PostMetadataProvider.class);
+ /**
+ * No specific information is provided for a forum post
+ */
+ public String getTypeSpecificInfo(DomainObject dobj) {
+ return null;
+ }
+
+ /**
+ * returns the default system Locale
+ */
+ public Locale getLocale(DomainObject dobj) {
+ return new SystemLocaleProvider().getLocale();
+ }
+
+ /**
+ * returns the subject of the post
+ * @see com.arsdigita.search.MetadataProvider#getTitle(com.arsdigita.domain.DomainObject)
+ */
+ public String getTitle(DomainObject dobj) {
+ Post post = (Post)dobj;
+ return post.getSubject();
+ }
+
+ /**
+ * returns the date of posting and the author
+ */
+ public String getSummary(DomainObject dobj) {
+ Post post = (Post)dobj;
+ return "Posted to " + post.getForum().getTitle() + " by " +
+ post.getFrom().getName() + " on " +
+ DateFormat.getDateInstance(DateFormat.MEDIUM).format(post.getSentDate());
+ }
+
+ public Date getCreationDate(DomainObject dobj) {
+ Post post = (Post)dobj;
+ return post.getSentDate();
+ }
+
+ public Party getCreationParty(DomainObject dobj) {
+ Post post = (Post)dobj;
+ return post.getFrom();
+ }
+
+ public Date getLastModifiedDate(DomainObject dobj) {
+ //we are not storing the date if the post is edited
+ return null;
+ }
+
+ public Party getLastModifiedParty(DomainObject dobj) {
+ //we are not storing the person that edits a post
+ return null;
+ }
+
+ public ContentProvider[] getContent(DomainObject dobj, ContentType type) {
+ List content = new ArrayList();
+
+ if (type.equals(ContentType.XML)) {
+ content.add(new XMLContentProvider("xml", (Post)dobj));
+ } else if (type.equals(ContentType.TEXT)) {
+ content.add(new TextContentProvider("text", (Post)dobj));
+ }
+
+ // don't deal with raw content - attached files are indexed separately
+
+ return (ContentProvider[])content.toArray(
+ new ContentProvider[content.size()]);
+ }
+ public String getContentSection(DomainObject dobj) {
+ return null;
+ }
+
+ public boolean isIndexable(DomainObject dobj) {
+ Post post = (Post)dobj;
+ s_log.debug("Post saved - status is " + post.getStatus() + ". Index Object? " + post.getStatus().equals(Post.APPROVED));
+
+ return post.getStatus().equals(Post.APPROVED);
+ }
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/search/TextContentProvider.java b/ccm-forum/src/com/arsdigita/forum/search/TextContentProvider.java
new file mode 100644
index 000000000..cb61d2944
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/search/TextContentProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.search;
+
+
+import com.arsdigita.domain.DomainObjectTextRenderer;
+import com.arsdigita.forum.Post;
+import com.arsdigita.search.ContentProvider;
+import com.arsdigita.search.ContentType;
+
+public class TextContentProvider implements ContentProvider {
+
+ private Post m_post;
+ private String m_context;
+
+ public TextContentProvider(String context, Post post) {
+ m_context = context;
+ m_post = post;
+ }
+
+ public String getContext() {
+ return m_context;
+ }
+
+ public ContentType getType() {
+ return ContentType.TEXT;
+ }
+
+ public byte[] getBytes() {
+
+ DomainObjectTextRenderer renderer = new DomainObjectTextRenderer();
+
+ renderer.walk(m_post, PostMetadataProvider.class.getName());
+
+ String text = renderer.getText();
+
+ // if required, retrieve file attachments here and add their content
+
+ return text.getBytes();
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/search/XMLContentProvider.java b/ccm-forum/src/com/arsdigita/forum/search/XMLContentProvider.java
new file mode 100644
index 000000000..ad9ab5ae0
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/search/XMLContentProvider.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.search;
+
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.domain.DomainObjectXMLRenderer;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.ui.Constants;
+import com.arsdigita.search.ContentProvider;
+import com.arsdigita.search.ContentType;
+import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.xml.Document;
+import com.arsdigita.xml.Element;
+
+public class XMLContentProvider implements ContentProvider, Constants {
+
+ private static final Logger s_log = Logger
+ .getLogger(XMLContentProvider.class);
+
+ private Post m_post;
+ private String m_context;
+
+ public XMLContentProvider(String context, Post post) {
+ m_context = context;
+ m_post = post;
+ }
+
+ public String getContext() {
+ return m_context;
+ }
+
+ public ContentType getType() {
+ return ContentType.XML;
+ }
+
+ public byte[] getBytes() {
+
+
+ Element root = new Element("forum:post", FORUM_XML_NS);
+ DomainObjectXMLRenderer renderer =
+ new DomainObjectXMLRenderer(root);
+
+ renderer.setWrapAttributes(true);
+ renderer.walk(m_post, PostMetadataProvider.class.getName());
+
+ Document doc = null;
+ try {
+ doc = new Document(root);
+ } catch (javax.xml.parsers.ParserConfigurationException ex) {
+ throw new UncheckedWrapperException("Unable to create xml document for post " + m_post.getID(), ex);
+ }
+ if (s_log.isDebugEnabled()) {
+ s_log.debug("XML is " + doc.toString(true));
+ }
+
+
+ String xml = doc.toString(true);
+ return xml.getBytes();
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesStep.java b/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesStep.java
new file mode 100644
index 000000000..30a85597f
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesStep.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormStep;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormProcessListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormValidationListener;
+import com.arsdigita.bebop.event.ParameterEvent;
+import com.arsdigita.bebop.form.FileUpload;
+import com.arsdigita.bebop.form.Submit;
+import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.parameters.ArrayParameter;
+import com.arsdigita.bebop.parameters.FileSizeValidationListener;
+import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
+import com.arsdigita.bebop.parameters.StringInRangeValidationListener;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.bebop.table.TableModelBuilder;
+import com.arsdigita.dispatcher.MultipartHttpServletRequest;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.domain.DomainObjectXMLRenderer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.PostFileAttachment;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.persistence.DataAssociationCursor;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.Assert;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author Chris Gilbert chris.gilbert@westsussex.gov.uk
+ *
+ * Wizard step to attach files to a post. This step may be bypassed
+ * if a forum administrator changes the forum settings on the UI
+ *
+ * nb - a simpler reuseable generic wizard file attachments step has been created
+ * forum will be refactored to use it in the future. see ccm-wsx-wizard-steps in contrib
+ */
+public class AttachedFilesStep
+ extends FormStep
+ implements Constants, FormInitListener, FormProcessListener, FormValidationListener {
+
+ private static Logger s_log = Logger.getLogger(AttachedFilesStep.class);
+ private ACSObjectSelectionModel m_post;
+
+
+
+ private AttachedFilesTable m_attachedFiles;
+ private FileUpload m_upload;
+ private TextArea m_description;
+ private Submit m_addFile;
+ private PostForm m_container;
+
+ private ArrayParameter m_newFiles = new ArrayParameter("newFiles");
+ private ArrayParameter m_existingFiles = new ArrayParameter("oldFiles");
+
+
+ public AttachedFilesStep(ACSObjectSelectionModel post, PostForm container) {
+ super("postFiles",
+ new SimpleContainer(
+ FORUM_XML_PREFIX + ":postFormFiles",
+ FORUM_XML_NS));
+
+ m_post = post;
+ m_container = container;
+ m_attachedFiles = new AttachedFilesTable(m_newFiles, m_existingFiles, this);
+
+ add(m_attachedFiles);
+
+ m_upload = new FileUpload("file", true);
+ m_upload.addValidationListener(new NotEmptyValidationListener(
+ Text
+ .gz("forum.ui.validation.file_null")) {
+ public void validate(ParameterEvent e) {
+ // don't fire validation if the next or previous button of the wizard has been pressed
+
+ if (m_addFile.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+ // this validation can fire any time - if there is no file then it won't fail
+ m_upload.addValidationListener(
+ new FileSizeValidationListener(Forum.getConfig().getMaxFileSize()));
+ add(m_upload);
+ m_description = new TextArea("fileDescription");
+ m_description.setCols(20);
+ m_description.setRows(5);
+
+ m_description
+ .addValidationListener(new StringInRangeValidationListener(
+ 0,
+ 4000,
+ Text.gz("forum.ui.validation.file_description_too_long")) {
+ public void validate(ParameterEvent e)
+ throws FormProcessException {
+ // don't fire validation if the next or previous button of the wizard has been pressed
+
+ if (m_addFile.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+ add(m_description);
+ m_addFile = new Submit("Add File");
+ add(m_addFile);
+ addInitListener(this);
+ addProcessListener(this);
+ addValidationListener(this);
+ }
+
+ /**
+ * Uploads the file and creates an orphaned PostFileAttachment
+ * that will be associated with the post when the wizard is completed
+ * or deleted if the wizard is cancelled.
+ */
+ public void process(FormSectionEvent e) throws FormProcessException {
+ FormData data = e.getFormData();
+ PageState state = e.getPageState();
+ if (m_addFile.isSelected(state)) {
+
+ PostFileAttachment attachment;
+ s_log.debug("adding file");
+ try {
+ String fileName = (String) m_upload.getValue(state);
+ s_log.debug("filename is " + fileName);
+ File file =
+ (
+ (MultipartHttpServletRequest) e
+ .getPageState()
+ .getRequest())
+ .getFile(
+ "file");
+ s_log.debug("uploaded file is " + file.getName());
+ //MimeType mimeType = MimeType.guessMimeTypeFromFile(fileName);
+ //s_log.debug("mime type is " + mimeType.getMimeType());
+ attachment = new PostFileAttachment();
+ attachment.loadFromFile(
+ fileName,
+ file,
+ "application/octet-stream");
+ attachment.setDescription(
+ (String) m_description.getValue(state));
+ BigDecimal id = attachment.getID();
+ String[] current = (String[]) state.getValue(m_newFiles);
+ if (current == null) {
+ current = new String[] { id.toString()};
+ } else {
+ List files = Arrays.asList(current);
+ current = new String[files.size() + 1];
+ Iterator it = files.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ current[i++] = (String) it.next();
+ }
+ current[i] = id.toString();
+ }
+ state.setValue(m_newFiles, current);
+ s_log.debug("File Uploaded");
+ m_description.setValue(state, null);
+
+ } catch (Exception ex) {
+ throw new FormProcessException(ex);
+ }
+ }
+ }
+
+ /**
+ * Prevent users navigating away from this page unintentionally without
+ * adding an uploaded file first
+ */
+ public void validate(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ if (!m_addFile.isSelected(state)
+ && StringUtils.isNotBlank((String) m_upload.getValue(state))) {
+ throw new FormProcessException(
+ (String) Text
+ .gz("forum.ui.validation.file_not_uploaded")
+ .localize());
+ }
+
+ }
+
+ public void removeFile(BigDecimal id, PageState state) {
+ String[] existingArray = (String[]) state.getValue(m_existingFiles);
+ if (existingArray != null) {
+ List existing = Arrays.asList(existingArray);
+ if (!existing.contains(id)) {
+ // this has been added during edit (or this is a new post)
+ s_log.debug("new file - I will actually delete it");
+ PostFileAttachment attachment = new PostFileAttachment(id);
+ attachment.delete();
+ }
+ }
+ // m_new_files cannot contain null if request is to delete file
+ Assert.exists(state.getValue(m_newFiles));
+ List newFiles =
+ new ArrayList(Arrays.asList((String[]) state.getValue(m_newFiles)));
+ newFiles.remove(id);
+ String[] current = new String[newFiles.size()];
+ Iterator it = newFiles.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ current[i++] = (String) it.next();
+ }
+ s_log.debug("size of new files array = " + current.length);
+ state.setValue(m_newFiles, current);
+
+ }
+
+ public DataCollection getCurrentFiles(PageState state) {
+
+ String[] currentArray = (String[]) state.getValue(m_newFiles);
+ if (currentArray != null && currentArray.length != 0) {
+ List current = Arrays.asList((String[]) state.getValue(m_newFiles));
+
+ DataCollection files =
+ SessionManager.getSession().retrieve(
+ PostFileAttachment.BASE_DATA_OBJECT_TYPE);
+ files.addFilter("id in :files").set("files", current);
+ return files;
+ }
+ return null;
+
+ }
+
+ /**
+ * called at the end of the wizard when the form is processed
+ * set the files attached to the post according to the
+ * file attachment step
+ * @param post
+ * @param state
+ */
+ public void attachFiles(Post post, PageState state) {
+
+ List newFiles = Collections.EMPTY_LIST;
+ String[] newFilesArray = (String[]) state.getValue(m_newFiles);
+ if (newFilesArray != null) {
+ newFiles = new ArrayList(Arrays.asList(newFilesArray));
+ }
+ String[] existing = (String[]) state.getValue(m_existingFiles);
+
+ if (existing != null) {
+ // we are editing a post - leave any unchanged files, delete any that have been
+ // removed
+ for (int i = 0; i < existing.length; i++) {
+ if (newFiles.contains(existing[i])) {
+ // no change to this one
+ newFiles.remove(existing[i]);
+ } else {
+ // file has been deleted in edit
+ PostFileAttachment file =
+ new PostFileAttachment(new BigDecimal(existing[i]));
+ post.removeFile(file);
+ // file deleted
+
+ }
+ }
+ }
+ Iterator it = newFiles.iterator();
+ while (it.hasNext()) {
+ // new files added
+ PostFileAttachment file =
+ new PostFileAttachment(new BigDecimal((String) it.next()));
+ post.addFile(file);
+ }
+ state.setValue(m_newFiles, null);
+ state.setValue(m_existingFiles, null);
+
+ }
+
+ public void register(Page p) {
+ super.register(p);
+
+ p.addGlobalStateParam(m_existingFiles);
+ p.addGlobalStateParam(m_newFiles);
+ }
+
+
+
+ public void init(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+
+ if (m_container
+ .getContext(state)
+ .equals(PostForm.EDIT_CONTEXT)) {
+
+ Post editPost = (Post) m_post.getSelectedObject(state);
+ DataAssociationCursor files = editPost.getFiles();
+ if (files.size() > 0) {
+
+ String[] fileIDs =
+ new String[new Long(files.size()).intValue()];
+ int i = 0;
+ while (files.next()) {
+
+ PostFileAttachment file =
+ (PostFileAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ fileIDs[i++] = file.getID().toString();
+ }
+ state.setValue(m_existingFiles, fileIDs);
+ state.setValue(m_newFiles, fileIDs);
+ }
+ }
+
+ }
+
+ /**
+ * generate xml for the confirmation step (unfortunately we can't just
+ * traverse the post because it hasn't been created at this point)
+ * @param state
+ * @param p
+ */
+ public void generatePostXML(PageState state, Element p) {
+ DataCollection files = getCurrentFiles(state);
+ if (files == null) {
+ return;
+
+ }
+ while(files.next()) {
+ PostFileAttachment file = (PostFileAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(p.newChildElement("files"));
+ xr.setWrapRoot(false);
+ xr.setWrapAttributes(true);
+ xr.setWrapObjects(false);
+ xr.walk(file, ConfirmStep.class.getName());
+ }
+ }
+
+
+ protected void clearParameters(PageState state) {
+ state.setValue(m_existingFiles, null);
+ state.setValue(m_newFiles, null);
+
+ }
+
+
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesTable.java b/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesTable.java
new file mode 100644
index 000000000..29d0e6c9b
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/AttachedFilesTable.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.ServletException;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.ControlLink;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleComponent;
+import com.arsdigita.bebop.parameters.ArrayParameter;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.cms.FileAsset;
+import com.arsdigita.cms.dispatcher.Utilities;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.PostFileAttachment;
+import com.arsdigita.forum.PostImageAttachment;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.messaging.MessagePart;
+import com.arsdigita.persistence.DataAssociationCursor;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.xml.Element;
+
+/**
+ * Semantic table with delete link. This could be extended to provide
+ * additional links eg move up/move down. New generic wizard
+ * file attachment table does include this functionality
+ * so it will be introduced when forum is refactored
+ *
+ * @author Chris Gilbert chris.gilbert@westsussex.gov.uk
+ * @version $Revision: 1.4 $ $DateTime: 2004/08/17 23:15:09 $
+ **/
+public class AttachedFilesTable extends SimpleComponent implements Constants {
+
+ // I have not implemented an edit link or a move up/down link although the data model
+ // is able to manage this, it seemed like a lot of work for a minor requirement for a forum
+ // currently, files are listed in the order they are added.
+
+ // to add extra links, define new keys for the control event and check key value in the
+ // respond method (see ThreadDisplay for example code)
+ //
+ // only issue is that when editing a post, the editor cannot change the description easily
+ // (though they could download the file to their PC, delete the existing one and recreate it)
+ private static Logger s_log = Logger.getLogger(AttachedFilesTable.class);
+ protected static final String ACTION_DELETE = "delete";
+
+ private ArrayParameter m_newFiles;
+ private ArrayParameter m_existingFiles;
+
+ private AttachedFilesStep m_parent;
+
+ public AttachedFilesTable(
+ ArrayParameter newFiles,
+ ArrayParameter existingFiles,
+ AttachedFilesStep parent) {
+ m_newFiles = newFiles;
+ m_existingFiles = existingFiles;
+ m_parent = parent;
+
+ }
+
+ public void respond(PageState state) throws ServletException {
+ super.respond(state);
+
+ String key = state.getControlEventName();
+ String value = state.getControlEventValue();
+ if (ACTION_DELETE.equals(key)) {
+ List existing = Collections.EMPTY_LIST;
+ String[] existingArray = (String[]) state.getValue(m_existingFiles);
+ if (existingArray != null) {
+ existing = Arrays.asList(existingArray);
+ }
+ if (!existing.contains(value)) {
+ // this has been added during edit
+ OID oid =
+ new OID(
+ PostFileAttachment.BASE_DATA_OBJECT_TYPE,
+ new BigDecimal(value));
+
+ DomainObjectFactory.newInstance(oid).delete();
+ }
+ List newFiles =
+ new ArrayList(
+ Arrays.asList((String[]) state.getValue(m_newFiles)));
+ newFiles.remove(value);
+ String[] current = new String[newFiles.size()];
+ Iterator it = newFiles.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ current[i++] = (String) it.next();
+ }
+ state.setValue(m_newFiles, current);
+
+
+ }
+
+ }
+ public void generateXML(PageState state, Element p) {
+ Element mainElement =
+ p.newChildElement(
+ FORUM_XML_PREFIX + ":attachedFiles",
+ FORUM_XML_NS);
+
+ DataCollection files = m_parent.getCurrentFiles(state);
+ if (files == null) {
+ return;
+ }
+ while (files.next()) {
+
+ PostFileAttachment file =
+ (PostFileAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ Element fileElement =
+ mainElement.newChildElement(
+ FORUM_XML_PREFIX + ":file",
+ FORUM_XML_NS);
+ fileElement.addAttribute("name", file.getName());
+ fileElement.addAttribute("url", Utilities.getAssetURL(file));
+ fileElement.addAttribute("description", file.getDescription());
+ generateActionXML(state, fileElement, file);
+ }
+
+ }
+
+ private void generateActionXML(
+ PageState state,
+ Element parent,
+ PostFileAttachment image) {
+ //separate method so that if future links require some logic
+ //to decide whether to display, it can be implemented here
+ parent.addAttribute("deleteLink", makeURL(state, ACTION_DELETE, image));
+ }
+
+ protected String makeURL(
+ PageState state,
+ String action,
+ PostFileAttachment file) {
+ state.setControlEvent(this, action, file.getID().toString());
+
+ String url = null;
+ try {
+ url = state.stateAsURL();
+ } catch (IOException ex) {
+ throw new UncheckedWrapperException("cannot create url", ex);
+ }
+ state.clearControlEvent();
+ return url;
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/CategoryAddForm.java b/ccm-forum/src/com/arsdigita/forum/ui/CategoryAddForm.java
index 169c664d5..c4c1cb49d 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/CategoryAddForm.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/CategoryAddForm.java
@@ -21,11 +21,14 @@ package com.arsdigita.forum.ui;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SaveCancelSection;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.form.TextArea;
import com.arsdigita.bebop.form.TextField;
@@ -45,12 +48,12 @@ import org.apache.log4j.Logger;
* parent category. temporary hack for testing purposes
*
* @author Sarah Barwig
- * @version $Revision: #9 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
+ * @version $Revision: 1.2 $ $Author: chrisg23 $ $DateTime: 2004/08/17 23:26:27 $
*/
public class CategoryAddForm extends Form {
public static final String versionId =
- "$Id: CategoryAddForm.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
+ "$Id: CategoryAddForm.java 1628 2007-09-17 08:10:40Z chrisg23 $" +
+ "$Author: chrisg23 $" +
"$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger
@@ -78,8 +81,24 @@ public class CategoryAddForm extends Form {
m_description.setWrap(TextArea.SOFT);
add(m_description);
- Submit submit = new Submit("Create topic");
+ // Cancel button added cg
+ // Would have used a saveCancel section but this would make existing
+ // stylesheets for legacy forums miss the buttons
+ Submit submit = new Submit(Text.gz("forum.ui.topic.save"));
+ final Submit cancel = new Submit(Text.gz("forum.ui.cancel"));
add(submit);
+ add(cancel);
+ addSubmissionListener(new FormSubmissionListener(){
+ public void submitted(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ if (cancel.isSelected(state)){
+ fireCompletionEvent(state);
+ throw new FormProcessException("cancelled");
+ }
+ }
+ });
+
+
/*
* Listener to process form data. Just adds the categories, then
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/CategoryView.java b/ccm-forum/src/com/arsdigita/forum/ui/CategoryView.java
index c2abc3772..b11040ceb 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/CategoryView.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/CategoryView.java
@@ -75,7 +75,7 @@ public class CategoryView extends SimpleContainer
Container categories = new SimpleContainer();
- Container linksPanel = new SimpleContainer("forum:topicOptions",
+ Container linksPanel = new SimpleContainer(Constants.FORUM_XML_PREFIX + ":topicOptions",
Constants.FORUM_XML_NS);
m_addCategoryLink = new ToggleLink(new Label(Text.gz("forum.ui.newTopic")));
m_addCategoryLink.setClassAttr("actionLink");
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/CategoryWidget.java b/ccm-forum/src/com/arsdigita/forum/ui/CategoryWidget.java
index 3b97bbdce..180a6de12 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/CategoryWidget.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/CategoryWidget.java
@@ -40,25 +40,28 @@ import java.util.TooManyListenersException;
* @author ron@arsdigita.com
* @author sarah@arsdigita.com
*
- * @version $Id: CategoryWidget.java 287 2005-02-22 00:29:02Z sskracic $
+ * @version $Id: CategoryWidget.java 1628 2007-09-17 08:10:40Z chrisg23 $
*/
public class CategoryWidget extends SingleSelect implements Constants {
public CategoryWidget(ParameterModel categoryParameter) {
super(categoryParameter);
- addOption(new Option(TOPIC_NONE.toString(),
- new Label(Text.gz("forum.ui.topic.none"))));
try {
addPrintListener(new PrintListener() {
public void prepare(PrintEvent e) {
PageState s = e.getPageState();
final Forum forum = getForum(s);
+ SingleSelect target = (SingleSelect) e.getTarget();
+
// Get categories for this forum
+ if (forum.noCategoryPostsAllowed()) {
+ target.addOption(new Option(TOPIC_NONE.toString(),
+ new Label(Text.gz("forum.ui.topic.none"))));
+ }
final Category root = forum.getRootCategory();
if (root != null) {
- SingleSelect target = (SingleSelect) e.getTarget();
addCategories(root, target);
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ConfirmStep.java b/ccm-forum/src/com/arsdigita/forum/ui/ConfirmStep.java
new file mode 100644
index 000000000..89ad22ce8
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ConfirmStep.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.util.Date;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.forum.Post;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.kernel.User;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author Chris Gilbert chris.gilbert@westsussex.gov.uk
+ *
+ * Traverse the post to output all it's attributes and associations for previewing
+ * (or rather, pretend to - the post isn't persistent until confirm step is complete
+ * so it can't be traversed. Instead, each step adds some xml to represent the data
+ * it has gathered
+ */
+public class ConfirmStep extends SimpleContainer implements Constants {
+
+ private PostForm m_container;
+ private ACSObjectSelectionModel m_post;
+
+ public ConfirmStep(ACSObjectSelectionModel post, PostForm container) {
+ m_container = container;
+ m_post = post;
+ }
+
+ public void generateXML(PageState state, Element parent) {
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":postConfirm",FORUM_XML_NS);
+ Date sent;
+ Party sender;
+ if (m_container.getContext(state).equals(PostForm.EDIT_CONTEXT)) {
+ Post post = (Post)m_post.getSelectedObject(state);
+ sent = post.getSentDate();
+ sender = post.getFrom();
+ } else {
+ sent = new Date();
+ sender = Kernel.getContext().getParty();
+ if (sender == null) {
+ sender = Kernel.getPublicUser();
+ }
+ }
+
+ content.newChildElement(Post.SENT).setText(sent.toString());
+
+ content.newChildElement(Post.SENDER).newChildElement(User.DISPLAY_NAME).setText(sender.getDisplayName());
+
+
+
+ m_container.generatePostXML(state, content);
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/Constants.java b/ccm-forum/src/com/arsdigita/forum/ui/Constants.java
index 142e2ecbc..2ecb0a038 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/Constants.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/Constants.java
@@ -25,12 +25,13 @@ import java.math.BigDecimal;
* XML namespaces, URLs, URL variable names, etc.
*
* @author Tracy Adams
- * @version $Revision: #8 $ $Date: 2004/08/17 $
+ * @version $Revision: 1.3 $ $Date: 2006/03/08 15:38:33 $
* @since ACS 4.7
*/
public interface Constants {
+ static final String FORUM_XML_PREFIX = "forum";
static final String FORUM_XML_NS = "http://www.arsdigita.com/forum/1.0";
static final String FORUM_MODE_VIEW = "view";
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/EditPostForm.java b/ccm-forum/src/com/arsdigita/forum/ui/EditPostForm.java
index b7acd4e09..0e184e910 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/EditPostForm.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/EditPostForm.java
@@ -37,7 +37,18 @@ import org.apache.log4j.Logger;
*
* @version $Revision #1 $DateTime: 2004/08/17 23:26:27 $
*/
-public class EditPostForm extends PostForm {
+public class EditPostForm { // extends PostForm {
+/*
+
+REMOVED chris Gilbert
+
+Edit step will be different depending whether post is root (category may be changed)
+or reply (category cannot be changed)
+
+UI refactored so that root post & reply to post forms are used for creation
+and editing
+
+
private static Logger s_log = Logger.getLogger(EditPostForm.class);
@@ -102,5 +113,5 @@ public class EditPostForm extends PostForm {
}
}
-
+*/
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ForumAlertsView.java b/ccm-forum/src/com/arsdigita/forum/ui/ForumAlertsView.java
index 5ebaf76d8..ec4f31c57 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ForumAlertsView.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ForumAlertsView.java
@@ -61,14 +61,14 @@ class ForumAlertsView extends SimpleContainer implements Constants {
}
private Component forumAlertsSegment() {
- SimpleContainer seg = new SimpleContainer("forum:forumAlerts",
+ SimpleContainer seg = new SimpleContainer(FORUM_XML_PREFIX + ":forumAlerts",
FORUM_XML_NS);
seg.add(forumAlertsForm());
return seg;
}
private Component threadAlertsSegment() {
- SimpleContainer seg = new SimpleContainer("forum:threadAlerts",
+ SimpleContainer seg = new SimpleContainer(FORUM_XML_PREFIX + ":threadAlerts",
FORUM_XML_NS);
seg.add(threadAlertsForm());
return seg;
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ForumComponent.java b/ccm-forum/src/com/arsdigita/forum/ui/ForumComponent.java
index 6809ea5a4..c67fae953 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ForumComponent.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ForumComponent.java
@@ -18,32 +18,36 @@
*/
package com.arsdigita.forum.ui;
-import com.arsdigita.bebop.PageState;
-import com.arsdigita.bebop.Page;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+
+import org.apache.log4j.Logger;
+
import com.arsdigita.bebop.ModalContainer;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.forum.ui.admin.ModerationView;
+import com.arsdigita.forum.ui.admin.PermissionsView;
+import com.arsdigita.forum.ui.admin.SetupView;
import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.Party;
-import com.arsdigita.kernel.security.UserContext;
+import com.arsdigita.kernel.permissions.PermissionDescriptor;
import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
-import com.arsdigita.kernel.permissions.PermissionDescriptor;
-import com.arsdigita.forum.ui.admin.ModerationView;
-import com.arsdigita.forum.Forum;
-import com.arsdigita.forum.ForumContext;
-import com.arsdigita.xml.Element;
+import com.arsdigita.kernel.security.UserContext;
import com.arsdigita.util.UncheckedWrapperException;
-
-import javax.servlet.ServletException;
-import org.apache.log4j.Logger;
-import java.io.IOException;
+import com.arsdigita.xml.Element;
/**
* The Bebop Page which provides the complete UI for the bboard application
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
*
- * @version $Revision: #11 $ $Author: sskracic $ $Date: 2004/08/17 $
+ * @version $Revision: 1.3 $ $Author: chrisg23 $ $Date: 2006/03/09 13:48:15 $
*/
public class ForumComponent extends ModalContainer implements Constants {
@@ -53,32 +57,39 @@ public class ForumComponent extends ModalContainer implements Constants {
public static final String MODE_TOPICS = "topics";
public static final String MODE_ALERTS = "alerts";
public static final String MODE_MODERATION = "moderation";
+ public static final String MODE_PERMISSIONS = "permissions";
+ public static final String MODE_SETUP = "setup";
private StringParameter m_mode;
/**
* Constructs the bboard use interface
*/
-
+ private SetupView m_setupView;
private ModerationView m_moderationView;
private ForumAlertsView m_alertsView;
private CategoryView m_topicView;
private ForumUserView m_userView;
+ private PermissionsView m_permissionsView;
public ForumComponent() {
- super("forum:forum", FORUM_XML_NS);
+ super(FORUM_XML_PREFIX + ":forum", FORUM_XML_NS);
m_mode = new StringParameter("mode");
+ m_setupView = new SetupView();
m_moderationView = new ModerationView();
m_alertsView = new ForumAlertsView();
m_topicView = new CategoryView();
m_userView = new ForumUserView();
+ m_permissionsView = new PermissionsView();
+ add(m_setupView);
add(m_moderationView);
add(m_alertsView);
add(m_topicView);
add(m_userView);
+ add(m_permissionsView);
setDefaultComponent(m_userView);
}
@@ -94,31 +105,56 @@ public class ForumComponent extends ModalContainer implements Constants {
super.respond(state);
+ Party party = Kernel.getContext().getParty();
+ Forum forum = ForumContext.getContext(state).getForum();
+
String mode = (String)state.getControlEventValue();
state.setValue(m_mode, mode);
+
+ setVisible(state, party, forum, mode);
+ }
+
+ protected void setVisible(
+ PageState state,
+ Party party,
+ Forum forum,
+ String mode) {
+ PermissionDescriptor forumAdmin =
+ new PermissionDescriptor(PrivilegeDescriptor.ADMIN, forum, party);
+
if (MODE_TOPICS.equals(mode)) {
+ if (Forum.getConfig().topicCreationByAdminOnly()) {
+ if (party == null) {
+ UserContext.redirectToLoginPage(state.getRequest());
+ }
+ PermissionService.assertPermission(forumAdmin);
+ }
setVisibleComponent(state, m_topicView);
} else if (MODE_ALERTS.equals(mode)) {
- if (Kernel.getContext().getParty() == null) {
+ if (party == null) {
UserContext.redirectToLoginPage(state.getRequest());
}
setVisibleComponent(state, m_alertsView);
} else if (MODE_MODERATION.equals(mode)) {
- Party party = Kernel.getContext().getParty();
if (party == null) {
UserContext.redirectToLoginPage(state.getRequest());
}
- Forum forum = ForumContext.getContext(state).getForum();
-
- PermissionDescriptor permission
- = new PermissionDescriptor(PrivilegeDescriptor.ADMIN,
- forum,
- party);
-
- PermissionService.assertPermission(permission);
-
+ PermissionService.assertPermission(forumAdmin);
setVisibleComponent(state, m_moderationView);
- } else {
+ } else if (MODE_PERMISSIONS.equals(mode)) {
+ if (party == null) {
+ UserContext.redirectToLoginPage(state.getRequest());
+ }
+ PermissionService.assertPermission(forumAdmin);
+
+ setVisibleComponent(state, m_permissionsView);
+ } else if (MODE_SETUP.equals(mode)) {
+ if (party == null) {
+ UserContext.redirectToLoginPage(state.getRequest());
+ }
+ PermissionService.assertPermission(forumAdmin);
+ setVisibleComponent(state, m_setupView);
+ } else if (MODE_THREADS.equals(mode)) {
setVisibleComponent(state, m_userView);
}
}
@@ -126,27 +162,45 @@ public class ForumComponent extends ModalContainer implements Constants {
public void generateXML(PageState state,
Element parent) {
Element content = generateParent(parent);
-
- generateModeXML(state, content, MODE_THREADS);
- generateModeXML(state, content, MODE_TOPICS);
- generateModeXML(state, content, MODE_ALERTS);
Forum forum = ForumContext.getContext(state).getForum();
content.addAttribute("title", forum.getTitle());
- content.addAttribute("noticeboard", (new Boolean(forum.isNoticeboard())).toString());
+ content.addAttribute(
+ "noticeboard",
+ (new Boolean(forum.isNoticeboard())).toString());
Party party = Kernel.getContext().getParty();
- if (party != null) {
+ if (party == null) {
+ party = Kernel.getPublicUser();
+ }
+
+ generateModes(state, content, party, forum);
+ generateChildrenXML(state, content);
+ }
+
+ protected void generateModes(
+ PageState state,
+ Element content,
+ Party party,
+ Forum forum) {
+ PermissionDescriptor permission =
+ new PermissionDescriptor(PrivilegeDescriptor.ADMIN, forum, party);
+
+ generateModeXML(state, content, MODE_THREADS);
+ if (!Forum.getConfig().topicCreationByAdminOnly()) {
+ generateModeXML(state, content, MODE_TOPICS);
+ }
+ generateModeXML(state, content, MODE_ALERTS);
- PermissionDescriptor permission
- = new PermissionDescriptor(PrivilegeDescriptor.ADMIN,
- forum,
- party);
if (PermissionService.checkPermission(permission)) {
generateModeXML(state, content, MODE_MODERATION);
+ if (Forum.getConfig().showNewTabs()) {
+ generateModeXML(state, content, MODE_SETUP);
+ generateModeXML(state, content, MODE_PERMISSIONS);
+ }
+ if (Forum.getConfig().topicCreationByAdminOnly()) {
+ generateModeXML(state, content, MODE_TOPICS);
}
}
-
- generateChildrenXML(state, content);
}
protected void generateModeXML(PageState state,
@@ -157,7 +211,8 @@ public class ForumComponent extends ModalContainer implements Constants {
current = MODE_THREADS;
}
- Element content = parent.newChildElement("forum:forumMode", FORUM_XML_NS);
+ Element content =
+ parent.newChildElement(FORUM_XML_PREFIX + ":forumMode", FORUM_XML_NS);
state.setControlEvent(this, "mode", mode);
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ForumResources.properties b/ccm-forum/src/com/arsdigita/forum/ui/ForumResources.properties
index 1df88f016..0b5caadc4 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ForumResources.properties
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ForumResources.properties
@@ -1,5 +1,6 @@
forum.ui.name=Name
forum.ui.description=Description
+forum.ui.cancel=Cancel
forum.ui.newTopic=New topic
forum.ui.topic.none=None
@@ -11,7 +12,7 @@ forum.ui.newPost=New thread
forum.ui.threads.viewAll=View all threads
forum.ui.thread.subscribe=Subscribe to thread
forum.ui.thread.unsubscribe=Unsubscribe to thread
-
+forum.ui.topic.save=Create Topic
forum.ui.moderate.label=Moderation:
forum.ui.moderate.switch.on=Turn on
@@ -27,3 +28,26 @@ forum.ui.noticeboard.status.on=On (replying disabled)
forum.ui.noticeboard.status.off=Off (replying enabled)
forum.ui.noticeboard.expiry_after=Expires after (in days)
forum.ui.noticeboard.change_expiry=Update
+
+forum.ui.settings.moderated=Moderated
+forum.ui.settings.noticeboard=Noticeboard (Disable Replying)
+forum.ui.settings.allowFiles=Allow File Attachments
+forum.ui.settings.allowImages=Allow images in posts
+forum.ui.settings.autosubscribe=Automatically subscribe thread starters
+forum.ui.settings.noCategoryPosts=Allow posts with no topic
+forum.ui.settings.anonymousPosts=Allow anonymous posts
+forum.ui.settings.save=Save Changes
+forum.ui.settings.introduction=Introduction
+forum.ui.settings.title=Forum Title
+
+forum.ui.validation.subject_null=Please enter a subject
+forum.ui.validation.body_null=Please enter a message
+forum.ui.validation.body_too_long=Your message is too long, only 4000 characters can be stored
+forum.ui.validation.image_file_null=Please use the browse button above to find an image to add
+forum.ui.validation.image_description_null=Please enter a description for the image (This will be displayed to users who cannot see the image)
+forum.ui.validation.image_description_too_long=Your description is too long, only 4000 characters can be stored
+forum.ui.validation.file_null=Please use the browse button above to find a file to add
+forum.ui.validation.file_description_too_long=Your description is too long, only 4000 characters can be stored
+forum.ui.validation.image_not_uploaded=To add the specified image, use the Add Image button before leaving this page. If you don't want to add the image, click Next or Previous.
+forum.ui.validation.file_not_uploaded=To add the specified file, use the Add File button before leaving this page. If you don't want to add the file, click Next or Previous.
+forum.ui.validation.introduction_too_long=Your introduction is too long, only 4000 characters can be stored
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ForumUserView.java b/ccm-forum/src/com/arsdigita/forum/ui/ForumUserView.java
index 65deeac3f..cd8972c3f 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ForumUserView.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ForumUserView.java
@@ -30,7 +30,13 @@ import com.arsdigita.bebop.ToggleLink;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.forum.Forum;
import com.arsdigita.forum.ForumContext;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.kernel.permissions.PermissionDescriptor;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.toolbox.ui.SecurityContainer;
import org.apache.log4j.Logger;
@@ -39,7 +45,7 @@ import org.apache.log4j.Logger;
*
* @author Kevin Scaldeferri (kevin@arsdigita.com)
*
- * @version $Revision: #8 $ $Author: sskracic $ $DateTime: 2004/08/17 23:26:27 $
+ * @version $Revision: 1.8 $ $Author: chrisg23 $ $DateTime: 2004/08/17 23:26:27 $
*/
public class ForumUserView extends SimpleContainer
implements Constants {
@@ -47,7 +53,7 @@ public class ForumUserView extends SimpleContainer
private static Logger s_log = Logger.getLogger(ForumUserView.class);
private Component m_forumView;
- private Component m_forumPost;
+ private PostForm m_forumPost;
private ModalContainer m_mode;
@@ -78,6 +84,7 @@ public class ForumUserView extends SimpleContainer
*/
p.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
+ s_log.debug("create link pressed");
PageState s = e.getPageState();
/*
if ("t".equals((String)s.getValue(m_newPostParam))) {
@@ -87,6 +94,7 @@ public class ForumUserView extends SimpleContainer
*/
if (m_newTopicLink.isSelected(s)) {
+ m_forumPost.setContext(s, PostForm.NEW_CONTEXT);
m_mode.setVisibleComponent(s, m_forumPost);
} else {
m_mode.setVisibleComponent(s, m_forumView);
@@ -106,10 +114,21 @@ public class ForumUserView extends SimpleContainer
Container forums = new SimpleContainer();
Container forumOptions = new SimpleContainer(
- "forum:forumOptions", Constants.FORUM_XML_NS);
+ FORUM_XML_PREFIX + ":forumOptions", Constants.FORUM_XML_NS);
m_newTopicLink = new ToggleLink(new Label(Text.gz("forum.ui.newPost")));
m_newTopicLink.setClassAttr("actionLink");
- forumOptions.add(m_newTopicLink);
+ // chris.gilbert@westsussex.gov.uk - security container added
+ SecurityContainer sc = new SecurityContainer(m_newTopicLink) {
+
+ protected boolean canAccess(Party party, PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ PermissionDescriptor createThread = new PermissionDescriptor(PrivilegeDescriptor.get(Forum.CREATE_THREAD_PRIVILEGE), forum, party);
+ return PermissionService.checkPermission(createThread);
+
+ }
+ };
+
+ forumOptions.add(sc);
forums.add(forumOptions);
// list of categories
@@ -124,8 +143,8 @@ public class ForumUserView extends SimpleContainer
return forums;
}
- private Component createForumPost() {
- Form editForm = new NewPostForm();
+ private PostForm createForumPost() {
+ PostForm editForm = new RootPostForm();
editForm.addCompletionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ForumUserView.this
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ImagesStep.java b/ccm-forum/src/com/arsdigita/forum/ui/ImagesStep.java
new file mode 100644
index 000000000..4dbca4eae
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ImagesStep.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.ServletException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormStep;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.RequestLocal;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormProcessListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormValidationListener;
+import com.arsdigita.bebop.event.ParameterEvent;
+import com.arsdigita.bebop.form.FileUpload;
+import com.arsdigita.bebop.form.Submit;
+import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.parameters.ArrayParameter;
+import com.arsdigita.bebop.parameters.FileSizeValidationListener;
+import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
+import com.arsdigita.bebop.parameters.StringInRangeValidationListener;
+import com.arsdigita.dispatcher.MultipartHttpServletRequest;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.domain.DomainObjectXMLRenderer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.PostImageAttachment;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.mimetypes.MimeType;
+import com.arsdigita.persistence.DataAssociationCursor;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * Wizard step for adding images, and displaying list of images
+ * already added
+ */
+public class ImagesStep
+ extends FormStep
+ implements Constants, FormProcessListener, FormValidationListener, FormInitListener {
+
+ private static Logger s_log = Logger.getLogger(ImagesStep.class);
+ private ACSObjectSelectionModel m_post;
+
+ private ImagesTable m_images;
+ private FileUpload m_upload;
+ private TextArea m_description;
+ private Submit m_addImage;
+
+ private PostForm m_container;
+ private ArrayParameter m_newImages = new ArrayParameter("images");
+ private ArrayParameter m_existingImages = new ArrayParameter("oldImages");
+
+ public ImagesStep(ACSObjectSelectionModel post, PostForm container) {
+ super(
+ "postImages",
+ new SimpleContainer(
+ FORUM_XML_PREFIX + ":postFormImages",
+ FORUM_XML_NS));
+
+ m_post = post;
+ m_container = container;
+ m_images = new ImagesTable(m_newImages, m_existingImages, this);
+
+ add(m_images);
+
+ m_upload = new FileUpload("image", true);
+ m_upload
+ .addValidationListener(new NotEmptyValidationListener(
+ Text
+ .gz("forum.ui.validation.image_file_null")) {
+ public void validate(ParameterEvent e) {
+ if (m_addImage.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+ m_upload
+ .addValidationListener(new FileSizeValidationListener(
+ Forum
+ .getConfig()
+ .getMaxImageSize()) {
+ public void validate(ParameterEvent e) {
+ if (m_addImage.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+ add(m_upload);
+ m_description = new TextArea("imageDescription");
+ m_description.setCols(20);
+ m_description.setRows(5);
+ m_description
+ .addValidationListener(new NotEmptyValidationListener(
+ Text
+ .gz("forum.ui.validation.image_description_null")) {
+ public void validate(ParameterEvent e) {
+ if (m_addImage.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+ m_description
+ .addValidationListener(new StringInRangeValidationListener(
+ 0,
+ 4000,
+ Text.gz("forum.ui.validation.image_description_too_long")) {
+ public void validate(ParameterEvent e)
+ throws FormProcessException {
+ if (m_addImage.isSelected(e.getPageState())) {
+ super.validate(e);
+ }
+ }
+ });
+
+ add(m_description);
+ m_addImage = new Submit("Add Image");
+ add(m_addImage);
+ addInitListener(this);
+
+ addProcessListener(this);
+ addValidationListener(this);
+ }
+
+ public void process(FormSectionEvent e) throws FormProcessException {
+ s_log.debug("process event fired");
+ FormData data = e.getFormData();
+ PageState state = e.getPageState();
+ if (m_addImage.isSelected(state)) {
+ PostImageAttachment a;
+ s_log.debug("adding file");
+ try {
+ String fileName = (String) m_upload.getValue(state);
+ s_log.debug("filename is " + fileName);
+ File file =
+ (
+ (MultipartHttpServletRequest) e
+ .getPageState()
+ .getRequest())
+ .getFile(
+ m_upload.getName());
+
+ s_log.debug("uploaded file is " + file.getName());
+ MimeType mimeType = MimeType.guessMimeTypeFromFile(fileName);
+ s_log.debug(
+ "Upload mime type is instance of " + mimeType.getClass());
+ s_log.debug(
+ "mime type is "
+ + (mimeType == null ? null : mimeType.getMimeType()));
+ a = new PostImageAttachment();
+ a.loadFromFile(fileName, file, null);
+ a.setDescription((String) m_description.getValue(state));
+ a.setMimeType(mimeType);
+ BigDecimal id = a.getID();
+ String[] current = (String[]) state.getValue(m_newImages);
+ if (current == null) {
+ current = new String[] { id.toString()};
+ } else {
+ List images = Arrays.asList(current);
+ current = new String[images.size() + 1];
+ Iterator it = images.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ current[i++] = (String) it.next();
+ }
+ current[i] = id.toString();
+ }
+ state.setValue(m_newImages, current);
+ s_log.debug("File Uploaded");
+
+ m_description.setValue(state, null);
+ } catch (Exception ex) {
+ throw new FormProcessException(ex);
+ }
+ }
+ }
+
+ /**
+ * Prevent users navigating away from this page unintentionally without
+ * adding an uploaded image first
+ */
+ public void validate(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ if (!m_addImage.isSelected(state)
+ && StringUtils.isNotBlank((String) m_upload.getValue(state))) {
+ throw new FormProcessException(
+ (String) Text
+ .gz("forum.ui.validation.image_not_uploaded")
+ .localize());
+ }
+
+ }
+
+ /**
+ * @param post
+ * @param state
+ */
+ public void attachImages(Post post, PageState state) {
+ List newImages = Collections.EMPTY_LIST;
+ String[] newImagesArray = (String[]) state.getValue(m_newImages);
+ if (newImagesArray != null) {
+ newImages = new ArrayList(Arrays.asList(newImagesArray));
+ }
+
+ String[] existing = (String[]) state.getValue(m_existingImages);
+ if (existing != null) {
+
+ for (int i = 0; i < existing.length; i++) {
+ if (newImages.contains(existing[i])) {
+ // no change to this one
+ newImages.remove(existing[i]);
+ } else {
+ // file has been deleted in edit
+ PostImageAttachment image =
+ new PostImageAttachment(new BigDecimal(existing[i]));
+ post.removeImage(image);
+
+ }
+ }
+ }
+ Iterator it = newImages.iterator();
+ while (it.hasNext()) {
+ // new files added
+ PostImageAttachment image =
+ new PostImageAttachment(new BigDecimal((String) it.next()));
+ post.addImage(image);
+ }
+ state.setValue(m_newImages, null);
+ state.setValue(m_existingImages, null);
+
+ }
+
+ public void register(Page p) {
+ super.register(p);
+
+ p.addGlobalStateParam(m_existingImages);
+ p.addGlobalStateParam(m_newImages);
+ }
+
+ public void init(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ if (m_container
+ .getContext(state)
+ .equals(PostForm.EDIT_CONTEXT)) {
+ Post editPost = (Post) m_post.getSelectedObject(state);
+ DataAssociationCursor files = editPost.getImages();
+ if (files.size() > 0) {
+
+ String[] fileIDs =
+ new String[new Long(files.size()).intValue()];
+ int i = 0;
+ while (files.next()) {
+
+ PostImageAttachment image =
+ (PostImageAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ fileIDs[i++] = image.getID().toString();
+ }
+ state.setValue(m_existingImages, fileIDs);
+ state.setValue(m_newImages, fileIDs);
+ }
+ }
+
+ }
+
+ public DataCollection getCurrentImages(PageState state) {
+
+ String[] currentArray = (String[]) state.getValue(m_newImages);
+ if (currentArray != null && currentArray.length != 0) {
+ List current =
+ Arrays.asList((String[]) state.getValue(m_newImages));
+
+ DataCollection images =
+ SessionManager.getSession().retrieve(
+ PostImageAttachment.BASE_DATA_OBJECT_TYPE);
+ images.addFilter("id in :files").set("files", current);
+ return images;
+ }
+ return null;
+
+ }
+
+ /**
+ * generate xml for the confirmation step (unfortunately we can't just
+ * traverse the post because it hasn't been created at this point)
+ * @param state
+ * @param p
+ */
+ public void generatePostXML(PageState state, Element p) {
+ DataCollection files = getCurrentImages(state);
+ if (files == null) {
+ return;
+
+ }
+
+ while (files.next()) {
+ PostImageAttachment image =
+ (PostImageAttachment) DomainObjectFactory.newInstance(
+ files.getDataObject());
+ DomainObjectXMLRenderer xr =
+ new DomainObjectXMLRenderer(p.newChildElement("images"));
+ xr.setWrapRoot(false);
+ xr.setWrapAttributes(true);
+ xr.setWrapObjects(false);
+ xr.walk(image, ConfirmStep.class.getName());
+
+ }
+ }
+
+ protected void clearParameters (PageState state) {
+ state.setValue(m_existingImages, null);
+ state.setValue(m_newImages, null);
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ImagesTable.java b/ccm-forum/src/com/arsdigita/forum/ui/ImagesTable.java
new file mode 100644
index 000000000..e2503b1cb
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ImagesTable.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.ServletException;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.ControlLink;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleComponent;
+import com.arsdigita.bebop.parameters.ArrayParameter;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.cms.FileAsset;
+import com.arsdigita.cms.dispatcher.Utilities;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.Post;
+import com.arsdigita.forum.PostFileAttachment;
+import com.arsdigita.forum.PostImageAttachment;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.messaging.MessagePart;
+import com.arsdigita.persistence.DataAssociationCursor;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.xml.Element;
+
+/**
+ * Semantic table with delete link. This could be extended to provide
+ * additional links eg move up/move down
+ *
+ * @author Chris Gilbert chris.gilbert@westsussex.gov.uk
+ * @version $Revision: 1.4 $ $DateTime: 2004/08/17 23:15:09 $
+ **/
+public class ImagesTable extends SimpleComponent implements Constants {
+
+ // I have not implemented an edit link or a move up/down link although the data model
+ // is able to manage this, it seemed like a lot of work for a minor requirement for a forum
+ // currently, files are listed in the order they are added.
+
+ // to add extra links, define new keys for the control event and check key value in the
+ // respond method (see ThreadDisplay for example code)
+ //
+ // only issue is that when editing a post, the editor cannot change the description easily
+ // (though they could download the file to their PC, delete the existing one and recreate it)
+ private static Logger s_log = Logger.getLogger(ImagesTable.class);
+ protected static final String ACTION_DELETE = "delete";
+
+ private ArrayParameter m_newImages;
+ // ie when post is being edited
+ private ArrayParameter m_existingImages;
+
+ private ImagesStep m_parent;
+
+ public ImagesTable(
+ ArrayParameter newImages,
+ ArrayParameter existingImages,
+ ImagesStep parent) {
+ m_newImages = newImages;
+ m_existingImages = existingImages;
+ m_parent = parent;
+
+ }
+
+ /**
+ * if image has been added during this session then delete it completely.
+ * If we are editing a post and we delete an image that was in the original
+ * post then just flag the image as deleted in case the editing is cancelled
+ */
+ public void respond(PageState state) throws ServletException {
+ super.respond(state);
+
+ String key = state.getControlEventName();
+ String value = state.getControlEventValue();
+
+ if (ACTION_DELETE.equals(key)) {
+ List existing = Collections.EMPTY_LIST;
+ String[] existingArray =
+ (String[]) state.getValue(m_existingImages);
+ if (existingArray != null) {
+ existing = Arrays.asList(existingArray);
+ }
+ if (!existing.contains(value)) {
+ // this has been added during edit
+ OID oid =
+ new OID(
+ PostImageAttachment.BASE_DATA_OBJECT_TYPE,
+ new BigDecimal(value));
+
+ DomainObjectFactory.newInstance(oid).delete();
+ }
+ List newImages =
+ new ArrayList(
+ Arrays.asList((String[]) state.getValue(m_newImages)));
+ newImages.remove(value);
+ String[] current = new String[newImages.size()];
+ Iterator it = newImages.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ current[i++] = (String) it.next();
+ }
+ state.setValue(m_newImages, current);
+
+ }
+
+ }
+ public void generateXML(PageState state, Element p) {
+ Element mainElement =
+ p.newChildElement(
+ FORUM_XML_PREFIX + ":attachedImages",
+ FORUM_XML_NS);
+ DataCollection images = m_parent.getCurrentImages(state);
+ if (images == null) {
+ return;
+ }
+
+ while (images.next()) {
+
+ PostImageAttachment image =
+ (PostImageAttachment) DomainObjectFactory.newInstance(
+ images.getDataObject());
+ Element imageElement =
+ mainElement.newChildElement(
+ FORUM_XML_PREFIX + ":image",
+ FORUM_XML_NS);
+ imageElement.addAttribute("name", image.getName());
+ imageElement.addAttribute("src", Utilities.getAssetURL(image));
+ imageElement.addAttribute("caption", image.getDescription());
+ generateActionXML(state, imageElement, image);
+ }
+
+ }
+
+ private void generateActionXML(
+ PageState state,
+ Element parent,
+ PostImageAttachment image) {
+ //separate method so that if future links require some logic
+ //to decide whether to display, it can be implemented here
+ parent.addAttribute("deleteLink", makeURL(state, ACTION_DELETE, image));
+ }
+
+ protected String makeURL(
+ PageState state,
+ String action,
+ PostImageAttachment image) {
+ state.setControlEvent(this, action, image.getID().toString());
+
+ String url = null;
+ try {
+ url = state.stateAsURL();
+ } catch (IOException ex) {
+ throw new UncheckedWrapperException("cannot create url", ex);
+ }
+ state.clearControlEvent();
+ return url;
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/MessageView.java b/ccm-forum/src/com/arsdigita/forum/ui/MessageView.java
index 453bf1b6c..d23c97441 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/MessageView.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/MessageView.java
@@ -23,6 +23,7 @@ import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.forum.Post;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.messaging.Message;
import com.arsdigita.domain.DomainObjectXMLRenderer;
import com.arsdigita.xml.Element;
@@ -33,12 +34,14 @@ import org.apache.log4j.Logger;
class MessageView extends SimpleComponent implements Constants {
private static final Logger s_log = Logger.getLogger(MessageView.class);
+ private ReplyToPostForm m_container;
private ACSObjectSelectionModel m_postModel;
private Post m_post;
/** For dynamically selected message views */
- public MessageView(ACSObjectSelectionModel postModel) {
+ public MessageView(ACSObjectSelectionModel postModel, ReplyToPostForm container) {
m_postModel = postModel;
+ m_container = container;
}
public MessageView(Post post) {
@@ -55,12 +58,18 @@ class MessageView extends SimpleComponent implements Constants {
public void generateXML(PageState state,
Element parent) {
- Post post = m_post;
+ Message post = m_post;
if (m_post == null) {
post = (Post)m_postModel.getSelectedObject(state);
}
+ if (m_container.getContext(state).equals(ReplyToPostForm.EDIT_CONTEXT)) {
+ // post in postmodel is the reply being edited, not the parent
+ post = post.getParent();
+ }
+
+
- Element messageEl = parent.newChildElement("forum:message",
+ Element messageEl = parent.newChildElement(FORUM_XML_PREFIX + ":message",
FORUM_XML_NS);
exportAttributes(messageEl);
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/NewPostForm.java b/ccm-forum/src/com/arsdigita/forum/ui/NewPostForm.java
deleted file mode 100755
index eafa73811..000000000
--- a/ccm-forum/src/com/arsdigita/forum/ui/NewPostForm.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-package com.arsdigita.forum.ui;
-
-import com.arsdigita.bebop.Container;
-import com.arsdigita.bebop.PageState;
-import com.arsdigita.bebop.parameters.BigDecimalParameter;
-import com.arsdigita.categorization.Category;
-import com.arsdigita.forum.ForumContext;
-import com.arsdigita.forum.Post;
-import com.arsdigita.forum.Forum;
-import com.arsdigita.kernel.Kernel;
-import com.arsdigita.web.RedirectSignal;
-import com.arsdigita.web.URL;
-
-import java.math.BigDecimal;
-
-import org.apache.log4j.Logger;
-
-/**
- * @see com.arsdigita.forum.Post.java
- * @see com.arsdigita.forum.EditPostForm.java
- */
-
-class NewPostForm extends PostForm {
- public static final String versionId =
- "$Id: NewPostForm.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
-
- private static final Logger s_log = Logger.getLogger(NewPostForm.class);
-
- private CategoryWidget m_category;
-
- public NewPostForm() {
- super("newPostForm");
- setupComponent();
- }
-
- protected Container dataEntryStep() {
- Container initial = super.dataEntryStep();
-
- m_category = new CategoryWidget(new BigDecimalParameter("topic"));
- initial.add(m_category);
-
- return initial;
- }
-
- protected Post getPost(PageState state,
- boolean create) {
- if (!create) {
- return null;
- }
-
- Post post = Post.create(ForumContext.getContext(state).getForum());
- post.setFrom(Kernel.getContext().getParty());
- return post;
- }
-
- protected void initWidgets(PageState state,
- Post post) {
- super.initWidgets(state, post);
- }
-
- protected void processWidgets(PageState state,
- Post post) {
- super.processWidgets(state,
- post);
-
- post.clearCategories();
- BigDecimal categoryID = (BigDecimal)m_category.getValue(state);
- if (categoryID != null &&
- !categoryID.equals(Constants.TOPIC_NONE)) {
-
- post.mapCategory(new Category(categoryID));
- }
-
- ForumContext ctx = ForumContext.getContext(state);
- Forum forum = ctx.getForum();
- if (forum.isModerated() &&
- !ctx.canModerate()) {
- post.setStatus(Post.PENDING);
- } else {
- post.setStatus(Post.APPROVED);
- }
-
- // XXX we shouldn't have to save the post yet
- // just to create a subscription :-(
- post.save();
- post.createThreadSubscription();
-
- throw new RedirectSignal(URL.here(state.getRequest(), "/"), true);
- }
-}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/PostForm.java b/ccm-forum/src/com/arsdigita/forum/ui/PostForm.java
index 7ad875ffc..da3c6da01 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/PostForm.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/PostForm.java
@@ -18,10 +18,10 @@
*/
package com.arsdigita.forum.ui;
-import com.arsdigita.bebop.Container;
+import org.apache.log4j.Logger;
+
import com.arsdigita.bebop.FormProcessException;
-import com.arsdigita.bebop.FormStep;
-import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Wizard;
@@ -29,20 +29,17 @@ import com.arsdigita.bebop.event.FormCancelListener;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
-import com.arsdigita.bebop.form.TextArea;
-import com.arsdigita.bebop.form.TextField;
-import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
-import com.arsdigita.bebop.parameters.StringLengthValidationListener;
+import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
import com.arsdigita.forum.Post;
+import com.arsdigita.forum.ThreadSubscription;
import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.User;
import com.arsdigita.kernel.security.UserContext;
-import com.arsdigita.toolbox.ui.TextTypeWidget;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
import com.arsdigita.xml.Element;
-import com.arsdigita.util.HtmlToText;
-import com.arsdigita.util.MessageType;
-
-import org.apache.log4j.Logger;
/**
* Class PostForm
@@ -50,150 +47,235 @@ import org.apache.log4j.Logger;
* @author Jon Orris (jorris@arsdigita.com)
*
* @version $Revision #1 $DateTime: 2004/08/17 23:26:27 $
+ *
+ * rewritten Chris Gilbert.
+ *
+ * Abstract form for behaviour shared by all types of post. Different types of
+ * post (new or reply) have different text screens, retrieved using
+ * the abstract getTextStep method and also may behave
+ * differently in final processing (final meaning on the last step
+ * of the wizard) by overriding the processWidgets method.
+ *
+ * They all share the remainder of the steps (currently add files, add images and preview)
+ * and processing relating to shared behaviour
*/
public abstract class PostForm extends Wizard implements Constants {
public static final String versionId =
- "$Id: PostForm.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
+ "$Id: PostForm.java 1628 2007-09-17 08:10:40Z chrisg23 $"
+ + "$Author: chrisg23 $"
+ + "$DateTime: 2004/08/17 23:26:27 $";
private static final Logger s_log = Logger.getLogger(PostForm.class);
- private TextField m_subject;
- private TextArea m_body;
- private TextTypeWidget m_bodyType;
+ private PostTextStep m_textStep;
+ private ImagesStep m_attachImages;
+ private AttachedFilesStep m_attachFiles;
+ private ConfirmStep m_confirm;
+ private ACSObjectSelectionModel m_post;
+
+ /**
+ * context is used because when editing, we might use the root post
+ * form (with topic selection) or the reply to post form (without
+ * topic selection). context allows form to behave appropriately
+ *
+ */
+ private StringParameter m_context = new StringParameter("context");
+ public static final String NEW_CONTEXT = "new";
+ public static final String REPLY_CONTEXT = "reply";
+ public static final String EDIT_CONTEXT = "edit";
+
+ /**
+ *
+ * Form used for new thread - no existing post object
+ *
+ */
public PostForm(String name) {
- super(name, new SimpleContainer());
- setMethod(POST);
+ this(name, null);
}
- protected void setupComponent() {
- add(dataEntryStep());
- add(confirmStep());
+ /**
+ * Used when editing an existing post
+ * @param name
+ * @param post
+ */
+ public PostForm(String name, ACSObjectSelectionModel post) {
+ super(name, new SimpleContainer(), Forum.getConfig().quickFinishAllowed(), true);
+ // note that encoding must be multipart/form-data,and method must be post
+ // in order for attachments to be uploaded. Ensure that these properties
+ // are carried through in XSL if not simply applying the default bebop
+ // templates
+ setEncType("multipart/form-data");
+ setMethod(POST);
+ //setMethod(GET);
+ m_post = post;
- addInitListener(new PostInitListener());
- addProcessListener(new PostProcessListener());
- addCancelListener(new PostCancelListener());
}
- protected void setSubject(PageState state,
- String text) {
- m_subject.setValue(state, text);
+ public void setContext(PageState state, String context) {
+ state.setValue(m_context, context);
}
- protected Container dataEntryStep() {
- FormStep initial = new FormStep(
- "initial",
- new SimpleContainer("forum:postForm", FORUM_XML_NS));
+ public String getContext(PageState state) {
+ return (String) state.getValue(m_context);
+ }
- m_subject = new TextField(new StringParameter("subject"));
- m_subject.addValidationListener(new NotEmptyValidationListener());
- m_subject.addValidationListener(new StringLengthValidationListener(250));
- m_subject.setSize(60);
- initial.add(m_subject);
+ protected void setupComponent() {
- m_body = new TextArea(new StringParameter("message"),
- 8, 60, TextArea.SOFT);
- m_body.addValidationListener(new NotEmptyValidationListener());
- m_body.addValidationListener(new StringLengthValidationListener(4000));
- initial.add(m_body);
+ m_textStep = getTextStep(m_post);
+ add(m_textStep);
+ m_attachImages = new ImagesStep(m_post, this);
+ add(m_attachImages);
+ m_attachFiles = new AttachedFilesStep(m_post, this);
+ add(m_attachFiles);
+ m_confirm = new ConfirmStep(m_post, this);
+ add(m_confirm);
- m_bodyType = new TextTypeWidget(new StringParameter("bodyType"),
- MessageType.TEXT_PLAIN);
- initial.add(m_bodyType);
+ addInitListener(new PostInitListener());
+ addCancelListener(new PostCancelListener());
+ addSubmissionListener(new PostSubmissionListener());
+ addProcessListener(new PostProcessListener());
- return initial;
}
- protected Container confirmStep() {
- SimpleContainer postContainer = new SimpleContainer
- ("forum:postConfirm", FORUM_XML_NS) {
+ public void register(Page p) {
+ super.register(p);
- public void generateXML(PageState state,
- Element parent) {
- Element content = generateParent(parent);
+ p.addGlobalStateParam(m_context);
- Element subject = content.newChildElement("subject");
- subject.setText((String)m_subject.getValue(state));
-
- Element body = content.newChildElement("body");
- body.setText(HtmlToText.generateHTMLText(
- (String)m_body.getValue(state),
- (String)m_bodyType.getValue(state)));
}
- };
- return postContainer;
- }
+ /**
+ * return text step appropriate for the type of post - reply doesn't give the option
+ * to choose a topic
+ * @param post
+ * @return
+ */
+ protected abstract PostTextStep getTextStep(ACSObjectSelectionModel m_post);
- protected abstract Post getPost(PageState state,
- boolean create);
-
- protected void initWidgets(PageState state,
- Post post) {
- if (post != null) {
- m_subject.setValue(state, post.getSubject());
- m_body.setValue(state, post.getBody());
- m_bodyType.setValue(state, post.getBodyType());
- }
- }
+ /**
+ * potentially create a new post object (unless we are editing one) Subclasses
+ * should create a post in whatever way is appropriate (eg a reply form
+ * will need to tie the new post to the one that is being replied to)
+ * @param state
+ * @return
+ */
+ protected abstract Post getPost(PageState state);
- protected void processWidgets(PageState state,
- Post post) {
- post.setSubject((String)m_subject.getValue(state));
- post.setBody((String)m_body.getValue(state),
- (String)m_bodyType.getValue(state));
- }
+ //
+ //
+ // FORM EVENT LISTENERS. NOTE THAT INDIVIDUAL STEP LISTENERS ARE
+ // NOTIFIED AFTER THE MAIN FORM LISTENERS - BE AWARE
+ //
+ //
+ //
private class PostInitListener implements FormInitListener {
public void init(FormSectionEvent e) {
+ s_log.debug("init called on parent form");
PageState state = e.getPageState();
- if ( Kernel.getContext().getParty() == null ) {
+ if (Kernel.getContext().getParty() == null
+ && !ForumContext
+ .getContext(state)
+ .getForum()
+ .anonymousPostsAllowed()) {
UserContext.redirectToLoginPage(state.getRequest());
}
- initWidgets(state,
- getPost(state, false));
}
}
+ private class PostSubmissionListener implements FormSubmissionListener {
- private class PostProcessListener implements FormProcessListener {
- public void process(FormSectionEvent e)
- throws FormProcessException {
-
- final PageState state = e.getPageState();
+ /**
+ * potentially skip steps of the wizard if the forum does not
+ * allow images or file attachments
+ */
+ public void submitted(FormSectionEvent e) {
+ s_log.debug("page submitted");
+ PageState state = e.getPageState();
+ ForumContext ctx = ForumContext.getContext(state);
+ Forum forum = ctx.getForum();
+ if (!forum.allowImageUploads()) {
+ hideStep(1, state);
+ }
+ if (!forum.allowFileAttachments()) {
+ hideStep(2, state);
+ }
+ }
+ }
- Post post = getPost(state, true);
- processWidgets(state, post);
+ private class PostCancelListener implements FormCancelListener {
+ public void cancel(FormSectionEvent e) throws FormProcessException {
- post.sendNotifications();
- post.sendModeratorAlerts();
+ PageState state = e.getPageState();
+ clearParameters(state);
+ fireCompletionEvent(state);
+ }
+ }
+ private class PostProcessListener implements FormProcessListener {
+ public void process(FormSectionEvent e) throws FormProcessException {
+ s_log.debug("process called on Parent Form");
+ final PageState state = e.getPageState();
+ Post post = getPost(state);
+ //m_post.setSelectedObject(state, post);
+ post.setStatus(state);
+ m_textStep.setText(post, state);
post.save();
+ m_attachFiles.attachFiles(post, state);
+ m_attachImages.attachImages(post, state);
+ // sort out notifications
+ if (getContext(state).equals(NEW_CONTEXT)) {
+ s_log.debug("new thread - create subscription");
+ ThreadSubscription sub = post.createThreadSubscription();
+ ForumContext ctx = ForumContext.getContext(state);
+ Forum forum = ctx.getForum();
+ if (forum.autoSubscribeThreadStarter()) {
+ User threadStarter = (User) Kernel.getContext().getParty();
+ if (threadStarter != null
+ && !threadStarter.equals(Kernel.getPublicUser())) {
+ s_log.debug("auto subscribing current user");
+ sub.subscribe(threadStarter);
+ }
+ }
+ }
+ post.sendNotifications((String) state.getValue(m_context));
+ post.sendModeratorAlerts();
+ clearParameters(state);
fireCompletionEvent(state);
- /* XXX: This is the right thing to do, however it results in
- the wizard not being reset. I haven't tracked down why.
- state.clearControlEvent();
- try {
- throw new RedirectSignal( state.stateAsURL(), true );
- } catch( IOException ex ) {
- throw new UncheckedWrapperException( ex );
}
- */
+ }
+
+
+ public Post getSelectedPost(PageState state) {
+ if (m_post == null) {
+ return null;
+ } else {
+ return (Post) m_post.getSelectedObject(state);
}
}
- private class PostCancelListener implements FormCancelListener {
- public void cancel(FormSectionEvent e)
- throws FormProcessException {
+ /**
+ * required for confirmation step. Post hasn't been created so we
+ * cannot traverse a domain object. Instead, the form is responsible
+ * for retrieving a representation of the post as it will appear when saved
+ * @param state
+ * @param content
+ */
+ protected void generatePostXML(PageState state, Element content) {
+ m_textStep.generatePostXML(state, content);
+ m_attachFiles.generatePostXML(state, content);
+ m_attachImages.generatePostXML(state, content);
- PageState state = e.getPageState();
- fireCompletionEvent(state);
}
+
+ private void clearParameters(PageState state) {
+ state.setValue(m_context, null);
+ m_attachImages.clearParameters(state);
+ m_attachFiles.clearParameters(state);
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/PostTextStep.java b/ccm-forum/src/com/arsdigita/forum/ui/PostTextStep.java
new file mode 100644
index 000000000..a7f4f71a6
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/PostTextStep.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+
+
+import com.arsdigita.bebop.Bebop;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormStep;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.form.DHTMLEditor;
+import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.form.TextField;
+import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
+import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.bebop.util.BebopConstants;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.Post;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.User;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.toolbox.ui.TextTypeWidget;
+import com.arsdigita.util.MessageType;
+import com.arsdigita.xml.Element;
+
+/**
+ * @author Chris Gilbert chris.gilbert@westsussex.gov.uk
+ *
+ * Shared behaviour for text step
+ */
+public abstract class PostTextStep extends FormStep implements Constants {
+
+ private static Logger s_log = Logger.getLogger(PostTextStep.class);
+ private PostForm m_container;
+
+ private static final String FCK_FORUM_CONFIG =
+ "/assets/fckeditor/config/fckconfig_forum.js";
+ private TextField m_subject;
+ private TextArea m_body;
+
+ private TextTypeWidget m_bodyType;
+
+
+ private ACSObjectSelectionModel m_post;
+
+ /**
+ * create a text step with title and message fields and message type selection list
+ * TO DO - add config parameter to conditionally replace latter 2 with a single FCKEditor instance
+ * @param post
+ * @param container
+ */
+ public PostTextStep(ACSObjectSelectionModel post, PostForm container) {
+ super(
+ "postText",
+ new SimpleContainer(FORUM_XML_PREFIX + ":postForm", FORUM_XML_NS));
+ m_container = container;
+ m_post = post;
+ m_subject = new TextField(new StringParameter("subject"));
+ m_subject.addValidationListener(
+ new NotEmptyValidationListener(
+ Text.gz("forum.ui.validation.subject_null")));
+ m_subject.setMaxLength(250);
+ m_subject.setSize(60);
+ add(m_subject);
+
+ if (Forum.getConfig().useWysiwygEditor()) {
+ m_body = new DHTMLEditor("message");
+ m_body.setRows(8);
+ m_body.setCols(60);
+ m_body.setMetaDataAttribute("width", "450");
+ m_body.setMetaDataAttribute("height", "300");
+ m_body.setWrap(DHTMLEditor.SOFT);
+ if (Bebop
+ .getConfig()
+ .getDHTMLEditor()
+ .equals(BebopConstants.BEBOP_FCKEDITOR)) {
+
+ ((DHTMLEditor) m_body).setConfig(
+ new DHTMLEditor.Config("forum", FCK_FORUM_CONFIG));
+ } else {
+
+ // remove this so end users cannot browse through back end folder system
+ ((DHTMLEditor) m_body).hideButton("insertlink");
+ }
+ } else {
+ m_body = new TextArea(new StringParameter("message"),
+ 8, 60, TextArea.SOFT);
+ }
+ // otherwise, standard HTMLArea config - may need to change this if anyone is still
+ // using html area
+
+ m_body.addValidationListener(
+ new NotEmptyValidationListener(
+ Text.gz("forum.ui.validation.body_null")));
+
+ add(m_body);
+
+ m_bodyType = new TextTypeWidget(new StringParameter("bodyType"),
+ MessageType.TEXT_PLAIN);
+
+ add(m_bodyType);
+
+ addInitListener(new InitTextStepListener());
+
+ }
+
+ /**
+ * allow subclasses to initialise subject field
+ * @param state
+ * @param text
+ */
+ protected void setSubject(PageState state, String text) {
+ m_subject.setValue(state, text);
+ }
+ /**
+ * allow subclasses to initialise message and message type fields
+ * @param state
+ * @param body
+ * @param bodyType
+ */
+ protected void setBody(PageState state, String body, String bodyType) {
+ m_body.setValue(state, body);
+ m_bodyType.setValue(state, bodyType);
+
+ }
+
+ protected void initWidgets(PageState state, Post post) {
+ StringBuffer body = new StringBuffer();
+ if (m_container.getContext(state).equals(PostForm.EDIT_CONTEXT)) {
+ if (Forum.getConfig().useWysiwygEditor()) {
+ body.append("\n\n");
+ body.append(
+ "Edited on "
+ + DateFormat.getDateInstance(DateFormat.SHORT).format(
+ new Date())
+ + " by "
+ + ((User) Kernel.getContext().getParty()).getName());
+ body.append("\n\n
\n\n
\n\n");
+ } else {
+ body.append("\n");
+ body.append(
+ "Edited on "
+ + DateFormat.getDateInstance(DateFormat.SHORT).format(
+ new Date())
+ + " by "
+ + ((User) Kernel.getContext().getParty()).getName());
+ body.append("\n\n");
+ }
+
+ }
+ body.append(post.getBody());
+ setSubject(state, post.getSubject());
+ setBody(state, body.toString(), post.getBodyType());
+
+ }
+
+ /*
+ *
+ *
+ * If a delete link is used, the parameter that tells the wizard not to
+ * reinitialize steps is ALSO lost, and so init listeners are fired again
+ *
+ */
+ private class InitTextStepListener implements FormInitListener {
+
+ public void init(FormSectionEvent e) throws FormProcessException {
+
+
+ s_log.debug("Init called on Text Step");
+ PageState state = e.getPageState();
+
+ if (Forum.getConfig().useWysiwygEditor()) {
+ m_bodyType.setValue(state, MessageType.TEXT_HTML);
+ m_bodyType.setVisible(state, false);
+ }
+ if (m_post != null) {
+ Post post = (Post) m_post.getSelectedObject(state);
+ initWidgets(state, post);
+ }
+
+ }
+
+ }
+ /**
+ *
+ */
+ public void setText(Post post, PageState state) {
+ post.setSubject((String) m_subject.getValue(state));
+
+ post.setBody((String) m_body.getValue(state), (String) m_bodyType.getValue(state));
+
+ }
+
+ /**
+ * @param state
+ * @param content
+ */
+ public void generatePostXML(PageState state, Element content) {
+ Element subject = content.newChildElement("subject");
+ subject.setText((String) m_subject.getValue(state));
+ Element body = content.newChildElement("body");
+ body.setText((String) m_body.getValue(state));
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostForm.java b/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostForm.java
index 2ef3fbf52..47dd355c5 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostForm.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostForm.java
@@ -19,12 +19,17 @@
package com.arsdigita.forum.ui;
import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.forum.Post;
import com.arsdigita.forum.ForumContext;
import com.arsdigita.forum.Forum;
import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.Party;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
import org.apache.log4j.Logger;
@@ -37,79 +42,51 @@ import org.apache.log4j.Logger;
*/
public class ReplyToPostForm extends PostForm {
public static final String versionId =
- "$Id: ReplyToPostForm.java 755 2005-09-02 13:42:47Z sskracic $" +
- "$Author: sskracic $" +
- "$DateTime: 2004/08/17 23:26:27 $";
+ "$Id: ReplyToPostForm.java 1628 2007-09-17 08:10:40Z chrisg23 $"
+ + "$Author: chrisg23 $"
+ + "$DateTime: 2004/08/17 23:26:27 $";
- private static final Logger s_log = Logger.getLogger
- (ReplyToPostForm.class);
+ private static final Logger s_log = Logger.getLogger(ReplyToPostForm.class);
- private ACSObjectSelectionModel m_parent;
-
- public ReplyToPostForm(ACSObjectSelectionModel parent) {
- super("replyPostForm");
- m_parent = parent;
+ public ReplyToPostForm(ACSObjectSelectionModel post) {
+ super("replyPostForm", post);
setupComponent();
- }
- public void register(Page p) {
- super.register(p);
-
- p.addGlobalStateParam(m_parent.getStateParameter());
- }
-
-
- protected Post getPost(PageState state,
- boolean create) {
- if (create) {
- Post post = (Post)((Post)m_parent.getSelectedObject(state)).replyTo();
- post.setFrom(Kernel.getContext().getParty());
- return post;
- }
- return null;
}
- protected Container dataEntryStep() {
- Container entryStep = super.dataEntryStep();
- MessageView replyTo = new MessageView(m_parent);
- entryStep.add(replyTo);
- return entryStep;
- }
- protected void initWidgets(PageState state,
- Post post) {
- super.initWidgets(state, post);
- Post parent = (Post)m_parent.getSelectedObject(state);
- String prefix = "Re:";
- String subject = parent.getSubject();
- if (subject.length() < 3 ||
- prefix.equalsIgnoreCase(subject.substring(0,3))) {
- setSubject(state, subject);
- } else {
- setSubject(state, prefix + " " + subject);
- }
+ protected PostTextStep getTextStep(ACSObjectSelectionModel post) {
+ return new ReplyToPostTextStep(post, this);
}
- protected void processWidgets(PageState state,
- Post post) {
- super.processWidgets(state, post);
+ /* (non-Javadoc)
+ * @see com.arsdigita.forum.ui.PostForm#getPost(com.arsdigita.bebop.PageState)
+ */
+ protected Post getPost(PageState state) {
+ Post reply;
+ if (getContext(state).equals(PostForm.REPLY_CONTEXT)) {
+ // post model contains the parent post, reply hasn't been created yet
+ Post parent = getSelectedPost(state);
+ reply = (Post) parent.replyTo();
+ Party party = Kernel.getContext().getParty();
+ if (party == null) {
+ // anonymous posts MUST be allowed if we have reached here
+ party = Kernel.getPublicUser();
+ }
- ForumContext ctx = ForumContext.getContext(state);
- Forum forum = ctx.getForum();
+ reply.setFrom(party);
- if (forum.isModerated() &&
- !ctx.canModerate()) {
- post.setStatus(Post.PENDING);
} else {
- post.setStatus(Post.APPROVED);
+ // reply is the post in the post model
+ reply = getSelectedPost(state);
}
+ return reply;
- post.setRefersTo(forum);
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostTextStep.java b/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostTextStep.java
new file mode 100644
index 000000000..f0611d061
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ReplyToPostTextStep.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.forum.Post;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ * reply to post text step automatically completes
+ * the subject field
+ *
+ * (nb other forums eg FirstClass allocate numbers to long
+ * chains of replies, so instead of having a tree with all
+ * posts having subject 're: original post' they have varied
+ * subjects 're:(2) original post'. If we wanted to implement
+ * similar, this is the place to do it
+ *
+ */
+public class ReplyToPostTextStep extends PostTextStep {
+
+ private static Logger s_log = Logger.getLogger(ReplyToPostTextStep.class);
+ private ReplyToPostForm m_container;
+
+ public ReplyToPostTextStep(
+ ACSObjectSelectionModel post,
+ ReplyToPostForm container) {
+ super(post, container);
+ MessageView inReplyTo = new MessageView(post, container);
+ m_container = container;
+ add(inReplyTo);
+
+ }
+
+ protected void initWidgets(PageState state, Post post) {
+ if (m_container.getContext(state).equals(ReplyToPostForm.EDIT_CONTEXT)) {
+ super.initWidgets(state, post);
+ } else {
+
+ s_log.debug("init called");
+ s_log.debug("parent is " + post);
+ String prefix = "Re:";
+ String subject = post.getSubject();
+
+ if (subject.length() < 3
+ || prefix.equalsIgnoreCase(subject.substring(0, 3))) {
+ setSubject(state, subject);
+ } else {
+ setSubject(state, prefix + " " + subject);
+ }
+ }
+
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/RootPostTextStep.java b/ccm-forum/src/com/arsdigita/forum/ui/RootPostTextStep.java
new file mode 100644
index 000000000..3d0d4bf36
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/RootPostTextStep.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui;
+
+import java.math.BigDecimal;
+
+import org.apache.log4j.Logger;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.parameters.BigDecimalParameter;
+import com.arsdigita.categorization.Category;
+import com.arsdigita.categorization.CategoryCollection;
+import com.arsdigita.forum.Post;
+import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+
+/**
+ * @author chris.gilbert@westsussex.gov.uk
+ *
+ * root post manages the category(topic) in
+ * addition to subject & body
+ */
+public class RootPostTextStep extends PostTextStep {
+
+ private static Logger s_log = Logger.getLogger(RootPostTextStep.class);
+ private CategoryWidget m_category;
+
+ public RootPostTextStep(ACSObjectSelectionModel post, PostForm container) {
+ super(post, container);
+
+ m_category = new CategoryWidget(new BigDecimalParameter("postTopic"));
+ add(m_category);
+
+ }
+
+ public void setText(Post post, PageState state) {
+ super.setText(post, state);
+ post.clearCategories();
+ // need to save post after setting mandatory fields
+ // (subject, body, status) and before mapping categories
+
+ post.save();
+ BigDecimal categoryID = (BigDecimal) m_category.getValue(state);
+ if (categoryID != null && !categoryID.equals(Constants.TOPIC_NONE)) {
+ post.mapCategory(new Category(categoryID));
+ }
+
+ }
+
+ protected void initWidgets(PageState state, Post post) {
+ super.initWidgets(state, post);
+ if (post != null) {
+ CategoryCollection categories = post.getCategories();
+ if (categories.next()) {
+ Category cat = categories.getCategory();
+ m_category.setValue(state, cat.getID());
+ } else {
+ m_category.setValue(state, Constants.TOPIC_NONE);
+ }
+ categories.close();
+ } else {
+ m_category.setValue(state, null);
+ }
+
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ThreadAlertsList.java b/ccm-forum/src/com/arsdigita/forum/ui/ThreadAlertsList.java
index 9b483b963..23b5aee00 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ThreadAlertsList.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ThreadAlertsList.java
@@ -57,11 +57,11 @@ public class ThreadAlertsList extends SimpleComponent
public void generateXML(PageState state,
Element parent) {
Element content = parent.newChildElement(
- "forum:threadAlertList", FORUM_XML_NS);
+ FORUM_XML_PREFIX + ":threadAlertList", FORUM_XML_NS);
exportAttributes(content);
DomainCollection subs = ThreadSubscription.
- getSubsForUser(Kernel.getContext().getParty());
+ getSubsForUser(Kernel.getContext().getParty(), state);
while (subs.next()) {
ThreadSubscription sub = (ThreadSubscription)subs.getDomainObject();
@@ -73,7 +73,7 @@ public class ThreadAlertsList extends SimpleComponent
public Element generateAlertXML(ThreadSubscription sub) {
Element subEl = new Element(
- "forum:threadAlert", FORUM_XML_NS);
+ FORUM_XML_PREFIX + ":threadAlert", FORUM_XML_NS);
ParameterMap map = new ParameterMap();
map.setParameter(THREAD_PARAM, sub.getThreadReal().getID());
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ThreadComponent.java b/ccm-forum/src/com/arsdigita/forum/ui/ThreadComponent.java
index eee1676ab..e17b12321 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ThreadComponent.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ThreadComponent.java
@@ -19,6 +19,7 @@
package com.arsdigita.forum.ui;
import com.arsdigita.forum.ForumContext;
+import com.arsdigita.forum.Post;
import com.arsdigita.forum.ThreadSubscription;
import com.arsdigita.forum.ui.admin.RejectionForm;
@@ -59,8 +60,8 @@ public class ThreadComponent extends ModalContainer implements Constants {
// References to sub-components for event access.
private Container m_threadView;
- private Form m_editForm;
- private Form m_replyForm;
+ private PostForm m_rootForm;
+ private PostForm m_replyForm;
private Form m_rejectForm;
private static final Logger s_log
@@ -83,15 +84,18 @@ public class ThreadComponent extends ModalContainer implements Constants {
private void initComponents() {
// Add the thread components to the modal container and maintain
// references for event manipulation purposes.
- m_editForm = new EditPostForm(m_postModel);
+ s_log.debug("creating edit post form");
+ m_rootForm = new RootPostForm(m_postModel);
m_replyForm = new ReplyToPostForm(m_postModel);
+ s_log.debug("creating reply to post form");
+ s_log.debug("creating reject form");
m_rejectForm = new RejectionForm(m_postModel);
- addForm(m_editForm);
+ addForm(m_rootForm);
addForm(m_replyForm);
addForm(m_rejectForm);
m_threadView = new SimpleContainer();
- Container linksPanel = new SimpleContainer("forum:threadOptions",
+ Container linksPanel = new SimpleContainer(FORUM_XML_PREFIX + ":threadOptions",
Constants.FORUM_XML_NS);
// Offer links to return to index or control alerts.
@@ -119,11 +123,21 @@ public class ThreadComponent extends ModalContainer implements Constants {
}
public void makeEditFormVisible(PageState state) {
- setVisibleComponent(state, m_editForm);
+ s_log.debug("making edit form visible");
+ Post post = (Post)m_postModel.getSelectedObject(state);
+ if (post.getRoot() == null) {
+ m_rootForm.setContext(state, ReplyToPostForm.EDIT_CONTEXT);
+ setVisibleComponent(state, m_rootForm);
+ } else {
+ m_replyForm.setContext(state, ReplyToPostForm.EDIT_CONTEXT);
+ setVisibleComponent(state, m_replyForm);
+ }
+
}
public void makeReplyFormVisible(PageState state) {
- s_log.debug("making reply form invisible");
+ s_log.debug("making reply form visible");
+ m_replyForm.setContext(state, PostForm.REPLY_CONTEXT);
setVisibleComponent(state, m_replyForm);
}
@@ -135,12 +149,14 @@ public class ThreadComponent extends ModalContainer implements Constants {
* Creates the component for viewing a thread.
*/
- private final void addForm(Form form) {
+ private final void addForm(final Form form) {
add(form);
form.addCompletionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
s_log.debug("FORM ACTION COMPLETED");
- makeListViewVisible(e.getPageState());
+ PageState ps = e.getPageState();
+ // ps.reset(form);
+ makeListViewVisible(ps);
}
});
@@ -148,7 +164,8 @@ public class ThreadComponent extends ModalContainer implements Constants {
public void cancel(FormSectionEvent e) {
s_log.debug("fire cancel listener");
PageState ps = e.getPageState();
- makeListViewVisible(e.getPageState());
+ // ps.reset(form);
+ makeListViewVisible(ps);
}
});
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ThreadDisplay.java b/ccm-forum/src/com/arsdigita/forum/ui/ThreadDisplay.java
index 59d54d470..63c50686b 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ThreadDisplay.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ThreadDisplay.java
@@ -18,48 +18,44 @@
*/
package com.arsdigita.forum.ui;
-import com.arsdigita.bebop.SimpleComponent;
-import com.arsdigita.bebop.parameters.IntegerParameter;
+import java.io.IOException;
+import java.math.BigDecimal;
+
+import javax.servlet.ServletException;
+
+import org.apache.log4j.Logger;
+
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
-
+import com.arsdigita.bebop.SimpleComponent;
+import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.domain.DomainCollection;
-import com.arsdigita.domain.DomainObjectXMLRenderer;
import com.arsdigita.domain.DomainObjectFactory;
-
-import com.arsdigita.persistence.DataCollection;
-import com.arsdigita.persistence.FilterFactory;
-import com.arsdigita.persistence.SessionManager;
-import com.arsdigita.persistence.OID;
-
-import com.arsdigita.kernel.Party;
+import com.arsdigita.domain.DomainObjectXMLRenderer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.forum.Post;
import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.Party;
+import com.arsdigita.kernel.permissions.PermissionDescriptor;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
-
import com.arsdigita.messaging.MessageThread;
import com.arsdigita.messaging.ThreadedMessage;
-
-import com.arsdigita.web.URL;
-import com.arsdigita.web.Web;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.FilterFactory;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.Assert;
+import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.RedirectSignal;
-
+import com.arsdigita.web.URL;
+import com.arsdigita.web.Web;
import com.arsdigita.xml.Element;
import com.arsdigita.xml.XML;
-import com.arsdigita.forum.Forum;
-import com.arsdigita.forum.Post;
-import com.arsdigita.forum.ForumContext;
-
-import com.arsdigita.util.Assert;
-import com.arsdigita.util.UncheckedWrapperException;
-import java.math.BigDecimal;
-
-import org.apache.log4j.Logger;
-
-import java.io.IOException;
-import javax.servlet.ServletException;
-
public class ThreadDisplay extends SimpleComponent implements Constants {
private static final Logger s_log =
@@ -67,8 +63,7 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
private IntegerParameter m_pageNumber =
new IntegerParameter(PAGINATOR_PARAM);
-
- private int m_pageSize = 10;
+ private int m_pageSize = Forum.getConfig().getThreadPageSize();
private static final String ACTION_EDIT = "edit";
private static final String ACTION_DELETE = "delete";
@@ -152,7 +147,7 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
} else if (ACTION_APPROVE.equals(key)) {
post.setStatus(Post.APPROVED);
post.save();
- post.sendNotifications();
+ post.sendNotifications(null);
} else if (ACTION_REJECT.equals(key)) {
m_post.setSelectedObject(state, post);
m_threadComponent.makeRejectFormVisible(state);
@@ -208,7 +203,7 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
public void generateXML(PageState state,
Element parent) {
- Element content = parent.newChildElement("forum:threadDisplay",
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":threadDisplay",
FORUM_XML_NS);
exportAttributes(content);
@@ -249,7 +244,7 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
while (messages.next()) {
Post message = (Post)messages.getDomainObject();
- Element messageEl = content.newChildElement("forum:message",
+ Element messageEl = content.newChildElement(FORUM_XML_PREFIX + ":message",
FORUM_XML_NS);
generateActionXML(state, messageEl, message);
@@ -291,12 +286,17 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
Party party = Kernel.getContext().getParty();
+ if (party == null) {
+ party = Kernel.getPublicUser();
+ }
if (post.canEdit(party)) {
parent.addAttribute("editURL",
makeURL(state, ACTION_EDIT, post));
}
- if (!ctx.getForum().isNoticeboard()) {
+ PermissionDescriptor canRespond = new PermissionDescriptor(PrivilegeDescriptor.get(Forum.RESPOND_TO_THREAD_PRIVILEGE), Kernel.getContext().getResource(), party);
+
+ if (!ctx.getForum().isNoticeboard() && PermissionService.checkPermission(canRespond)) {
parent.addAttribute("replyURL",
makeURL(state, ACTION_REPLY, post));
}
@@ -325,7 +325,7 @@ public class ThreadDisplay extends SimpleComponent implements Constants {
long begin,
long end,
long objectCount) {
- Element paginator = parent.newChildElement("forum:paginator", FORUM_XML_NS);
+ Element paginator = parent.newChildElement(FORUM_XML_PREFIX + ":paginator", FORUM_XML_NS);
URL here = Web.getContext().getRequestURL();
ParameterMap params = new ParameterMap(here.getParameterMap());
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/ThreadList.java b/ccm-forum/src/com/arsdigita/forum/ui/ThreadList.java
index b5b6015a8..ba09573e8 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/ThreadList.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/ThreadList.java
@@ -77,7 +77,7 @@ public class ThreadList extends SimpleComponent implements Constants {
public void generateXML(PageState state,
Element parent) {
- Element content = parent.newChildElement("forum:threadList", FORUM_XML_NS);
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":threadList", FORUM_XML_NS);
ThreadCollection threads = getThreads(state);
@@ -113,7 +113,7 @@ public class ThreadList extends SimpleComponent implements Constants {
while (threads.next()) {
MessageThread thread = threads.getMessageThread();
- Element threadEl = content.newChildElement("forum:thread", FORUM_XML_NS);
+ Element threadEl = content.newChildElement(FORUM_XML_PREFIX + ":thread", FORUM_XML_NS);
ParameterMap map = new ParameterMap();
map.setParameter(THREAD_PARAM, thread.getID());
@@ -139,7 +139,7 @@ public class ThreadList extends SimpleComponent implements Constants {
long begin,
long end,
long objectCount) {
- Element paginator = parent.newChildElement("forum:paginator", FORUM_XML_NS);
+ Element paginator = parent.newChildElement(FORUM_XML_PREFIX + ":paginator", FORUM_XML_NS);
URL here = Web.getContext().getRequestURL();
ParameterMap params = new ParameterMap(here.getParameterMap());
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/TopicList.java b/ccm-forum/src/com/arsdigita/forum/ui/TopicList.java
index b399964b3..6027d0680 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/TopicList.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/TopicList.java
@@ -49,7 +49,7 @@ public class TopicList extends SimpleComponent implements Constants {
public void generateXML(PageState state,
Element parent) {
- Element content = parent.newChildElement("forum:topicList",
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":topicList",
FORUM_XML_NS);
exportAttributes(content);
@@ -63,7 +63,7 @@ public class TopicList extends SimpleComponent implements Constants {
DataQuery unCategory = forum.getUnCategory();
while (unCategory.next()) {
- Element noTopic = content.newChildElement("forum:noTopicSummary",
+ Element noTopic = content.newChildElement(FORUM_XML_PREFIX + ":noTopicSummary",
FORUM_XML_NS);
Element id = noTopic.newChildElement("id");
@@ -81,7 +81,7 @@ public class TopicList extends SimpleComponent implements Constants {
public void generateQueryXML(Element parent,
DataQuery query) {
while (query.next()) {
- Element content = parent.newChildElement("forum:topicSummary",
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":topicSummary",
FORUM_XML_NS);
Iterator keys = s_catProps.iterator();
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/TopicSelector.java b/ccm-forum/src/com/arsdigita/forum/ui/TopicSelector.java
index d54e5d49a..a6f829bc3 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/TopicSelector.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/TopicSelector.java
@@ -40,7 +40,7 @@ public class TopicSelector extends SimpleComponent implements Constants {
public void generateXML(PageState state,
Element parent) {
- Element content = parent.newChildElement("forum:topicSelector",
+ Element content = parent.newChildElement(FORUM_XML_PREFIX + ":topicSelector",
FORUM_XML_NS);
URL url = URL.request(state.getRequest(), null);
@@ -60,7 +60,7 @@ public class TopicSelector extends SimpleComponent implements Constants {
while (cursor.next()) {
Category c = new Category(cursor.getDataObject());
- Element topicEl = content.newChildElement("forum:topic", FORUM_XML_NS);
+ Element topicEl = content.newChildElement(FORUM_XML_PREFIX + ":topic", FORUM_XML_NS);
DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(topicEl);
xr.setWrapRoot(false);
xr.setWrapAttributes(true);
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/AdminEditPane.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/AdminEditPane.java
new file mode 100644
index 000000000..a85b181b2
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/AdminEditPane.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.BoxPanel;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.util.Assert;
+import org.apache.log4j.Logger;
+
+
+
+
+public class AdminEditPane extends SimpleContainer {
+ private Forum m_forum;
+
+ private static final Logger s_log = Logger.getLogger(AdminEditPane.class);
+
+ public AdminEditPane() {
+
+ GroupMemberDisplay members = new GroupMemberDisplay() {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ Group g = forum.getAdminGroup();
+ Assert.exists(g, Group.class);
+
+ return g;
+ }
+ };
+ members.setIdAttr("Forum-Admin");
+ add(members);
+
+ Form form = new Form("adminUserPicker",
+ new BoxPanel(BoxPanel.VERTICAL));
+ form.add(new GroupMemberPicker("admin") {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ return forum.getAdminGroup();
+ }
+ });
+ form.setIdAttr("adminMemberUserPicker");
+ add(form);
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberDisplay.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberDisplay.java
index ffd5e284c..38387330f 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberDisplay.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberDisplay.java
@@ -21,17 +21,20 @@ package com.arsdigita.forum.ui.admin;
import com.arsdigita.bebop.PageState;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.ui.Constants;
import com.arsdigita.kernel.Party;
import com.arsdigita.kernel.Group;
import com.arsdigita.kernel.PartyCollection;
import com.arsdigita.persistence.DataQuery;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.xml.Element;
+
import java.math.BigDecimal;
-public abstract class GroupMemberDisplay extends MembersDisplay {
+public abstract class GroupMemberDisplay extends MembersDisplay implements Constants {
protected abstract Group getGroup(PageState ps);
@@ -64,6 +67,13 @@ public abstract class GroupMemberDisplay extends MembersDisplay {
Group group = getGroup(ps);
group.removeMemberOrSubgroup(party);
group.save();
+
+ }
+
+ public void generateXML(PageState state, Element parent) {
+ Element container = parent.newChildElement(FORUM_XML_PREFIX + ":memberList", FORUM_XML_NS);
+ container.addAttribute("group", getGroup(state).getName());
+ super.generateXML(state, container);
}
}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberPicker.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberPicker.java
index ec98e8af7..25014577e 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberPicker.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/GroupMemberPicker.java
@@ -52,6 +52,19 @@ public abstract class GroupMemberPicker extends UserPicker {
private Option m_groups;
public GroupMemberPicker() {
+ super();
+ }
+
+
+ /**
+ * Constructor gives the picker widget
+ * a request parameter based on the context
+ * hence allowing several pickers on one page
+ * without them getting their parameters
+ * mixed up
+ */
+ public GroupMemberPicker(String context) {
+ super(context);
}
protected void addWidgets() {
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/ModeratorEditPane.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/ModeratorEditPane.java
index e2d774f03..f09c93633 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/admin/ModeratorEditPane.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/ModeratorEditPane.java
@@ -65,7 +65,7 @@ public class ModeratorEditPane extends SimpleContainer {
Form form = new Form("userPicker",
new BoxPanel(BoxPanel.VERTICAL));
- form.add(new GroupMemberPicker() {
+ form.add(new GroupMemberPicker("moderator") {
public Group getGroup(PageState state) {
Forum forum = ForumContext.getContext(state).getForum();
return forum.getModerationGroup();
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/PermissionsView.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/PermissionsView.java
new file mode 100644
index 000000000..4f4b76eed
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/PermissionsView.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.SimpleContainer;
+
+
+import org.apache.log4j.Logger;
+
+/**
+ * A component that allows users and groups to be added to
+ * a choice of access groups.
+ *
+ * Note, as privileges cascade, any user only needs
+ * to be in one group (though it doesn't matter if
+ * they are put into more than one
+ */
+public class PermissionsView extends SimpleContainer {
+ private static final Logger s_log = Logger.getLogger
+ (PermissionsView.class);
+
+ private AdminEditPane m_adminPane;
+ private ModeratorEditPane m_moderatorPane;
+ private ThreadCreatorEditPane m_creatorPane;
+ private ThreadResponderEditPane m_responderPane;
+ private ReaderEditPane m_readerPane;
+
+
+
+ public PermissionsView() {
+
+ m_adminPane = new AdminEditPane();
+ add(m_adminPane);
+
+ m_moderatorPane = new ModeratorEditPane();
+ add(m_moderatorPane);
+ m_creatorPane = new ThreadCreatorEditPane();
+ add(m_creatorPane);
+ m_responderPane = new ThreadResponderEditPane();
+ add(m_responderPane);
+ m_readerPane = new ReaderEditPane();
+ add(m_readerPane);
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/ReaderEditPane.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/ReaderEditPane.java
new file mode 100644
index 000000000..9bd253e72
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/ReaderEditPane.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.BoxPanel;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.util.Assert;
+import org.apache.log4j.Logger;
+
+
+
+
+public class ReaderEditPane extends SimpleContainer {
+ private Forum m_forum;
+
+ private static final Logger s_log = Logger.getLogger(ReaderEditPane.class);
+
+ public ReaderEditPane() {
+
+ GroupMemberDisplay members = new GroupMemberDisplay() {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ Group g = forum.getReadGroup();
+ Assert.exists(g, Group.class);
+
+ return g;
+ }
+ };
+ members.setIdAttr("Forum-Readers");
+ add(members);
+
+ Form form = new Form("readerUserPicker",
+ new BoxPanel(BoxPanel.VERTICAL));
+ form.add(new GroupMemberPicker("reader") {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ return forum.getReadGroup();
+ }
+ });
+ form.setIdAttr("readerMemberUserPicker");
+ add(form);
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/RejectionForm.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/RejectionForm.java
index 55dcad961..b010c95bf 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/admin/RejectionForm.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/RejectionForm.java
@@ -18,6 +18,9 @@
*/
package com.arsdigita.forum.ui.admin;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+
import com.arsdigita.bebop.Container;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.FormStep;
@@ -25,22 +28,28 @@ import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Wizard;
+import com.arsdigita.bebop.event.ParameterEvent;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.form.TextField;
+import com.arsdigita.bebop.parameters.EmailValidationListener;
import com.arsdigita.forum.ForumContext;
import com.arsdigita.forum.Post;
import com.arsdigita.forum.Forum;
import com.arsdigita.forum.ui.Constants;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
+import com.arsdigita.kernel.Kernel;
import com.arsdigita.kernel.Party;
+import com.arsdigita.mail.Mail;
import com.arsdigita.messaging.Message;
import com.arsdigita.messaging.MessageThread;
import com.arsdigita.messaging.ThreadedMessage;
import com.arsdigita.notification.Notification;
+import com.arsdigita.util.HtmlToText;
import com.arsdigita.util.StringUtils;
import org.apache.log4j.Logger;
@@ -49,8 +58,8 @@ public class RejectionForm extends Wizard implements Constants {
private static final Logger s_log = Logger.getLogger(RejectionForm.class);
private ACSObjectSelectionModel m_postModel;
- private Notification m_notification;
-
+ private Label m_recipientLabel;
+ private TextField m_recipient;
private TextArea m_textArea;
protected final static String ALERT_BLURB
@@ -58,6 +67,8 @@ public class RejectionForm extends Wizard implements Constants {
protected final static String SEPARATOR
= "\n\n" + StringUtils.repeat('-',20) + "\n\n";
+ protected final static String HTML_SEPARATOR
+ = "
";
public RejectionForm(ACSObjectSelectionModel postModel) {
super("postRejectionForm");
@@ -72,8 +83,26 @@ public class RejectionForm extends Wizard implements Constants {
FormStep form = new FormStep("initial",
new BoxPanel(BoxPanel.VERTICAL));
+ m_recipientLabel = new Label("Recipient Email (Optional)");
+ form.add(m_recipientLabel);
+ m_recipient = new TextField("recipient");
+ m_recipient.addValidationListener(new EmailValidationListener() {
+ /* (non-Javadoc)
+ * @see com.arsdigita.bebop.parameters.EmailValidationListener#validate(com.arsdigita.bebop.event.ParameterEvent)
+ */
+ public void validate(ParameterEvent e) throws FormProcessException {
+ if (!StringUtils.emptyString(m_recipient.getValue(e.getPageState()))) {
+
+ super.validate(e);
+ }
+ }
+ });
+ m_recipient.setMetaDataAttribute("label","Recipient email(optional)" );
+ form.add(m_recipient);
form.add(new Label("Message"));
+
m_textArea = new TextArea("bodyText");
+ m_textArea.setMetaDataAttribute("label", "Message");
form.add(m_textArea);
return form;
@@ -86,7 +115,8 @@ public class RejectionForm extends Wizard implements Constants {
PageState state = e.getPageState();
Post post = (Post)m_postModel.getSelectedObject(state);
Label l = (Label) e.getTarget();
- l.setLabel((String)getHeader(post));
+ l.setOutputEscaping(false);
+ l.setLabel((String)getHeader(post));
}
});
@@ -96,8 +126,9 @@ public class RejectionForm extends Wizard implements Constants {
Post post = (Post)m_postModel.getSelectedObject(state);
Label l = (Label) e.getTarget();
l.setOutputEscaping(false);
- String body = StringUtils.quoteHtml(getBody(post, state));
- l.setLabel("" + body + "
");
+ //String body = StringUtils.quoteHtml(getBody(post, state));
+ //l.setLabel("" + body + "
");
+ l.setLabel(getBody(post, state));
}
});
@@ -106,7 +137,9 @@ public class RejectionForm extends Wizard implements Constants {
PageState state = e.getPageState();
Post post = (Post)m_postModel.getSelectedObject(state);
Label l = (Label) e.getTarget();
- l.setLabel((String)getSignature());
+ l.setOutputEscaping(false);
+
+ l.setLabel(Mail.getConfig().sendHTMLMessageAsHTMLEmail() ? getHTMLSignature() : StringUtils.replace(getSignature(), "\n", "
"));
}
});
@@ -122,6 +155,13 @@ public class RejectionForm extends Wizard implements Constants {
public void init(FormSectionEvent event) throws FormProcessException {
PageState state = event.getPageState();
m_textArea.setValue( state, "");
+ m_recipient.setValue(state, "");
+ if (!ForumContext.getContext(state).getForum().anonymousPostsAllowed()) {
+ // optional recipient field is only relevent if post was made
+ // anonymously
+ m_recipientLabel.setVisible(state, false);
+ m_recipient.setVisible(state, false);
+ }
}
}
@@ -129,23 +169,31 @@ public class RejectionForm extends Wizard implements Constants {
private String getHeader(Post post) {
StringBuffer header = new StringBuffer();
header.append("Forum : ");
- header.append(post.getForum().getDisplayName()).append("\n");
+ header.append(post.getForum().getDisplayName()).append("
");
header.append("Subject : ");
- header.append(post.getSubject()).append("\n\n");
+ header.append(post.getSubject()).append("
");
return header.toString();
}
private String getBody(Post post, PageState state) {
StringBuffer body = new StringBuffer();
- body.append("Your message has been rejected by the moderator.\n");
+ body.append("
Your message has been rejected by the moderator.
");
- body.append("The moderator has given the following reasons:\n\n");
+ body.append("The moderator has given the following reasons:
");
body.append((String)m_textArea.getValue(state));
- body.append("\n\n");
+ body.append("
");
+
+ body.append("The content of the message follows:
");
+ body.append("Subject: " + post.getSubject() + "
");
+ body.append(post.getBody() + "
");
+ // additional comments cg. Need to make this whole email configurable - see notifications. Much better
+ String instructions = Forum.getConfig().getRejectionMessage();
+ if (instructions != null) {
+ body.append(instructions);
+ body.append("
");
+ }
+
- body.append("The content of the message follows:\n\n");
- body.append("Subject: " + post.getSubject() + "\n");
- body.append(post.getBody() + "\n\n\n");
return body.toString();
}
@@ -157,6 +205,13 @@ public class RejectionForm extends Wizard implements Constants {
return sig.toString();
}
+ private String getHTMLSignature() {
+ StringBuffer sig = new StringBuffer();
+ sig.append(HTML_SEPARATOR);
+ sig.append(ALERT_BLURB);
+ return sig.toString();
+}
+
private class RejectionProcessListener implements FormProcessListener {
public void process(FormSectionEvent event) throws FormProcessException {
PageState state = event.getPageState();
@@ -189,35 +244,80 @@ public class RejectionForm extends Wizard implements Constants {
fireCompletionEvent(state);
}
+ /**
+ * if optional email address has been entered on the form, send rejection
+ * notice to that address. Otherwise, sent to post author (unless anonymous post)
+ *
+ * @param post
+ * @param state
+ */
private void sendNotice(Post post, PageState state) {
Forum forum = ForumContext.getContext(state).getForum();
+ Party noticeSender = forum.getModerationGroup();
+ if (noticeSender == null ) {
+ noticeSender = post.getModerator();
+ }
+
+ StringBuffer rejectionNoticeBody = new StringBuffer();
+ rejectionNoticeBody.append(getHeader(post));
+ rejectionNoticeBody.append(getBody(post, state));
+ StringBuffer nonHTMLRejectionNotice = new StringBuffer(new HtmlToText().convert(rejectionNoticeBody.toString()));
+ rejectionNoticeBody.append(getHTMLSignature());
+ nonHTMLRejectionNotice.append(getSignature());
+ if (!StringUtils.emptyString(m_recipient.getValue(state) )) {
+ Mail mailMessage = new Mail();
+ mailMessage.setTo((String)m_recipient.getValue(state));
+ mailMessage.setFrom(noticeSender.getPrimaryEmail().getEmailAddress());
+ mailMessage.setSubject("Moderation notice " + post.getForum().getDisplayName());
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ rejectionNoticeBody.append(getHTMLSignature());
+ mailMessage.setBody(rejectionNoticeBody.toString(), nonHTMLRejectionNotice.toString());
+ } else {
+ mailMessage.setBody(nonHTMLRejectionNotice.toString());
+ }
+
+ try {
+ mailMessage.send();
+ } catch (SendFailedException e) {
+ s_log.error("Couldn't send forum post rejection message for post " + post.getID(), e);
+ } catch (MessagingException e) {
+ s_log.error("Couldn't send forum post rejection message for post " + post.getID(), e);
+ }
+ return;
+ } else if (!post.getFrom().equals(Kernel.getPublicUser())) {
Notification notice = new Notification();
notice.setTo(post.getFrom());
notice.setHeader(getHeader(post));
Message message = new Message();
- Party noticeSender = forum.getModerationGroup();
- if (noticeSender == null ) {
- noticeSender = post.getModerator();
- }
+
+
message.setFrom(noticeSender);
message.setSubject("Moderation notice "
+ post.getForum().getDisplayName());
- message.setBody(getBody(post, state), Message.TEXT_PLAIN);
+ if (Mail.getConfig().sendHTMLMessageAsHTMLEmail()) {
+ notice.setHeader(getHeader(post));
+ message.setBody(getBody(post, state), Message.TEXT_HTML);
+ notice.setSignature(getHTMLSignature());
+
+ } else {
+ notice.setHeader(new HtmlToText().convert(getHeader(post)));
+ message.setBody(new HtmlToText().convert(getBody(post, state)), Message.TEXT_PLAIN);
+ notice.setSignature(getSignature());
+ }
notice.setMessage(message);
- notice.setSignature(getSignature());
s_log.debug("sending notification" + message +
"\n to: " + post.getFrom().getName() );
- notice.save();
- }
}
+ }
}
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/SetupView.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/SetupView.java
new file mode 100644
index 000000000..6e856e1dc
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/SetupView.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SaveCancelSection;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormProcessListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormSubmissionListener;
+import com.arsdigita.bebop.form.CheckboxGroup;
+import com.arsdigita.bebop.form.Option;
+import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.form.TextField;
+import com.arsdigita.bebop.parameters.IntegerParameter;
+import com.arsdigita.bebop.parameters.StringInRangeValidationListener;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.forum.ui.Constants;
+import com.arsdigita.forum.ui.Text;
+import com.arsdigita.web.Application;
+
+import org.apache.log4j.Logger;
+
+/**
+ * form that allows forum admin to set options
+ * that apply to this forum instance
+ */
+public class SetupView
+ extends Form
+ implements FormInitListener, FormSubmissionListener, FormProcessListener, Constants {
+ private static final Logger s_log = Logger.getLogger(SetupView.class);
+
+ // values for checkboxes
+ private static final String MODERATED = "moderated";
+ private static final String NOTICEBOARD = "noticeboard";
+ private static final String ALLOW_FILES = "filesAllowed";
+ private static final String ALLOW_IMAGES = "imagesallowed";
+ private static final String AUTOSUBSCRIBE_THREAD_STARTERS = "autosubscribe";
+ private static final String NO_CATEGORY_POSTS_ALLOWED = "nocategory";
+ private static final String ANONYMOUS_POSTS_ALLOWED = "anonymous";
+
+ private CheckboxGroup m_settings;
+ private TextField m_expiry;
+ private SaveCancelSection m_saveCancel;
+ private TextArea m_introduction;
+ private TextField m_title;
+
+ public SetupView() {
+ super("setupForm", new SimpleContainer("forum:setup", FORUM_XML_NS));
+ m_settings = new CheckboxGroup("settings");
+ m_settings.addOption(
+ new Option(
+ MODERATED,
+ (String) Text.gz("forum.ui.settings.moderated").localize()));
+ m_settings.addOption(
+ new Option(
+ NOTICEBOARD,
+ (String) Text.gz("forum.ui.settings.noticeboard").localize()));
+ m_settings.addOption(
+ new Option(
+ ALLOW_FILES,
+ (String) Text.gz("forum.ui.settings.allowFiles").localize()));
+ m_settings.addOption(
+ new Option(
+ ALLOW_IMAGES,
+ (String) Text.gz("forum.ui.settings.allowImages").localize()));
+ m_settings.addOption(
+ new Option(
+ AUTOSUBSCRIBE_THREAD_STARTERS,
+ (String) Text
+ .gz("forum.ui.settings.autosubscribe")
+ .localize()));
+
+ m_settings.addOption(
+ new Option(
+ NO_CATEGORY_POSTS_ALLOWED,
+ (String) Text
+ .gz("forum.ui.settings.noCategoryPosts")
+ .localize()));
+ m_settings.addOption(
+ new Option(
+ ANONYMOUS_POSTS_ALLOWED,
+ (String) Text
+ .gz("forum.ui.settings.anonymousPosts")
+ .localize()));
+
+
+
+ m_expiry = new TextField(new IntegerParameter("expiry"));
+ m_expiry.setMetaDataAttribute("label", (String)Text.gz("forum.ui.noticeboard.expiry_after").localize());
+ m_saveCancel = new SaveCancelSection();
+ m_saveCancel.getSaveButton().setButtonLabel(Text.gz("forum.ui.settings.save"));
+ m_introduction = new TextArea("introduction", 8, 60, TextArea.SOFT);
+ m_introduction.addValidationListener(new StringInRangeValidationListener(0, 4000, Text.gz("forum.ui.validation.introduction_too_long")));
+ m_introduction.setMetaDataAttribute("label", (String)Text.gz("forum.ui.settings.introduction").localize());
+
+ m_title = new TextField("title");
+ m_title.setMetaDataAttribute("label", (String)Text.gz("forum.ui.settings.title").localize());
+ m_title.setSize(70);
+
+ add(m_title);
+ add(m_introduction);
+ add(m_settings);
+ add(m_expiry);
+ add(m_saveCancel);
+
+ addInitListener(this);
+ addSubmissionListener(this);
+ addProcessListener(this);
+ }
+
+ public void init(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ Forum forum = ForumContext.getContext(state).getForum();
+ Set settingsSet = new HashSet();
+ if (forum.isModerated()) {
+ settingsSet.add(MODERATED);
+ }
+ if (forum.isNoticeboard()) {
+ settingsSet.add(NOTICEBOARD);
+ }
+ if (forum.allowFileAttachments()) {
+ settingsSet.add(ALLOW_FILES);
+ }
+ if (forum.allowImageUploads()) {
+ settingsSet.add(ALLOW_IMAGES);
+ }
+ if (forum.autoSubscribeThreadStarter()) {
+ settingsSet.add(AUTOSUBSCRIBE_THREAD_STARTERS);
+ }
+ if (forum.noCategoryPostsAllowed()) {
+ settingsSet.add(NO_CATEGORY_POSTS_ALLOWED);
+ }
+ if (forum.anonymousPostsAllowed()) {
+ settingsSet.add(ANONYMOUS_POSTS_ALLOWED);
+ }
+ m_settings.setValue(state, settingsSet.toArray());
+
+ m_expiry.setValue(state, new Integer(forum.getExpireAfter()));
+
+ m_introduction.setValue(state, forum.getIntroduction());
+
+ m_title.setValue(state, forum.getTitle());
+
+ }
+
+ public void submitted(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+
+ if (m_saveCancel.getCancelButton().isSelected(state)) {
+ s_log.debug("cancelled");
+ throw new FormProcessException("cancelled");
+ }
+ }
+
+ public void process(FormSectionEvent e) throws FormProcessException {
+ PageState state = e.getPageState();
+ Forum forum = ForumContext.getContext(state).getForum();
+ String[] settingsArray = (String[]) m_settings.getValue(state);
+ List settings = Collections.EMPTY_LIST;
+ if (settingsArray != null) {
+
+ settings = Arrays.asList(settingsArray);
+ }
+ forum.setModerated(settings.contains(MODERATED));
+ forum.setNoticeboard(settings.contains(NOTICEBOARD));
+ // could remove any existing files but i don't think that would be desirable
+ forum.setAllowFileAttachments(settings.contains(ALLOW_FILES));
+ forum.setAllowImageUploads(settings.contains(ALLOW_IMAGES));
+ forum.setAutoSubscribeThreadCreator(settings.contains(AUTOSUBSCRIBE_THREAD_STARTERS));
+ forum.setNoCategoryPostsAllowed(settings.contains(NO_CATEGORY_POSTS_ALLOWED));
+ forum.setAnonymousPostsAllowed(settings.contains(ANONYMOUS_POSTS_ALLOWED));
+
+ forum.setTitle((String)m_title.getValue(state));
+ forum.setIntroduction((String)m_introduction.getValue(state));
+ Integer expiry = (m_expiry.getValue(state) == null) ? new Integer(0) : (Integer) m_expiry.getValue(state);
+ int newExpiry = expiry.intValue();
+ if (forum.getExpireAfter() != newExpiry) {
+ forum.setExpireAfter(newExpiry);
+ }
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadCreatorEditPane.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadCreatorEditPane.java
new file mode 100644
index 000000000..cf3cc9d16
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadCreatorEditPane.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.BoxPanel;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.util.Assert;
+import org.apache.log4j.Logger;
+
+
+
+public class ThreadCreatorEditPane extends SimpleContainer {
+ private Forum m_forum;
+
+ private static final Logger s_log = Logger.getLogger(ThreadCreatorEditPane.class);
+
+ public ThreadCreatorEditPane() {
+
+ GroupMemberDisplay members = new GroupMemberDisplay() {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ Group g = forum.getThreadCreateGroup();
+ Assert.exists(g, Group.class);
+
+ return g;
+ }
+ };
+ add(members);
+
+ Form form = new Form("threadCreateUserPicker",
+ new BoxPanel(BoxPanel.VERTICAL));
+ form.add(new GroupMemberPicker("creator") {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ return forum.getThreadCreateGroup();
+ }
+ });
+ form.setIdAttr("threadCreateMemberUserPicker");
+ add(form);
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadResponderEditPane.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadResponderEditPane.java
new file mode 100644
index 000000000..0b28aa244
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/ThreadResponderEditPane.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.ui.admin;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.BoxPanel;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumContext;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.util.Assert;
+import org.apache.log4j.Logger;
+
+
+
+
+public class ThreadResponderEditPane extends SimpleContainer {
+ private Forum m_forum;
+
+ private static final Logger s_log = Logger.getLogger(ThreadResponderEditPane.class);
+
+ public ThreadResponderEditPane() {
+
+ GroupMemberDisplay members = new GroupMemberDisplay() {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ Group g = forum.getThreadResponderGroup();
+ Assert.exists(g, Group.class);
+
+ return g;
+ }
+ };
+ add(members);
+
+ Form form = new Form("threadReplyUserPicker",
+ new BoxPanel(BoxPanel.VERTICAL));
+ form.add(new GroupMemberPicker("responder") {
+ public Group getGroup(PageState state) {
+ Forum forum = ForumContext.getContext(state).getForum();
+ return forum.getThreadResponderGroup();
+ }
+ });
+ form.setIdAttr("threadReplyMemberUserPicker");
+ add(form);
+
+ }
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/ui/admin/UserPicker.java b/ccm-forum/src/com/arsdigita/forum/ui/admin/UserPicker.java
index 01c4edfc9..3fde324df 100755
--- a/ccm-forum/src/com/arsdigita/forum/ui/admin/UserPicker.java
+++ b/ccm-forum/src/com/arsdigita/forum/ui/admin/UserPicker.java
@@ -57,8 +57,23 @@ public abstract class UserPicker extends FormSection
private TextField m_name;
private List m_userList;
private Paginator m_pg;
+ // used to differentiate betwen multiple instances on a page (else all get initialised
+ // with the same value)
+ private String m_context;
public UserPicker() {
+ this("");
+ }
+
+ /**
+ * Constructor gives the picker widget
+ * a request parameter based on the context
+ * hence allowing several pickers on one page
+ * without them getting their parameters
+ * mixed up
+ */
+ public UserPicker(String context) {
+ m_context = context;
addWidgets();
addDisplay();
@@ -67,12 +82,12 @@ public abstract class UserPicker extends FormSection
}
protected void addWidgets() {
- m_nameParam = new StringParameter("name");
+ m_nameParam = new StringParameter(m_context + "name");
BoxPanel attrs = new BoxPanel( BoxPanel.HORIZONTAL );
Label nameLab = new Label( "Name" );
- m_name = new TextField("name1");
+ m_name = new TextField(m_context + "name1");
attrs.add( nameLab );
attrs.add( m_name );
diff --git a/ccm-forum/src/com/arsdigita/forum/upgrade/CreateContainerGroups.java b/ccm-forum/src/com/arsdigita/forum/upgrade/CreateContainerGroups.java
new file mode 100644
index 000000000..f30212044
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/upgrade/CreateContainerGroups.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.upgrade;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.log4j.Logger;
+
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.ForumSubscription;
+import com.arsdigita.forum.ThreadCollection;
+import com.arsdigita.forum.ThreadSubscription;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.kernel.GroupCollection;
+import com.arsdigita.messaging.MessageThread;
+import com.arsdigita.packaging.Program;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.Session;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.persistence.TransactionContext;
+import com.arsdigita.web.ApplicationType;
+
+/**
+ * @author cgyg9330
+ *
+ * Tidy up existing Forum groups
+ *
+ *
+ */
+public class CreateContainerGroups extends Program {
+
+ public CreateContainerGroups() {
+ super("CreateGroups", "1.0.0", "");
+ }
+
+ private static Logger s_log = Logger.getLogger(CreateContainerGroups.class);
+
+ public void doRun(CommandLine cmdLine) {
+ try {
+
+ final Session session = SessionManager.getSession();
+
+ final TransactionContext tc = session.getTransactionContext();
+
+ DataCollection types = session.retrieve(ApplicationType.BASE_DATA_OBJECT_TYPE);
+ types.addEqualsFilter("objectType", Forum.BASE_DATA_OBJECT_TYPE);
+ if (types.next()) {
+ ApplicationType forumApps = (ApplicationType)DomainObjectFactory.newInstance(types.getDataObject());
+ if (forumApps.getGroup() == null) {
+
+ forumApps.createGroup();
+ types.close();
+ s_log.debug("created app type group");
+ System.out.println("created app type group");
+ } else {
+ s_log.debug("Forum app type group exists");
+ System.out.println("Forum app type group exists");
+ }
+ }
+
+ DataCollection existingForums =
+ session.retrieve(Forum.BASE_DATA_OBJECT_TYPE);
+ while (existingForums.next()) {
+
+ Forum forum =
+ (Forum) DomainObjectFactory.newInstance(
+ existingForums.getDataObject());
+ s_log.debug("****************" + forum.getTitle());
+ System.out.println("****************" + forum.getTitle());
+ Group existingGroup = forum.getGroup();
+ if (existingGroup == null) {
+
+ tc.beginTxn();
+
+ forum.createGroup();
+
+ Group container = forum.getGroup();
+ forum.getAdminGroup().setName(forum.getTitle() + " Administrators");
+ forum.getModerationGroup().setName(forum.getTitle() + " Moderators");
+ forum.getThreadCreateGroup().setName(forum.getTitle() + " Thread Creators");
+ forum.getThreadResponderGroup().setName(forum.getTitle() + " Thread Responders");
+ forum.getReadGroup().setName(forum.getTitle() + " Readers");
+ container.addSubgroup(forum.getAdminGroup());
+ container.addSubgroup(forum.getModerationGroup());
+ container.addSubgroup(forum.getThreadCreateGroup());
+ container.addSubgroup(forum.getThreadResponderGroup());
+ container.addSubgroup(forum.getReadGroup());
+ DataCollection subscriptions = forum.getSubscriptions();
+ while (subscriptions.next()) {
+ ForumSubscription forumSubscription =
+ (ForumSubscription) DomainObjectFactory.newInstance(
+ subscriptions.getDataObject());
+ Group subscriptionGroup = forumSubscription.getGroup();
+ subscriptionGroup.setName(
+ forumSubscription.getSubscriptionGroupName());
+ container.addSubgroup(subscriptionGroup);
+ }
+ GroupCollection subgroups = container.getSubgroups();
+ subgroups.addEqualsFilter(
+ "name",
+ Forum.THREAD_SUBSCRIPTION_GROUPS_NAME);
+ if (subgroups.size() == 0) {
+
+ Group threadSubscriptions = new Group();
+ threadSubscriptions.setName(
+ Forum.THREAD_SUBSCRIPTION_GROUPS_NAME);
+ container.addSubgroup(threadSubscriptions);
+ ThreadCollection threads = forum.getThreads();
+ while (threads.next()) {
+ MessageThread thread = threads.getMessageThread();
+ ThreadSubscription subscription =
+ ThreadSubscription.getThreadSubscription(thread);
+ if (subscription != null) {
+ Group group = subscription.getGroup();
+ group.setName(subscription.getSubscriptionGroupName(forum));
+ threadSubscriptions.addSubgroup(group);
+ }
+ }
+ }
+ tc.commitTxn();
+ } else {
+ System.out.println(
+ "group exists for "
+ + forum.getTitle()
+ + " - skipping to next forum");
+
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ s_log.error("error occured", e);
+ }
+ }
+
+ public static final void main(final String[] args) {
+ new CreateContainerGroups().run(args);
+ }
+
+}
diff --git a/ccm-forum/src/com/arsdigita/forum/upgrade/CreateGroupsAndPortletType.java b/ccm-forum/src/com/arsdigita/forum/upgrade/CreateGroupsAndPortletType.java
new file mode 100644
index 000000000..f956ba889
--- /dev/null
+++ b/ccm-forum/src/com/arsdigita/forum/upgrade/CreateGroupsAndPortletType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 Chris Gilbert. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.forum.upgrade;
+
+import org.apache.commons.cli.CommandLine;
+
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.forum.Forum;
+import com.arsdigita.forum.portlet.MyForumsPortlet;
+import com.arsdigita.kernel.Group;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.KernelExcursion;
+import com.arsdigita.packaging.Program;
+import com.arsdigita.persistence.DataCollection;
+import com.arsdigita.persistence.Session;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.persistence.TransactionContext;
+import com.arsdigita.portal.PortletType;
+
+/**
+ * @author cgyg9330
+ *
+ * Used for upgrade from legacy forum
+ */
+public class CreateGroupsAndPortletType extends Program {
+
+ public CreateGroupsAndPortletType() {
+ super("CreateGroups", "1.0.0", "");
+ }
+
+ public void doRun(CommandLine cmdLine) {
+ new KernelExcursion() {
+ public void excurse() {
+ setEffectiveParty(Kernel.getSystemParty());
+
+ final Session session = SessionManager.getSession();
+
+ final TransactionContext tc = session.getTransactionContext();
+ tc.beginTxn();
+
+ DataCollection existingForums =
+ session.retrieve(Forum.BASE_DATA_OBJECT_TYPE);
+ while (existingForums.next()) {
+ Forum forum =
+ (Forum) DomainObjectFactory.newInstance(
+ existingForums.getDataObject());
+ Group admin = new Group();
+ admin.setName(forum.getTitle() + " Administrators");
+ forum.setAdminGroup(admin);
+
+ Group threadCreators = new Group();
+ threadCreators.setName(forum.getTitle() + " Thread Creators");
+ forum.setThreadCreatorGroup(threadCreators);
+ threadCreators.addMember(Kernel.getPublicUser());
+ Group threadResponders = new Group();
+ threadResponders.setName(forum.getTitle() + " Thread Responders");
+ forum.setThreadResponderGroup(threadResponders);
+ Group threadReaders = new Group();
+ threadReaders.setName(forum.getTitle() + " Readers");
+ forum.setReaderGroup(threadReaders);
+
+ }
+
+
+ PortletType type = PortletType
+ .createPortletType("My Forums",
+ PortletType.WIDE_PROFILE,
+ MyForumsPortlet.BASE_DATA_OBJECT_TYPE);
+ type.setDescription("Lists forums that user has access to, with last posting date");
+
+ tc.commitTxn();
+ }
+ }.run();
+ }
+
+ public static final void main(final String[] args) {
+ new CreateGroupsAndPortletType().run(args);
+ }
+
+}
+
diff --git a/ccm-forum/web/WEB-INF/bebop-define.tld b/ccm-forum/web/WEB-INF/bebop-define.tld
index d34f653f2..e69de29bb 100755
--- a/ccm-forum/web/WEB-INF/bebop-define.tld
+++ b/ccm-forum/web/WEB-INF/bebop-define.tld
@@ -1,395 +0,0 @@
-
-
-
-
-
- 1.0
- 1.1
- bebop-define
- http://www.arsdigita.com/bebop-define/tld/1.0
-
- this is a tag library for defining Bebop pages via JSP.
-
-
- page
- com.arsdigita.bebop.jsp.DefinePage
- com.arsdigita.bebop.jsp.DefinePageExtraInfo
- JSP
-
- title
- false
- true
-
-
- name
- true
- true
-
-
- application
- false
- true
-
-
- master
- false
- true
-
-
- pageClass
- false
- true
-
-
- cache
- false
- true
-
-
-
-
- component
- com.arsdigita.bebop.jsp.DefineComponentImpl
- com.arsdigita.bebop.jsp.DefineComponentExtraInfo
- JSP
-
- name
- false
- true
-
-
- classname
- true
- true
-
-
-
-
- form
- com.arsdigita.bebop.jsp.DefineForm
- com.arsdigita.bebop.jsp.DefineFormExtraInfo
- JSP
-
- name
- true
- true
-
-
- encType
- false
- true
-
-
- method
- false
- true
-
-
- action
- false
- true
-
-
- onSubmit
- false
- true
-
-
- onReset
- false
- true
-
-
-
-
- link
- com.arsdigita.bebop.jsp.DefineLink
- JSP
-
- url
- true
- true
-
-
- name
- false
- true
-
-
-
-
- image
- com.arsdigita.bebop.jsp.DefineImage
- JSP
-
- src
- true
- true
-
-
- alt
- false
- true
-
-
- width
- false
- true
-
-
- height
- false
- true
-
-
- border
- false
- true
-
-
- name
- false
- true
-
-
-
-
- tabbedPane
- com.arsdigita.bebop.jsp.DefineTabbedPane
- JSP
-
- name
- true
- true
-
-
-
-
- tab
- com.arsdigita.bebop.jsp.DefineTab
- JSP
-
- name
- true
- true
-
-
- label
- true
- true
-
-
-
-
- text
- com.arsdigita.bebop.jsp.DefineText
- com.arsdigita.bebop.jsp.DefineWidgetExtraInfo
- JSP
-
- name
- true
- true
-
-
- type
- false
- true
-
-
- size
- false
- true
-
-
- maxlength
- false
- true
-
-
-
-
- password
- com.arsdigita.bebop.jsp.DefinePassword
- com.arsdigita.bebop.jsp.DefineWidgetExtraInfo
- JSP
-
- name
- true
- true
-
-
- size
- false
- true
-
-
- maxlength
- false
- true
-
-
-
-
- textArea
- com.arsdigita.bebop.jsp.DefineTextArea
- com.arsdigita.bebop.jsp.DefineWidgetExtraInfo
- JSP
-
- name
- true
- true
-
-
- type
- false
- true
-
-
- rows
- false
- true
-
-
- cols
- false
- true
-
-
- wrap
- false
- true
-
-
-
-
- submit
- com.arsdigita.bebop.jsp.DefineSubmit
- JSP
-
- name
- true
- true
-
-
- label
- false
- true
-
-
- bundle
- false
- true
-
-
-
-
- option
- com.arsdigita.bebop.jsp.DefineOption
- JSP
-
- name
- true
- true
-
-
- value
- false
- true
-
-
- selected
- false
- true
-
-
- bundle
- false
- true
-
-
-
-
- radioGroup
- com.arsdigita.bebop.jsp.DefineRadioGroup
- JSP
-
- name
- true
- true
-
-
-
-
- checkboxGroup
- com.arsdigita.bebop.jsp.DefineCheckboxGroup
- JSP
-
- name
- true
- true
-
-
- vertical
- false
- true
-
-
-
-
- select
- com.arsdigita.bebop.jsp.DefineSelect
- JSP
-
- name
- true
- true
-
-
- onChange
- false
- true
-
-
-
-
- multipleSelect
- com.arsdigita.bebop.jsp.DefineMultipleSelect
- JSP
-
- name
- true
- true
-
-
-
-
- slave
- com.arsdigita.bebop.jsp.DefineSlave
- empty
-
-
-
- list
- com.arsdigita.bebop.jsp.DefineList
- com.arsdigita.bebop.jsp.DefineListExtraInfo
- JSP
-
- name
- true
- true
-
-
-
-
- table
- com.arsdigita.bebop.jsp.DefineTable
- com.arsdigita.bebop.jsp.DefineTableExtraInfo
- JSP
-
- name
- true
- true
-
-
-
-
diff --git a/ccm-forum/web/WEB-INF/bebop-show.tld b/ccm-forum/web/WEB-INF/bebop-show.tld
index ab98aba89..e69de29bb 100755
--- a/ccm-forum/web/WEB-INF/bebop-show.tld
+++ b/ccm-forum/web/WEB-INF/bebop-show.tld
@@ -1,117 +0,0 @@
-
-
-
-
-
- 1.0
- 1.1
- bebop-define
- http://www.arsdigita.com/bebop-define/tld/1.0
-
- this is a tag library for showing components from Bebop pages
- inside of a JSP.
-
-
- page
- com.arsdigita.bebop.jsp.ShowPage
- com.arsdigita.bebop.jsp.ShowPageExtraInfo
- JSP
-
- pageClass
- false
- true
-
-
- master
- false
- true
-
-
-
-
- all
- com.arsdigita.bebop.jsp.ShowAll
- JSP
-
-
-
- component
- com.arsdigita.bebop.jsp.ShowComponent
- JSP
-
- name
- true
- true
-
-
-
-
- form
- com.arsdigita.bebop.jsp.ShowForm
- JSP
-
- name
- true
- true
-
-
-
-
- list
- com.arsdigita.bebop.jsp.ShowList
- JSP
-
- name
- true
- true
-
-
-
-
-
- listItem
- com.arsdigita.bebop.jsp.ShowListItem
- empty
-
-
-
- table
- com.arsdigita.bebop.jsp.ShowTable
- JSP
-
- name
- true
- true
-
-
-
-
- thead
- com.arsdigita.bebop.jsp.ShowTableHeader
- JSP
-
-
-
- tbody
- com.arsdigita.bebop.jsp.ShowTableBody
- JSP
-
-
-
- row
- com.arsdigita.bebop.jsp.ShowTableRow
- JSP
-
-
-
- col
- com.arsdigita.bebop.jsp.ShowListItem
- empty
-
-
-
- slave
- com.arsdigita.bebop.jsp.ShowSlave
- JSP
-
-
diff --git a/ccm-forum/web/WEB-INF/web.xml b/ccm-forum/web/WEB-INF/web.xml
index 492539423..55af8b58f 100755
--- a/ccm-forum/web/WEB-INF/web.xml
+++ b/ccm-forum/web/WEB-INF/web.xml
@@ -23,15 +23,4 @@
/main/*
-
-
- /WEB-INF/bebop-show.tld
- /WEB-INF/bebop-show.tld
-
-
-
- /WEB-INF/bebop-define.tld
- /WEB-INF/bebop-define.tld
-
-
diff --git a/ccm-forum/web/packages/forum/xsl/forum.xsl b/ccm-forum/web/packages/forum/xsl/forum.xsl
index 846311947..b6523f3ff 100755
--- a/ccm-forum/web/packages/forum/xsl/forum.xsl
+++ b/ccm-forum/web/packages/forum/xsl/forum.xsl
@@ -479,10 +479,10 @@
|
-
+
| Topic: |
- |
+ |