/**
* 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.service.transactional;
import org.jtalks.common.model.permissions.GeneralPermission;
import org.jtalks.jcommune.model.dao.PrivateMessageDao;
import org.jtalks.jcommune.model.dto.PageRequest;
import org.jtalks.jcommune.model.entity.JCUser;
import org.jtalks.jcommune.model.entity.JCommuneProperty;
import org.jtalks.jcommune.model.entity.PrivateMessage;
import org.jtalks.jcommune.model.entity.PrivateMessageStatus;
import org.jtalks.jcommune.service.PrivateMessageService;
import org.jtalks.jcommune.service.UserService;
import org.jtalks.jcommune.plugin.api.exceptions.NotFoundException;
import org.jtalks.jcommune.service.nontransactional.MailService;
import org.jtalks.jcommune.service.nontransactional.UserDataCacheService;
import org.jtalks.jcommune.service.security.SecurityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.List;
/**
* The implementation of PrivateMessageServices.
*
* @author Pavel Vervenko
* @author Kirill Afonin
* @author Max Malakhov
*/
public class TransactionalPrivateMessageService
extends AbstractTransactionalEntityService<PrivateMessage, PrivateMessageDao> implements PrivateMessageService {
public static final int DEFAULT_MESSAGE_COUNT = 0;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final SecurityService securityService;
private final UserService userService;
private final UserDataCacheService userDataCache;
private final MailService mailService;
private final JCommuneProperty sendingNotificationsEnabledProperty;
/**
* Creates the instance of service.
*
* @param pmDao PrivateMessageDao
* @param securityService for retrieving current user
* @param userService for getting user by name
* @param userDataCache service for cache for user data
* @param mailService for sending email notifications
*/
public TransactionalPrivateMessageService(PrivateMessageDao pmDao,
SecurityService securityService,
UserService userService,
UserDataCacheService userDataCache,
MailService mailService,
JCommuneProperty sendingNotificationsEnabledProperty) {
super(pmDao);
this.securityService = securityService;
this.userService = userService;
this.userDataCache = userDataCache;
this.mailService = mailService;
this.sendingNotificationsEnabledProperty = sendingNotificationsEnabledProperty;
}
/**
* {@inheritDoc}
*/
@Override
public Page<PrivateMessage> getInboxForCurrentUser(String page) {
JCUser currentUser = userService.getCurrentUser();
PageRequest pageRequest = new PageRequest(page, currentUser.getPageSize());
return this.getDao().getAllForUser(currentUser, pageRequest);
}
/**
* {@inheritDoc}
*/
@Override
public Page<PrivateMessage> getOutboxForCurrentUser(String page) {
JCUser currentUser = userService.getCurrentUser();
PageRequest pageRequest = new PageRequest(page, currentUser.getPageSize());
return this.getDao().getAllFromUser(currentUser, pageRequest);
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasPermission(#userFrom.id, 'USER', 'ProfilePermission.SEND_PRIVATE_MESSAGES')")
public PrivateMessage sendMessage(String title, String body, JCUser recipient, JCUser userFrom) {
PrivateMessage pm = new PrivateMessage(recipient, userFrom, title, body);
pm.setRead(false);
pm.setStatus(PrivateMessageStatus.SENT);
this.getDao().saveOrUpdate(pm);
userDataCache.incrementNewMessageCountFor(recipient.getUsername());
securityService.createAclBuilder().grant(GeneralPermission.READ).to(recipient).on(pm).flush();
securityService.createAclBuilder().grant(GeneralPermission.READ).to(userFrom).on(pm).flush();
if (isSendNotificationMessage(recipient)) {
mailService.sendReceivedPrivateMessageNotification(recipient, pm);
}
logger.debug("Private message to user {} was sent. Message id={}", recipient.getUsername(), pm.getId());
return pm;
}
/**
* Check - sending notification is allow
*
* @param user User for which we check allow sending pm notification
* @return flag with value (send or not)
*/
private boolean isSendNotificationMessage(JCUser user) {
return (sendingNotificationsEnabledProperty.booleanValue() && user.isSendPmNotification());
}
/**
* {@inheritDoc}
*/
@Override
public Page<PrivateMessage> getDraftsForCurrentUser(String page) {
JCUser currentUser = userService.getCurrentUser();
PageRequest pageRequest = new PageRequest(page, currentUser.getPageSize());
return this.getDao().getDraftsForUser(currentUser, pageRequest);
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasPermission(#userFrom.id, 'USER', 'ProfilePermission.SEND_PRIVATE_MESSAGES')")
public void saveDraft(long id, JCUser userTo, String title, String body, JCUser userFrom) {
PrivateMessage pm;
if (this.getDao().isExist(id)) {
pm = this.getDao().get(id);
pm.setUserTo(userTo);
pm.setTitle(title);
pm.setBody(body);
} else {
pm = new PrivateMessage(userTo, userFrom, title, body);
pm.setStatus(PrivateMessageStatus.DRAFT);
}
this.getDao().saveOrUpdate(pm);
JCUser user = userService.getCurrentUser();
securityService.createAclBuilder().grant(GeneralPermission.READ).to(user).on(pm).flush();
securityService.createAclBuilder().grant(GeneralPermission.WRITE).to(user).on(pm).flush();
logger.debug("Updated private message draft. Message id={}", pm.getId());
}
/**
* {@inheritDoc}
*/
@Override
public int currentUserNewPmCount() {
String username = securityService.getCurrentUserUsername();
if (username == null) {
return DEFAULT_MESSAGE_COUNT;
}
Integer count = userDataCache.getNewPmCountFor(username);
if (count != null) {
return count;
}
count = this.getDao().getNewMessagesCountFor(username);
userDataCache.putNewPmCount(username, count);
return count;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasPermission(#userFrom.id, 'USER', 'ProfilePermission.SEND_PRIVATE_MESSAGES')")
public PrivateMessage sendDraft(long id, String title, String body,
JCUser recipient, JCUser userFrom) throws NotFoundException {
PrivateMessage pm = new PrivateMessage(recipient, userFrom, title, body);
pm.setId(id);
pm.setRead(false);
pm.setStatus(PrivateMessageStatus.SENT);
this.getDao().saveOrUpdate(pm);
userDataCache.incrementNewMessageCountFor(recipient.getUsername());
securityService.deleteFromAcl(pm);
securityService.createAclBuilder().grant(GeneralPermission.READ).to(recipient).on(pm).flush();
securityService.createAclBuilder().grant(GeneralPermission.READ).to(userFrom).on(pm).flush();
if (isSendNotificationMessage(recipient)) {
mailService.sendReceivedPrivateMessageNotification(recipient, pm);
}
logger.debug("Private message(was draft) to user {} was sent. Message id={}",
recipient.getUsername(), pm.getId());
return pm;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasPermission(#id, 'PRIVATE_MESSAGE', 'GeneralPermission.READ')")
public PrivateMessage get(Long id) throws NotFoundException {
PrivateMessage pm = super.get(id);
if (!hasCurrentUserAccessToPM(pm)) {
throw new NotFoundException(String.format("current user has no right to read pm %s with id %d",
userService.getCurrentUser(), id));
}
if (this.ifMessageShouldBeMarkedAsRead(pm)) {
pm.setRead(true);
this.getDao().saveOrUpdate(pm);
userDataCache.decrementNewMessageCountFor(pm.getUserTo().getUsername());
}
return pm;
}
/**
* Checks if the private message should be marked as read.
* The follwing conditions are checked:
* <p>1. Current user is the recepient
* <p>2. Message is not read already
* <p>3. Message is not a draft
*
* @param pm private messag to be tested
* @return if message should be marked as read
*/
private boolean ifMessageShouldBeMarkedAsRead(PrivateMessage pm) {
return currentUserIsAuthor(userService.getCurrentUser(), pm)
&& !pm.isRead()
&& !pm.getStatus().equals(PrivateMessageStatus.DRAFT);
}
/**
* {@inheritDoc}
*/
@Override
public String delete(List<Long> ids) throws NotFoundException {
JCUser currentUser = userService.getCurrentUser();
String result = "inbox";
for (Long id : ids) {
PrivateMessage message = this.get(id);
switch (message.getStatus()) {
case DRAFT:
this.getDao().delete(message);
result = "drafts";
break;
case DELETED_FROM_INBOX:
this.getDao().delete(message);
result = "outbox";
break;
case DELETED_FROM_OUTBOX:
this.getDao().delete(message);
result = "inbox";
break;
case SENT:
if (currentUser.equals(message.getUserFrom())) {
message.setStatus(PrivateMessageStatus.DELETED_FROM_OUTBOX);
result = "outbox";
} else {
message.setStatus(PrivateMessageStatus.DELETED_FROM_INBOX);
result = "inbox";
}
break;
default:
break;
}
}
return result;
}
private boolean hasCurrentUserAccessToPM(PrivateMessage privateMessage) throws NotFoundException {
JCUser currentUser = userService.getCurrentUser();
PrivateMessageStatus messageStatus = privateMessage.getStatus();
if (currentUser.equals(privateMessage.getUserFrom()) &&
(messageStatus.equals(PrivateMessageStatus.DELETED_FROM_OUTBOX))) {
return false;
}
return !(currentUserIsAuthor(currentUser, privateMessage) &&
(messageStatus.equals(PrivateMessageStatus.DELETED_FROM_INBOX)));
}
private boolean currentUserIsAuthor(JCUser currentUser, PrivateMessage privateMessage) {
boolean isAuthor = false;
try { //because a recipient can be deleted.
isAuthor = currentUser.equals(privateMessage.getUserTo());
} catch (org.hibernate.ObjectNotFoundException e) {
logger.warn("The recipient doesn't exist", e);
}
return isAuthor;
}
/**
* {@inheritDoc}
*/
@Override
@PreAuthorize("hasPermission(#senderId, 'USER', 'ProfilePermission.SEND_PRIVATE_MESSAGES')")
public void checkPermissionsToSend(Long senderId) {
logger.debug("Check permission to send private message for user - " + senderId);
}
}