/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * 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. */ package com.liferay.social.privatemessaging.service.impl; import com.liferay.mail.kernel.model.MailMessage; import com.liferay.mail.kernel.service.MailService; import com.liferay.message.boards.kernel.model.MBMessage; import com.liferay.message.boards.kernel.model.MBMessageConstants; import com.liferay.petra.content.ContentUtil; import com.liferay.portal.kernel.bean.BeanReference; import com.liferay.portal.kernel.exception.NoSuchUserException; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Company; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.model.UserNotificationDeliveryConstants; import com.liferay.portal.kernel.module.configuration.ConfigurationException; import com.liferay.portal.kernel.module.configuration.ConfigurationProviderUtil; import com.liferay.portal.kernel.notifications.UserNotificationManagerUtil; import com.liferay.portal.kernel.security.auth.PrincipalException; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.settings.CompanyServiceSettingsLocator; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.FastDateFormatConstants; import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil; import com.liferay.portal.kernel.util.ObjectValuePair; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.webserver.WebServerServletTokenUtil; import com.liferay.portal.kernel.workflow.WorkflowConstants; import com.liferay.social.privatemessaging.configuration.PrivateMessagingConfiguration; import com.liferay.social.privatemessaging.constants.PrivateMessagingPortletKeys; import com.liferay.social.privatemessaging.model.PrivateMessagingConstants; import com.liferay.social.privatemessaging.model.UserThread; import com.liferay.social.privatemessaging.service.base.UserThreadLocalServiceBaseImpl; import java.io.InputStream; import java.text.Format; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.mail.internet.InternetAddress; /** * @author Scott Lee * @author Jonathan Lee * @author Peter Fellwock */ public class UserThreadLocalServiceImpl extends UserThreadLocalServiceBaseImpl { @Override public MBMessage addPrivateMessage( long userId, long mbThreadId, String to, String subject, String body, List<ObjectValuePair<String, InputStream>> inputStreamOVPs, ThemeDisplay themeDisplay) throws PortalException { long parentMBMessageId = MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID; List<User> recipients = null; if (mbThreadId != 0) { if (Validator.isNull(fetchUserThread(userId, mbThreadId))) { if (_log.isWarnEnabled()) { StringBundler sb = new StringBundler(5); sb.append("User "); sb.append(userId); sb.append(" attempted to add a message to thread "); sb.append(mbThreadId); sb.append(" through the Private Messaging portlet"); _log.warn(sb.toString()); } throw new PrincipalException( "User " + userId + " cannot access thread " + mbThreadId + " through the Private Messaging portlet"); } List<MBMessage> mbMessages = mbMessageLocalService.getThreadMessages( mbThreadId, WorkflowConstants.STATUS_ANY); MBMessage lastMBMessage = mbMessages.get(mbMessages.size() - 1); parentMBMessageId = lastMBMessage.getMessageId(); subject = lastMBMessage.getSubject(); } else { recipients = parseRecipients(userId, to); if (recipients.isEmpty()) { return null; } } return addPrivateMessage( userId, mbThreadId, parentMBMessageId, recipients, subject, body, inputStreamOVPs, themeDisplay); } @Override public MBMessage addPrivateMessageBranch( long userId, long parentMBMessageId, String body, List<ObjectValuePair<String, InputStream>> inputStreamOVPs, ThemeDisplay themeDisplay) throws PortalException { long mbThreadId = 0; MBMessage parentMessage = mbMessageLocalService.getMBMessage( parentMBMessageId); List<User> recipients = new ArrayList<>(); recipients.add(userLocalService.getUser(parentMessage.getUserId())); return addPrivateMessage( userId, mbThreadId, parentMBMessageId, recipients, parentMessage.getSubject(), body, inputStreamOVPs, themeDisplay); } @Override public void addUserThread( long userId, long mbThreadId, long topMBMessageId, boolean read, boolean deleted) throws PortalException { long userThreadId = counterLocalService.increment(); User user = userLocalService.getUser(userId); UserThread userThread = userThreadPersistence.create(userThreadId); userThread.setCompanyId(user.getCompanyId()); userThread.setUserId(userId); userThread.setUserName(user.getFullName()); userThread.setCreateDate(new Date()); userThread.setModifiedDate(new Date()); userThread.setMbThreadId(mbThreadId); userThread.setTopMBMessageId(topMBMessageId); userThread.setRead(read); userThread.setDeleted(deleted); userThreadPersistence.update(userThread); } @Override public void deleteUser(long userId) throws PortalException { List<UserThread> userThreads = userThreadPersistence.findByUserId( userId); for (UserThread userThread : userThreads) { userThreadPersistence.remove(userThread.getUserThreadId()); } } @Override public void deleteUserThread(long userId, long mbThreadId) throws PortalException { UserThread userThread = userThreadPersistence.findByU_M( userId, mbThreadId); userThread.setDeleted(true); userThreadPersistence.update(userThread); } @Override public UserThread fetchUserThread(long userId, long mbThreadId) throws PortalException { return userThreadPersistence.fetchByU_M(userId, mbThreadId); } @Override public List<UserThread> getMBThreadUserThreads(long mbThreadId) { return userThreadPersistence.findByMBThreadId(mbThreadId); } @Override public UserThread getUserThread(long userId, long mbThreadId) throws PortalException { return userThreadPersistence.findByU_M(userId, mbThreadId); } @Override public int getUserUserThreadCount(long userId, boolean deleted) { return userThreadPersistence.countByU_D(userId, deleted); } @Override public int getUserUserThreadCount( long userId, boolean read, boolean deleted) { return userThreadPersistence.countByU_R_D(userId, read, deleted); } @Override public List<UserThread> getUserUserThreads(long userId, boolean deleted) { return userThreadPersistence.findByU_D(userId, deleted); } @Override public List<UserThread> getUserUserThreads( long userId, boolean read, boolean deleted) { return userThreadPersistence.findByU_R_D(userId, read, deleted); } @Override public List<UserThread> getUserUserThreads( long userId, boolean deleted, int start, int end) { return userThreadPersistence.findByU_D(userId, deleted, start, end); } @Override public void markUserThreadAsRead(long userId, long mbThreadId) throws PortalException { UserThread userThread = userThreadPersistence.findByU_M( userId, mbThreadId); userThread.setRead(true); userThreadPersistence.update(userThread); } @Override public void markUserThreadAsUnread(long userId, long mbThreadId) throws PortalException { UserThread userThread = userThreadPersistence.findByU_M( userId, mbThreadId); userThread.setRead(false); userThreadPersistence.update(userThread); } @Override public void updateUserName(User user) { String userName = user.getFullName(); List<UserThread> userThreads = userThreadPersistence.findByUserId( user.getUserId()); for (UserThread userThread : userThreads) { if (!userName.equals(userThread.getUserName())) { userThread.setUserName(userName); userThreadPersistence.update(userThread); } } } protected MBMessage addPrivateMessage( long userId, long mbThreadId, long parentMBMessageId, List<User> recipients, String subject, String body, List<ObjectValuePair<String, InputStream>> inputStreamOVPs, ThemeDisplay themeDisplay) throws PortalException { User user = userLocalService.getUser(userId); Group group = groupLocalService.getCompanyGroup(user.getCompanyId()); long categoryId = PrivateMessagingConstants.PRIVATE_MESSAGING_CATEGORY_ID; if (Validator.isNull(subject)) { subject = StringUtil.shorten(body, 50); } boolean anonymous = false; double priority = 0.0; boolean allowPingbacks = false; ServiceContext serviceContext = new ServiceContext(); serviceContext.setWorkflowAction(WorkflowConstants.ACTION_SAVE_DRAFT); MBMessage mbMessage = mbMessageLocalService.addMessage( userId, user.getScreenName(), group.getGroupId(), categoryId, mbThreadId, parentMBMessageId, subject, body, MBMessageConstants.DEFAULT_FORMAT, inputStreamOVPs, anonymous, priority, allowPingbacks, serviceContext); if (mbThreadId == 0) { for (User recipient : recipients) { if (recipient.getUserId() != userId) { addUserThread( recipient.getUserId(), mbMessage.getThreadId(), mbMessage.getMessageId(), false, false); } } addUserThread( userId, mbMessage.getThreadId(), mbMessage.getMessageId(), true, false); } else { List<UserThread> userThreads = userThreadPersistence.findByMBThreadId(mbMessage.getThreadId()); for (UserThread userThread : userThreads) { userThread.setModifiedDate(new Date()); if (userThread.getUserId() == userId) { userThread.setRead(true); } else { userThread.setRead(false); } if (userThread.isDeleted()) { userThread.setTopMBMessageId(mbMessage.getMessageId()); userThread.setDeleted(false); } userThreadPersistence.update(userThread); } } // Email try { sendEmail(mbMessage.getMessageId(), themeDisplay); } catch (Exception e) { throw new SystemException(e); } // Notifications sendNotificationEvent(mbMessage); return mbMessage; } protected PrivateMessagingConfiguration getPrivateMessagingConfiguration( long companyId) { if (_privateMessagingConfiguration == null) { try { _privateMessagingConfiguration = ConfigurationProviderUtil.getConfiguration( PrivateMessagingConfiguration.class, new CompanyServiceSettingsLocator( companyId, "com.liferay.social.privatemessaging." + "configuration.PrivateMessagingConfiguration")); } catch (ConfigurationException ce) { _log.error("Unable to get private message configuration", ce); } } return _privateMessagingConfiguration; } protected String getThreadURL( User user, long threadId, ThemeDisplay themeDisplay) throws Exception { Group group = user.getGroup(); long plid = PortalUtil.getPlidFromPortletId( group.getGroupId(), true, PrivateMessagingPortletKeys.PRIVATE_MESSAGING); Layout layout = layoutLocalService.fetchLayout(plid); if (layout == null) { return StringPool.BLANK; } String privateMessageURL = PortalUtil.getLayoutFullURL( layout, themeDisplay, false); return privateMessageURL + "/-/private_messaging/thread/" + threadId; } protected List<User> parseRecipients(long userId, String to) throws PortalException { User user = userLocalService.getUser(userId); String[] recipients = StringUtil.split(to); List<User> users = new ArrayList<>(); for (String recipient : recipients) { int x = recipient.indexOf(CharPool.LESS_THAN); int y = recipient.indexOf(CharPool.GREATER_THAN); try { String screenName = recipient; if ((x != -1) && (y != -1)) { screenName = recipient.substring(x + 1, y); } User recipientUser = userLocalService.getUserByScreenName( user.getCompanyId(), screenName); if (!users.contains(recipientUser)) { users.add(recipientUser); } } catch (NoSuchUserException nsue) { // LPS-52675 if (_log.isDebugEnabled()) { _log.debug(nsue, nsue); } } } return users; } protected void sendEmail(long mbMessageId, ThemeDisplay themeDisplay) throws Exception { MBMessage mbMessage = mbMessageLocalService.getMBMessage(mbMessageId); User sender = userLocalService.getUser(mbMessage.getUserId()); Company company = companyLocalService.getCompany(sender.getCompanyId()); InternetAddress from = new InternetAddress(company.getEmailAddress()); PrivateMessagingConfiguration privateMessagingConfiguration = getPrivateMessagingConfiguration(themeDisplay.getCompanyId()); String subject = ContentUtil.get( UserThreadLocalServiceImpl.class.getClassLoader(), privateMessagingConfiguration.emailSubject()); subject = StringUtil.replace( subject, new String[] {"[$COMPANY_NAME$]", "[$FROM_NAME$]"}, new String[] {company.getName(), sender.getFullName()}); String body = ContentUtil.get( UserThreadLocalServiceImpl.class.getClassLoader(), privateMessagingConfiguration.emailBody()); long portraitId = sender.getPortraitId(); String tokenId = WebServerServletTokenUtil.getToken( sender.getPortraitId()); String portraitURL = themeDisplay.getPortalURL() + themeDisplay.getPathImage() + "/user_" + (sender.isFemale() ? "female" : "male") + "_portrait?img_id=" + portraitId + "&t=" + tokenId; body = StringUtil.replace( body, new String[] { "[$BODY$]", "[$COMPANY_NAME$]", "[$FROM_AVATAR$]", "[$FROM_NAME$]", "[$FROM_PROFILE_URL$]", "[$SUBJECT$]" }, new String[] { mbMessage.getBody(), company.getName(), portraitURL, sender.getFullName(), sender.getDisplayURL(themeDisplay), mbMessage.getSubject() }); List<UserThread> userThreads = userThreadLocalService.getMBThreadUserThreads( mbMessage.getThreadId()); for (UserThread userThread : userThreads) { if ((userThread.getUserId() == mbMessage.getUserId()) || !UserNotificationManagerUtil.isDeliver( userThread.getUserId(), PrivateMessagingPortletKeys.PRIVATE_MESSAGING, PrivateMessagingConstants.NEW_MESSAGE, 0, UserNotificationDeliveryConstants.TYPE_EMAIL)) { continue; } User recipient = userLocalService.getUser(userThread.getUserId()); String threadURL = getThreadURL( recipient, mbMessage.getThreadId(), themeDisplay); if (Validator.isNull(threadURL)) { continue; } InternetAddress to = new InternetAddress( recipient.getEmailAddress()); Format dateFormatDateTime = FastDateFormatFactoryUtil.getDateTime( FastDateFormatConstants.LONG, FastDateFormatConstants.SHORT, recipient.getLocale(), recipient.getTimeZone()); String userThreadBody = StringUtil.replace( body, new String[] {"[$SENT_DATE$]", "[$THREAD_URL$]"}, new String[] { dateFormatDateTime.format(mbMessage.getCreateDate()), threadURL }); MailMessage mailMessage = new MailMessage( from, to, subject, userThreadBody, true); _mailService.sendEmail(mailMessage); } } protected void sendNotificationEvent(MBMessage mbMessage) throws PortalException { JSONObject notificationEventJSONObject = JSONFactoryUtil.createJSONObject(); notificationEventJSONObject.put("classPK", mbMessage.getMessageId()); notificationEventJSONObject.put("userId", mbMessage.getUserId()); List<UserThread> userThreads = userThreadLocalService.getMBThreadUserThreads( mbMessage.getThreadId()); for (UserThread userThread : userThreads) { if ((userThread.getUserId() == mbMessage.getUserId()) || !UserNotificationManagerUtil.isDeliver( userThread.getUserId(), PrivateMessagingPortletKeys.PRIVATE_MESSAGING, 0, PrivateMessagingConstants.NEW_MESSAGE, UserNotificationDeliveryConstants.TYPE_WEBSITE)) { continue; } userNotificationEventLocalService.sendUserNotificationEvents( userThread.getUserId(), PrivateMessagingPortletKeys.PRIVATE_MESSAGING, UserNotificationDeliveryConstants.TYPE_WEBSITE, notificationEventJSONObject); } } private static final Log _log = LogFactoryUtil.getLog( UserThreadLocalServiceImpl.class); @BeanReference(type = MailService.class) private MailService _mailService; private PrivateMessagingConfiguration _privateMessagingConfiguration; }