/*
* Copyright (c) JForum Team. All rights reserved.
*
* The software in this package is published under the terms of the LGPL
* license a copy of which has been included with this distribution in the
* license.txt file.
*
* The JForum Project
* http://www.jforum.net
*/
package net.jforum.repository;
import java.util.Date;
import java.util.List;
import net.jforum.entities.Forum;
import net.jforum.entities.ForumStats;
import net.jforum.entities.Group;
import net.jforum.entities.Post;
import net.jforum.entities.Topic;
import net.jforum.entities.util.PaginatedResult;
import net.jforum.util.ConfigKeys;
import net.jforum.util.JForumConfig;
import org.apache.commons.lang.ArrayUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import br.com.caelum.vraptor.ioc.Component;
/**
* @author Rafael Steil
*/
@Component
public class ForumRepository extends HibernateGenericDAO<Forum> implements Repository<Forum> {
private JForumConfig config;
public ForumRepository(Session session) {
super(session);
}
public void setJforumConfig(JForumConfig config) {
this.config = config;
}
public void moveTopics(Forum toForum, int... topicIds) {
session.createQuery("update Topic t set t.movedId = t.forum.id, t.forum = :newForum " +
" where t.id in (:ids)")
.setParameterList("ids", ArrayUtils.toObject(topicIds))
.setParameter("newForum", toForum)
.executeUpdate();
session.createQuery("update Post p set p.forum = :forum where p.topic.id in (:ids)")
.setParameterList("ids", ArrayUtils.toObject(topicIds))
.setParameter("forum", toForum)
.executeUpdate();
}
@Override
public void add(Forum entity) {
entity.setDisplayOrder(this.getMaxDisplayOrder());
super.add(entity);
}
@SuppressWarnings("unchecked")
public List<Group> getModerators(Forum forum) {
return session.createQuery("select distinct r.group from Role r " +
" join r.roleValues rv " +
" where r.name = 'moderate_forum' " +
" and rv = :forum")
.setEntity("forum", forum)
.setComment("forumDAO.getModerators")
.setCacheable(true)
.setCacheRegion("forumDAO.getModerators")
.list();
}
@SuppressWarnings("unchecked")
public List<Topic> getTopicsPendingModeration(Forum forum) {
return session.createQuery("select t from Topic t left join fetch t.posts post" +
" where post.moderate = true" +
" or t.pendingModeration = true" +
" and t.forum = :forum" +
" order by t.id, post.id")
.setEntity("forum", forum)
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
.setComment("forumDAO.getTopicsPendingModeration")
.list();
}
public Post getLastPost(Forum forum) {
return (Post)session.createQuery("from Post p where p.id = (select max(p2.id) from Post p2" +
" where p2.forum = :forum and p2.moderate = false)")
.setParameter("forum", forum)
.setComment("forumDao.getLastPost")
.uniqueResult();
}
public int getTotalMessages() {
return (Integer)session.createCriteria(Post.class)
.setProjection(Projections.rowCount())
.setCacheable(true)
.setCacheRegion("forumDAO.getTotalMessages")
.setComment("forumDAO.getTotalMessages")
.uniqueResult();
}
public int getTotalPosts(Forum forum) {
return (Integer)session.createCriteria(Post.class)
.setProjection(Projections.rowCount())
.add(Restrictions.eq("forum", forum))
.setCacheable(true)
.setCacheRegion("forumDAO.getTotalPosts#" + forum.getId())
.setComment("forumDAO.getTotalPosts")
.uniqueResult();
}
public int getTotalTopics(Forum forum) {
return (Integer)session.createCriteria(Topic.class)
.setProjection(Projections.rowCount())
.add(Restrictions.eq("pendingModeration", false))
.add(Restrictions.eq("forum", forum))
.setCacheable(true)
.setCacheRegion("forumDAO.getTotalTopics#" + forum.getId())
.setComment("forumDAO.getTotalTopics")
.uniqueResult();
}
/**
* Selects all topics associated to a specific forum.
*
* @param forum The forum to select the topics
* @return <code>List</code> with all topics found. Each entry is a <code>net.jforum.Topic</code> object
* @param startFrom int
* @param count int
*/
@SuppressWarnings("unchecked")
public List<Topic> getTopics(Forum forum, int startFrom, int count) {
boolean includeMoved = this.config == null || !this.config.getBoolean(ConfigKeys.QUERY_IGNORE_TOPIC_MOVED);
Criteria criteria = session.createCriteria(Topic.class)
.createAlias("firstPost", "fp")
.createAlias("lastPost", "lp");
if (includeMoved) {
criteria.add(Restrictions.or(Restrictions.eq("forum", forum), Restrictions.eq("movedId", forum.getId())));
}
else {
criteria.add(Restrictions.eq("forum", forum));
}
return criteria.add(Restrictions.eq("pendingModeration", false))
.addOrder(Order.desc("type"))
.addOrder(Order.desc("lastPost"))
.setFirstResult(startFrom)
.setMaxResults(count)
.setCacheable(startFrom == 0) // FIXME cache other pages? should find a good solution. Also, check the eviction rules if changing this
.setCacheRegion("forumDAO.getTopics#" + forum.getId()) // Related to the fixme above
.setComment("forumDAO.getTopics")
.list();
}
@SuppressWarnings("unchecked")
public PaginatedResult<Topic> getNewMessages(Date from, int start, int recordsPerPage) {
int total = ((Number)session.createQuery("select count(*) from Topic t " +
"where t.pendingModeration = false and t.lastPost.date >= :date")
.setParameter("date", from)
.setComment("forumDao.getNewMessagesCount")
.uniqueResult()).intValue();
List<Topic> results = session.createQuery("from Topic t " +
"join fetch t.lastPost lp where t.pendingModeration = false and lp.date >= :date")
.setParameter("date", from)
.setFirstResult(start)
.setMaxResults(recordsPerPage)
.setComment("forumDao.getNewMessages")
.list();
return new PaginatedResult<Topic>(results, total);
}
@SuppressWarnings("unchecked")
public List<Forum> findAll() {
return session.createQuery("select new Forum(forum.id) from Forum as forum)").list();
}
private int getMaxDisplayOrder() {
Integer displayOrder = (Integer)session.createCriteria(this.persistClass)
.setProjection(Projections.max("displayOrder"))
.uniqueResult();
return displayOrder == null ? 1 : displayOrder + 1;
}
public ForumStats getForumStats() {
ForumStats s = new ForumStats();
s.setPosts(this.getTotalMessages());
s.setTotalUsers(((Number)session.createQuery("select count(*) from User").uniqueResult()).intValue());
s.setTotalTopics(((Number)session.createQuery("select count(*) from Topic").uniqueResult()).intValue());
Date today = new Date();
Date firstPostDate = (Date)session.createQuery("select min(p.date) from Post p").uniqueResult();
s.setPostsPerDay(firstPostDate != null ? (double)s.getPosts() / this.daysUntilToday(today, firstPostDate) : 0);
s.setTopicsPerDay(firstPostDate != null ? (double)s.getTopics() / this.daysUntilToday(today, firstPostDate) : 0);
Date firstRegisteredUserDate = (Date)session.createQuery("select min(u.registrationDate) from User u").uniqueResult();
s.setUsersPerDay(firstRegisteredUserDate != null ? (double)s.getUsers() / this.daysUntilToday(today, firstRegisteredUserDate) : 0);
return s;
}
public ForumStats getForumStats(List<Group> groups) {
ForumStats s = new ForumStats();
// Total users
s.setTotalUsers(((Number)session.createQuery("select count(*) from User u where u.groups in (:groups)")
.setParameterList("groups", groups)
.uniqueResult()).intValue());
return s;
}
private int daysUntilToday(Date today, Date from)
{
int days = (int) ((today.getTime() - from.getTime()) / (24 * 60 * 60 * 1000));
return days == 0 ? 1 : days;
}
}