package org.activityinfo.server.digest.activity; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Provider; import org.activityinfo.server.database.hibernate.entity.Partner; import org.activityinfo.server.database.hibernate.entity.SiteHistory; import org.activityinfo.server.database.hibernate.entity.User; import org.activityinfo.server.database.hibernate.entity.UserDatabase; import org.activityinfo.server.digest.DigestModelBuilder; import org.activityinfo.server.digest.UserDigest; import org.activityinfo.server.digest.activity.ActivityDigestModel.ActivityMap; import org.activityinfo.server.digest.activity.ActivityDigestModel.DatabaseModel; import org.activityinfo.server.digest.activity.ActivityDigestModel.PartnerActivityModel; import javax.persistence.EntityManager; import javax.persistence.Query; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.logging.Logger; public class ActivityDigestModelBuilder implements DigestModelBuilder { private static final Logger LOGGER = Logger.getLogger(ActivityDigestModelBuilder.class.getName()); private final Provider<EntityManager> entityManager; @Inject public ActivityDigestModelBuilder(Provider<EntityManager> entityManager) { this.entityManager = entityManager; } @Override public ActivityDigestModel createModel(UserDigest userDigest) throws IOException { ActivityDigestModel model = new ActivityDigestModel(userDigest); List<UserDatabase> databases = findDatabases(userDigest.getUser()); LOGGER.finest("found " + databases.size() + " database(s) for user " + userDigest.getUser().getId()); if (!databases.isEmpty()) { for (UserDatabase database : databases) { createDatabaseModel(model, database); } } return model; } private void createDatabaseModel(ActivityDigestModel model, UserDatabase database) throws IOException { SiteHistory lastEdit = findLastEdit(database); // only include databases that are known to be edited at least once if (lastEdit != null) { DatabaseModel databaseModel = new DatabaseModel(model, database, lastEdit); List<SiteHistory> ownerHistories = findSiteHistory(databaseModel, database.getOwner()); ActivityMap ownerActivityMap = new ActivityMap(databaseModel, database.getOwner(), ownerHistories); databaseModel.setOwnerActivityMap(ownerActivityMap); List<Partner> partners = findPartners(databaseModel); LOGGER.finest("building user activity digest for user " + model.getUserDigest().getUser().getId() + " and database " + database.getId() + " - found " + partners.size() + " partner(s)"); if (!partners.isEmpty()) { for (Partner partner : partners) { PartnerActivityModel partnerModel = new PartnerActivityModel(databaseModel, partner); List<User> partnerUsers = findUsers(partnerModel); LOGGER.finest("found users " + partnerUsers + " for partner " + partner.getName()); if (!partnerUsers.isEmpty()) { for (User partnerUser : partnerUsers) { List<SiteHistory> histories = findSiteHistory(databaseModel, partnerUser); ActivityMap activityMap = new ActivityMap(databaseModel, partnerUser, histories); partnerModel.addActivityMap(activityMap); } } } } } } /** * @param user * @return all UserDatabases for the specified user where the user is the database owner, or where the database has * a UserPermission for the specified user with allowDesign set to true. If the user happens to have his * emailnotification preference set to false, an empty list is returned. */ @VisibleForTesting @SuppressWarnings("unchecked") List<UserDatabase> findDatabases(User user) { // sanity check if (!user.isEmailNotification()) { return new ArrayList<UserDatabase>(); } Query query = entityManager.get() .createQuery("select distinct d from UserDatabase d left join d.userPermissions p " + "where (d.owner = :user or (p.user = :user and p.allowDesign = true))" + " and d.dateDeleted is null " + "order by d.name"); query.setParameter("user", user); return query.getResultList(); } /** * @param databaseModel * @return the partners linked to the specified database via a userpermission */ @VisibleForTesting @SuppressWarnings("unchecked") List<Partner> findPartners(DatabaseModel databaseModel) { Query query = entityManager.get().createQuery("select distinct p.partner from UserPermission p " + "where p.database = :database " + "order by p.partner.name"); query.setParameter("database", databaseModel.getDatabase()); return query.getResultList(); } /** * @param partnerModel * @return the users linked to the specified database and partner via a userpermission where allowEdit is set to * true. */ @VisibleForTesting @SuppressWarnings("unchecked") List<User> findUsers(PartnerActivityModel partnerModel) { Query query = entityManager.get().createQuery("select distinct p.user from UserPermission p " + "where p.database = :database and p.partner = :partner and p" + ".allowEdit = true " + "order by p.user.name"); query.setParameter("database", partnerModel.getDatabaseModel().getDatabase()); query.setParameter("partner", partnerModel.getPartner()); return query.getResultList(); } /** * @param databaseModel * @param editor * @return the sitehistory edited since the specified timestamp (milliseconds) and linked to the specified database * and user. */ @VisibleForTesting @SuppressWarnings("unchecked") List<SiteHistory> findSiteHistory(DatabaseModel databaseModel, User editor) { Query query = entityManager.get().createQuery("select distinct h from SiteHistory h " + "where h.site.activity.database = :database and h.user = :user " + "and h.timeCreated >= :from " + "order by h.timeCreated"); query.setParameter("database", databaseModel.getDatabase()); query.setParameter("user", editor); query.setParameter("from", databaseModel.getModel().getUserDigest().getFrom()); return query.getResultList(); } @VisibleForTesting @SuppressWarnings("unchecked") SiteHistory findLastEdit(UserDatabase database) { Query query = entityManager.get().createQuery("select h from SiteHistory h " + "where h.site.activity.database = :database " + "order by h.timeCreated desc"); query.setParameter("database", database); query.setMaxResults(1); List<SiteHistory> list = query.getResultList(); return (list != null && list.size() == 1) ? list.get(0) : null; } }