001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.messageboards.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
025    import com.liferay.portal.kernel.repository.model.FileEntry;
026    import com.liferay.portal.kernel.repository.model.Folder;
027    import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
028    import com.liferay.portal.kernel.search.Indexable;
029    import com.liferay.portal.kernel.search.IndexableType;
030    import com.liferay.portal.kernel.search.Indexer;
031    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
032    import com.liferay.portal.kernel.util.Constants;
033    import com.liferay.portal.kernel.util.ContentTypes;
034    import com.liferay.portal.kernel.util.ListUtil;
035    import com.liferay.portal.kernel.util.ObjectValuePair;
036    import com.liferay.portal.kernel.util.OrderByComparator;
037    import com.liferay.portal.kernel.util.ParamUtil;
038    import com.liferay.portal.kernel.util.PropsKeys;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.util.WebKeys;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
045    import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
046    import com.liferay.portal.model.Company;
047    import com.liferay.portal.model.Group;
048    import com.liferay.portal.model.ModelHintsUtil;
049    import com.liferay.portal.model.ResourceConstants;
050    import com.liferay.portal.model.User;
051    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
052    import com.liferay.portal.security.auth.PrincipalException;
053    import com.liferay.portal.service.ServiceContext;
054    import com.liferay.portal.service.ServiceContextUtil;
055    import com.liferay.portal.theme.ThemeDisplay;
056    import com.liferay.portal.util.Portal;
057    import com.liferay.portal.util.PortalUtil;
058    import com.liferay.portal.util.PortletKeys;
059    import com.liferay.portal.util.PrefsPropsUtil;
060    import com.liferay.portal.util.PropsValues;
061    import com.liferay.portal.util.SubscriptionSender;
062    import com.liferay.portlet.PortletURLFactoryUtil;
063    import com.liferay.portlet.asset.model.AssetEntry;
064    import com.liferay.portlet.asset.model.AssetLinkConstants;
065    import com.liferay.portlet.blogs.model.BlogsEntry;
066    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
067    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
068    import com.liferay.portlet.messageboards.MessageBodyException;
069    import com.liferay.portlet.messageboards.MessageSubjectException;
070    import com.liferay.portlet.messageboards.NoSuchDiscussionException;
071    import com.liferay.portlet.messageboards.RequiredMessageException;
072    import com.liferay.portlet.messageboards.model.MBCategory;
073    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
074    import com.liferay.portlet.messageboards.model.MBDiscussion;
075    import com.liferay.portlet.messageboards.model.MBMessage;
076    import com.liferay.portlet.messageboards.model.MBMessageConstants;
077    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
078    import com.liferay.portlet.messageboards.model.MBThread;
079    import com.liferay.portlet.messageboards.model.MBThreadConstants;
080    import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
081    import com.liferay.portlet.messageboards.model.impl.MBMessageDisplayImpl;
082    import com.liferay.portlet.messageboards.service.base.MBMessageLocalServiceBaseImpl;
083    import com.liferay.portlet.messageboards.social.MBActivityKeys;
084    import com.liferay.portlet.messageboards.util.MBSubscriptionSender;
085    import com.liferay.portlet.messageboards.util.MBUtil;
086    import com.liferay.portlet.messageboards.util.MailingListThreadLocal;
087    import com.liferay.portlet.messageboards.util.comparator.MessageCreateDateComparator;
088    import com.liferay.portlet.messageboards.util.comparator.MessageThreadComparator;
089    import com.liferay.portlet.messageboards.util.comparator.ThreadLastPostDateComparator;
090    import com.liferay.portlet.social.model.SocialActivity;
091    import com.liferay.portlet.social.model.SocialActivityConstants;
092    import com.liferay.portlet.trash.util.TrashUtil;
093    import com.liferay.util.SerializableUtil;
094    
095    import java.io.InputStream;
096    
097    import java.util.ArrayList;
098    import java.util.Collections;
099    import java.util.Comparator;
100    import java.util.Date;
101    import java.util.List;
102    
103    import javax.portlet.PortletPreferences;
104    import javax.portlet.PortletRequest;
105    import javax.portlet.PortletURL;
106    
107    import javax.servlet.http.HttpServletRequest;
108    
109    import net.htmlparser.jericho.Source;
110    import net.htmlparser.jericho.StartTag;
111    
112    /**
113     * @author Brian Wing Shun Chan
114     * @author Raymond Aug??
115     * @author Mika Koivisto
116     * @author Jorge Ferrer
117     * @author Juan Fern??ndez
118     * @author Shuyang Zhou
119     */
120    public class MBMessageLocalServiceImpl extends MBMessageLocalServiceBaseImpl {
121    
122            @Override
123            public MBMessage addDiscussionMessage(
124                            long userId, String userName, long groupId, String className,
125                            long classPK, int workflowAction)
126                    throws PortalException, SystemException {
127    
128                    long threadId = 0;
129                    long parentMessageId = MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID;
130                    String subject = String.valueOf(classPK);
131                    String body = subject;
132    
133                    ServiceContext serviceContext = new ServiceContext();
134    
135                    serviceContext.setWorkflowAction(workflowAction);
136    
137                    boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
138    
139                    WorkflowThreadLocal.setEnabled(false);
140    
141                    try {
142                            return addDiscussionMessage(
143                                    userId, userName, groupId, className, classPK, threadId,
144                                    parentMessageId, subject, body, serviceContext);
145                    }
146                    finally {
147                            WorkflowThreadLocal.setEnabled(workflowEnabled);
148                    }
149            }
150    
151            @Override
152            public MBMessage addDiscussionMessage(
153                            long userId, String userName, long groupId, String className,
154                            long classPK, long threadId, long parentMessageId, String subject,
155                            String body, ServiceContext serviceContext)
156                    throws PortalException, SystemException {
157    
158                    // Message
159    
160                    long categoryId = MBCategoryConstants.DISCUSSION_CATEGORY_ID;
161    
162                    if (Validator.isNull(subject)) {
163                            if (Validator.isNotNull(body)) {
164                                    int pos = Math.min(body.length(), 50);
165    
166                                    subject = body.substring(0, pos) + "...";
167                            }
168                            else {
169                                    throw new MessageBodyException();
170                            }
171                    }
172    
173                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
174                            Collections.emptyList();
175                    boolean anonymous = false;
176                    double priority = 0.0;
177                    boolean allowPingbacks = false;
178    
179                    serviceContext.setAddGroupPermissions(true);
180                    serviceContext.setAddGuestPermissions(true);
181                    serviceContext.setAttribute("className", className);
182                    serviceContext.setAttribute("classPK", String.valueOf(classPK));
183    
184                    MBMessage message = addMessage(
185                            userId, userName, groupId, categoryId, threadId, parentMessageId,
186                            subject, body, MBMessageConstants.DEFAULT_FORMAT, inputStreamOVPs,
187                            anonymous, priority, allowPingbacks, serviceContext);
188    
189                    // Discussion
190    
191                    if (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
192                            long classNameId = PortalUtil.getClassNameId(className);
193    
194                            MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
195                                    classNameId, classPK);
196    
197                            if (discussion == null) {
198                                    mbDiscussionLocalService.addDiscussion(
199                                            userId, classNameId, classPK, message.getThreadId(),
200                                            serviceContext);
201                            }
202                    }
203    
204                    return message;
205            }
206    
207            @Override
208            public MBMessage addMessage(
209                            long userId, String userName, long groupId, long categoryId,
210                            long threadId, long parentMessageId, String subject, String body,
211                            String format,
212                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
213                            boolean anonymous, double priority, boolean allowPingbacks,
214                            ServiceContext serviceContext)
215                    throws PortalException, SystemException {
216    
217                    // Message
218    
219                    User user = userPersistence.findByPrimaryKey(userId);
220                    userName = user.isDefaultUser() ? userName : user.getFullName();
221                    subject = ModelHintsUtil.trimString(
222                            MBMessage.class.getName(), "subject", subject);
223    
224                    PortletPreferences preferences =
225                            ServiceContextUtil.getPortletPreferences(serviceContext);
226    
227                    if (preferences != null) {
228                            if (!MBUtil.isAllowAnonymousPosting(preferences)) {
229                                    if (anonymous || user.isDefaultUser()) {
230                                            throw new PrincipalException();
231                                    }
232                            }
233                    }
234    
235                    if (user.isDefaultUser()) {
236                            anonymous = true;
237                    }
238    
239                    Date now = new Date();
240    
241                    long messageId = counterLocalService.increment();
242    
243                    body = SanitizerUtil.sanitize(
244                            user.getCompanyId(), groupId, userId, MBMessage.class.getName(),
245                            messageId, "text/" + format, body);
246    
247                    validate(subject, body);
248    
249                    subject = getSubject(subject, body);
250                    body = getBody(subject, body);
251    
252                    MBMessage message = mbMessagePersistence.create(messageId);
253    
254                    message.setUuid(serviceContext.getUuid());
255                    message.setGroupId(groupId);
256                    message.setCompanyId(user.getCompanyId());
257                    message.setUserId(user.getUserId());
258                    message.setUserName(userName);
259                    message.setCreateDate(serviceContext.getCreateDate(now));
260                    message.setModifiedDate(serviceContext.getModifiedDate(now));
261    
262                    if (threadId > 0) {
263                            message.setThreadId(threadId);
264                    }
265    
266                    if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
267                            message.setPriority(priority);
268                    }
269    
270                    message.setAllowPingbacks(allowPingbacks);
271                    message.setStatus(WorkflowConstants.STATUS_DRAFT);
272                    message.setStatusByUserId(user.getUserId());
273                    message.setStatusByUserName(userName);
274                    message.setStatusDate(serviceContext.getModifiedDate(now));
275    
276                    // Thread
277    
278                    if (parentMessageId != MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
279                            MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(
280                                    parentMessageId);
281    
282                            if (parentMessage == null) {
283                                    parentMessageId = MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID;
284                            }
285                    }
286    
287                    MBThread thread = null;
288    
289                    if (threadId > 0) {
290                            thread = mbThreadPersistence.fetchByPrimaryKey(threadId);
291                    }
292    
293                    if ((thread == null) ||
294                            (parentMessageId == MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID)) {
295    
296                            thread = mbThreadLocalService.addThread(
297                                    categoryId, message, serviceContext);
298                    }
299    
300                    if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) &&
301                            (thread.getPriority() != priority)) {
302    
303                            thread.setPriority(priority);
304    
305                            mbThreadPersistence.update(thread);
306    
307                            updatePriorities(thread.getThreadId(), priority);
308                    }
309    
310                    // Message
311    
312                    message.setCategoryId(categoryId);
313                    message.setThreadId(thread.getThreadId());
314                    message.setRootMessageId(thread.getRootMessageId());
315                    message.setParentMessageId(parentMessageId);
316                    message.setSubject(subject);
317                    message.setBody(body);
318                    message.setFormat(format);
319                    message.setAnonymous(anonymous);
320    
321                    if (message.isDiscussion()) {
322                            long classNameId = PortalUtil.getClassNameId(
323                                    (String)serviceContext.getAttribute("className"));
324                            long classPK = ParamUtil.getLong(serviceContext, "classPK");
325    
326                            message.setClassNameId(classNameId);
327                            message.setClassPK(classPK);
328                    }
329    
330                    message.setExpandoBridgeAttributes(serviceContext);
331    
332                    mbMessagePersistence.update(message);
333    
334                    // Attachments
335    
336                    if (!inputStreamOVPs.isEmpty()) {
337                            Folder folder = message.addAttachmentsFolder();
338    
339                            PortletFileRepositoryUtil.addPortletFileEntries(
340                                    message.getGroupId(), userId, MBMessage.class.getName(),
341                                    message.getMessageId(), PortletKeys.MESSAGE_BOARDS,
342                                    folder.getFolderId(), inputStreamOVPs);
343                    }
344    
345                    // Resources
346    
347                    if (!message.isDiscussion()) {
348                            if (user.isDefaultUser()) {
349                                    addMessageResources(message, true, true);
350                            }
351                            else if (serviceContext.isAddGroupPermissions() ||
352                                             serviceContext.isAddGuestPermissions()) {
353    
354                                    addMessageResources(
355                                            message, serviceContext.isAddGroupPermissions(),
356                                            serviceContext.isAddGuestPermissions());
357                            }
358                            else {
359                                    addMessageResources(
360                                            message, serviceContext.getGroupPermissions(),
361                                            serviceContext.getGuestPermissions());
362                            }
363                    }
364    
365                    // Asset
366    
367                    updateAsset(
368                            userId, message, serviceContext.getAssetCategoryIds(),
369                            serviceContext.getAssetTagNames(),
370                            serviceContext.getAssetLinkEntryIds(),
371                            serviceContext.isAssetEntryVisible());
372    
373                    // Workflow
374    
375                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
376                            user.getCompanyId(), groupId, userId,
377                            message.getWorkflowClassName(), message.getMessageId(), message,
378                            serviceContext);
379    
380                    return message;
381            }
382    
383            @Override
384            public MBMessage addMessage(
385                            long userId, String userName, long groupId, long categoryId,
386                            String subject, String body, String format,
387                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
388                            boolean anonymous, double priority, boolean allowPingbacks,
389                            ServiceContext serviceContext)
390                    throws PortalException, SystemException {
391    
392                    long threadId = 0;
393                    long parentMessageId = 0;
394    
395                    return addMessage(
396                            userId, userName, groupId, categoryId, threadId, parentMessageId,
397                            subject, body, format, inputStreamOVPs, anonymous, priority,
398                            allowPingbacks, serviceContext);
399            }
400    
401            @Override
402            public MBMessage addMessage(
403                            long userId, String userName, long categoryId, String subject,
404                            String body, ServiceContext serviceContext)
405                    throws PortalException, SystemException {
406    
407                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
408                            categoryId);
409    
410                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
411                            Collections.emptyList();
412    
413                    return addMessage(
414                            userId, userName, category.getGroupId(), categoryId, 0, 0, subject,
415                            body, MBMessageConstants.DEFAULT_FORMAT, inputStreamOVPs, false,
416                            0.0, false, serviceContext);
417            }
418    
419            @Override
420            public void addMessageResources(
421                            long messageId, boolean addGroupPermissions,
422                            boolean addGuestPermissions)
423                    throws PortalException, SystemException {
424    
425                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
426    
427                    addMessageResources(message, addGroupPermissions, addGuestPermissions);
428            }
429    
430            @Override
431            public void addMessageResources(
432                            long messageId, String[] groupPermissions,
433                            String[] guestPermissions)
434                    throws PortalException, SystemException {
435    
436                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
437    
438                    addMessageResources(message, groupPermissions, guestPermissions);
439            }
440    
441            @Override
442            public void addMessageResources(
443                            MBMessage message, boolean addGroupPermissions,
444                            boolean addGuestPermissions)
445                    throws PortalException, SystemException {
446    
447                    resourceLocalService.addResources(
448                            message.getCompanyId(), message.getGroupId(), message.getUserId(),
449                            MBMessage.class.getName(), message.getMessageId(), false,
450                            addGroupPermissions, addGuestPermissions);
451            }
452    
453            @Override
454            public void addMessageResources(
455                            MBMessage message, String[] groupPermissions,
456                            String[] guestPermissions)
457                    throws PortalException, SystemException {
458    
459                    resourceLocalService.addModelResources(
460                            message.getCompanyId(), message.getGroupId(), message.getUserId(),
461                            MBMessage.class.getName(), message.getMessageId(), groupPermissions,
462                            guestPermissions);
463            }
464    
465            @Indexable(type = IndexableType.DELETE)
466            @Override
467            public MBMessage deleteDiscussionMessage(long messageId)
468                    throws PortalException, SystemException {
469    
470                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
471    
472                    deleteDiscussionSocialActivities(BlogsEntry.class.getName(), message);
473    
474                    return deleteMessage(message);
475            }
476    
477            @Override
478            public void deleteDiscussionMessages(String className, long classPK)
479                    throws PortalException, SystemException {
480    
481                    try {
482                            long classNameId = PortalUtil.getClassNameId(className);
483    
484                            MBDiscussion discussion = mbDiscussionPersistence.findByC_C(
485                                    classNameId, classPK);
486    
487                            List<MBMessage> messages = mbMessagePersistence.findByT_P(
488                                    discussion.getThreadId(),
489                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, 0, 1);
490    
491                            if (!messages.isEmpty()) {
492                                    MBMessage message = messages.get(0);
493    
494                                    deleteDiscussionSocialActivities(
495                                            BlogsEntry.class.getName(), message);
496    
497                                    mbThreadLocalService.deleteThread(message.getThreadId());
498                            }
499    
500                            mbDiscussionPersistence.remove(discussion);
501                    }
502                    catch (NoSuchDiscussionException nsde) {
503                            if (_log.isDebugEnabled()) {
504                                    _log.debug(nsde.getMessage());
505                            }
506                    }
507            }
508    
509            @Indexable(type = IndexableType.DELETE)
510            @Override
511            public MBMessage deleteMessage(long messageId)
512                    throws PortalException, SystemException {
513    
514                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
515    
516                    return deleteMessage(message);
517            }
518    
519            @Indexable(type = IndexableType.DELETE)
520            @Override
521            public MBMessage deleteMessage(MBMessage message)
522                    throws PortalException, SystemException {
523    
524                    // Attachments
525    
526                    long folderId = message.getAttachmentsFolderId();
527    
528                    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
529                            PortletFileRepositoryUtil.deleteFolder(folderId);
530                    }
531    
532                    // Thread
533    
534                    int count = mbMessagePersistence.countByThreadId(message.getThreadId());
535    
536                    if (count == 1) {
537    
538                            // Attachments
539    
540                            long threadAttachmentsFolderId =
541                                    message.getThreadAttachmentsFolderId();
542    
543                            if (threadAttachmentsFolderId !=
544                                            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
545    
546                                    PortletFileRepositoryUtil.deleteFolder(
547                                            threadAttachmentsFolderId);
548                            }
549    
550                            // Subscriptions
551    
552                            subscriptionLocalService.deleteSubscriptions(
553                                    message.getCompanyId(), MBThread.class.getName(),
554                                    message.getThreadId());
555    
556                            // Thread
557    
558                            MBThread thread = mbThreadPersistence.findByPrimaryKey(
559                                    message.getThreadId());
560    
561                            mbThreadPersistence.remove(thread);
562    
563                            // Category
564    
565                            if ((message.getCategoryId() !=
566                                            MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
567                                    (message.getCategoryId() !=
568                                            MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
569    
570                                    MBUtil.updateCategoryStatistics(
571                                            message.getCompanyId(), message.getCategoryId());
572                            }
573    
574                            // Indexer
575    
576                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
577                                    MBThread.class);
578    
579                            indexer.delete(thread);
580                    }
581                    else {
582                            MBThread thread = mbThreadPersistence.findByPrimaryKey(
583                                    message.getThreadId());
584    
585                            // Message is a root message
586    
587                            if (thread.getRootMessageId() == message.getMessageId()) {
588                                    List<MBMessage> childrenMessages =
589                                            mbMessagePersistence.findByT_P(
590                                                    message.getThreadId(), message.getMessageId());
591    
592                                    if (childrenMessages.size() > 1) {
593                                            throw new RequiredMessageException(
594                                                    String.valueOf(message.getMessageId()));
595                                    }
596                                    else if (childrenMessages.size() == 1) {
597                                            MBMessage childMessage = childrenMessages.get(0);
598    
599                                            childMessage.setRootMessageId(childMessage.getMessageId());
600                                            childMessage.setParentMessageId(
601                                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
602    
603                                            mbMessagePersistence.update(childMessage);
604    
605                                            List<MBMessage> repliesMessages =
606                                                    mbMessagePersistence.findByThreadReplies(
607                                                            message.getThreadId());
608    
609                                            for (MBMessage repliesMessage : repliesMessages) {
610                                                    repliesMessage.setRootMessageId(
611                                                            childMessage.getMessageId());
612    
613                                                    mbMessagePersistence.update(repliesMessage);
614                                            }
615    
616                                            thread.setRootMessageId(childMessage.getMessageId());
617                                            thread.setRootMessageUserId(childMessage.getUserId());
618    
619                                            mbThreadPersistence.update(thread);
620                                    }
621                            }
622    
623                            // Message is a child message
624    
625                            else {
626                                    List<MBMessage> childrenMessages =
627                                            mbMessagePersistence.findByT_P(
628                                                    message.getThreadId(), message.getMessageId());
629    
630                                    // Message has children messages
631    
632                                    if (!childrenMessages.isEmpty()) {
633                                            for (MBMessage childMessage : childrenMessages) {
634                                                    childMessage.setParentMessageId(
635                                                            message.getParentMessageId());
636    
637                                                    mbMessagePersistence.update(childMessage);
638                                            }
639                                    }
640                                    else {
641                                            MessageCreateDateComparator comparator =
642                                                    new MessageCreateDateComparator(true);
643    
644                                            MBMessage lastMessage =
645                                                    mbMessagePersistence.fetchByT_S_Last(
646                                                            thread.getThreadId(),
647                                                            WorkflowConstants.STATUS_APPROVED, comparator);
648    
649                                            if ((lastMessage != null) &&
650                                                    (message.getMessageId() ==
651                                                            lastMessage.getMessageId())) {
652    
653                                                    MBMessage parentMessage =
654                                                            mbMessagePersistence.findByPrimaryKey(
655                                                                    message.getParentMessageId());
656    
657                                                    thread.setLastPostByUserId(parentMessage.getUserId());
658                                                    thread.setLastPostDate(parentMessage.getModifiedDate());
659    
660                                                    mbThreadPersistence.update(thread);
661                                            }
662                                    }
663                            }
664    
665                            // Thread
666    
667                            if (message.isApproved()) {
668                                    MBUtil.updateThreadMessageCount(
669                                            thread.getCompanyId(), thread.getThreadId());
670                            }
671    
672                            // Category
673    
674                            if ((message.getCategoryId() !=
675                                            MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
676                                    (message.getCategoryId() !=
677                                            MBCategoryConstants.DISCUSSION_CATEGORY_ID) &&
678                                    !message.isDraft()) {
679    
680                                    MBUtil.updateCategoryMessageCount(
681                                            message.getCompanyId(), message.getCategoryId());
682                            }
683    
684                            // Indexer
685    
686                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
687                                    MBThread.class);
688    
689                            indexer.reindex(thread);
690                    }
691    
692                    // Asset
693    
694                    assetEntryLocalService.deleteEntry(
695                            message.getWorkflowClassName(), message.getMessageId());
696    
697                    // Expando
698    
699                    expandoRowLocalService.deleteRows(message.getMessageId());
700    
701                    // Ratings
702    
703                    ratingsStatsLocalService.deleteStats(
704                            message.getWorkflowClassName(), message.getMessageId());
705    
706                    // Resources
707    
708                    if (!message.isDiscussion()) {
709                            resourceLocalService.deleteResource(
710                                    message.getCompanyId(), message.getWorkflowClassName(),
711                                    ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
712                    }
713    
714                    // Message
715    
716                    mbMessagePersistence.remove(message);
717    
718                    // Statistics
719    
720                    if (!message.isDiscussion()) {
721                            mbStatsUserLocalService.updateStatsUser(
722                                    message.getGroupId(), message.getUserId());
723                    }
724    
725                    // Workflow
726    
727                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
728                            message.getCompanyId(), message.getGroupId(),
729                            message.getWorkflowClassName(), message.getMessageId());
730    
731                    return message;
732            }
733    
734            @Override
735            public void deleteMessageAttachment(long messageId, String fileName)
736                    throws PortalException, SystemException {
737    
738                    MBMessage message = getMessage(messageId);
739    
740                    long folderId = message.getAttachmentsFolderId();
741    
742                    if (folderId == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
743                            return;
744                    }
745    
746                    PortletFileRepositoryUtil.deletePortletFileEntry(
747                            message.getGroupId(), folderId, fileName);
748            }
749    
750            @Override
751            public void deleteMessageAttachments(long messageId)
752                    throws PortalException, SystemException {
753    
754                    MBMessage message = getMessage(messageId);
755    
756                    long folderId = message.getAttachmentsFolderId();
757    
758                    if (folderId == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
759                            return;
760                    }
761    
762                    PortletFileRepositoryUtil.deletePortletFileEntries(
763                            message.getGroupId(), folderId);
764            }
765    
766            @Override
767            public List<MBMessage> getCategoryMessages(
768                            long groupId, long categoryId, int status, int start, int end)
769                    throws SystemException {
770    
771                    if (status == WorkflowConstants.STATUS_ANY) {
772                            return mbMessagePersistence.findByG_C(
773                                    groupId, categoryId, start, end);
774                    }
775                    else {
776                            return mbMessagePersistence.findByG_C_S(
777                                    groupId, categoryId, status, start, end);
778                    }
779            }
780    
781            @Override
782            public List<MBMessage> getCategoryMessages(
783                            long groupId, long categoryId, int status, int start, int end,
784                            OrderByComparator obc)
785                    throws SystemException {
786    
787                    if (status == WorkflowConstants.STATUS_ANY) {
788                            return mbMessagePersistence.findByG_C(
789                                    groupId, categoryId, start, end, obc);
790                    }
791                    else {
792                            return mbMessagePersistence.findByG_C_S(
793                                    groupId, categoryId, status, start, end, obc);
794                    }
795            }
796    
797            @Override
798            public int getCategoryMessagesCount(
799                            long groupId, long categoryId, int status)
800                    throws SystemException {
801    
802                    if (status == WorkflowConstants.STATUS_ANY) {
803                            return mbMessagePersistence.countByG_C(groupId, categoryId);
804                    }
805                    else {
806                            return mbMessagePersistence.countByG_C_S(
807                                    groupId, categoryId, status);
808                    }
809            }
810    
811            @Override
812            public List<MBMessage> getCompanyMessages(
813                            long companyId, int status, int start, int end)
814                    throws SystemException {
815    
816                    if (status == WorkflowConstants.STATUS_ANY) {
817                            return mbMessagePersistence.findByCompanyId(companyId, start, end);
818                    }
819                    else {
820                            return mbMessagePersistence.findByC_S(
821                                    companyId, status, start, end);
822                    }
823            }
824    
825            @Override
826            public List<MBMessage> getCompanyMessages(
827                            long companyId, int status, int start, int end,
828                            OrderByComparator obc)
829                    throws SystemException {
830    
831                    if (status == WorkflowConstants.STATUS_ANY) {
832                            return mbMessagePersistence.findByCompanyId(
833                                    companyId, start, end, obc);
834                    }
835                    else {
836                            return mbMessagePersistence.findByC_S(
837                                    companyId, status, start, end, obc);
838                    }
839            }
840    
841            @Override
842            public int getCompanyMessagesCount(long companyId, int status)
843                    throws SystemException {
844    
845                    if (status == WorkflowConstants.STATUS_ANY) {
846                            return mbMessagePersistence.countByCompanyId(companyId);
847                    }
848                    else {
849                            return mbMessagePersistence.countByC_S(companyId, status);
850                    }
851            }
852    
853            @Override
854            public MBMessageDisplay getDiscussionMessageDisplay(
855                            long userId, long groupId, String className, long classPK,
856                            int status)
857                    throws PortalException, SystemException {
858    
859                    return getDiscussionMessageDisplay(
860                            userId, groupId, className, classPK, status,
861                            MBThreadConstants.THREAD_VIEW_COMBINATION);
862            }
863    
864            @Override
865            public MBMessageDisplay getDiscussionMessageDisplay(
866                            long userId, long groupId, String className, long classPK,
867                            int status, String threadView)
868                    throws PortalException, SystemException {
869    
870                    long classNameId = PortalUtil.getClassNameId(className);
871    
872                    MBMessage message = null;
873    
874                    MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
875                            classNameId, classPK);
876    
877                    if (discussion != null) {
878                            List<MBMessage> messages = mbMessagePersistence.findByT_P(
879                                    discussion.getThreadId(),
880                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
881    
882                            message = messages.get(0);
883                    }
884                    else {
885                            boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
886    
887                            WorkflowThreadLocal.setEnabled(false);
888    
889                            try {
890                                    String subject = String.valueOf(classPK);
891                                    //String body = subject;
892    
893                                    message = addDiscussionMessage(
894                                            userId, null, groupId, className, classPK, 0,
895                                            MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID, subject,
896                                            subject, new ServiceContext());
897                            }
898                            catch (SystemException se) {
899                                    if (_log.isWarnEnabled()) {
900                                            _log.warn(
901                                                    "Add failed, fetch {threadId=0, parentMessageId=" +
902                                                            MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID + "}");
903                                    }
904    
905                                    List<MBMessage> messages = mbMessagePersistence.findByT_P(
906                                            0, MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID);
907    
908                                    if (messages.isEmpty()) {
909                                            throw se;
910                                    }
911    
912                                    message = messages.get(0);
913                            }
914                            finally {
915                                    WorkflowThreadLocal.setEnabled(workflowEnabled);
916                            }
917                    }
918    
919                    return getMessageDisplay(userId, message, status, threadView, false);
920            }
921    
922            @Override
923            public int getDiscussionMessagesCount(
924                            long classNameId, long classPK, int status)
925                    throws SystemException {
926    
927                    MBDiscussion discussion = mbDiscussionPersistence.fetchByC_C(
928                            classNameId, classPK);
929    
930                    if (discussion == null) {
931                            return 0;
932                    }
933    
934                    int count = 0;
935    
936                    if (status == WorkflowConstants.STATUS_ANY) {
937                            count = mbMessagePersistence.countByThreadId(
938                                    discussion.getThreadId());
939                    }
940                    else {
941                            count = mbMessagePersistence.countByT_S(
942                                    discussion.getThreadId(), status);
943                    }
944    
945                    if (count >= 1) {
946                            return count - 1;
947                    }
948                    else {
949                            return 0;
950                    }
951            }
952    
953            @Override
954            public int getDiscussionMessagesCount(
955                            String className, long classPK, int status)
956                    throws SystemException {
957    
958                    long classNameId = PortalUtil.getClassNameId(className);
959    
960                    return getDiscussionMessagesCount(classNameId, classPK, status);
961            }
962    
963            @Override
964            public List<MBDiscussion> getDiscussions(String className)
965                    throws SystemException {
966    
967                    long classNameId = PortalUtil.getClassNameId(className);
968    
969                    return mbDiscussionPersistence.findByClassNameId(classNameId);
970            }
971    
972            @Override
973            public List<MBMessage> getGroupMessages(
974                            long groupId, int status, int start, int end)
975                    throws SystemException {
976    
977                    if (status == WorkflowConstants.STATUS_ANY) {
978                            return mbMessagePersistence.findByGroupId(groupId, start, end);
979                    }
980                    else {
981                            return mbMessagePersistence.findByG_S(groupId, status, start, end);
982                    }
983            }
984    
985            @Override
986            public List<MBMessage> getGroupMessages(
987                            long groupId, int status, int start, int end, OrderByComparator obc)
988                    throws SystemException {
989    
990                    if (status == WorkflowConstants.STATUS_ANY) {
991                            return mbMessagePersistence.findByGroupId(groupId, start, end, obc);
992                    }
993                    else {
994                            return mbMessagePersistence.findByG_S(
995                                    groupId, status, start, end, obc);
996                    }
997            }
998    
999            @Override
1000            public List<MBMessage> getGroupMessages(
1001                            long groupId, long userId, int status, int start, int end)
1002                    throws SystemException {
1003    
1004                    if (status == WorkflowConstants.STATUS_ANY) {
1005                            return mbMessagePersistence.findByG_U(groupId, userId, start, end);
1006                    }
1007                    else {
1008                            return mbMessagePersistence.findByG_U_S(
1009                                    groupId, userId, status, start, end);
1010                    }
1011            }
1012    
1013            @Override
1014            public List<MBMessage> getGroupMessages(
1015                            long groupId, long userId, int status, int start, int end,
1016                            OrderByComparator obc)
1017                    throws SystemException {
1018    
1019                    if (status == WorkflowConstants.STATUS_ANY) {
1020                            return mbMessagePersistence.findByG_U(
1021                                    groupId, userId, start, end, obc);
1022                    }
1023                    else {
1024                            return mbMessagePersistence.findByG_U_S(
1025                                    groupId, userId, status, start, end, obc);
1026                    }
1027            }
1028    
1029            @Override
1030            public int getGroupMessagesCount(long groupId, int status)
1031                    throws SystemException {
1032    
1033                    if (status == WorkflowConstants.STATUS_ANY) {
1034                            return mbMessagePersistence.countByGroupId(groupId);
1035                    }
1036                    else {
1037                            return mbMessagePersistence.countByG_S(groupId, status);
1038                    }
1039            }
1040    
1041            @Override
1042            public int getGroupMessagesCount(long groupId, long userId, int status)
1043                    throws SystemException {
1044    
1045                    if (status == WorkflowConstants.STATUS_ANY) {
1046                            return mbMessagePersistence.countByG_U(groupId, userId);
1047                    }
1048                    else {
1049                            return mbMessagePersistence.countByG_U_S(groupId, userId, status);
1050                    }
1051            }
1052    
1053            @Override
1054            public MBMessage getMessage(long messageId)
1055                    throws PortalException, SystemException {
1056    
1057                    return mbMessagePersistence.findByPrimaryKey(messageId);
1058            }
1059    
1060            @Override
1061            public MBMessageDisplay getMessageDisplay(
1062                            long userId, long messageId, int status, String threadView,
1063                            boolean includePrevAndNext)
1064                    throws PortalException, SystemException {
1065    
1066                    MBMessage message = getMessage(messageId);
1067    
1068                    return getMessageDisplay(
1069                            userId, message, status, threadView, includePrevAndNext);
1070            }
1071    
1072            @Override
1073            public MBMessageDisplay getMessageDisplay(
1074                            long userId, MBMessage message, int status, String threadView,
1075                            boolean includePrevAndNext)
1076                    throws PortalException, SystemException {
1077    
1078                    MBCategory category = null;
1079    
1080                    if ((message.getCategoryId() !=
1081                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
1082                            (message.getCategoryId() !=
1083                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
1084    
1085                            category = mbCategoryPersistence.findByPrimaryKey(
1086                                    message.getCategoryId());
1087                    }
1088                    else {
1089                            category = new MBCategoryImpl();
1090    
1091                            category.setCategoryId(message.getCategoryId());
1092                            category.setDisplayStyle(MBCategoryConstants.DEFAULT_DISPLAY_STYLE);
1093                    }
1094    
1095                    MBMessage parentMessage = null;
1096    
1097                    if (message.isReply()) {
1098                            parentMessage = mbMessagePersistence.findByPrimaryKey(
1099                                    message.getParentMessageId());
1100                    }
1101    
1102                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1103                            message.getThreadId());
1104    
1105                    if (message.isApproved() && !message.isDiscussion()) {
1106                            mbThreadLocalService.incrementViewCounter(thread.getThreadId(), 1);
1107    
1108                            if (thread.getRootMessageUserId() != userId) {
1109                                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
1110                                            thread.getRootMessageId());
1111    
1112                                    socialActivityLocalService.addActivity(
1113                                            userId, rootMessage.getGroupId(), MBMessage.class.getName(),
1114                                            rootMessage.getMessageId(),
1115                                            SocialActivityConstants.TYPE_VIEW, StringPool.BLANK, 0);
1116                            }
1117                    }
1118    
1119                    MBThread previousThread = null;
1120                    MBThread nextThread = null;
1121    
1122                    if (message.isApproved() && includePrevAndNext) {
1123                            ThreadLastPostDateComparator comparator =
1124                                    new ThreadLastPostDateComparator(false);
1125    
1126                            MBThread[] prevAndNextThreads =
1127                                    mbThreadPersistence.findByG_C_PrevAndNext(
1128                                            message.getThreadId(), message.getGroupId(),
1129                                            message.getCategoryId(), comparator);
1130    
1131                            previousThread = prevAndNextThreads[0];
1132                            nextThread = prevAndNextThreads[2];
1133                    }
1134    
1135                    return new MBMessageDisplayImpl(
1136                            message, parentMessage, category, thread, previousThread,
1137                            nextThread, status, threadView, this);
1138            }
1139    
1140            @Override
1141            public List<MBMessage> getMessages(
1142                            String className, long classPK, int status)
1143                    throws SystemException {
1144    
1145                    long classNameId = PortalUtil.getClassNameId(className);
1146    
1147                    if (status == WorkflowConstants.STATUS_ANY) {
1148                            return mbMessagePersistence.findByC_C(classNameId, classPK);
1149                    }
1150                    else {
1151                            return mbMessagePersistence.findByC_C_S(
1152                                    classNameId, classPK, status);
1153                    }
1154            }
1155    
1156            @Override
1157            public List<MBMessage> getNoAssetMessages() throws SystemException {
1158                    return mbMessageFinder.findByNoAssets();
1159            }
1160    
1161            @Override
1162            public int getPositionInThread(long messageId)
1163                    throws PortalException, SystemException {
1164    
1165                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1166    
1167                    return mbMessageFinder.countByC_T(
1168                            message.getCreateDate(), message.getThreadId());
1169            }
1170    
1171            @Override
1172            public List<MBMessage> getThreadMessages(long threadId, int status)
1173                    throws SystemException {
1174    
1175                    return getThreadMessages(
1176                            threadId, status, new MessageThreadComparator());
1177            }
1178    
1179            @Override
1180            public List<MBMessage> getThreadMessages(
1181                            long threadId, int status, Comparator<MBMessage> comparator)
1182                    throws SystemException {
1183    
1184                    List<MBMessage> messages = null;
1185    
1186                    if (status == WorkflowConstants.STATUS_ANY) {
1187                            messages = mbMessagePersistence.findByThreadId(threadId);
1188                    }
1189                    else {
1190                            messages = mbMessagePersistence.findByT_S(threadId, status);
1191                    }
1192    
1193                    return ListUtil.sort(messages, comparator);
1194            }
1195    
1196            @Override
1197            public List<MBMessage> getThreadMessages(
1198                            long threadId, int status, int start, int end)
1199                    throws SystemException {
1200    
1201                    if (status == WorkflowConstants.STATUS_ANY) {
1202                            return mbMessagePersistence.findByThreadId(threadId, start, end);
1203                    }
1204                    else {
1205                            return mbMessagePersistence.findByT_S(threadId, status, start, end);
1206                    }
1207            }
1208    
1209            @Override
1210            public int getThreadMessagesCount(long threadId, int status)
1211                    throws SystemException {
1212    
1213                    if (status == WorkflowConstants.STATUS_ANY) {
1214                            return mbMessagePersistence.countByThreadId(threadId);
1215                    }
1216                    else {
1217                            return mbMessagePersistence.countByT_S(threadId, status);
1218                    }
1219            }
1220    
1221            @Override
1222            public List<MBMessage> getThreadRepliesMessages(
1223                            long threadId, int status, int start, int end)
1224                    throws SystemException {
1225    
1226                    if (status == WorkflowConstants.STATUS_ANY) {
1227                            return mbMessagePersistence.findByThreadReplies(
1228                                    threadId, start, end);
1229                    }
1230                    else {
1231                            return mbMessagePersistence.findByTR_S(
1232                                    threadId, status, start, end);
1233                    }
1234            }
1235    
1236            @Override
1237            public List<MBMessage> getUserDiscussionMessages(
1238                            long userId, long classNameId, long classPK, int status, int start,
1239                            int end, OrderByComparator obc)
1240                    throws SystemException {
1241    
1242                    if (status == WorkflowConstants.STATUS_ANY) {
1243                            return mbMessagePersistence.findByU_C_C(
1244                                    userId, classNameId, classPK, start, end, obc);
1245                    }
1246                    else {
1247                            return mbMessagePersistence.findByU_C_C_S(
1248                                    userId, classNameId, classPK, status, start, end, obc);
1249                    }
1250            }
1251    
1252            @Override
1253            public List<MBMessage> getUserDiscussionMessages(
1254                            long userId, long[] classNameIds, int status, int start, int end,
1255                            OrderByComparator obc)
1256                    throws SystemException {
1257    
1258                    if (status == WorkflowConstants.STATUS_ANY) {
1259                            return mbMessagePersistence.findByU_C(
1260                                    userId, classNameIds, start, end, obc);
1261                    }
1262                    else {
1263                            return mbMessagePersistence.findByU_C_S(
1264                                    userId, classNameIds, status, start, end, obc);
1265                    }
1266            }
1267    
1268            @Override
1269            public List<MBMessage> getUserDiscussionMessages(
1270                            long userId, String className, long classPK, int status, int start,
1271                            int end, OrderByComparator obc)
1272                    throws SystemException {
1273    
1274                    long classNameId = PortalUtil.getClassNameId(className);
1275    
1276                    return getUserDiscussionMessages(
1277                            userId, classNameId, classPK, status, start, end, obc);
1278            }
1279    
1280            @Override
1281            public int getUserDiscussionMessagesCount(
1282                            long userId, long classNameId, long classPK, int status)
1283                    throws SystemException {
1284    
1285                    if (status == WorkflowConstants.STATUS_ANY) {
1286                            return mbMessagePersistence.countByU_C_C(
1287                                    userId, classNameId, classPK);
1288                    }
1289                    else {
1290                            return mbMessagePersistence.countByU_C_C_S(
1291                                    userId, classNameId, classPK, status);
1292                    }
1293            }
1294    
1295            @Override
1296            public int getUserDiscussionMessagesCount(
1297                            long userId, long[] classNameIds, int status)
1298                    throws SystemException {
1299    
1300                    if (status == WorkflowConstants.STATUS_ANY) {
1301                            return mbMessagePersistence.countByU_C(userId, classNameIds);
1302                    }
1303                    else {
1304                            return mbMessagePersistence.countByU_C_S(
1305                                    userId, classNameIds, status);
1306                    }
1307            }
1308    
1309            @Override
1310            public int getUserDiscussionMessagesCount(
1311                            long userId, String className, long classPK, int status)
1312                    throws SystemException {
1313    
1314                    long classNameId = PortalUtil.getClassNameId(className);
1315    
1316                    return getUserDiscussionMessagesCount(
1317                            userId, classNameId, classPK, status);
1318            }
1319    
1320            @Override
1321            public long moveMessageAttachmentToTrash(
1322                            long userId, long messageId, String fileName)
1323                    throws PortalException, SystemException {
1324    
1325                    MBMessage message = getMessage(messageId);
1326    
1327                    long folderId = message.getAttachmentsFolderId();
1328    
1329                    FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
1330                            message.getGroupId(), folderId, fileName);
1331    
1332                    PortletFileRepositoryUtil.movePortletFileEntryToTrash(
1333                            userId, fileEntry.getFileEntryId());
1334    
1335                    return fileEntry.getFileEntryId();
1336            }
1337    
1338            @Override
1339            public void restoreMessageAttachmentFromTrash(
1340                            long userId, long messageId, String deletedFileName)
1341                    throws PortalException, SystemException {
1342    
1343                    MBMessage message = getMessage(messageId);
1344    
1345                    Folder folder = message.addAttachmentsFolder();
1346    
1347                    PortletFileRepositoryUtil.restorePortletFileEntryFromTrash(
1348                            message.getGroupId(), userId, folder.getFolderId(),
1349                            deletedFileName);
1350            }
1351    
1352            @Override
1353            public void subscribeMessage(long userId, long messageId)
1354                    throws PortalException, SystemException {
1355    
1356                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1357    
1358                    subscriptionLocalService.addSubscription(
1359                            userId, message.getGroupId(), MBThread.class.getName(),
1360                            message.getThreadId());
1361            }
1362    
1363            @Override
1364            public void unsubscribeMessage(long userId, long messageId)
1365                    throws PortalException, SystemException {
1366    
1367                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1368    
1369                    subscriptionLocalService.deleteSubscription(
1370                            userId, MBThread.class.getName(), message.getThreadId());
1371            }
1372    
1373            @Override
1374            public void updateAnswer(long messageId, boolean answer, boolean cascade)
1375                    throws PortalException, SystemException {
1376    
1377                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1378    
1379                    updateAnswer(message, answer, cascade);
1380            }
1381    
1382            @Override
1383            public void updateAnswer(MBMessage message, boolean answer, boolean cascade)
1384                    throws PortalException, SystemException {
1385    
1386                    if (message.isAnswer() != answer) {
1387                            message.setAnswer(answer);
1388    
1389                            mbMessagePersistence.update(message);
1390                    }
1391    
1392                    if (cascade) {
1393                            List<MBMessage> messages = mbMessagePersistence.findByT_P(
1394                                    message.getThreadId(), message.getMessageId());
1395    
1396                            for (MBMessage curMessage : messages) {
1397                                    updateAnswer(curMessage, answer, cascade);
1398                            }
1399                    }
1400            }
1401    
1402            @Override
1403            public void updateAsset(
1404                            long userId, MBMessage message, long[] assetCategoryIds,
1405                            String[] assetTagNames, long[] assetLinkEntryIds)
1406                    throws PortalException, SystemException {
1407    
1408                    updateAsset(
1409                            userId, message, assetCategoryIds, assetTagNames, assetLinkEntryIds,
1410                            true);
1411            }
1412    
1413            @Override
1414            public MBMessage updateDiscussionMessage(
1415                            long userId, long messageId, String className, long classPK,
1416                            String subject, String body, ServiceContext serviceContext)
1417                    throws PortalException, SystemException {
1418    
1419                    if (Validator.isNull(subject)) {
1420                            if (Validator.isNotNull(body)) {
1421                                    int pos = Math.min(body.length(), 50);
1422    
1423                                    subject = body.substring(0, pos) + "...";
1424                            }
1425                            else {
1426                                    throw new MessageBodyException();
1427                            }
1428                    }
1429    
1430                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
1431                            Collections.emptyList();
1432                    List<String> existingFiles = new ArrayList<String>();
1433                    double priority = 0.0;
1434                    boolean allowPingbacks = false;
1435    
1436                    serviceContext.setAttribute("className", className);
1437                    serviceContext.setAttribute("classPK", String.valueOf(classPK));
1438    
1439                    return updateMessage(
1440                            userId, messageId, subject, body, inputStreamOVPs, existingFiles,
1441                            priority, allowPingbacks, serviceContext);
1442            }
1443    
1444            @Override
1445            public MBMessage updateMessage(
1446                            long userId, long messageId, String subject, String body,
1447                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
1448                            List<String> existingFiles, double priority, boolean allowPingbacks,
1449                            ServiceContext serviceContext)
1450                    throws PortalException, SystemException {
1451    
1452                    // Message
1453    
1454                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1455    
1456                    int oldStatus = message.getStatus();
1457    
1458                    Date modifiedDate = serviceContext.getModifiedDate(new Date());
1459                    subject = ModelHintsUtil.trimString(
1460                            MBMessage.class.getName(), "subject", subject);
1461                    body = SanitizerUtil.sanitize(
1462                            message.getCompanyId(), message.getGroupId(), userId,
1463                            MBMessage.class.getName(), messageId, "text/" + message.getFormat(),
1464                            body);
1465    
1466                    validate(subject, body);
1467    
1468                    subject = getSubject(subject, body);
1469                    body = getBody(subject, body);
1470    
1471                    message.setModifiedDate(modifiedDate);
1472                    message.setSubject(subject);
1473                    message.setBody(body);
1474                    message.setAllowPingbacks(allowPingbacks);
1475    
1476                    if (priority != MBThreadConstants.PRIORITY_NOT_GIVEN) {
1477                            message.setPriority(priority);
1478                    }
1479    
1480                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1481                            message.getThreadId());
1482    
1483                    if (serviceContext.getWorkflowAction() ==
1484                                    WorkflowConstants.ACTION_SAVE_DRAFT) {
1485    
1486                            if (!message.isDraft() && !message.isPending()) {
1487                                    message.setStatus(WorkflowConstants.STATUS_DRAFT);
1488    
1489                                    // Thread
1490    
1491                                    User user = userPersistence.findByPrimaryKey(userId);
1492    
1493                                    updateThreadStatus(
1494                                            thread, message, user, oldStatus, modifiedDate);
1495    
1496                                    // Asset
1497    
1498                                    assetEntryLocalService.updateVisible(
1499                                            message.getWorkflowClassName(), message.getMessageId(),
1500                                            false);
1501    
1502                                    if (!message.isDiscussion()) {
1503    
1504                                            // Indexer
1505    
1506                                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1507                                                    MBMessage.class);
1508    
1509                                            indexer.delete(message);
1510                                    }
1511                            }
1512                    }
1513    
1514                    // Attachments
1515    
1516                    if (!inputStreamOVPs.isEmpty() || !existingFiles.isEmpty()) {
1517                            List<FileEntry> fileEntries = message.getAttachmentsFileEntries();
1518    
1519                            for (FileEntry fileEntry : fileEntries) {
1520                                    String fileEntryId = String.valueOf(fileEntry.getFileEntryId());
1521    
1522                                    if (!existingFiles.contains(fileEntryId)) {
1523                                            if (!TrashUtil.isTrashEnabled(message.getGroupId())) {
1524                                                    deleteMessageAttachment(
1525                                                            messageId, fileEntry.getTitle());
1526                                            }
1527                                            else {
1528                                                    moveMessageAttachmentToTrash(
1529                                                            userId, messageId, fileEntry.getTitle());
1530                                            }
1531                                    }
1532                            }
1533    
1534                            Folder folder = message.addAttachmentsFolder();
1535    
1536                            PortletFileRepositoryUtil.addPortletFileEntries(
1537                                    message.getGroupId(), userId, MBMessage.class.getName(),
1538                                    message.getMessageId(), PortletKeys.MESSAGE_BOARDS,
1539                                    folder.getFolderId(), inputStreamOVPs);
1540                    }
1541                    else {
1542                            if (TrashUtil.isTrashEnabled(message.getGroupId())) {
1543                                    List<FileEntry> fileEntries =
1544                                            message.getAttachmentsFileEntries();
1545    
1546                                    for (FileEntry fileEntry : fileEntries) {
1547                                            moveMessageAttachmentToTrash(
1548                                                    userId, messageId, fileEntry.getTitle());
1549                                    }
1550                            }
1551                    }
1552    
1553                    message.setExpandoBridgeAttributes(serviceContext);
1554    
1555                    mbMessagePersistence.update(message);
1556    
1557                    // Thread
1558    
1559                    if ((priority != MBThreadConstants.PRIORITY_NOT_GIVEN) &&
1560                            (thread.getPriority() != priority)) {
1561    
1562                            thread.setPriority(priority);
1563    
1564                            mbThreadPersistence.update(thread);
1565    
1566                            updatePriorities(thread.getThreadId(), priority);
1567                    }
1568    
1569                    // Asset
1570    
1571                    updateAsset(
1572                            userId, message, serviceContext.getAssetCategoryIds(),
1573                            serviceContext.getAssetTagNames(),
1574                            serviceContext.getAssetLinkEntryIds());
1575    
1576                    // Workflow
1577    
1578                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
1579                            message.getCompanyId(), message.getGroupId(), userId,
1580                            message.getWorkflowClassName(), message.getMessageId(), message,
1581                            serviceContext);
1582    
1583                    return message;
1584            }
1585    
1586            @Override
1587            public MBMessage updateMessage(long messageId, String body)
1588                    throws PortalException, SystemException {
1589    
1590                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1591    
1592                    message.setBody(body);
1593    
1594                    mbMessagePersistence.update(message);
1595    
1596                    return message;
1597            }
1598    
1599            @Override
1600            public MBMessage updateStatus(
1601                            long userId, long messageId, int status,
1602                            ServiceContext serviceContext)
1603                    throws PortalException, SystemException {
1604    
1605                    // Message
1606    
1607                    MBMessage message = getMessage(messageId);
1608    
1609                    int oldStatus = message.getStatus();
1610    
1611                    User user = userPersistence.findByPrimaryKey(userId);
1612                    Date now = new Date();
1613    
1614                    Date modifiedDate = serviceContext.getModifiedDate(now);
1615    
1616                    message.setStatus(status);
1617                    message.setStatusByUserId(userId);
1618                    message.setStatusByUserName(user.getFullName());
1619                    message.setStatusDate(modifiedDate);
1620    
1621                    mbMessagePersistence.update(message);
1622    
1623                    // Thread
1624    
1625                    MBThread thread = mbThreadPersistence.findByPrimaryKey(
1626                            message.getThreadId());
1627    
1628                    updateThreadStatus(thread, message, user, oldStatus, modifiedDate);
1629    
1630                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1631                            MBMessage.class);
1632    
1633                    if (status == WorkflowConstants.STATUS_APPROVED) {
1634                            if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
1635    
1636                                    // Asset
1637    
1638                                    if (serviceContext.isAssetEntryVisible() &&
1639                                            ((message.getClassNameId() == 0) ||
1640                                             (message.getParentMessageId() != 0))) {
1641    
1642                                            Date publishDate = null;
1643    
1644                                            AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
1645                                                    message.getWorkflowClassName(), message.getMessageId());
1646    
1647                                            if ((assetEntry != null) &&
1648                                                    (assetEntry.getPublishDate() != null)) {
1649    
1650                                                    publishDate = assetEntry.getPublishDate();
1651                                            }
1652                                            else {
1653                                                    publishDate = now;
1654    
1655                                                    serviceContext.setCommand(Constants.ADD);
1656                                            }
1657    
1658                                            assetEntryLocalService.updateEntry(
1659                                                    message.getWorkflowClassName(), message.getMessageId(),
1660                                                    publishDate, true);
1661                                    }
1662    
1663                                    if (serviceContext.isCommandAdd()) {
1664    
1665                                            // Social
1666    
1667                                            JSONObject extraDataJSONObject =
1668                                                    JSONFactoryUtil.createJSONObject();
1669    
1670                                            extraDataJSONObject.put("title", message.getSubject());
1671    
1672                                            if (!message.isDiscussion() ) {
1673                                                    if (!message.isAnonymous() && !user.isDefaultUser()) {
1674                                                            long receiverUserId = 0;
1675    
1676                                                            MBMessage parentMessage =
1677                                                                    mbMessagePersistence.fetchByPrimaryKey(
1678                                                                            message.getParentMessageId());
1679    
1680                                                            if (parentMessage != null) {
1681                                                                    receiverUserId = parentMessage.getUserId();
1682                                                            }
1683    
1684                                                            socialActivityLocalService.addActivity(
1685                                                                    userId, message.getGroupId(),
1686                                                                    MBMessage.class.getName(),
1687                                                                    message.getMessageId(),
1688                                                                    MBActivityKeys.ADD_MESSAGE,
1689                                                                    extraDataJSONObject.toString(), receiverUserId);
1690    
1691                                                            if ((parentMessage != null) &&
1692                                                                    (receiverUserId != userId)) {
1693    
1694                                                                    socialActivityLocalService.addActivity(
1695                                                                            userId, parentMessage.getGroupId(),
1696                                                                            MBMessage.class.getName(),
1697                                                                            parentMessage.getMessageId(),
1698                                                                            MBActivityKeys.REPLY_MESSAGE,
1699                                                                            extraDataJSONObject.toString(), 0);
1700                                                            }
1701                                                    }
1702                                            }
1703                                            else {
1704                                                    String className = (String)serviceContext.getAttribute(
1705                                                            "className");
1706                                                    long classPK = ParamUtil.getLong(
1707                                                            serviceContext, "classPK");
1708                                                    long parentMessageId = message.getParentMessageId();
1709    
1710                                                    if (parentMessageId !=
1711                                                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
1712    
1713                                                            AssetEntry assetEntry =
1714                                                                    assetEntryLocalService.fetchEntry(
1715                                                                            className, classPK);
1716    
1717                                                            if (assetEntry != null) {
1718                                                                    extraDataJSONObject.put(
1719                                                                            "messageId", message.getMessageId());
1720    
1721                                                                    socialActivityLocalService.addActivity(
1722                                                                            userId, assetEntry.getGroupId(), className,
1723                                                                            classPK,
1724                                                                            SocialActivityConstants.TYPE_ADD_COMMENT,
1725                                                                            extraDataJSONObject.toString(),
1726                                                                            assetEntry.getUserId());
1727                                                            }
1728                                                    }
1729                                            }
1730                                    }
1731                            }
1732    
1733                            // Subscriptions
1734    
1735                            notifySubscribers((MBMessage)message.clone(), serviceContext);
1736    
1737                            // Indexer
1738    
1739                            indexer.reindex(message);
1740    
1741                            // Ping
1742    
1743                            pingPingback(message, serviceContext);
1744                    }
1745                    else if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
1746    
1747                            // Asset
1748    
1749                            assetEntryLocalService.updateVisible(
1750                                    message.getWorkflowClassName(), message.getMessageId(), false);
1751    
1752                            // Indexer
1753    
1754                            indexer.delete(message);
1755                    }
1756    
1757                    // Statistics
1758    
1759                    if (!message.isDiscussion()) {
1760                            mbStatsUserLocalService.updateStatsUser(
1761                                    message.getGroupId(), userId,
1762                                    serviceContext.getModifiedDate(now));
1763                    }
1764    
1765                    return message;
1766            }
1767    
1768            @Override
1769            public void updateUserName(long userId, String userName)
1770                    throws SystemException {
1771    
1772                    List<MBMessage> messages = mbMessagePersistence.findByUserId(userId);
1773    
1774                    for (MBMessage message : messages) {
1775                            message.setUserName(userName);
1776    
1777                            mbMessagePersistence.update(message);
1778                    }
1779            }
1780    
1781            protected void deleteDiscussionSocialActivities(
1782                            String className, MBMessage message)
1783                    throws PortalException, SystemException {
1784    
1785                    MBDiscussion discussion = mbDiscussionPersistence.findByThreadId(
1786                            message.getThreadId());
1787    
1788                    long classNameId = PortalUtil.getClassNameId(className);
1789                    long classPK = discussion.getClassPK();
1790    
1791                    if (discussion.getClassNameId() != classNameId) {
1792                            return;
1793                    }
1794    
1795                    List<SocialActivity> socialActivities =
1796                            socialActivityLocalService.getActivities(
1797                                    0, className, classPK, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
1798    
1799                    for (SocialActivity socialActivity : socialActivities) {
1800                            if (Validator.isNull(socialActivity.getExtraData())) {
1801                                    continue;
1802                            }
1803    
1804                            JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(
1805                                    socialActivity.getExtraData());
1806    
1807                            long extraDataMessageId = extraDataJSONObject.getLong("messageId");
1808    
1809                            if (message.getMessageId() == extraDataMessageId) {
1810                                    socialActivityLocalService.deleteActivity(
1811                                            socialActivity.getActivityId());
1812                            }
1813                    }
1814            }
1815    
1816            protected String getBody(String subject, String body) {
1817                    if (Validator.isNull(body)) {
1818                            return subject;
1819                    }
1820    
1821                    return body;
1822            }
1823    
1824            protected String getMessageURL(
1825                            MBMessage message, ServiceContext serviceContext)
1826                    throws PortalException, SystemException {
1827    
1828                    HttpServletRequest request = serviceContext.getRequest();
1829    
1830                    if (request == null) {
1831                            return StringPool.BLANK;
1832                    }
1833    
1834                    String layoutURL = getLayoutURL(
1835                            message.getGroupId(), PortletKeys.MESSAGE_BOARDS, serviceContext);
1836    
1837                    if (Validator.isNotNull(layoutURL)) {
1838                            return layoutURL + Portal.FRIENDLY_URL_SEPARATOR +
1839                                    "message_boards/view_message/" + message.getMessageId();
1840                    }
1841                    else {
1842                            long controlPanelPlid = PortalUtil.getControlPanelPlid(
1843                                    serviceContext.getCompanyId());
1844    
1845                            PortletURL portletURL = PortletURLFactoryUtil.create(
1846                                    request, PortletKeys.MESSAGE_BOARDS_ADMIN, controlPanelPlid,
1847                                    PortletRequest.RENDER_PHASE);
1848    
1849                            portletURL.setParameter(
1850                                    "struts_action", "/message_boards_admin/view_message");
1851                            portletURL.setParameter(
1852                                    "messageId", String.valueOf(message.getMessageId()));
1853    
1854                            return portletURL.toString();
1855                    }
1856            }
1857    
1858            protected String getSubject(String subject, String body) {
1859                    if (Validator.isNull(subject)) {
1860                            return StringUtil.shorten(body);
1861                    }
1862    
1863                    return subject;
1864            }
1865    
1866            protected void notifyDiscussionSubscribers(
1867                            MBMessage message, ServiceContext serviceContext)
1868                    throws SystemException {
1869    
1870                    if (!PrefsPropsUtil.getBoolean(
1871                                    message.getCompanyId(),
1872                                    PropsKeys.DISCUSSION_EMAIL_COMMENTS_ADDED_ENABLED)) {
1873    
1874                            return;
1875                    }
1876    
1877                    String contentURL = (String)serviceContext.getAttribute("contentURL");
1878    
1879                    String userAddress = StringPool.BLANK;
1880                    String userName = (String)serviceContext.getAttribute(
1881                            "pingbackUserName");
1882    
1883                    if (Validator.isNull(userName)) {
1884                            userAddress = PortalUtil.getUserEmailAddress(message.getUserId());
1885                            userName = PortalUtil.getUserName(
1886                                    message.getUserId(), StringPool.BLANK);
1887                    }
1888    
1889                    String fromName = PrefsPropsUtil.getString(
1890                            message.getCompanyId(), PropsKeys.ADMIN_EMAIL_FROM_NAME);
1891                    String fromAddress = PrefsPropsUtil.getString(
1892                            message.getCompanyId(), PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);
1893    
1894                    String subject = PrefsPropsUtil.getContent(
1895                            message.getCompanyId(), PropsKeys.DISCUSSION_EMAIL_SUBJECT);
1896                    String body = PrefsPropsUtil.getContent(
1897                            message.getCompanyId(), PropsKeys.DISCUSSION_EMAIL_BODY);
1898    
1899                    SubscriptionSender subscriptionSender = new SubscriptionSender();
1900    
1901                    subscriptionSender.setBody(body);
1902                    subscriptionSender.setCompanyId(message.getCompanyId());
1903                    subscriptionSender.setContextAttribute(
1904                            "[$COMMENTS_BODY$]", message.getBody(true), false);
1905                    subscriptionSender.setContextAttributes(
1906                            "[$COMMENTS_USER_ADDRESS$]", userAddress, "[$COMMENTS_USER_NAME$]",
1907                            userName, "[$CONTENT_URL$]", contentURL);
1908                    subscriptionSender.setFrom(fromAddress, fromName);
1909                    subscriptionSender.setHtmlFormat(true);
1910                    subscriptionSender.setMailId(
1911                            "mb_discussion", message.getCategoryId(), message.getMessageId());
1912                    subscriptionSender.setScopeGroupId(message.getGroupId());
1913                    subscriptionSender.setServiceContext(serviceContext);
1914                    subscriptionSender.setSubject(subject);
1915                    subscriptionSender.setUserId(message.getUserId());
1916    
1917                    String className = (String)serviceContext.getAttribute("className");
1918                    long classPK = ParamUtil.getLong(serviceContext, "classPK");
1919    
1920                    subscriptionSender.addPersistedSubscribers(className, classPK);
1921    
1922                    subscriptionSender.flushNotificationsAsync();
1923            }
1924    
1925            protected void notifySubscribers(
1926                            MBMessage message, ServiceContext serviceContext)
1927                    throws PortalException, SystemException {
1928    
1929                    String layoutFullURL = serviceContext.getLayoutFullURL();
1930    
1931                    if (!message.isApproved() || Validator.isNull(layoutFullURL)) {
1932                            return;
1933                    }
1934    
1935                    if (message.isDiscussion()) {
1936                            try {
1937                                    notifyDiscussionSubscribers(message, serviceContext);
1938                            }
1939                            catch (Exception e) {
1940                                    _log.error(e, e);
1941                            }
1942    
1943                            return;
1944                    }
1945    
1946                    PortletPreferences preferences =
1947                            ServiceContextUtil.getPortletPreferences(serviceContext);
1948    
1949                    if (preferences == null) {
1950                            long ownerId = message.getGroupId();
1951                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1952                            long plid = PortletKeys.PREFS_PLID_SHARED;
1953                            String portletId = PortletKeys.MESSAGE_BOARDS;
1954                            String defaultPreferences = null;
1955    
1956                            preferences = portletPreferencesLocalService.getPreferences(
1957                                    message.getCompanyId(), ownerId, ownerType, plid, portletId,
1958                                    defaultPreferences);
1959                    }
1960    
1961                    if (serviceContext.isCommandAdd() &&
1962                            MBUtil.getEmailMessageAddedEnabled(preferences)) {
1963                    }
1964                    else if (serviceContext.isCommandUpdate() &&
1965                                     MBUtil.getEmailMessageUpdatedEnabled(preferences)) {
1966                    }
1967                    else {
1968                            return;
1969                    }
1970    
1971                    Company company = companyPersistence.findByPrimaryKey(
1972                            message.getCompanyId());
1973    
1974                    Group group = groupPersistence.findByPrimaryKey(message.getGroupId());
1975    
1976                    String emailAddress = PortalUtil.getUserEmailAddress(
1977                            message.getUserId());
1978                    String fullName = PortalUtil.getUserName(
1979                            message.getUserId(), message.getUserName());
1980    
1981                    if (message.isAnonymous()) {
1982                            emailAddress = StringPool.BLANK;
1983                            fullName = serviceContext.translate("anonymous");
1984                    }
1985    
1986                    MBCategory category = message.getCategory();
1987    
1988                    String categoryName = category.getName();
1989    
1990                    if (category.getCategoryId() ==
1991                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
1992    
1993                            categoryName = serviceContext.translate("message-boards-home");
1994    
1995                            categoryName += " - " + group.getDescriptiveName();
1996                    }
1997    
1998                    List<Long> categoryIds = new ArrayList<Long>();
1999    
2000                    categoryIds.add(message.getCategoryId());
2001    
2002                    if (message.getCategoryId() !=
2003                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
2004    
2005                            categoryIds.addAll(category.getAncestorCategoryIds());
2006                    }
2007    
2008                    String fromName = MBUtil.getEmailFromName(
2009                            preferences, message.getCompanyId());
2010                    String fromAddress = MBUtil.getEmailFromAddress(
2011                            preferences, message.getCompanyId());
2012    
2013                    String replyToAddress = StringPool.BLANK;
2014    
2015                    if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
2016                            replyToAddress = MBUtil.getReplyToAddress(
2017                                    message.getCategoryId(), message.getMessageId(),
2018                                    company.getMx(), fromAddress);
2019                    }
2020    
2021                    String subject = null;
2022                    String body = null;
2023                    String signature = null;
2024    
2025                    if (serviceContext.isCommandUpdate()) {
2026                            subject = MBUtil.getEmailMessageUpdatedSubject(preferences);
2027                            body = MBUtil.getEmailMessageUpdatedBody(preferences);
2028                            signature = MBUtil.getEmailMessageUpdatedSignature(preferences);
2029                    }
2030                    else {
2031                            subject = MBUtil.getEmailMessageAddedSubject(preferences);
2032                            body = MBUtil.getEmailMessageAddedBody(preferences);
2033                            signature = MBUtil.getEmailMessageAddedSignature(preferences);
2034                    }
2035    
2036                    boolean htmlFormat = MBUtil.getEmailHtmlFormat(preferences);
2037    
2038                    if (Validator.isNotNull(signature)) {
2039                            String signatureSeparator = null;
2040    
2041                            if (htmlFormat) {
2042                                    signatureSeparator = "<br />--<br />";
2043                            }
2044                            else {
2045                                    signatureSeparator = "\n--\n";
2046                            }
2047    
2048                            body += signatureSeparator + signature;
2049                    }
2050    
2051                    String messageBody = message.getBody();
2052    
2053                    if (htmlFormat && message.isFormatBBCode()) {
2054                            try {
2055                                    messageBody = BBCodeTranslatorUtil.getHTML(messageBody);
2056    
2057                                    HttpServletRequest request = serviceContext.getRequest();
2058    
2059                                    if (request != null) {
2060                                            ThemeDisplay themeDisplay =
2061                                                    (ThemeDisplay)request.getAttribute(
2062                                                            WebKeys.THEME_DISPLAY);
2063    
2064                                            messageBody = MBUtil.replaceMessageBodyPaths(
2065                                                    themeDisplay, messageBody);
2066                                    }
2067                            }
2068                            catch (Exception e) {
2069                                    _log.error(
2070                                            "Could not parse message " + message.getMessageId() +
2071                                                    " " + e.getMessage());
2072                            }
2073                    }
2074    
2075                    String inReplyTo = null;
2076    
2077                    if (message.getParentMessageId() !=
2078                                    MBMessageConstants.DEFAULT_PARENT_MESSAGE_ID) {
2079    
2080                            inReplyTo = PortalUtil.getMailId(
2081                                    company.getMx(), MBUtil.MESSAGE_POP_PORTLET_PREFIX,
2082                                    message.getCategoryId(), message.getParentMessageId());
2083                    }
2084    
2085                    SubscriptionSender subscriptionSenderPrototype =
2086                            new MBSubscriptionSender();
2087    
2088                    subscriptionSenderPrototype.setBody(body);
2089                    subscriptionSenderPrototype.setBulk(
2090                            PropsValues.MESSAGE_BOARDS_EMAIL_BULK);
2091                    subscriptionSenderPrototype.setCompanyId(message.getCompanyId());
2092                    subscriptionSenderPrototype.setContextAttribute(
2093                            "[$MESSAGE_BODY$]", messageBody, false);
2094                    subscriptionSenderPrototype.setContextAttributes(
2095                            "[$CATEGORY_NAME$]", categoryName, "[$MAILING_LIST_ADDRESS$]",
2096                            replyToAddress, "[$MESSAGE_ID$]", message.getMessageId(),
2097                            "[$MESSAGE_SUBJECT$]", message.getSubject(), "[$MESSAGE_URL$]",
2098                            getMessageURL(message, serviceContext), "[$MESSAGE_USER_ADDRESS$]",
2099                            emailAddress, "[$MESSAGE_USER_NAME$]", fullName);
2100                    subscriptionSenderPrototype.setFrom(fromAddress, fromName);
2101                    subscriptionSenderPrototype.setHtmlFormat(htmlFormat);
2102                    subscriptionSenderPrototype.setInReplyTo(inReplyTo);
2103                    subscriptionSenderPrototype.setMailId(
2104                            MBUtil.MESSAGE_POP_PORTLET_PREFIX, message.getCategoryId(),
2105                            message.getMessageId());
2106                    subscriptionSenderPrototype.setPortletId(PortletKeys.MESSAGE_BOARDS);
2107                    subscriptionSenderPrototype.setReplyToAddress(replyToAddress);
2108                    subscriptionSenderPrototype.setScopeGroupId(message.getGroupId());
2109                    subscriptionSenderPrototype.setServiceContext(serviceContext);
2110                    subscriptionSenderPrototype.setSubject(subject);
2111                    subscriptionSenderPrototype.setUserId(message.getUserId());
2112    
2113                    SubscriptionSender subscriptionSender =
2114                            (SubscriptionSender)SerializableUtil.clone(
2115                                    subscriptionSenderPrototype);
2116    
2117                    subscriptionSender.addPersistedSubscribers(
2118                            MBCategory.class.getName(), message.getGroupId());
2119    
2120                    for (long categoryId : categoryIds) {
2121                            if (categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
2122                                    subscriptionSender.addPersistedSubscribers(
2123                                            MBCategory.class.getName(), categoryId);
2124                            }
2125                    }
2126    
2127                    subscriptionSender.addPersistedSubscribers(
2128                            MBThread.class.getName(), message.getThreadId());
2129    
2130                    subscriptionSender.flushNotificationsAsync();
2131    
2132                    if (!MailingListThreadLocal.isSourceMailingList()) {
2133                            for (long categoryId : categoryIds) {
2134                                    MBSubscriptionSender sourceMailingListSubscriptionSender =
2135                                            (MBSubscriptionSender)SerializableUtil.clone(
2136                                                    subscriptionSenderPrototype);
2137    
2138                                    sourceMailingListSubscriptionSender.setBulk(false);
2139    
2140                                    sourceMailingListSubscriptionSender.addMailingListSubscriber(
2141                                            message.getGroupId(), categoryId);
2142    
2143                                    sourceMailingListSubscriptionSender.flushNotificationsAsync();
2144                            }
2145                    }
2146            }
2147    
2148            protected void pingPingback(
2149                    MBMessage message, ServiceContext serviceContext) {
2150    
2151                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
2152                            !message.isAllowPingbacks() || !message.isApproved()) {
2153    
2154                            return;
2155                    }
2156    
2157                    String layoutFullURL = serviceContext.getLayoutFullURL();
2158    
2159                    if (Validator.isNull(layoutFullURL)) {
2160                            return;
2161                    }
2162    
2163                    String sourceUri =
2164                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR +
2165                                    "message_boards/view_message/" + message.getMessageId();
2166    
2167                    Source source = new Source(message.getBody(true));
2168    
2169                    List<StartTag> startTags = source.getAllStartTags("a");
2170    
2171                    for (StartTag startTag : startTags) {
2172                            String targetUri = startTag.getAttributeValue("href");
2173    
2174                            if (Validator.isNotNull(targetUri)) {
2175                                    try {
2176                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
2177                                    }
2178                                    catch (Exception e) {
2179                                            _log.error("Error while sending pingback " + targetUri, e);
2180                                    }
2181                            }
2182                    }
2183            }
2184    
2185            protected void updateAsset(
2186                            long userId, MBMessage message, long[] assetCategoryIds,
2187                            String[] assetTagNames, long[] assetLinkEntryIds,
2188                            boolean assetEntryVisible)
2189                    throws PortalException, SystemException {
2190    
2191                    boolean visible = false;
2192    
2193                    if (assetEntryVisible && message.isApproved() &&
2194                            ((message.getClassNameId() == 0) ||
2195                             (message.getParentMessageId() != 0))) {
2196    
2197                            visible = true;
2198                    }
2199    
2200                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
2201                            userId, message.getGroupId(), message.getCreateDate(),
2202                            message.getModifiedDate(), message.getWorkflowClassName(),
2203                            message.getMessageId(), message.getUuid(), 0, assetCategoryIds,
2204                            assetTagNames, visible, null, null, null, ContentTypes.TEXT_HTML,
2205                            message.getSubject(), null, null, null, null, 0, 0, null, false);
2206    
2207                    assetLinkLocalService.updateLinks(
2208                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
2209                            AssetLinkConstants.TYPE_RELATED);
2210            }
2211    
2212            protected void updatePriorities(long threadId, double priority)
2213                    throws SystemException {
2214    
2215                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
2216                            threadId);
2217    
2218                    for (MBMessage message : messages) {
2219                            if (message.getPriority() != priority) {
2220                                    message.setPriority(priority);
2221    
2222                                    mbMessagePersistence.update(message);
2223                            }
2224                    }
2225            }
2226    
2227            protected void updateThreadStatus(
2228                            MBThread thread, MBMessage message, User user, int oldStatus,
2229                            Date modifiedDate)
2230                    throws PortalException, SystemException {
2231    
2232                    MBCategory category = null;
2233    
2234                    int status = message.getStatus();
2235    
2236                    if ((thread.getCategoryId() !=
2237                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
2238                            (thread.getCategoryId() !=
2239                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
2240    
2241                            category = mbCategoryPersistence.findByPrimaryKey(
2242                                    thread.getCategoryId());
2243                    }
2244    
2245                    if ((thread.getRootMessageId() == message.getMessageId()) &&
2246                            (oldStatus != status)) {
2247    
2248                            thread.setModifiedDate(modifiedDate);
2249                            thread.setStatus(status);
2250                            thread.setStatusByUserId(user.getUserId());
2251                            thread.setStatusByUserName(user.getFullName());
2252                            thread.setStatusDate(modifiedDate);
2253                    }
2254    
2255                    if (status == oldStatus) {
2256                            return;
2257                    }
2258    
2259                    if (status == WorkflowConstants.STATUS_APPROVED) {
2260                            if (message.isAnonymous()) {
2261                                    thread.setLastPostByUserId(0);
2262                            }
2263                            else {
2264                                    thread.setLastPostByUserId(message.getUserId());
2265                            }
2266    
2267                            thread.setLastPostDate(modifiedDate);
2268    
2269                            if (category != null) {
2270                                    category.setLastPostDate(modifiedDate);
2271    
2272                                    category = mbCategoryPersistence.update(category);
2273                            }
2274                    }
2275    
2276                    if ((oldStatus == WorkflowConstants.STATUS_APPROVED) ||
2277                            (status == WorkflowConstants.STATUS_APPROVED)) {
2278    
2279                            // Thread
2280    
2281                            MBUtil.updateThreadMessageCount(
2282                                    thread.getCompanyId(), thread.getThreadId());
2283    
2284                            // Category
2285    
2286                            if ((category != null) &&
2287                                    (thread.getRootMessageId() == message.getMessageId())) {
2288    
2289                                    MBUtil.updateCategoryStatistics(
2290                                            category.getCompanyId(), category.getCategoryId());
2291                            }
2292    
2293                            if ((category != null) &&
2294                                    !(thread.getRootMessageId() == message.getMessageId())) {
2295    
2296                                    MBUtil.updateCategoryMessageCount(
2297                                            category.getCompanyId(), category.getCategoryId());
2298                            }
2299                    }
2300    
2301                    // Indexer
2302    
2303                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
2304                            MBThread.class);
2305    
2306                    indexer.reindex(thread);
2307    
2308                    mbThreadPersistence.update(thread);
2309            }
2310    
2311            protected void validate(String subject, String body)
2312                    throws PortalException {
2313    
2314                    if (Validator.isNull(subject) && Validator.isNull(body)) {
2315                            throw new MessageSubjectException();
2316                    }
2317            }
2318    
2319            private static Log _log = LogFactoryUtil.getLog(
2320                    MBMessageLocalServiceImpl.class);
2321    
2322    }