package managers;
import models.Account;
import models.Notification;
import models.base.BaseModel;
import models.enums.EmailNotifications;
import play.db.jpa.JPA;
import play.db.jpa.JPAApi;
import javax.inject.Inject;
import javax.persistence.NoResultException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Iven on 17.12.2015.
*/
public class NotificationManager implements BaseManager {
@Inject
JPAApi jpaApi;
@Override
public void create(Object object) {
jpaApi.em().persist(object);
}
@Override
public void update(Object object) {
((Notification) object).updatedAt();
jpaApi.em().merge(object);
}
@Override
public void delete(Object object) {
jpaApi.em().remove(object);
}
/**
* Returns a list of notifications by a specific user account ID.
*
* @param accountId User account ID
* @param maxResults Maximum results
* @param offsetResults Offset of results
* @return List of notifications
* @throws Throwable
*/
@SuppressWarnings("unchecked")
public List<Notification> findByAccountId(final Long accountId, final int maxResults, final int offsetResults) throws Throwable {
return (List<Notification>) jpaApi.em()
.createQuery("FROM Notification n WHERE n.recipient.id = :accountId ORDER BY n.isRead ASC, n.updatedAt DESC")
.setParameter("accountId", accountId)
.setMaxResults(maxResults)
.setFirstResult(offsetResults)
.getResultList();
}
/**
* Returns a list of notifications <b>sent</b> by a specific account ID.
*
* @param senderId User account ID
* @return List of notifications
* @throws Throwable
*/
@SuppressWarnings("unchecked")
public List<Notification> findBySenderId(final Long senderId) {
return (List<Notification>) jpaApi.em()
.createQuery("FROM Notification n WHERE n.sender.id = :senderId")
.setParameter("senderId", senderId)
.getResultList();
}
/**
* Returns a list of notifications by a specific user account ID for a specific page.
*
* @param accountId User account ID
* @param maxResults Maximum results
* @param currentPage Current page
* @return List of notifications
* @throws Throwable
*/
public List<Notification> findByAccountIdForPage(final Long accountId, int maxResults, int currentPage) throws Throwable {
return findByAccountId(accountId, maxResults, (currentPage * maxResults) - maxResults);
}
/**
* Returns a list of unread notifications by a specific user account ID.
*
* @param accountId User account ID
* @return List of notifications
* @throws Throwable
*/
public static List<Notification> findByAccountIdUnread(final Long accountId) throws Throwable {
return JPA.em()
.createQuery("FROM Notification n WHERE n.recipient.id = :accountId AND n.isRead = false", Notification.class)
.setParameter("accountId", accountId)
.setMaxResults(10)
.getResultList();
}
/**
* Deletes a notification with containing a specific reference.
*
* @param reference BaseModel reference
*/
public void deleteReferences(final BaseModel reference) {
jpaApi.em().createQuery("DELETE FROM Notification n WHERE n.referenceId = :referenceId")
.setParameter("referenceId", reference.id)
.executeUpdate();
}
/**
* Deletes a notification for a specific account ID containing a specific reference.
*
* @param reference BaseModel reference
* @param accountId User account ID
*/
public void deleteReferencesForAccountId(final BaseModel reference, final long accountId) {
jpaApi.em().createQuery("DELETE FROM Notification n WHERE n.referenceId = :referenceId AND n.recipient.id = :accountId")
.setParameter("referenceId", reference.id)
.setParameter("accountId", accountId)
.executeUpdate();
}
/**
* Deletes all notifications for a specific account ID
*
* @param accountId User account ID
*/
public void deleteNotificationsForAccount(final long accountId) {
jpaApi.em().createQuery("DELETE FROM Notification n WHERE n.recipient.id = :accountId")
.setParameter("accountId", accountId)
.executeUpdate();
}
/**
* Returns a specific notification by its ID.
*
* @param id Notification ID
* @return Notification instance
*/
public Notification findById(Long id) {
return jpaApi.em().find(Notification.class, id);
}
/**
* Returns a notification by a reference ID and a recipient ID.
*
* @param referenceId Reference ID
* @param recipientId Recipient ID
* @return Notification instance
* @throws NoResultException
*/
public static Notification findByReferenceIdAndRecipientId(Long referenceId, Long recipientId) throws NoResultException {
return JPA.createFor("defaultPersistenceUnit").withTransaction(() -> {
return JPA.em().createQuery("FROM Notification n WHERE n.referenceId = :referenceId AND n.recipient.id = :recipientId", Notification.class)
.setParameter("referenceId", referenceId)
.setParameter("recipientId", recipientId)
.getSingleResult();
});
}
/**
* Returns a specific notification by its rendered content.
*
* @param renderedContent Rendered content to select
* @return Notification instance
*/
public List<Notification> findByRenderedContent(String renderedContent) throws NoResultException {
return jpaApi.em()
.createQuery("FROM Notification n WHERE n.rendered = :renderedContent", Notification.class)
.setParameter("renderedContent", renderedContent)
.getResultList();
}
/**
* Counts all notifications for an account ID.
*
* @param accountId User account ID
* @return Number of notifications
*/
public int countNotificationsForAccountId(final Long accountId) {
return ((Number) jpaApi.em()
.createQuery("SELECT COUNT(n) FROM Notification n WHERE n.recipient.id = :accountId")
.setParameter("accountId", accountId)
.getSingleResult()).intValue();
}
/**
* Counts all unread notifications for an account ID.
*
* @param accountId User account ID
* @return Number of notifications
*/
public static int countUnreadNotificationsForAccountId(final Long accountId) {
return ((Number) JPA.em()
.createQuery("SELECT COUNT(n) FROM Notification n WHERE n.recipient.id = :accountId AND n.isRead = false")
.setParameter("accountId", accountId)
.getSingleResult()).intValue();
}
/**
* Returns a map with recipients as a key and a list of unsent and unread notifications
* as value. The map contains recipients, who wish to receive either hourly emails or
* daily, if the current hour is equal the desired receiving hour.
* <p>
* Example: {<Account>: <List<Notification>, <Account>: <List<Notification>, ...}
*
* @return Map of accounts containing list of unsent and unread notifications
* @throws Throwable
*/
@SuppressWarnings("unchecked")
public Map<Account, List<Notification>> findUsersWithDailyHourlyEmailNotifications() throws Throwable {
Map<Account, List<Notification>> accountMap = new HashMap<>();
List<Object[]> notificationsRecipients = findRecipients();
// translate list of notifications and accounts into map
for (Object[] entry : notificationsRecipients) {
Notification notification = (Notification) entry[0];
Account account = (Account) entry[1];
List<Notification> listForAccount;
// add account and new list of notifications, if not set already, otherwise load list
if (!accountMap.containsKey(account)) {
listForAccount = new ArrayList<>();
accountMap.put(account, listForAccount);
} else {
listForAccount = accountMap.get(account);
}
// add notification to list for account
listForAccount.add(notification);
}
return accountMap;
}
@SuppressWarnings("unchecked")
private List<Object[]> findRecipients() {
return jpaApi.withTransaction(() -> {
return jpaApi.em()
.createQuery("FROM Notification n JOIN n.recipient a WHERE n.isSent = false AND n.isRead = false "
+ "AND ((a.emailNotifications = :daily AND HOUR(CURRENT_TIME) = a.dailyEmailNotificationHour) "
+ "OR a.emailNotifications = :hourly) ORDER BY n.recipient.id DESC"
)
.setParameter("daily", EmailNotifications.COLLECTED_DAILY)
.setParameter("hourly", EmailNotifications.HOURLY)
.getResultList();
});
}
/**
* Marks all unread notifications as read for an account.
*
* @param account Account
*/
public void markAllAsRead(Account account) {
jpaApi.em()
.createQuery("UPDATE Notification n SET n.isRead = true WHERE n.recipient = :account AND n.isRead = false")
.setParameter("account", account)
.executeUpdate();
}
}