/**
* Copyright (C) 2011 JTalks.org Team
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.model.entity;
import org.hibernate.search.annotations.*;
import org.joda.time.DateTime;
import org.jtalks.common.model.entity.Entity;
import org.jtalks.jcommune.model.search.BbCodeFilterBridge;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Represents the simple version of post of the forum
* with String content.<br/>
* Always included in the {@link Topic}. Topic itself should contain at lest one Post <br/>
* All fields of this object are required and can't be null.<br/>
* The topic field will be updated automatically when called Topic.addPost(Post). <br/>
* The Post deletes automatically if the parent Topic deleted.
*
* @author Pavel Vervenko
* @author Kirill Afonin
* @author Anuar Nurmakanov
*/
public class Post extends Entity implements SubscriptionAwareEntity {
public static final String URL_SUFFIX = "/posts/";
private DateTime creationDate;
private DateTime modificationDate;
private JCUser userCreated;
private String postContent;
private Topic topic;
private int rating;
private List<PostComment> comments = new ArrayList<>();
private Set<PostVote> votes = new HashSet<>();
public static final int MAX_LENGTH = 20000;
public static final int MIN_LENGTH = 2;
/**
* Name of the field in the index for Russian.
*/
public static final String POST_CONTENT_FIELD_RU = "postContentRu";
/**
* Name of the field in the index for default language(English).
*/
public static final String POST_CONTENT_FIELD_DEF = "postContent";
/**
* For Hibernate use only
*/
protected Post() {
}
/**
* Creates the Post instance with required fields.
* Creation date is set to now.
*
* @param userCreated user who create the post
* @param postContent content of the post
*/
public Post(JCUser userCreated, String postContent) {
this.creationDate = new DateTime();
this.userCreated = userCreated;
this.postContent = postContent;
}
/**
* Used to find out the current post index on JSP page.
* We can't invoke a method there so use an explicit getter.
*
* @return index of this post ina topic, starting from 0
*/
public int getPostIndexInTopic(){
return topic.getPosts().indexOf(this);
}
/**
* @return the postDate
*/
public DateTime getCreationDate() {
return creationDate;
}
/**
* @return date and time when the post was changed last time
*/
public DateTime getModificationDate() {
return modificationDate;
}
/**
* @param postDate the postDate to set
*/
protected void setCreationDate(DateTime postDate) {
this.creationDate = postDate;
}
/**
* @param modificationDate date and time when the post was changed last time
*/
protected void setModificationDate(DateTime modificationDate) {
this.modificationDate = modificationDate;
}
/**
* Set modification date to now. The post's topic's
* modification date will be also set to now
*
* @return new modification date
*/
public DateTime updateModificationDate() {
this.modificationDate = new DateTime();
return this.modificationDate;
}
/**
* Updates creation date of post. Sets it to NOW
*
* We need this operation for drafts. We can't update modification date of draft because
* if we set it after posting draft it will be marked with "last modified" label
*
* @return new creation date of post
*/
public DateTime updateCreationDate() {
this.creationDate = new DateTime();
return this.creationDate;
}
/**
* @return date and time where post what last time modified or created otherwise
*/
public DateTime getLastTouchedDate() {
return modificationDate == null ? creationDate : modificationDate;
}
/**
* @return the userCreated
*/
public JCUser getUserCreated() {
return userCreated;
}
/**
* Set the User who create this post.
*
* @param userCreated the userCreated to set
*/
protected void setUserCreated(JCUser userCreated) {
this.userCreated = userCreated;
}
/**
* @return the postContent
*/
@Fields({
@Field(name = POST_CONTENT_FIELD_RU,
analyzer = @Analyzer(definition = "russianJtalksAnalyzer")),
@Field(name = POST_CONTENT_FIELD_DEF,
analyzer = @Analyzer(definition = "defaultJtalksAnalyzer"))
})
@FieldBridge(impl = BbCodeFilterBridge.class)
public String getPostContent() {
return postContent;
}
/**
* @param postContent the postContent to set
*/
public void setPostContent(String postContent) {
this.postContent = postContent;
}
/**
* @return the topic
*/
@ContainedIn
public Topic getTopic() {
return topic;
}
/**
* @param topic the Topic to set
*/
public void setTopic(Topic topic) {
this.topic = topic;
}
/**
* Gets list of comments of the post
*
* @return list of comments
*/
public List<PostComment> getComments() {
return comments;
}
/**
* Sets specified list of comments to the post
*
* @param comments list of comments to set
*/
public void setComments(List<PostComment> comments) {
this.comments = comments;
}
/**
* Adds specified comment to the post
*
* @param comment comment to add
*/
public void addComment(PostComment comment) {
comment.setPost(this);
comments.add(comment);
}
/**
* Gets rating of the post.
* Rating introduced to provide ability to vote for posts.
* In some topic types post may be ordered by rating.
*
* @return rating of the post
*/
public int getRating() {
return rating;
}
/**
* Sets specified rating to current post
*
* @param rating rating to set
*/
public void setRating(int rating) {
this.rating = rating;
}
/**
* Gets set of votes for this post
*
* @return set of votes for this post
*/
public Set<PostVote> getVotes() {
return votes;
}
/**
* Sets set of votes as votes for this post. Needed only for Hibernate
* use {@link #putVote(PostVote)} to add or update vote of post
*
* @param votes set of votes to set
*/
public void setVotes(Set<PostVote> votes) {
this.votes = votes;
}
/**
* Adds new vote to the post or overrides existent
*
* @param vote vote to add or override
*/
public void putVote(PostVote vote) {
vote.setPost(this);
for (PostVote storedVote : votes) {
if (storedVote.getUser().equals(vote.getUser()) && storedVote.getPost().equals(vote.getPost())) {
storedVote.setVotedUp(vote.isVotedUp());
storedVote.setVoteDate(vote.getVoteDate());
return;
}
}
votes.add(vote);
}
/**
* Determines if user voted up for the post
*
* @param user user to check
*
* @return true if user voted up for the post
* false if user voted down for the post
* false if user not voted for the post
*/
public boolean isVotedUpBy(JCUser user) {
for (PostVote vote : votes) {
if (vote.getUser().equals(user)) {
return vote.isVotedUp();
}
}
return false;
}
/**
* Determines if user voted down for the post
*
* @param user user to check
*
* @return true if user voted down for the post
* false if user voted up for the post
* false if user not voted for the post
*/
public boolean isVotedDownBy(JCUser user) {
for (PostVote vote : votes) {
if (vote.getUser().equals(user)) {
return !vote.isVotedUp();
}
}
return false;
}
/**
* Determines if user can vote for the post in specified direction.
* If direction is true possibility to vote up will be checked.
* If direction if false possibility to vote down will be checked.
*
* @param user user to check
* @param direction direction of vote
*
* @return true if user can vote in specified direction otherwise false
*/
public boolean canBeVotedBy(JCUser user, boolean direction) {
return direction ? !isVotedUpBy(user) : !isVotedDownBy(user);
}
/**
* Calculates changes in rating of the posh which will be made by specified vote
*
* @param vote vote for calculating changes;
*
* @return 0 if user can't vote in direction specified by vote
* +/- 1 if user votes first time in up/down direction
* +/- 2 if user changes his vote from negative to positive/from positive to negative
*/
public int calculateRatingChanges(PostVote vote) {
if (canBeVotedBy(vote.getUser(), vote.isVotedUp())) {
if (isVotedDownBy(vote.getUser())) {
return 2;
} else if (isVotedUpBy(vote.getUser())) {
return -2;
} else {
return vote.isVotedUp() ? 1 : -1;
}
}
return 0;
}
/**
* Creates and returns new list of comments of the current post which is not marked as removed. We cant use
* hibernate "WHERE" clause due caching issue. Additionally we may need to retrieve comments which is marked as
* removed in future. To manipulate with list of comments use {@link #getComments()} and
* {@link #setComments(java.util.List)} methods.
*
* @return newly created list of comments which not marked as deleted
*/
public List<PostComment> getNotRemovedComments() {
List<PostComment> notRemovedComments = new ArrayList<>();
for (PostComment comment : getComments()) {
if (comment.getDeletionDate() == null) {
notRemovedComments.add(comment);
}
}
return notRemovedComments;
}
/**
* {@inheritDoc}
*/
@Override
public Set<JCUser> getSubscribers() {
return getTopic().getSubscribers();
}
/**
* {@inheritDoc}
*/
@Override
public String getUrlSuffix() {
return URL_SUFFIX + getId();
}
/**
* {@inheritDoc}
*/
@Override
public <T extends SubscriptionAwareEntity> String getUnsubscribeLinkForSubscribersOf(Class<T> clazz) {
return getTopic().getUnsubscribeLinkForSubscribersOf(clazz);
}
}