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