* Erweitert, so daß per Konfiguration eingestellt werden kann, ob ein Autor einen eigenen Beitrag löschen darf, falls es der letzte Eintrag im Thread ist
 * Dateien werden nun als Download Verknüpft, nicht mehr als direkte Ansicht

git-svn-id: https://svn.libreccm.org/ccm/trunk@1407 8810af33-2d31-482b-a856-94f89814c4df
master
quasi 2011-12-28 08:59:05 +00:00
parent d29337b7f1
commit e7f5bd0a98
9 changed files with 458 additions and 422 deletions

View File

@ -731,6 +731,18 @@ public class Forum extends Application {
party))); party)));
} }
/**
* checks if the user can delete posts in this forum
*/
public boolean canDelete(Party party) {
return ((getConfig().canAdminEditPosts()
|| getConfig().canAuthorDeletePosts())
&& PermissionService.checkPermission(
new PermissionDescriptor(PrivilegeDescriptor.DELETE,
this,
party)));
}
public boolean canAdminister(Party party) { public boolean canAdminister(Party party) {
return PermissionService.checkPermission( return PermissionService.checkPermission(
new PermissionDescriptor(PrivilegeDescriptor.ADMIN, new PermissionDescriptor(PrivilegeDescriptor.ADMIN,

View File

@ -49,6 +49,7 @@ public class ForumConfig extends AbstractConfig {
private Parameter m_adminEditPosts; private Parameter m_adminEditPosts;
private Parameter m_authorEditPosts; private Parameter m_authorEditPosts;
private Parameter m_authorDeletePosts;
private Parameter m_digestUserEmail; private Parameter m_digestUserEmail;
private Parameter m_replyHostName; private Parameter m_replyHostName;
private Parameter m_disablePageCaching; private Parameter m_disablePageCaching;
@ -74,6 +75,10 @@ public class ForumConfig extends AbstractConfig {
"com.arsdigita.forum.author_can_edit_posts", "com.arsdigita.forum.author_can_edit_posts",
Parameter.REQUIRED, Parameter.REQUIRED,
Boolean.TRUE); Boolean.TRUE);
m_authorDeletePosts = new BooleanParameter(
"com.arsdigita.forum.author_can_delete_posts",
Parameter.REQUIRED,
Boolean.TRUE);
m_replyHostName = new StringParameter( m_replyHostName = new StringParameter(
"com.arsdigita.forum.reply_host_name", "com.arsdigita.forum.reply_host_name",
Parameter.OPTIONAL, Parameter.OPTIONAL,
@ -134,6 +139,7 @@ public class ForumConfig extends AbstractConfig {
register(m_digestUserEmail); register(m_digestUserEmail);
register(m_adminEditPosts); register(m_adminEditPosts);
register(m_authorEditPosts); register(m_authorEditPosts);
register(m_authorDeletePosts);
register(m_replyHostName); register(m_replyHostName);
register(m_adapters); register(m_adapters);
register(m_disablePageCaching); register(m_disablePageCaching);
@ -162,6 +168,10 @@ public class ForumConfig extends AbstractConfig {
return ((Boolean)get(m_authorEditPosts)).booleanValue(); return ((Boolean)get(m_authorEditPosts)).booleanValue();
} }
boolean canAuthorDeletePosts() {
return ((Boolean)get(m_authorDeletePosts)).booleanValue();
}
public String getDigestUserEmail() { public String getDigestUserEmail() {
String email = (String)get(m_digestUserEmail); String email = (String)get(m_digestUserEmail);
if (email == null) { if (email == null) {
@ -295,5 +305,5 @@ public class ForumConfig extends AbstractConfig {
public boolean deleteNotifications () { public boolean deleteNotifications () {
return ((Boolean)get(m_deleteSentSubscriptionNotifications)).booleanValue(); return ((Boolean)get(m_deleteSentSubscriptionNotifications)).booleanValue();
} }
} }

View File

@ -24,10 +24,15 @@ com.arsdigita.forum.admin_only_to_create_topics.format=[boolean]
com.arsdigita.forum.admin_only_to_create_topics.example=true|false 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.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.purpose=Whether authors can edit their posts
com.arsdigita.forum.author_can_edit_posts.format=[boolean] com.arsdigita.forum.author_can_edit_posts.format=[boolean]
com.arsdigita.forum.author_can_edit_posts.example=true|false com.arsdigita.forum.author_can_edit_posts.example=true|false
com.arsdigita.forum.author_can_delete_posts.title=Authors can delete posts
com.arsdigita.forum.author_can_delete_posts.purpose=Whether authors can delete their posts as long it is the last in the thread
com.arsdigita.forum.author_can_delete_posts.format=[boolean]
com.arsdigita.forum.author_can_delete_posts.example=true|false
com.arsdigita.forum.disable_page_caching.title=Disable client & middleware page caching 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.purpose=Disable caching, particularly for situations where users share PCs
com.arsdigita.forum.disable_page_caching.format=[boolean] com.arsdigita.forum.disable_page_caching.format=[boolean]

View File

@ -157,6 +157,16 @@ public final class ForumContext {
return m_canAdminister; return m_canAdminister;
} }
/**
*
* @return
*/
public boolean canDelete(Post post) {
Party party = Kernel.getContext().getParty();
return post.canDelete(party);
}
/** /**
* *
* @return * @return

View File

@ -114,39 +114,31 @@ import com.arsdigita.util.Assert;
* @author Nobuko Asakai (nasakai@redhat.com) * @author Nobuko Asakai (nasakai@redhat.com)
*/ */
public class Post extends ThreadedMessage { public class Post extends ThreadedMessage {
private static final Logger s_log = Logger.getLogger(Post.class);
private static final Logger s_log = Logger.getLogger(Post.class);
/** PDL property for marking the approval state of a message, one /** PDL property for marking the approval state of a message, one
* of 'approved', 'rejected', 'reapprove', 'supressed' */ * of 'approved', 'rejected', 'reapprove', 'supressed' */
public static final String STATUS = "status"; public static final String STATUS = "status";
/** ID of the administrator who last changed the status of a /** ID of the administrator who last changed the status of a
* message */ * message */
public static final String MODERATOR = "moderator"; public static final String MODERATOR = "moderator";
/** /**
* 0..n association with PostImageAttachments * 0..n association with PostImageAttachments
*/ */
public static final String IMAGE_ATTACHMENTS = "images"; public static final String IMAGE_ATTACHMENTS = "images";
/** /**
* 0..n association with PostFileAttachments * 0..n association with PostFileAttachments
*/ */
public static final String FILE_ATTACHMENTS = "files"; public static final String FILE_ATTACHMENTS = "files";
/** The status strings */ /** The status strings */
public static final String PENDING = "pending"; public static final String PENDING = "pending";
public static final String APPROVED = "approved"; public static final String APPROVED = "approved";
public static final String REJECTED = "rejected"; public static final String REJECTED = "rejected";
public static final String REAPPROVE = "reapprove"; public static final String REAPPROVE = "reapprove";
public static final String SUPPRESSED = "suppressed"; public static final String SUPPRESSED = "suppressed";
public static final String POST_STATUS_SUBQUERY = public static final String POST_STATUS_SUBQUERY =
"com.arsdigita.forum.threadModerationStatus"; "com.arsdigita.forum.threadModerationStatus";
private Party m_moderator; private Party m_moderator;
// referred to afterSave method // referred to afterSave method
private boolean m_wasNew; private boolean m_wasNew;
@ -155,13 +147,13 @@ public class Post extends ThreadedMessage {
* other words, all bboard messages are ThreadedMessages. * other words, all bboard messages are ThreadedMessages.
*/ */
public static final String BASE_DATA_OBJECT_TYPE = public static final String BASE_DATA_OBJECT_TYPE =
"com.arsdigita.forum.Post"; "com.arsdigita.forum.Post";
private Post() { private Post() {
this(BASE_DATA_OBJECT_TYPE); this(BASE_DATA_OBJECT_TYPE);
} }
public Post(String typeName) { public Post(String typeName) {
super(typeName); super(typeName);
} }
@ -169,9 +161,9 @@ public class Post extends ThreadedMessage {
super(oid); super(oid);
} }
public Post(BigDecimal id) { public Post(BigDecimal id) {
this(new OID(BASE_DATA_OBJECT_TYPE, id)); this(new OID(BASE_DATA_OBJECT_TYPE, id));
} }
public Post(DataObject obj) { public Post(DataObject obj) {
super(obj); super(obj);
@ -217,10 +209,10 @@ public class Post extends ThreadedMessage {
BigDecimal id = getID(); BigDecimal id = getID();
// XXX this isn't really the host we want // XXX this isn't really the host we want
setRFCMessageID(id + ".bboard@" + setRFCMessageID(id + ".bboard@"
Forum.getConfig().getReplyHostName()); + Forum.getConfig().getReplyHostName());
setReplyTo(getRefersTo() + ".bboard@" + setReplyTo(getRefersTo() + ".bboard@"
Forum.getConfig().getReplyHostName()); + Forum.getConfig().getReplyHostName());
super.beforeSave(); super.beforeSave();
@ -239,8 +231,8 @@ public class Post extends ThreadedMessage {
s_log.info("Setting context for " + getOID() + " to " + root.getOID()); s_log.info("Setting context for " + getOID() + " to " + root.getOID());
PermissionService.setContext(this, root); PermissionService.setContext(this, root);
s_log.info( "Setting context for " + root.getOID() + " to " + s_log.info("Setting context for " + root.getOID() + " to "
forum.getOID()); + forum.getOID());
PermissionService.setContext(root, forum); PermissionService.setContext(root, forum);
// originally this was created in beforeSave, but this was when only // originally this was created in beforeSave, but this was when only
// noticeboard (reply disabled) forums could have a lifecycle. Now that // noticeboard (reply disabled) forums could have a lifecycle. Now that
@ -251,7 +243,7 @@ public class Post extends ThreadedMessage {
if (m_wasNew) { if (m_wasNew) {
if (getRoot() == null && forum.getExpireAfter() > 0) { if (getRoot() == null && forum.getExpireAfter() > 0) {
s_log.info("Creating expiration lifecycle for " + getOID()); s_log.info("Creating expiration lifecycle for " + getOID());
setLifecycle(forum.getLifecycleDefinition()); setLifecycle(forum.getLifecycleDefinition());
} }
} }
m_wasNew = false; m_wasNew = false;
@ -263,7 +255,7 @@ public class Post extends ThreadedMessage {
while (files.next()) { while (files.next()) {
PostFileAttachment file = PostFileAttachment file =
(PostFileAttachment) DomainObjectFactory.newInstance( (PostFileAttachment) DomainObjectFactory.newInstance(
files.getDataObject()); files.getDataObject());
if (getStatus().equals(APPROVED)) { if (getStatus().equals(APPROVED)) {
file.setLive(); file.setLive();
} else { } else {
@ -277,15 +269,16 @@ public class Post extends ThreadedMessage {
/** /**
* Sends out the notifications for any subscriptions to the forum * Sends out the notifications for any subscriptions to the forum
* or thread to which this message belongs. Only sends * or thread to which this message belongs. Only sends
* notifications if the post is approved. * notifications if the post is approved.
*/ */
public void sendNotifications(final String context) { public void sendNotifications(final String context) {
KernelExcursion ex = new KernelExcursion() { KernelExcursion ex = new KernelExcursion() {
protected void excurse() {
setEffectiveParty(Kernel.getSystemParty()); protected void excurse() {
doSendNotifications(context); setEffectiveParty(Kernel.getSystemParty());
} doSendNotifications(context);
}; }
};
ex.run(); ex.run();
} }
@ -295,59 +288,58 @@ public class Post extends ThreadedMessage {
*/ */
public void sendModeratorAlerts() { public void sendModeratorAlerts() {
if (!getStatus().equals(APPROVED)) { if (!getStatus().equals(APPROVED)) {
// don't send if pre-approved (ie posted by a moderator) // don't send if pre-approved (ie posted by a moderator)
KernelExcursion ex = new KernelExcursion() { KernelExcursion ex = new KernelExcursion() {
protected void excurse() { protected void excurse() {
setEffectiveParty(Kernel.getSystemParty()); setEffectiveParty(Kernel.getSystemParty());
doSendModeratorAlerts(); doSendModeratorAlerts();
} }
}; };
ex.run(); ex.run();
} else { } else {
s_log.debug("not sending moderator alerts because the post " + s_log.debug("not sending moderator alerts because the post "
"was pre-approved (created by an approver)"); + "was pre-approved (created by an approver)");
} }
} }
private void doSendNotifications(String context) { private void doSendNotifications(String context) {
s_log.debug("sending user notifications"); s_log.debug("sending user notifications");
Forum forum = getForum(); Forum forum = getForum();
if (getStatus().equals(APPROVED)) { if (getStatus().equals(APPROVED)) {
s_log.debug("Sending forum level subsriptions"); s_log.debug("Sending forum level subsriptions");
DataCollection subscriptions = forum.getSubscriptions(); DataCollection subscriptions = forum.getSubscriptions();
while (subscriptions.next()) { while (subscriptions.next()) {
ForumSubscription subscription = (ForumSubscription) ForumSubscription subscription = (ForumSubscription) DomainObjectFactory.newInstance(
DomainObjectFactory.newInstance(
subscriptions.getDataObject()); subscriptions.getDataObject());
s_log.debug("notification to " + subscription.getOID()); s_log.debug("notification to " + subscription.getOID());
subscription.sendNotification(Post.this, Forum.getConfig() subscription.sendNotification(Post.this, Forum.getConfig().deleteNotifications());
.deleteNotifications());
} }
s_log.debug("Sending thread level subsriptions"); s_log.debug("Sending thread level subsriptions");
if (context == null || !context.equals(PostForm.NEW_CONTEXT)) { if (context == null || !context.equals(PostForm.NEW_CONTEXT)) {
ThreadSubscription sub = ThreadSubscription sub =
ThreadSubscription.getThreadSubscription(getThread()); ThreadSubscription.getThreadSubscription(getThread());
if (sub == null) { if (sub == null) {
s_log.error( s_log.error(
"Got a null ThreadSubscription from " "Got a null ThreadSubscription from "
+ "Post # " + "Post # "
+ getID()); + getID());
} else { } else {
sub.sendNotification(this, Forum.getConfig().deleteNotifications()); sub.sendNotification(this, Forum.getConfig().deleteNotifications());
} }
} }
} else { } else {
s_log.debug("Not sending notifications because the " + s_log.debug("Not sending notifications because the "
"message is not approved"); + "message is not approved");
}
} }
}
private void doSendModeratorAlerts() { private void doSendModeratorAlerts() {
if (s_log.isDebugEnabled()) { if (s_log.isDebugEnabled()) {
@ -361,18 +353,16 @@ public class Post extends ThreadedMessage {
DataCollection alerts = forum.getModerationAlerts(); DataCollection alerts = forum.getModerationAlerts();
while (alerts.next()) { while (alerts.next()) {
ModerationAlert alert ModerationAlert alert = (ModerationAlert) DomainObjectFactory.newInstance(
= (ModerationAlert) alerts.getDataObject());
DomainObjectFactory.newInstance( s_log.debug("Processing moderation alert " + alert.getOID());
alerts.getDataObject()); alert.sendNotification(this, Forum.getConfig().deleteNotifications());
s_log.debug("Processing moderation alert " + alert.getOID());
alert.sendNotification(this, Forum.getConfig().deleteNotifications());
} }
} else { } else {
s_log.debug("Not sending moderator alerts because the " + s_log.debug("Not sending moderator alerts because the "
"forum is not moderated"); + "forum is not moderated");
}
} }
}
/** /**
* Set the Forum that contains this post. Just a wrapper for the * Set the Forum that contains this post. Just a wrapper for the
@ -381,7 +371,6 @@ public class Post extends ThreadedMessage {
* *
* @param forum the Forum that contains this post. * @param forum the Forum that contains this post.
*/ */
public void setForum(Forum forum) { public void setForum(Forum forum) {
setRefersTo(forum); setRefersTo(forum);
} }
@ -399,12 +388,10 @@ public class Post extends ThreadedMessage {
* *
* @param category the Category for this post. * @param category the Category for this post.
*/ */
public void mapCategory(Category category) public void mapCategory(Category category)
throws PersistenceException { throws PersistenceException {
if (isNew()) { if (isNew()) {
throw new PersistenceException throw new PersistenceException("Post must be persistent to map categories");
("Post must be persistent to map categories");
} }
category.addChild(this); category.addChild(this);
category.save(); category.save();
@ -413,34 +400,33 @@ public class Post extends ThreadedMessage {
/** /**
* Clears categories for this post. Used when editing a post * Clears categories for this post. Used when editing a post
*/ */
public void clearCategories() { public void clearCategories() {
DataCollection categories = DataCollection categories =
SessionManager.getSession().retrieve( SessionManager.getSession().retrieve(
Category.BASE_DATA_OBJECT_TYPE); Category.BASE_DATA_OBJECT_TYPE);
categories.addEqualsFilter( categories.addEqualsFilter(
Category.CHILD_OBJECTS + "." + ACSObject.ID, Category.CHILD_OBJECTS + "." + ACSObject.ID,
getID()); getID());
while (categories.next()) { while (categories.next()) {
Category cat = Category cat =
(Category) DomainObjectFactory.newInstance( (Category) DomainObjectFactory.newInstance(
categories.getDataObject()); categories.getDataObject());
cat.removeChild(this); cat.removeChild(this);
} }
// above is slower than data operation implementation below, // above is slower than data operation implementation below,
// but data op caused problems in persistence. If edited post // but data op caused problems in persistence. If edited post
// had topic unchanged, then attempt was made to assign topic // had topic unchanged, then attempt was made to assign topic
// category before data op had cleared existing. Hence exception // category before data op had cleared existing. Hence exception
// - attempt to map object to same cat twice // - attempt to map object to same cat twice
/* /*
DataOperation clearCategories = DataOperation clearCategories =
SessionManager.getSession().retrieveDataOperation( SessionManager.getSession().retrieveDataOperation(
"com.arsdigita.forum.clearCategories"); "com.arsdigita.forum.clearCategories");
clearCategories.setParameter("postID", this.getID()); clearCategories.setParameter("postID", this.getID());
clearCategories.execute(); clearCategories.execute();
return;*/ return;*/
} }
/** /**
@ -451,41 +437,41 @@ public class Post extends ThreadedMessage {
} }
/** /**
* creates a ThreadSubscription, and returns it but only if this is a root, * creates a ThreadSubscription, and returns it but only if this is a root,
* else return null * else return null
* Note, you must save() the Post before calling this method. * Note, you must save() the Post before calling this method.
*/ */
public ThreadSubscription createThreadSubscription() { public ThreadSubscription createThreadSubscription() {
ThreadSubscription sub = null; ThreadSubscription sub = null;
if (getRoot() == null) { if (getRoot() == null) {
sub = new ThreadSubscription(); sub = new ThreadSubscription();
sub.setThread(getThread()); sub.setThread(getThread());
sub.save(); sub.save();
} }
return sub; return sub;
} }
public ThreadSubscription getSubscription() { public ThreadSubscription getSubscription() {
MessageThread thread; MessageThread thread;
if (getRoot() != null) { if (getRoot() != null) {
thread = getRootMsg().getThread(); thread = getRootMsg().getThread();
} else { } else {
thread = getThread(); thread = getThread();
} }
DataCollection subscriptions = DataCollection subscriptions =
SessionManager.getSession().retrieve( SessionManager.getSession().retrieve(
ThreadSubscription.BASE_DATA_OBJECT_TYPE); ThreadSubscription.BASE_DATA_OBJECT_TYPE);
subscriptions.addEqualsFilter( subscriptions.addEqualsFilter(
ThreadSubscription.THREAD, ThreadSubscription.THREAD,
thread.getID()); thread.getID());
ThreadSubscription subscription = null; ThreadSubscription subscription = null;
while (subscriptions.next()) { while (subscriptions.next()) {
subscription = subscription =
(ThreadSubscription) DomainObjectFactory.newInstance( (ThreadSubscription) DomainObjectFactory.newInstance(
subscriptions.getDataObject()); subscriptions.getDataObject());
} }
return subscription; return subscription;
} }
/** /**
@ -498,64 +484,78 @@ public class Post extends ThreadedMessage {
Party author = getFrom(); //determin sender / author of message Party author = getFrom(); //determin sender / author of message
// cg added - for anonymous posts, don't allow editing, else everyone // cg added - for anonymous posts, don't allow editing, else everyone
// could edit everyone else's posts // could edit everyone else's posts
return ( !author.equals(Kernel.getPublicUser()) return (!author.equals(Kernel.getPublicUser())
&& Forum.getConfig().canAuthorEditPosts() && Forum.getConfig().canAuthorEditPosts()
&& author.equals(party) ) && author.equals(party))
|| getForum().canEdit(party); || getForum().canEdit(party);
}
/**
* Determines if the User has permission to delete this Post.
* Note that you probably don't want to use this over and
* over for a list of messages because the permission check
* on the forum is not cached.
*/
public boolean canDelete(Party party) {
Party author = getFrom(); //determin sender / author of message
// cg added - for anonymous posts, don't allow editing, else everyone
// could edit everyone else's posts
return (!author.equals(Kernel.getPublicUser())
&& Forum.getConfig().canAuthorDeletePosts()
&& author.equals(party))
|| getForum().canDelete(party);
} }
public void setStatus(String status) { public void setStatus(String status) {
Assert.isTrue( Assert.isTrue(
(status.equals(APPROVED) (status.equals(APPROVED)
|| status.equals(REJECTED) || status.equals(REJECTED)
|| status.equals(REAPPROVE) || status.equals(REAPPROVE)
|| status.equals(SUPPRESSED) || status.equals(SUPPRESSED)
|| status.equals(PENDING) || status.equals(PENDING)),
), "The status must be one of " + APPROVED
"The status must be one of " + APPROVED + ", " + REJECTED
+ ", " + REJECTED + ", " + REAPPROVE
+ ", " + REAPPROVE + ", " + SUPPRESSED
+ ", "+ SUPPRESSED + ", the input was " + status);
+ ", the input was " + status
);
set(STATUS, status); set(STATUS, status);
} }
/** /**
* set the status of a new post according to the priviliges of * set the status of a new post according to the priviliges of
* the current user - used by UI when creating new post or reply * the current user - used by UI when creating new post or reply
* @param state * @param state
*/ */
public void setStatus(PageState state) { public void setStatus(PageState state) {
setStatus(state, null); setStatus(state, null);
} }
/** /**
* set the status of an edited post according to the privileges * set the status of an edited post according to the privileges
* of the current user and the status of the post that is being * of the current user and the status of the post that is being
* edited - used by the edit post UI * edited - used by the edit post UI
* @param state * @param state
* @param previousStatus * @param previousStatus
*/ */
public void setStatus(PageState state, String previousStatus) { public void setStatus(PageState state, String previousStatus) {
ForumContext ctx = ForumContext.getContext(state); ForumContext ctx = ForumContext.getContext(state);
Forum forum = ctx.getForum(); Forum forum = ctx.getForum();
// set status of edited post // set status of edited post
if (forum.isModerated() && !ctx.canModerate()) { if (forum.isModerated() && !ctx.canModerate()) {
if (Post.APPROVED.equals(previousStatus)) { if (Post.APPROVED.equals(previousStatus)) {
setStatus(Post.REAPPROVE); setStatus(Post.REAPPROVE);
} else { } else {
setStatus(Post.PENDING); setStatus(Post.PENDING);
} }
} else { } else {
setStatus(Post.APPROVED); setStatus(Post.APPROVED);
} }
} }
public String getStatus() { public String getStatus() {
return (String)get(STATUS); return (String) get(STATUS);
} }
public void setModerator(Party moderator) { public void setModerator(Party moderator) {
@ -566,26 +566,24 @@ public class Post extends ThreadedMessage {
if (m_moderator == null) { if (m_moderator == null) {
DataObject moderatorData = (DataObject) get(MODERATOR); DataObject moderatorData = (DataObject) get(MODERATOR);
if (moderatorData != null) { if (moderatorData != null) {
m_moderator = (Party) DomainObjectFactory.newInstance m_moderator = (Party) DomainObjectFactory.newInstance(moderatorData);
(moderatorData);
} }
} }
return m_moderator; return m_moderator;
} }
// note that the replies to this post are deleted in beforeDelete() of // note that the replies to this post are deleted in beforeDelete() of
// ThreadedMessage (and hence beforeDelete is called recursively on their replies) // ThreadedMessage (and hence beforeDelete is called recursively on their replies)
protected void beforeDelete() { protected void beforeDelete() {
s_log.debug("Post - before delete " + getID()); s_log.debug("Post - before delete " + getID());
// threaded message recursively deletes children // threaded message recursively deletes children
super.beforeDelete(); super.beforeDelete();
// remove any nt_requests // remove any nt_requests
DataCollection requests = DataCollection requests =
SessionManager.getSession().retrieve( SessionManager.getSession().retrieve(
Notification.BASE_DATA_OBJECT_TYPE); Notification.BASE_DATA_OBJECT_TYPE);
requests.addEqualsFilter(Notification.MESSAGE_ID, this.getID()); requests.addEqualsFilter(Notification.MESSAGE_ID, this.getID());
while (requests.next()) { while (requests.next()) {
Notification no = new Notification(requests.getDataObject().getOID()); Notification no = new Notification(requests.getDataObject().getOID());
no.setMessageDelete(Boolean.FALSE); no.setMessageDelete(Boolean.FALSE);
@ -593,23 +591,23 @@ public class Post extends ThreadedMessage {
} }
if (getRoot() == null) { if (getRoot() == null) {
s_log.debug( s_log.debug(
"Root post - get rid of thread subscription and thread"); "Root post - get rid of thread subscription and thread");
// This posting is the root of the thread. Remove the thread subscription and thread // This posting is the root of the thread. Remove the thread subscription and thread
MessageThread thread = getThread(); MessageThread thread = getThread();
ThreadSubscription sub = ThreadSubscription sub =
ThreadSubscription.getThreadSubscription(thread); ThreadSubscription.getThreadSubscription(thread);
if (sub != null) { if (sub != null) {
// if unconfirmed post, then threadsubscription has not been created // if unconfirmed post, then threadsubscription has not been created
sub.delete(); sub.delete();
} }
if (thread != null) { if (thread != null) {
thread.delete(); thread.delete();
}
} }
}
} }
// package access only // package access only
void setLifecycle(LifecycleDefinition life) { void setLifecycle(LifecycleDefinition life) {
@ -619,91 +617,86 @@ public class Post extends ThreadedMessage {
cycle.save(); cycle.save();
} }
public void addImage(PostImageAttachment image) { public void addImage(PostImageAttachment image) {
DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS); DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS);
image.addToAssociation(images); image.addToAssociation(images);
long currentImageCount = images.getDataAssociationCursor().size(); long currentImageCount = images.getDataAssociationCursor().size();
image.setImageOrder((int) currentImageCount); image.setImageOrder((int) currentImageCount);
} }
public void removeImage(PostImageAttachment image) { public void removeImage(PostImageAttachment image) {
DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS); DataAssociation images = (DataAssociation) get(Post.IMAGE_ATTACHMENTS);
image.removeFromAssociation(images); image.removeFromAssociation(images);
renumberImages(); renumberImages();
} }
// image order for a new image is based on the count of existing // 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 // images, hence necessary to fill in any gaps when images are deleted
private void renumberImages() { private void renumberImages() {
int count = 1; int count = 1;
DataAssociationCursor images = getImages(); DataAssociationCursor images = getImages();
while (images.next()) { while (images.next()) {
PostImageAttachment image = PostImageAttachment image =
(PostImageAttachment) DomainObjectFactory.newInstance( (PostImageAttachment) DomainObjectFactory.newInstance(
images.getDataObject()); images.getDataObject());
image.setImageOrder(count); image.setImageOrder(count);
count++; count++;
} }
} }
public DataAssociationCursor getImages() { public DataAssociationCursor getImages() {
DataAssociationCursor images = DataAssociationCursor images =
((DataAssociation) get(Post.IMAGE_ATTACHMENTS)) ((DataAssociation) get(Post.IMAGE_ATTACHMENTS)).getDataAssociationCursor();
.getDataAssociationCursor(); images.addOrder(PostImageAttachment.IMAGE_ORDER);
images.addOrder(PostImageAttachment.IMAGE_ORDER); return images;
return images; }
}
public void addFile(PostFileAttachment file) { public void addFile(PostFileAttachment file) {
DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS); DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS);
file.addToAssociation(files); file.addToAssociation(files);
PermissionService.setContext(file, this); PermissionService.setContext(file, this);
long currentFileCount = files.getDataAssociationCursor().size(); long currentFileCount = files.getDataAssociationCursor().size();
file.setFileOrder((int) currentFileCount); file.setFileOrder((int) currentFileCount);
} }
public void removeFile(PostFileAttachment file) { public void removeFile(PostFileAttachment file) {
DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS); DataAssociation files = (DataAssociation) get(Post.FILE_ATTACHMENTS);
file.removeFromAssociation(files); file.removeFromAssociation(files);
renumberFiles(); renumberFiles();
} }
// file order for a new file is based on the count of existing // 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 // 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++;
}
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;
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.
/** *
* 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);
// should really be static - revisit this - refer to MessageThread for use
protected void addReplyFilter(DataCollection replies) {
replies.addEqualsFilter(STATUS, APPROVED);
}
}
} }

View File

@ -18,16 +18,14 @@
*/ */
package com.arsdigita.forum; package com.arsdigita.forum;
import com.arsdigita.cms.ContentItem; import com.arsdigita.cms.Asset;
import com.arsdigita.cms.dispatcher.AssetURLFinder; import com.arsdigita.cms.dispatcher.AssetURLFinder;
import com.arsdigita.kernel.NoValidURLException; import com.arsdigita.kernel.NoValidURLException;
import com.arsdigita.kernel.URLFinder; import com.arsdigita.kernel.URLFinder;
import com.arsdigita.kernel.URLService;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID; import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.SessionManager; import com.arsdigita.web.Web;
import com.arsdigita.util.Assert; import com.arsdigita.web.WebConfig;
/** /**
* @author chris.gilbert@westsussex.gov.uk * @author chris.gilbert@westsussex.gov.uk
@ -36,32 +34,41 @@ import com.arsdigita.util.Assert;
*/ */
public class PostFileAttachmentURLFinder implements URLFinder { public class PostFileAttachmentURLFinder implements URLFinder {
private static final AssetURLFinder s_assetFinder = new AssetURLFinder(); private static final AssetURLFinder s_assetFinder = new AssetURLFinder();
/** /**
* *
* find URL for a file attachment by finding its post * find URL for a file attachment by finding its post
* *
* @param oid the OID of the file attachment * @param oid the OID of the file attachment
* @param content the context of the search (ie draft/live) * @param content the context of the search (ie draft/live)
*/ */
public String find(OID oid, String context) throws NoValidURLException { public String find(OID oid, String context) throws NoValidURLException {
// a draft attachment is one where the post hasn't been saved yet // 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 // the behaviour is the same as far as finding the url goes
return find(oid); return find(oid);
}
/**
* }
* find URL for the context of a file attachment. Delegates to
* AssetURLFinder. /**
* *
* @param oid the OID of the file attachment * find URL for the context of a file attachment. Delegates to
* * AssetURLFinder.
*/ *
public String find(OID oid) throws NoValidURLException { * @param oid the OID of the file attachment
return s_assetFinder.find(oid); *
} */
public String find(OID oid) throws NoValidURLException {
WebConfig config = Web.getConfig();
StringBuilder url = new StringBuilder();
url.append(config.getDispatcherServletPath());
url.append(config.getDispatcherContextPath());
url.append("/cms-service/download/asset/?asset_id=");
url.append(oid.get(Asset.ID).toString());
return url.toString();
// return s_assetFinder.find(oid);
}
} }

View File

@ -356,7 +356,7 @@ public class AttachedFilesStep
while(files.next()) { while(files.next()) {
PostFileAttachment file = (PostFileAttachment) DomainObjectFactory.newInstance( PostFileAttachment file = (PostFileAttachment) DomainObjectFactory.newInstance(
files.getDataObject()); files.getDataObject());
DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(p.newChildElement(FORUM_XML_PREFIX + "files")); DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(p.newChildElement(FORUM_XML_PREFIX + ":files", FORUM_XML_NS));
xr.setWrapRoot(false); xr.setWrapRoot(false);
xr.setWrapAttributes(true); xr.setWrapAttributes(true);
xr.setWrapObjects(false); xr.setWrapObjects(false);

View File

@ -25,13 +25,13 @@ import java.math.BigDecimal;
* XML namespaces, URLs, URL variable names, etc. * XML namespaces, URLs, URL variable names, etc.
* *
* @author <a href="mailto:teadams@arsdigita.com">Tracy Adams</a> * @author <a href="mailto:teadams@arsdigita.com">Tracy Adams</a>
* @version $Revision: 1.3 $ $Date: 2006/03/08 15:38:33 $ * @version $Revision: 1.3 $ $Date: 2006/03/08 15:38:33 $
* @since ACS 4.7 * @since ACS 4.7
*/ */
public interface Constants { public interface Constants {
static final String FORUM_XML_PREFIX = "forum"; static final String FORUM_XML_PREFIX = "forum";
static final String FORUM_XML_NS = "http://www.arsdigita.com/forum/1.0"; static final String FORUM_XML_NS = "http://www.arsdigita.com/forum/1.0";
static final String FORUM_MODE_VIEW = "view"; static final String FORUM_MODE_VIEW = "view";

View File

@ -68,18 +68,15 @@ import com.arsdigita.xml.XML;
public class DiscussionPostsList extends SimpleComponent implements Constants { public class DiscussionPostsList extends SimpleComponent implements Constants {
private static final Logger s_log = private static final Logger s_log =
Logger.getLogger(DiscussionPostsList.class); Logger.getLogger(DiscussionPostsList.class);
private IntegerParameter m_pageNumber = private IntegerParameter m_pageNumber =
new IntegerParameter(PAGINATOR_PARAM); new IntegerParameter(PAGINATOR_PARAM);
private int m_pageSize = Forum.getConfig().getThreadPageSize(); private int m_pageSize = Forum.getConfig().getThreadPageSize();
private static final String ACTION_EDIT = "edit"; private static final String ACTION_EDIT = "edit";
private static final String ACTION_DELETE = "delete"; private static final String ACTION_DELETE = "delete";
private static final String ACTION_REPLY = "reply"; private static final String ACTION_REPLY = "reply";
private static final String ACTION_APPROVE = "approve"; private static final String ACTION_APPROVE = "approve";
private static final String ACTION_REJECT = "reject"; private static final String ACTION_REJECT = "reject";
private DiscussionThreadSimpleView m_threadMessagesPanel; private DiscussionThreadSimpleView m_threadMessagesPanel;
private ACSObjectSelectionModel m_post; private ACSObjectSelectionModel m_post;
@ -90,12 +87,11 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
* @param threadMessagesPanel * @param threadMessagesPanel
*/ */
public DiscussionPostsList(ACSObjectSelectionModel post, public DiscussionPostsList(ACSObjectSelectionModel post,
DiscussionThreadSimpleView threadMessagesPanel) { DiscussionThreadSimpleView threadMessagesPanel) {
m_threadMessagesPanel = threadMessagesPanel; m_threadMessagesPanel = threadMessagesPanel;
m_post = post; m_post = post;
} }
/** /**
* *
* @param p * @param p
@ -112,56 +108,66 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
* @throws ServletException * @throws ServletException
*/ */
public void respond(PageState state) public void respond(PageState state)
throws ServletException { throws ServletException {
super.respond(state); super.respond(state);
String key = state.getControlEventName(); String key = state.getControlEventName();
String value = state.getControlEventValue(); String value = state.getControlEventValue();
OID oid = new OID(Post.BASE_DATA_OBJECT_TYPE, OID oid = new OID(Post.BASE_DATA_OBJECT_TYPE,
new BigDecimal(value)); new BigDecimal(value));
ForumContext ctx = ForumContext.getContext(state); ForumContext ctx = ForumContext.getContext(state);
Post post = (Post)DomainObjectFactory.newInstance(oid); Post post = (Post) DomainObjectFactory.newInstance(oid);
if (ACTION_EDIT.equals(key)) { if (ACTION_EDIT.equals(key)) {
m_post.setSelectedObject(state, post); m_post.setSelectedObject(state, post);
m_threadMessagesPanel.makeEditFormVisible(state); m_threadMessagesPanel.makeEditFormVisible(state);
} else if (ACTION_DELETE.equals(key)) { } else if (ACTION_DELETE.equals(key)) {
Assert.isTrue(ctx.canAdminister(), "can administer forums"); // Assert.isTrue(ctx.canDelete(post), "can administer forums");
MessageThread thread = ctx.getMessageThread(); MessageThread thread = ctx.getMessageThread();
ThreadedMessage root = thread.getRootMessage(); ThreadedMessage root = thread.getRootMessage();
if ( s_log.isDebugEnabled() ) { if (s_log.isDebugEnabled()) {
s_log.debug("message: " + post.getOID() + s_log.debug("message: " + post.getOID()
" root: " + root.getOID() + + " root: " + root.getOID()
" thread: " + thread.getOID()); + " thread: " + thread.getOID());
} }
if ( ctx.getForum().isModerated() ) { if (ctx.getForum().isModerated()) {
if ( !ctx.canModerate() ) { if (!ctx.canModerate()) {
Assert.isTrue(ctx.canAdminister(), "can administer forums");
post.setStatus(Post.SUPPRESSED); post.setStatus(Post.SUPPRESSED);
post.save(); post.save();
} else if (post.equals(root)) { } else if (post.equals(root)) {
Assert.isTrue(ctx.canDelete(post), "can delete posts");
s_log.debug("Deleting entire thread"); s_log.debug("Deleting entire thread");
post.delete(); post.delete();
Forum forum = ctx.getForum(); Forum forum = ctx.getForum();
URL url = URL.there(state.getRequest(), forum, null ); URL url = URL.there(state.getRequest(), forum, null);
throw new RedirectSignal( url, true ); throw new RedirectSignal(url, true);
} else { } else {
Assert.isTrue(ctx.canDelete(post), "can delete posts");
s_log.debug("Deleting message"); s_log.debug("Deleting message");
post.delete(); post.delete();
} }
} else if (post.equals(root)) { } else if (post.equals(root)) {
Assert.isTrue(ctx.canDelete(post), "can delete posts");
s_log.debug("Deleting entire thread"); s_log.debug("Deleting entire thread");
post.delete(); post.delete();
Forum forum = ctx.getForum(); Forum forum = ctx.getForum();
URL url = URL.there(state.getRequest(), forum, null ); URL url = URL.there(state.getRequest(), forum, null);
throw new RedirectSignal( url, true ); throw new RedirectSignal(url, true);
} else { } else {
Assert.isTrue(ctx.canDelete(post), "can delete posts");
s_log.debug("Deleting message"); s_log.debug("Deleting message");
post.delete(); post.delete();
} }
@ -179,9 +185,9 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
state.clearControlEvent(); state.clearControlEvent();
try { try {
throw new RedirectSignal( state.stateAsURL(), true ); throw new RedirectSignal(state.stateAsURL(), true);
} catch( IOException ex ) { } catch (IOException ex) {
throw new UncheckedWrapperException( ex ); throw new UncheckedWrapperException(ex);
} }
} }
@ -197,10 +203,9 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
Forum forum = context.getForum(); Forum forum = context.getForum();
BigDecimal rootID = context.getMessageThread(). BigDecimal rootID = context.getMessageThread().
getRootMessage().getID(); getRootMessage().getID();
DataCollection messages = SessionManager.getSession().retrieve DataCollection messages = SessionManager.getSession().retrieve(Post.BASE_DATA_OBJECT_TYPE);
(Post.BASE_DATA_OBJECT_TYPE);
// Hide replies if we're in noticeboard mode // Hide replies if we're in noticeboard mode
if (forum.isNoticeboard()) { if (forum.isNoticeboard()) {
@ -210,21 +215,14 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
FilterFactory ff = messages.getFilterFactory(); FilterFactory ff = messages.getFilterFactory();
messages.addFilter( messages.addFilter(
ff.or() ff.or().addFilter(ff.and().addFilter(ff.equals("root", null)).addFilter(ff.equals("id", rootID))).addFilter(ff.equals("root", rootID)));
.addFilter(ff.and()
.addFilter(ff.equals("root", null))
.addFilter(ff.equals("id", rootID)))
.addFilter(ff.equals("root", rootID)));
messages.addOrderWithNull("sortKey", "---", true); messages.addOrderWithNull("sortKey", "---", true);
// Add a filter to only show approved messages // Add a filter to only show approved messages
if (forum.isModerated() && !forum.canModerate(party)) { if (forum.isModerated() && !forum.canModerate(party)) {
messages.addFilter(ff.or() messages.addFilter(ff.or().addFilter(ff.equals("status", Post.APPROVED)).addFilter(ff.equals("sender.id", party == null
.addFilter(ff.equals("status", Post.APPROVED)) ? null : party.getID())));
.addFilter(ff.equals("sender.id", party == null ?
null : party.getID()))
);
} }
return new DomainCollection(messages); return new DomainCollection(messages);
@ -237,22 +235,21 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
*/ */
@Override @Override
public void generateXML(PageState state, public void generateXML(PageState state,
Element parent) { Element parent) {
Element content = parent.newChildElement(FORUM_XML_PREFIX + Element content = parent.newChildElement(FORUM_XML_PREFIX
":threadDisplay", + ":threadDisplay",
FORUM_XML_NS); FORUM_XML_NS);
exportAttributes(content); exportAttributes(content);
Forum forum = ForumContext.getContext(state).getForum(); Forum forum = ForumContext.getContext(state).getForum();
content.addAttribute("forumTitle", forum.getTitle()); content.addAttribute("forumTitle", forum.getTitle());
content.addAttribute("noticeboard", (new Boolean(forum.isNoticeboard())). content.addAttribute("noticeboard", (new Boolean(forum.isNoticeboard())).toString());
toString());
DomainCollection messages = getMessages(state); DomainCollection messages = getMessages(state);
Integer page = (Integer)state.getValue(m_pageNumber); Integer page = (Integer) state.getValue(m_pageNumber);
int pageNumber = (page == null ? 1 : page.intValue()); int pageNumber = (page == null ? 1 : page.intValue());
long objectCount = messages.size(); long objectCount = messages.size();
int pageCount = (int)Math.ceil((double)objectCount / (double)m_pageSize); int pageCount = (int) Math.ceil((double) objectCount / (double) m_pageSize);
if (pageNumber < 1) { if (pageNumber < 1) {
pageNumber = 1; pageNumber = 1;
@ -262,29 +259,30 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
pageNumber = (pageCount == 0 ? 1 : pageCount); pageNumber = (pageCount == 0 ? 1 : pageCount);
} }
long begin = ((pageNumber-1) * m_pageSize); long begin = ((pageNumber - 1) * m_pageSize);
int count = (int)Math.min(m_pageSize, (objectCount - begin)); int count = (int) Math.min(m_pageSize, (objectCount - begin));
long end = begin + count; long end = begin + count;
generatePaginatorXML(content, generatePaginatorXML(content,
pageNumber, pageNumber,
pageCount, pageCount,
m_pageSize, m_pageSize,
begin, begin,
end, end,
objectCount); objectCount);
if (begin != 0 || end != 0) { if (begin != 0 || end != 0) {
messages.setRange(new Integer((int)begin+1), messages.setRange(new Integer((int) begin + 1),
new Integer((int)end+1)); new Integer((int) end + 1));
} }
while (messages.next()) { while (messages.next()) {
Post message = (Post)messages.getDomainObject(); Post message = (Post) messages.getDomainObject();
Element messageEl = content.newChildElement(FORUM_XML_PREFIX + ":message", Element messageEl = content.newChildElement(FORUM_XML_PREFIX + ":message",
FORUM_XML_NS); FORUM_XML_NS);
generateActionXML(state, messageEl, message); generateActionXML(state, messageEl, message,
(messages.getPosition() == messages.size()) ? true : false );
DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(messageEl); DomainObjectXMLRenderer xr = new DomainObjectXMLRenderer(messageEl);
xr.setWrapRoot(false); xr.setWrapRoot(false);
@ -299,60 +297,62 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
/** /**
* *
* @param state * @param state
* @param parent * @param parent Parent XML element to add any additional elements
* @param post * @param post Current post to generate action links for
* @param isLast Post is last in list
*/ */
protected void generateActionXML(PageState state, protected void generateActionXML(PageState state,
Element parent, Element parent,
Post post) { Post post,
boolean isLast) {
ForumContext ctx = ForumContext.getContext(state); ForumContext ctx = ForumContext.getContext(state);
String status = post.getStatus();
if (ctx.canModerate()) {
if (!status.equals(Post.REJECTED) &&
!status.equals(Post.SUPPRESSED) ) {
parent.addAttribute("rejectURL",
makeURL(state, ACTION_REJECT, post));
}
}
if (ctx.canModerate() &&
!post.getStatus().equals(post.APPROVED)) {
parent.addAttribute("approveURL",
makeURL(state, ACTION_APPROVE, post));
}
if (ctx.canAdminister()) {
parent.addAttribute("deleteURL",
makeURL(state, ACTION_DELETE, post));
}
Party party = Kernel.getContext().getParty(); Party party = Kernel.getContext().getParty();
if (party == null) { if (party == null) {
party = Kernel.getPublicUser(); party = Kernel.getPublicUser();
}
if (post.canEdit(party)) {
parent.addAttribute("editURL",
makeURL(state, ACTION_EDIT, post));
} }
PermissionDescriptor canRespond = new PermissionDescriptor( String status = post.getStatus();
PrivilegeDescriptor.get(Forum.RESPOND_TO_THREAD_PRIVILEGE), if (ctx.canModerate()) {
Kernel.getContext().getResource(), party); if (!status.equals(Post.REJECTED)
&& !status.equals(Post.SUPPRESSED)) {
if (!ctx.getForum().isNoticeboard() && PermissionService. parent.addAttribute("rejectURL",
checkPermission(canRespond)) { makeURL(state, ACTION_REJECT, post));
}
}
if (ctx.canModerate()
&& !post.getStatus().equals(post.APPROVED)) {
parent.addAttribute("approveURL",
makeURL(state, ACTION_APPROVE, post));
}
if (ctx.canAdminister() || (post.canDelete(party) && isLast)) {
parent.addAttribute("deleteURL",
makeURL(state, ACTION_DELETE, post));
}
if (post.canEdit(party)) {
parent.addAttribute("editURL",
makeURL(state, ACTION_EDIT, post));
}
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", parent.addAttribute("replyURL",
makeURL(state, ACTION_REPLY, post)); makeURL(state, ACTION_REPLY, post));
} }
} }
protected String makeURL(PageState state, protected String makeURL(PageState state,
String action, String action,
Post post) { Post post) {
state.setControlEvent(this, action,post.getID().toString()); state.setControlEvent(this, action, post.getID().toString());
String url = null; String url = null;
try { try {
@ -365,35 +365,34 @@ public class DiscussionPostsList extends SimpleComponent implements Constants {
} }
protected void generatePaginatorXML(Element parent, protected void generatePaginatorXML(Element parent,
int pageNumber, int pageNumber,
int pageCount, int pageCount,
int pageSize, int pageSize,
long begin, long begin,
long end, long end,
long objectCount) { long objectCount) {
Element paginator = parent.newChildElement(FORUM_XML_PREFIX + Element paginator = parent.newChildElement(FORUM_XML_PREFIX
":paginator", FORUM_XML_NS); + ":paginator", FORUM_XML_NS);
URL here = Web.getContext().getRequestURL(); URL here = Web.getContext().getRequestURL();
ParameterMap params = new ParameterMap(here.getParameterMap()); ParameterMap params = new ParameterMap(here.getParameterMap());
params.clearParameter(PAGINATOR_PARAM); params.clearParameter(PAGINATOR_PARAM);
URL url = new URL(here.getScheme(), URL url = new URL(here.getScheme(),
here.getServerName(), here.getServerName(),
here.getServerPort(), here.getServerPort(),
here.getContextPath(), here.getContextPath(),
here.getServletPath(), here.getServletPath(),
here.getPathInfo(), here.getPathInfo(),
params); params);
paginator.addAttribute("param", PAGINATOR_PARAM); paginator.addAttribute("param", PAGINATOR_PARAM);
paginator.addAttribute("baseURL", XML.format(url)); paginator.addAttribute("baseURL", XML.format(url));
paginator.addAttribute("pageNumber", XML.format(new Integer(pageNumber))); paginator.addAttribute("pageNumber", XML.format(new Integer(pageNumber)));
paginator.addAttribute("pageCount", XML.format(new Integer(pageCount))); paginator.addAttribute("pageCount", XML.format(new Integer(pageCount)));
paginator.addAttribute("pageSize", XML.format(new Integer(pageSize))); paginator.addAttribute("pageSize", XML.format(new Integer(pageSize)));
paginator.addAttribute("objectBegin", XML.format(new Long(begin+1))); paginator.addAttribute("objectBegin", XML.format(new Long(begin + 1)));
paginator.addAttribute("objectEnd", XML.format(new Long(end))); paginator.addAttribute("objectEnd", XML.format(new Long(end)));
paginator.addAttribute("objectCount", XML.format(new Long(objectCount))); paginator.addAttribute("objectCount", XML.format(new Long(objectCount)));
} }
} }