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-94f89814c4dfmaster
parent
0885de7620
commit
ffa005c685
|
|
@ -2,11 +2,12 @@
|
|||
<ccm:application xmlns:ccm="http://ccm.redhat.com/ccm-project"
|
||||
name="ccm-forum"
|
||||
prettyName="Forum"
|
||||
version="6.5.0"
|
||||
version="6.5.2"
|
||||
release="1">
|
||||
<ccm:dependencies>
|
||||
<ccm:requires name="ccm-core" version="6.2.0" relation="ge"/>
|
||||
<ccm:requires name="ccm-cms" version="6.2.0" relation="ge"/>
|
||||
|
||||
<ccm:requires name="ccm-core" version="6.5.3"/>
|
||||
<ccm:requires name="ccm-cms" version="6.5.3"/>
|
||||
</ccm:dependencies>
|
||||
<ccm:contacts>
|
||||
<ccm:contact uri="http://www.redhat.com/software/rhea" type="website"/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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" };
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
alter table forum_forums add (anonymous_posts_allowed CHAR(1));
|
||||
|
||||
update forum_forums set anonymous_posts_allowed = 0;
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE FORUM_FORUMS ADD (
|
||||
INTRODUCTION VARCHAR2(4000) );
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
alter table forum_forums add (no_category_posts_allowed CHAR(1));
|
||||
|
||||
update forum_forums set no_category_posts_allowed = 1;
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
@ -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');
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
alter table forum_forums add (subscribe_thread_starter CHAR(1));
|
||||
|
||||
update forum_forums set subscribe_thread_starter = 0;
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -79,6 +79,8 @@
|
|||
<xrd:property name="/object/root"/>
|
||||
<xrd:property name="/object/categories"/>
|
||||
<xrd:property name="/object/sender"/>
|
||||
<xrd:property name="/object/images"/>
|
||||
<xrd:property name="/object/files"/>
|
||||
</xrd:associations>
|
||||
</xrd:adapter>
|
||||
</xrd:context>
|
||||
|
|
@ -132,4 +134,77 @@
|
|||
</xrd:adapter>
|
||||
</xrd:context>
|
||||
|
||||
|
||||
|
||||
<xrd:context name="com.arsdigita.forum.ui.ConfirmStep">
|
||||
<xrd:adapter objectType="com.arsdigita.forum.PostFileAttachment">
|
||||
<xrd:attributes rule="exclude"/>
|
||||
</xrd:adapter>
|
||||
|
||||
<xrd:adapter objectType="com.arsdigita.forum.PostImageAttachment">
|
||||
<xrd:attributes rule="exclude"/>
|
||||
</xrd:adapter>
|
||||
|
||||
|
||||
<!-- <xrd:adapter objectType="com.arsdigita.forum.Post"
|
||||
formatter="com.arsdigita.forum.ui.MessageXMLFormatter">
|
||||
|
||||
<xrd:attributes rule="exclude">
|
||||
<xrd:property name="/object/id"/>
|
||||
<xrd:property name="/object/objectType"/>
|
||||
<xrd:property name="/object/defaultDomainClass"/>
|
||||
<xrd:property name="/object/displayName"/>
|
||||
<xrd:property name="/object/replyTo"/>
|
||||
<xrd:property name="/object/objectID"/>
|
||||
<xrd:property name="/object/messageID"/>
|
||||
<xrd:property name="/object/root"/>
|
||||
<xrd:property name="/object/inReplyTo"/>
|
||||
|
||||
<xrd:property name="/object/categories/objectType"/>
|
||||
<xrd:property name="/object/categories/defaultDomainClass"/>
|
||||
<xrd:property name="/object/categories/displayName"/>
|
||||
<xrd:property name="/object/categories/isAbstract"/>
|
||||
<xrd:property name="/object/categories/isEnabled"/>
|
||||
<xrd:property name="/object/categories/defaultAncestors"/>
|
||||
|
||||
<xrd:property name="/object/sender/id"/>
|
||||
<xrd:property name="/object/sender/objectType"/>
|
||||
<xrd:property name="/object/sender/defaultDomainClass"/>
|
||||
</xrd:attributes>
|
||||
|
||||
<xrd:associations rule="include">
|
||||
<xrd:property name="/object/root"/>
|
||||
<xrd:property name="/object/categories"/>
|
||||
<xrd:property name="/object/sender"/>
|
||||
<xrd:property name="/object/images"/>
|
||||
<xrd:property name="/object/files"/>
|
||||
</xrd:associations>
|
||||
</xrd:adapter> -->
|
||||
</xrd:context>
|
||||
|
||||
<xrd:context name="com.arsdigita.forum.search.PostMetadataProvider">
|
||||
<xrd:adapter objectType="com.arsdigita.forum.Post">
|
||||
<xrd:attributes rule="include">
|
||||
<xrd:property name="/object/subject"/>
|
||||
<xrd:property name="/object/body"/>
|
||||
<xrd:property name="/object/images/description"/>
|
||||
|
||||
</xrd:attributes>
|
||||
<xrd:associations rule="include">
|
||||
<xrd:property name="/object/images"/>
|
||||
</xrd:associations>
|
||||
</xrd:adapter>
|
||||
</xrd:context>
|
||||
|
||||
<xrd:context name="com.arsdigita.forum.search.FileAttachmentMetadataProvider">
|
||||
<xrd:adapter objectType="com.arsdigita.forum.PostFileAttachment">
|
||||
<xrd:attributes rule="exclude">
|
||||
|
||||
</xrd:attributes>
|
||||
|
||||
</xrd:adapter>
|
||||
</xrd:context>
|
||||
|
||||
|
||||
|
||||
</xrd:adapters>
|
||||
|
|
|
|||
|
|
@ -5,4 +5,11 @@
|
|||
<version from="1.4.3" to="1.4.4">
|
||||
<script sql="ccm-forum/upgrade/::database::-1.4.3-1.4.4.sql"/>
|
||||
</version>
|
||||
<version from="6.5.0" to="6.5.1">
|
||||
<script sql="ccm-forum/upgrade/::database::-6.5.0-6.5.1.sql"/>
|
||||
<script class="com.arsdigita.forum.upgrade.CreateGroupsAndPortletType"/>
|
||||
</version>
|
||||
<version from="6.5.1" to="6.5.2">
|
||||
<script class="com.arsdigita.forum.upgrade.CreateContainerGroups"/>
|
||||
</version>
|
||||
</upgrade>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
//////
|
||||
//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";
|
||||
|
||||
public static final String FORUM_MODERATION_PRIVILEGE
|
||||
= "forum_moderation";
|
||||
|
||||
///////
|
||||
// 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;
|
||||
}
|
||||
|
|
@ -150,6 +194,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.
|
||||
*/
|
||||
|
|
@ -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() {
|
||||
|
|
@ -286,6 +451,38 @@ public class Forum extends Application {
|
|||
return (DataAssociation)get(POSTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,10 +555,10 @@ public class Forum extends Application {
|
|||
}
|
||||
|
||||
return threads;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets up instant and daily subscriptions for the forum. Daily
|
||||
* digests will appear to come from the specified user. The
|
||||
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,33 +18,34 @@
|
|||
*/
|
||||
package com.arsdigita.forum;
|
||||
|
||||
import com.arsdigita.runtime.AbstractConfig;
|
||||
import com.arsdigita.util.parameter.BooleanParameter;
|
||||
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.web.Web;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
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.StringParameter;
|
||||
import com.arsdigita.util.parameter.URLParameter;
|
||||
import com.arsdigita.web.Web;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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 <<a href="mailto:jross@redhat.com">jross@redhat.com</a>>
|
||||
* @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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("</font>");
|
||||
} else {
|
||||
sb.append(getReturnURLMessage((Post)post));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,55 +18,47 @@
|
|||
*/
|
||||
package com.arsdigita.forum;
|
||||
|
||||
import com.arsdigita.db.DbHelper;
|
||||
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.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.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.messaging.ThreadedMessage;
|
||||
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.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.kernel.ACSObjectInstantiator;
|
||||
import com.arsdigita.kernel.ResourceTypeConfig;
|
||||
import com.arsdigita.kernel.ResourceType;
|
||||
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.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);
|
||||
|
||||
|
|
@ -90,6 +82,29 @@ public class Initializer extends CompoundInitializer {
|
|||
return new Forum(dataObject);
|
||||
}
|
||||
});
|
||||
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() {
|
||||
|
|
@ -106,6 +121,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() {
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
|||
*
|
||||
*</ul>
|
||||
*</p>
|
||||
|
||||
*
|
||||
*
|
||||
* @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);
|
||||
|
||||
}
|
||||
if (thread != null) {
|
||||
thread.delete();
|
||||
for (Iterator it = replies.iterator(); it.hasNext(); ) {
|
||||
Post reply = new Post( (DataObject) it.next());
|
||||
reply.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <code>DataObject</code> is retrieved
|
||||
* from the persistent storage mechanism with an <code>OID</code>
|
||||
* specified by <i>oid</i>.
|
||||
*
|
||||
* @param oid The <code>OID</code> for the retrieved
|
||||
* <code>DataObject</code>.
|
||||
**/
|
||||
public PostImageAttachment(OID oid) {
|
||||
super(oid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. The contained <code>DataObject</code> is retrieved
|
||||
* from the persistent storage mechanism with an <code>OID</code>
|
||||
* specified by <i>id</i> and <code>ContentPage.BASE_DATA_OBJECT_TYPE</code>.
|
||||
*
|
||||
* @param id The <code>id</code> for the retrieved
|
||||
* <code>DataObject</code>.
|
||||
**/
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 = "<br><br>\n<hr>\n<br><br>\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("<font size='medium' face='Verdana, Arial, Helvetica, sans-serif'>");
|
||||
sb.append("Forum : ");
|
||||
sb.append(post.getForum().getDisplayName()).append("\n<br>");
|
||||
sb.append("Subject : ");
|
||||
sb.append(post.getSubject()).append("\n<br>");
|
||||
sb.append("Posted by: ");
|
||||
sb.append(author).append("\n<br><br>");
|
||||
} 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 + "</font>";
|
||||
} 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("<br><a href='" + url.getURL() + "'>" + url.getURL() + "</a>");
|
||||
} 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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* <font color="red">Experimental</font>
|
||||
* 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());
|
||||
|
||||
subs.setParameter("userID", party.getID());
|
||||
|
||||
return new DomainCollection(new DataQueryDataCollectionAdapter(subs, "subscription")) {
|
||||
public DomainObject getDomainObject() {
|
||||
return new ThreadSubscription(m_dataCollection.getDataObject());
|
||||
// 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());
|
||||
}
|
||||
};
|
||||
|
||||
return new DomainCollection(subscriptions);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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("</font>");
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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", "");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <a href=\"" + url + "\">" +
|
||||
owner.getSubject() + "</a> - 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <a href="mailto:chris.gilbert@westsussex.gov.uk">chris.gilbert@westsussex.gov.uk</a>
|
||||
*
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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 <a href="mailto:chris.gilbert@westsussex.gov.uk">chris.gilbert@westsussex.gov.uk</a>
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <a href=mailto:sarah@arsdigita.com>Sarah Barwig</a>
|
||||
* @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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <a href="mailto:chris.gilbert@westsussex.gov.uk">chris.gilbert@westsussex.gov.uk</a>
|
||||
*
|
||||
* 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -25,12 +25,13 @@ import java.math.BigDecimal;
|
|||
* XML namespaces, URLs, URL variable names, etc.
|
||||
*
|
||||
* @author <a href="mailto:teadams@arsdigita.com">Tracy Adams</a>
|
||||
* @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";
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -18,32 +18,36 @@
|
|||
*/
|
||||
package com.arsdigita.forum.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.ModalContainer;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.kernel.Kernel;
|
||||
import com.arsdigita.kernel.Party;
|
||||
import com.arsdigita.kernel.security.UserContext;
|
||||
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.util.UncheckedWrapperException;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import java.io.IOException;
|
||||
|
||||
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.permissions.PermissionDescriptor;
|
||||
import com.arsdigita.kernel.permissions.PermissionService;
|
||||
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
|
||||
import com.arsdigita.kernel.security.UserContext;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <a href="mailto:chris.gilbert@westsussex.gov.uk">chris.gilbert@westsussex.gov.uk</a>
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
public void setContext(PageState state, String context) {
|
||||
state.setValue(m_context, context);
|
||||
}
|
||||
|
||||
public String getContext(PageState state) {
|
||||
return (String) state.getValue(m_context);
|
||||
}
|
||||
|
||||
protected void setupComponent() {
|
||||
add(dataEntryStep());
|
||||
add(confirmStep());
|
||||
|
||||
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);
|
||||
|
||||
addInitListener(new PostInitListener());
|
||||
addProcessListener(new PostProcessListener());
|
||||
addCancelListener(new PostCancelListener());
|
||||
addSubmissionListener(new PostSubmissionListener());
|
||||
addProcessListener(new PostProcessListener());
|
||||
|
||||
}
|
||||
|
||||
protected void setSubject(PageState state,
|
||||
String text) {
|
||||
m_subject.setValue(state, text);
|
||||
public void register(Page p) {
|
||||
super.register(p);
|
||||
|
||||
p.addGlobalStateParam(m_context);
|
||||
|
||||
}
|
||||
|
||||
protected Container dataEntryStep() {
|
||||
FormStep initial = new FormStep(
|
||||
"initial",
|
||||
new SimpleContainer("forum:postForm", FORUM_XML_NS));
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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_bodyType = new TextTypeWidget(new StringParameter("bodyType"),
|
||||
MessageType.TEXT_PLAIN);
|
||||
initial.add(m_bodyType);
|
||||
|
||||
return initial;
|
||||
}
|
||||
|
||||
protected Container confirmStep() {
|
||||
SimpleContainer postContainer = new SimpleContainer
|
||||
("forum:postConfirm", FORUM_XML_NS) {
|
||||
|
||||
public void generateXML(PageState state,
|
||||
Element parent) {
|
||||
Element content = generateParent(parent);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
Post post = getPost(state, true);
|
||||
processWidgets(state, post);
|
||||
|
||||
post.sendNotifications();
|
||||
post.sendModeratorAlerts();
|
||||
|
||||
post.save();
|
||||
|
||||
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 );
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PostCancelListener implements FormCancelListener {
|
||||
public void cancel(FormSectionEvent e)
|
||||
throws FormProcessException {
|
||||
public void cancel(FormSectionEvent e) throws FormProcessException {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Post getSelectedPost(PageState state) {
|
||||
if (m_post == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (Post) m_post.getSelectedObject(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
private void clearParameters(PageState state) {
|
||||
state.setValue(m_context, null);
|
||||
m_attachImages.clearParameters(state);
|
||||
m_attachFiles.clearParameters(state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <a href="mailto:chris.gilbert@westsussex.gov.uk">chris.gilbert@westsussex.gov.uk</a>
|
||||
*
|
||||
* 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("<p>\n<i>\n");
|
||||
body.append(
|
||||
"Edited on "
|
||||
+ DateFormat.getDateInstance(DateFormat.SHORT).format(
|
||||
new Date())
|
||||
+ " by "
|
||||
+ ((User) Kernel.getContext().getParty()).getName());
|
||||
body.append("\n</i>\n</p>\n\n<br/>\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));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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 PostTextStep getTextStep(ACSObjectSelectionModel post) {
|
||||
return new ReplyToPostTextStep(post, this);
|
||||
}
|
||||
|
||||
protected Container dataEntryStep() {
|
||||
Container entryStep = super.dataEntryStep();
|
||||
MessageView replyTo = new MessageView(m_parent);
|
||||
entryStep.add(replyTo);
|
||||
|
||||
return entryStep;
|
||||
/* (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();
|
||||
}
|
||||
|
||||
protected void initWidgets(PageState state,
|
||||
Post post) {
|
||||
super.initWidgets(state, post);
|
||||
reply.setFrom(party);
|
||||
|
||||
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);
|
||||
}
|
||||
// reply is the post in the post model
|
||||
reply = getSelectedPost(state);
|
||||
}
|
||||
return reply;
|
||||
|
||||
protected void processWidgets(PageState state,
|
||||
Post post) {
|
||||
super.processWidgets(state, post);
|
||||
|
||||
ForumContext ctx = ForumContext.getContext(state);
|
||||
Forum forum = ctx.getForum();
|
||||
|
||||
if (forum.isModerated() &&
|
||||
!ctx.canModerate()) {
|
||||
post.setStatus(Post.PENDING);
|
||||
} else {
|
||||
post.setStatus(Post.APPROVED);
|
||||
}
|
||||
|
||||
post.setRefersTo(forum);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,47 +18,43 @@
|
|||
*/
|
||||
package com.arsdigita.forum.ui;
|
||||
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.bebop.parameters.IntegerParameter;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
||||
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.kernel.Kernel;
|
||||
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.web.ParameterMap;
|
||||
import com.arsdigita.web.RedirectSignal;
|
||||
|
||||
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.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
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.DomainObjectFactory;
|
||||
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.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;
|
||||
|
||||
public class ThreadDisplay extends SimpleComponent implements Constants {
|
||||
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
= "<hr>";
|
||||
|
||||
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,6 +115,7 @@ public class RejectionForm extends Wizard implements Constants {
|
|||
PageState state = e.getPageState();
|
||||
Post post = (Post)m_postModel.getSelectedObject(state);
|
||||
Label l = (Label) e.getTarget();
|
||||
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("<pre>" + body + "</pre>");
|
||||
//String body = StringUtils.quoteHtml(getBody(post, state));
|
||||
//l.setLabel("<pre>" + body + "</pre>");
|
||||
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", "<br>"));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -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("<br>");
|
||||
header.append("Subject : ");
|
||||
header.append(post.getSubject()).append("\n\n");
|
||||
header.append(post.getSubject()).append("<br><br>");
|
||||
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("<br><br>Your message has been rejected by the moderator.<br><br>");
|
||||
|
||||
body.append("The moderator has given the following reasons:\n\n");
|
||||
body.append("The moderator has given the following reasons:<br><br>");
|
||||
body.append((String)m_textArea.getValue(state));
|
||||
body.append("\n\n");
|
||||
body.append("<br><br>");
|
||||
|
||||
body.append("The content of the message follows:<br><br>");
|
||||
body.append("Subject: " + post.getSubject() + "<br>");
|
||||
body.append(post.getBody() + "<br><br><br>");
|
||||
// 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("<br><br>");
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,395 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
|
||||
|
||||
<taglib>
|
||||
<tlibversion>1.0</tlibversion>
|
||||
<jspversion>1.1</jspversion>
|
||||
<shortname>bebop-define</shortname>
|
||||
<uri>http://www.arsdigita.com/bebop-define/tld/1.0</uri>
|
||||
|
||||
<info>this is a tag library for defining Bebop pages via JSP.</info>
|
||||
|
||||
<tag>
|
||||
<name>page</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefinePage</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefinePageExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>title</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>application</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>master</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>pageClass</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>cache</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>component</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineComponentImpl</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineComponentExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>classname</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>form</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineForm</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineFormExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>encType</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>method</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>action</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>onSubmit</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>onReset</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>link</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineLink</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>url</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>image</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineImage</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>src</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>alt</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>width</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>height</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>border</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>tabbedPane</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineTabbedPane</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>tab</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineTab</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>label</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>text</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineText</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineWidgetExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>type</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>size</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>maxlength</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>password</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefinePassword</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineWidgetExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>size</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>maxlength</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>textArea</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineTextArea</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineWidgetExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>type</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>rows</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>cols</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>wrap</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>submit</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineSubmit</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>label</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>bundle</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>option</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineOption</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>value</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>selected</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>bundle</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>radioGroup</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineRadioGroup</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>checkboxGroup</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineCheckboxGroup</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>vertical</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>select</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineSelect</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>onChange</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>multipleSelect</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineMultipleSelect</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>slave</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineSlave</tagclass>
|
||||
<bodycontent>empty</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>list</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineList</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineListExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>table</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.DefineTable</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.DefineTableExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
</taglib>
|
||||
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
|
||||
|
||||
<taglib>
|
||||
<tlibversion>1.0</tlibversion>
|
||||
<jspversion>1.1</jspversion>
|
||||
<shortname>bebop-define</shortname>
|
||||
<uri>http://www.arsdigita.com/bebop-define/tld/1.0</uri>
|
||||
|
||||
<info>this is a tag library for showing components from Bebop pages
|
||||
inside of a JSP.</info>
|
||||
|
||||
<tag>
|
||||
<name>page</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowPage</tagclass>
|
||||
<teiclass>com.arsdigita.bebop.jsp.ShowPageExtraInfo</teiclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>pageClass</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>master</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>all</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowAll</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>component</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowComponent</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>form</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowForm</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>list</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowList</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
|
||||
<tag>
|
||||
<name>listItem</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowListItem</tagclass>
|
||||
<bodycontent>empty</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>table</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowTable</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
<attribute>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>thead</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowTableHeader</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>tbody</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowTableBody</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>row</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowTableRow</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>col</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowListItem</tagclass>
|
||||
<bodycontent>empty</bodycontent>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<name>slave</name>
|
||||
<tagclass>com.arsdigita.bebop.jsp.ShowSlave</tagclass>
|
||||
<bodycontent>JSP</bodycontent>
|
||||
</tag>
|
||||
</taglib>
|
||||
|
|
@ -23,15 +23,4 @@
|
|||
<url-pattern>/main/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- TAGLIBS -->
|
||||
<taglib>
|
||||
<taglib-uri>/WEB-INF/bebop-show.tld</taglib-uri>
|
||||
<taglib-location>/WEB-INF/bebop-show.tld</taglib-location>
|
||||
</taglib>
|
||||
|
||||
<taglib>
|
||||
<taglib-uri>/WEB-INF/bebop-define.tld</taglib-uri>
|
||||
<taglib-location>/WEB-INF/bebop-define.tld</taglib-location>
|
||||
</taglib>
|
||||
|
||||
</web-app>
|
||||
|
|
|
|||
|
|
@ -479,10 +479,10 @@
|
|||
<td width="100%"><xsl:apply-templates select="bebop:select[@name='bodyType']"/></td>
|
||||
</tr>
|
||||
<xsl:choose>
|
||||
<xsl:when test="bebop:select[@name='topic']">
|
||||
<xsl:when test="bebop:select[@name='postTopic']">
|
||||
<tr class="even">
|
||||
<td>Topic:</td>
|
||||
<td width="100%"><xsl:apply-templates select="bebop:select[@name='topic']"/></td>
|
||||
<td width="100%"><xsl:apply-templates select="bebop:select[@name='postTopic']"/></td>
|
||||
</tr>
|
||||
</xsl:when>
|
||||
<xsl:when test="forum:message">
|
||||
|
|
|
|||
Loading…
Reference in New Issue