001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.messageboards.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.lock.LockManagerUtil;
020    import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
021    import com.liferay.portal.kernel.util.HtmlUtil;
022    import com.liferay.portal.kernel.util.ObjectValuePair;
023    import com.liferay.portal.kernel.util.ParamUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.workflow.WorkflowConstants;
028    import com.liferay.portal.model.Company;
029    import com.liferay.portal.model.Group;
030    import com.liferay.portal.model.User;
031    import com.liferay.portal.security.auth.PrincipalException;
032    import com.liferay.portal.security.permission.ActionKeys;
033    import com.liferay.portal.security.permission.PermissionChecker;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.PropsValues;
038    import com.liferay.portlet.messageboards.exception.LockedThreadException;
039    import com.liferay.portlet.messageboards.model.MBCategory;
040    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
041    import com.liferay.portlet.messageboards.model.MBMessage;
042    import com.liferay.portlet.messageboards.model.MBMessageConstants;
043    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
044    import com.liferay.portlet.messageboards.model.MBThread;
045    import com.liferay.portlet.messageboards.model.MBThreadConstants;
046    import com.liferay.portlet.messageboards.service.base.MBMessageServiceBaseImpl;
047    import com.liferay.portlet.messageboards.service.permission.MBCategoryPermission;
048    import com.liferay.portlet.messageboards.service.permission.MBDiscussionPermission;
049    import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
050    import com.liferay.portlet.messageboards.util.MBUtil;
051    import com.liferay.portlet.messageboards.util.comparator.MessageCreateDateComparator;
052    import com.liferay.util.RSSUtil;
053    
054    import com.sun.syndication.feed.synd.SyndContent;
055    import com.sun.syndication.feed.synd.SyndContentImpl;
056    import com.sun.syndication.feed.synd.SyndEntry;
057    import com.sun.syndication.feed.synd.SyndEntryImpl;
058    import com.sun.syndication.feed.synd.SyndFeed;
059    import com.sun.syndication.feed.synd.SyndFeedImpl;
060    import com.sun.syndication.feed.synd.SyndLink;
061    import com.sun.syndication.feed.synd.SyndLinkImpl;
062    import com.sun.syndication.io.FeedException;
063    
064    import java.io.File;
065    import java.io.FileInputStream;
066    import java.io.FileNotFoundException;
067    import java.io.InputStream;
068    
069    import java.util.ArrayList;
070    import java.util.Collections;
071    import java.util.Date;
072    import java.util.List;
073    
074    /**
075     * @author Brian Wing Shun Chan
076     * @author Mika Koivisto
077     * @author Shuyang Zhou
078     */
079    public class MBMessageServiceImpl extends MBMessageServiceBaseImpl {
080    
081            @Override
082            public MBMessage addDiscussionMessage(
083                            long groupId, String className, long classPK, long threadId,
084                            long parentMessageId, String subject, String body,
085                            ServiceContext serviceContext)
086                    throws PortalException {
087    
088                    User user = getGuestOrUser();
089    
090                    MBDiscussionPermission.check(
091                            getPermissionChecker(), user.getCompanyId(),
092                            serviceContext.getScopeGroupId(), className, classPK,
093                            ActionKeys.ADD_DISCUSSION);
094    
095                    return mbMessageLocalService.addDiscussionMessage(
096                            user.getUserId(), null, groupId, className, classPK, threadId,
097                            parentMessageId, subject, body, serviceContext);
098            }
099    
100            /**
101             * @deprecated As of 6.2.0, replaced by {@link #addMessage(long, String,
102             *             String, String, List, boolean, double, boolean,
103             *             ServiceContext)}
104             */
105            @Deprecated
106            @Override
107            public MBMessage addMessage(
108                            long groupId, long categoryId, long threadId, long parentMessageId,
109                            String subject, String body, String format,
110                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
111                            boolean anonymous, double priority, boolean allowPingbacks,
112                            ServiceContext serviceContext)
113                    throws PortalException {
114    
115                    return addMessage(
116                            parentMessageId, subject, body, format, inputStreamOVPs, anonymous,
117                            priority, allowPingbacks, serviceContext);
118            }
119    
120            @Override
121            public MBMessage addMessage(
122                            long groupId, long categoryId, String subject, String body,
123                            String format,
124                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
125                            boolean anonymous, double priority, boolean allowPingbacks,
126                            ServiceContext serviceContext)
127                    throws PortalException {
128    
129                    MBCategoryPermission.check(
130                            getPermissionChecker(), groupId, categoryId,
131                            ActionKeys.ADD_MESSAGE);
132    
133                    if (!MBCategoryPermission.contains(
134                                    getPermissionChecker(), groupId, categoryId,
135                                    ActionKeys.ADD_FILE)) {
136    
137                            inputStreamOVPs = Collections.emptyList();
138                    }
139    
140                    if (!MBCategoryPermission.contains(
141                                    getPermissionChecker(), groupId, categoryId,
142                                    ActionKeys.UPDATE_THREAD_PRIORITY)) {
143    
144                            priority = MBThreadConstants.PRIORITY_NOT_GIVEN;
145                    }
146    
147                    return mbMessageLocalService.addMessage(
148                            getGuestOrUserId(), null, groupId, categoryId, subject, body,
149                            format, inputStreamOVPs, anonymous, priority, allowPingbacks,
150                            serviceContext);
151            }
152    
153            @Override
154            public MBMessage addMessage(
155                            long groupId, long categoryId, String subject, String body,
156                            String format, String fileName, File file, boolean anonymous,
157                            double priority, boolean allowPingbacks,
158                            ServiceContext serviceContext)
159                    throws FileNotFoundException, PortalException {
160    
161                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
162                            new ArrayList<>();
163    
164                    InputStream inputStream = new FileInputStream(file);
165    
166                    ObjectValuePair<String, InputStream> inputStreamOVP =
167                            new ObjectValuePair<>(fileName, inputStream);
168    
169                    inputStreamOVPs.add(inputStreamOVP);
170    
171                    return addMessage(
172                            groupId, categoryId, subject, body, format, inputStreamOVPs,
173                            anonymous, priority, allowPingbacks, serviceContext);
174            }
175    
176            @Override
177            public MBMessage addMessage(
178                            long categoryId, String subject, String body,
179                            ServiceContext serviceContext)
180                    throws PortalException {
181    
182                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
183                            categoryId);
184    
185                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
186                            Collections.emptyList();
187    
188                    return addMessage(
189                            category.getGroupId(), categoryId, subject, body,
190                            MBMessageConstants.DEFAULT_FORMAT, inputStreamOVPs, false, 0.0,
191                            false, serviceContext);
192            }
193    
194            @Override
195            public MBMessage addMessage(
196                            long parentMessageId, String subject, String body, String format,
197                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
198                            boolean anonymous, double priority, boolean allowPingbacks,
199                            ServiceContext serviceContext)
200                    throws PortalException {
201    
202                    MBMessage parentMessage = mbMessagePersistence.findByPrimaryKey(
203                            parentMessageId);
204    
205                    checkReplyToPermission(
206                            parentMessage.getGroupId(), parentMessage.getCategoryId(),
207                            parentMessageId);
208    
209                    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");
210    
211                    int workFlowAction = serviceContext.getWorkflowAction();
212    
213                    if ((workFlowAction == WorkflowConstants.STATUS_DRAFT) && !preview &&
214                            !serviceContext.isSignedIn()) {
215    
216                            MBMessagePermission.check(
217                                    getPermissionChecker(), parentMessageId, ActionKeys.UPDATE);
218                    }
219    
220                    if (LockManagerUtil.isLocked(
221                                    MBThread.class.getName(), parentMessage.getThreadId())) {
222    
223                            StringBundler sb = new StringBundler(4);
224    
225                            sb.append("Thread is locked for class name ");
226                            sb.append(MBThread.class.getName());
227                            sb.append(" and class PK ");
228                            sb.append(parentMessage.getThreadId());
229    
230                            throw new LockedThreadException(sb.toString());
231                    }
232    
233                    if (!MBCategoryPermission.contains(
234                                    getPermissionChecker(), parentMessage.getGroupId(),
235                                    parentMessage.getCategoryId(), ActionKeys.ADD_FILE)) {
236    
237                            inputStreamOVPs = Collections.emptyList();
238                    }
239    
240                    if (!MBCategoryPermission.contains(
241                                    getPermissionChecker(), parentMessage.getGroupId(),
242                                    parentMessage.getCategoryId(),
243                                    ActionKeys.UPDATE_THREAD_PRIORITY)) {
244    
245                            priority = MBThreadConstants.PRIORITY_NOT_GIVEN;
246                    }
247    
248                    return mbMessageLocalService.addMessage(
249                            getGuestOrUserId(), null, parentMessage.getGroupId(),
250                            parentMessage.getCategoryId(), parentMessage.getThreadId(),
251                            parentMessageId, subject, body, format, inputStreamOVPs, anonymous,
252                            priority, allowPingbacks, serviceContext);
253            }
254    
255            @Override
256            public void addMessageAttachment(
257                            long messageId, String fileName, File file, String mimeType)
258                    throws PortalException {
259    
260                    MBMessage message = mbMessageLocalService.getMBMessage(messageId);
261    
262                    if (LockManagerUtil.isLocked(
263                                    MBThread.class.getName(), message.getThreadId())) {
264    
265                            StringBundler sb = new StringBundler(4);
266    
267                            sb.append("Thread is locked for class name ");
268                            sb.append(MBThread.class.getName());
269                            sb.append(" and class PK ");
270                            sb.append(message.getThreadId());
271    
272                            throw new LockedThreadException(sb.toString());
273                    }
274    
275                    MBCategoryPermission.contains(
276                            getPermissionChecker(), message.getGroupId(),
277                            message.getCategoryId(), ActionKeys.ADD_FILE);
278    
279                    mbMessageLocalService.addMessageAttachment(
280                            getUserId(), messageId, fileName, file, mimeType);
281            }
282    
283            @Override
284            public void deleteDiscussionMessage(long messageId) throws PortalException {
285                    MBDiscussionPermission.check(
286                            getPermissionChecker(), messageId, ActionKeys.DELETE_DISCUSSION);
287    
288                    mbMessageLocalService.deleteDiscussionMessage(messageId);
289            }
290    
291            /**
292             * @deprecated As of 7.0.0, replaced by {@link
293             *             #deleteDiscussionMessage(long)}
294             */
295            @Deprecated
296            @Override
297            public void deleteDiscussionMessage(
298                            long groupId, String className, long classPK,
299                            String permissionClassName, long permissionClassPK,
300                            long permissionOwnerId, long messageId)
301                    throws PortalException {
302    
303                    deleteDiscussionMessage(messageId);
304            }
305    
306            @Override
307            public void deleteMessage(long messageId) throws PortalException {
308                    MBMessagePermission.check(
309                            getPermissionChecker(), messageId, ActionKeys.DELETE);
310    
311                    mbMessageLocalService.deleteMessage(messageId);
312            }
313    
314            @Override
315            public void deleteMessageAttachment(long messageId, String fileName)
316                    throws PortalException {
317    
318                    MBMessagePermission.check(
319                            getPermissionChecker(), messageId, ActionKeys.UPDATE);
320    
321                    mbMessageLocalService.deleteMessageAttachment(messageId, fileName);
322            }
323    
324            @Override
325            public void deleteMessageAttachments(long messageId)
326                    throws PortalException {
327    
328                    MBMessagePermission.check(
329                            getPermissionChecker(), messageId, ActionKeys.DELETE);
330    
331                    mbMessageLocalService.deleteMessageAttachments(messageId);
332            }
333    
334            @Override
335            public void emptyMessageAttachments(long messageId) throws PortalException {
336                    MBMessagePermission.check(
337                            getPermissionChecker(), messageId, ActionKeys.DELETE);
338    
339                    mbMessageLocalService.emptyMessageAttachments(messageId);
340            }
341    
342            @Override
343            public List<MBMessage> getCategoryMessages(
344                            long groupId, long categoryId, int status, int start, int end)
345                    throws PortalException {
346    
347                    List<MBMessage> messages = new ArrayList<>();
348    
349                    List<MBMessage> categoryMessages =
350                            mbMessageLocalService.getCategoryMessages(
351                                    groupId, categoryId, status, start, end);
352    
353                    for (MBMessage message : categoryMessages) {
354                            if (MBMessagePermission.contains(
355                                            getPermissionChecker(), message, ActionKeys.VIEW)) {
356    
357                                    messages.add(message);
358                            }
359                    }
360    
361                    return messages;
362            }
363    
364            @Override
365            public int getCategoryMessagesCount(
366                    long groupId, long categoryId, int status) {
367    
368                    return mbMessageLocalService.getCategoryMessagesCount(
369                            groupId, categoryId, status);
370            }
371    
372            @Override
373            public String getCategoryMessagesRSS(
374                            long groupId, long categoryId, int status, int max, String type,
375                            double version, String displayStyle, String feedURL,
376                            String entryURL, ThemeDisplay themeDisplay)
377                    throws PortalException {
378    
379                    String name = StringPool.BLANK;
380                    String description = StringPool.BLANK;
381    
382                    MBCategory category = mbCategoryLocalService.fetchMBCategory(
383                            categoryId);
384    
385                    if (category == null) {
386                            Group group = groupLocalService.getGroup(categoryId);
387    
388                            groupId = group.getGroupId();
389                            categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
390                            name = group.getDescriptiveName();
391                            description = group.getDescription();
392                    }
393                    else {
394                            groupId = category.getGroupId();
395                            name = category.getName();
396                            description = category.getDescription();
397                    }
398    
399                    List<MBMessage> messages = new ArrayList<>();
400    
401                    int lastIntervalStart = 0;
402                    boolean listNotExhausted = true;
403                    MessageCreateDateComparator comparator =
404                            new MessageCreateDateComparator(false);
405    
406                    while ((messages.size() < max) && listNotExhausted) {
407                            List<MBMessage> messageList =
408                                    mbMessageLocalService.getCategoryMessages(
409                                            groupId, categoryId, status, lastIntervalStart,
410                                            lastIntervalStart + max, comparator);
411    
412                            lastIntervalStart += max;
413                            listNotExhausted = (messageList.size() == max);
414    
415                            for (MBMessage message : messageList) {
416                                    if (messages.size() >= max) {
417                                            break;
418                                    }
419    
420                                    if (MBMessagePermission.contains(
421                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
422    
423                                            messages.add(message);
424                                    }
425                            }
426                    }
427    
428                    return exportToRSS(
429                            name, description, type, version, displayStyle, feedURL, entryURL,
430                            messages, themeDisplay);
431            }
432    
433            @Override
434            public String getCompanyMessagesRSS(
435                            long companyId, int status, int max, String type, double version,
436                            String displayStyle, String feedURL, String entryURL,
437                            ThemeDisplay themeDisplay)
438                    throws PortalException {
439    
440                    Company company = companyPersistence.findByPrimaryKey(companyId);
441    
442                    String name = company.getName();
443                    String description = company.getName();
444    
445                    List<MBMessage> messages = new ArrayList<>();
446    
447                    int lastIntervalStart = 0;
448                    boolean listNotExhausted = true;
449                    MessageCreateDateComparator comparator =
450                            new MessageCreateDateComparator(false);
451    
452                    while ((messages.size() < max) && listNotExhausted) {
453                            List<MBMessage> messageList =
454                                    mbMessageLocalService.getCompanyMessages(
455                                            companyId, status, lastIntervalStart,
456                                            lastIntervalStart + max, comparator);
457    
458                            lastIntervalStart += max;
459                            listNotExhausted = (messageList.size() == max);
460    
461                            for (MBMessage message : messageList) {
462                                    if (messages.size() >= max) {
463                                            break;
464                                    }
465    
466                                    if (MBMessagePermission.contains(
467                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
468    
469                                            messages.add(message);
470                                    }
471                            }
472                    }
473    
474                    return exportToRSS(
475                            name, description, type, version, displayStyle, feedURL, entryURL,
476                            messages, themeDisplay);
477            }
478    
479            @Override
480            public int getGroupMessagesCount(long groupId, int status) {
481                    if (status == WorkflowConstants.STATUS_ANY) {
482                            return mbMessagePersistence.filterCountByGroupId(groupId);
483                    }
484                    else {
485                            return mbMessagePersistence.filterCountByG_S(groupId, status);
486                    }
487            }
488    
489            @Override
490            public String getGroupMessagesRSS(
491                            long groupId, int status, int max, String type, double version,
492                            String displayStyle, String feedURL, String entryURL,
493                            ThemeDisplay themeDisplay)
494                    throws PortalException {
495    
496                    String name = StringPool.BLANK;
497                    String description = StringPool.BLANK;
498    
499                    List<MBMessage> messages = new ArrayList<>();
500    
501                    int lastIntervalStart = 0;
502                    boolean listNotExhausted = true;
503                    MessageCreateDateComparator comparator =
504                            new MessageCreateDateComparator(false);
505    
506                    while ((messages.size() < max) && listNotExhausted) {
507                            List<MBMessage> messageList =
508                                    mbMessageLocalService.getGroupMessages(
509                                            groupId, status, lastIntervalStart, lastIntervalStart + max,
510                                            comparator);
511    
512                            lastIntervalStart += max;
513                            listNotExhausted = (messageList.size() == max);
514    
515                            for (MBMessage message : messageList) {
516                                    if (messages.size() >= max) {
517                                            break;
518                                    }
519    
520                                    if (MBMessagePermission.contains(
521                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
522    
523                                            messages.add(message);
524                                    }
525                            }
526                    }
527    
528                    if (!messages.isEmpty()) {
529                            MBMessage message = messages.get(messages.size() - 1);
530    
531                            name = message.getSubject();
532                            description = message.getSubject();
533                    }
534    
535                    return exportToRSS(
536                            name, description, type, version, displayStyle, feedURL, entryURL,
537                            messages, themeDisplay);
538            }
539    
540            @Override
541            public String getGroupMessagesRSS(
542                            long groupId, long userId, int status, int max, String type,
543                            double version, String displayStyle, String feedURL,
544                            String entryURL, ThemeDisplay themeDisplay)
545                    throws PortalException {
546    
547                    String name = StringPool.BLANK;
548                    String description = StringPool.BLANK;
549    
550                    List<MBMessage> messages = new ArrayList<>();
551    
552                    int lastIntervalStart = 0;
553                    boolean listNotExhausted = true;
554                    MessageCreateDateComparator comparator =
555                            new MessageCreateDateComparator(false);
556    
557                    while ((messages.size() < max) && listNotExhausted) {
558                            List<MBMessage> messageList =
559                                    mbMessageLocalService.getGroupMessages(
560                                            groupId, userId, status, lastIntervalStart,
561                                            lastIntervalStart + max, comparator);
562    
563                            lastIntervalStart += max;
564                            listNotExhausted = (messageList.size() == max);
565    
566                            for (MBMessage message : messageList) {
567                                    if (messages.size() >= max) {
568                                            break;
569                                    }
570    
571                                    if (MBMessagePermission.contains(
572                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
573    
574                                            messages.add(message);
575                                    }
576                            }
577                    }
578    
579                    if (!messages.isEmpty()) {
580                            MBMessage message = messages.get(messages.size() - 1);
581    
582                            name = message.getSubject();
583                            description = message.getSubject();
584                    }
585    
586                    return exportToRSS(
587                            name, description, type, version, displayStyle, feedURL, entryURL,
588                            messages, themeDisplay);
589            }
590    
591            @Override
592            public MBMessage getMessage(long messageId) throws PortalException {
593                    MBMessagePermission.check(
594                            getPermissionChecker(), messageId, ActionKeys.VIEW);
595    
596                    return mbMessageLocalService.getMessage(messageId);
597            }
598    
599            @Override
600            public MBMessageDisplay getMessageDisplay(
601                            long messageId, int status, boolean includePrevAndNext)
602                    throws PortalException {
603    
604                    MBMessagePermission.check(
605                            getPermissionChecker(), messageId, ActionKeys.VIEW);
606    
607                    return mbMessageLocalService.getMessageDisplay(
608                            getGuestOrUserId(), messageId, status, includePrevAndNext);
609            }
610    
611            /**
612             * @deprecated As of 7.0.0, replaced by {@link #getMessageDisplay(long, int,
613             *             boolean)}
614             */
615            @Deprecated
616            @Override
617            public MBMessageDisplay getMessageDisplay(
618                            long messageId, int status, String threadView,
619                            boolean includePrevAndNext)
620                    throws PortalException {
621    
622                    MBMessagePermission.check(
623                            getPermissionChecker(), messageId, ActionKeys.VIEW);
624    
625                    return mbMessageLocalService.getMessageDisplay(
626                            getGuestOrUserId(), messageId, status, threadView,
627                            includePrevAndNext);
628            }
629    
630            @Override
631            public int getThreadAnswersCount(
632                    long groupId, long categoryId, long threadId) {
633    
634                    return mbMessagePersistence.filterCountByG_C_T_A(
635                            groupId, categoryId, threadId, true);
636            }
637    
638            @Override
639            public List<MBMessage> getThreadMessages(
640                    long groupId, long categoryId, long threadId, int status, int start,
641                    int end) {
642    
643                    if (status == WorkflowConstants.STATUS_ANY) {
644                            return mbMessagePersistence.filterFindByG_C_T(
645                                    groupId, categoryId, threadId, start, end);
646                    }
647                    else {
648                            return mbMessagePersistence.filterFindByG_C_T_S(
649                                    groupId, categoryId, threadId, status, start, end);
650                    }
651            }
652    
653            @Override
654            public int getThreadMessagesCount(
655                    long groupId, long categoryId, long threadId, int status) {
656    
657                    if (status == WorkflowConstants.STATUS_ANY) {
658                            return mbMessagePersistence.filterCountByG_C_T(
659                                    groupId, categoryId, threadId);
660                    }
661                    else {
662                            return mbMessagePersistence.filterCountByG_C_T_S(
663                                    groupId, categoryId, threadId, status);
664                    }
665            }
666    
667            @Override
668            public String getThreadMessagesRSS(
669                            long threadId, int status, int max, String type, double version,
670                            String displayStyle, String feedURL, String entryURL,
671                            ThemeDisplay themeDisplay)
672                    throws PortalException {
673    
674                    String name = StringPool.BLANK;
675                    String description = StringPool.BLANK;
676    
677                    List<MBMessage> messages = new ArrayList<>();
678    
679                    MBThread thread = mbThreadLocalService.getThread(threadId);
680    
681                    if (MBMessagePermission.contains(
682                                    getPermissionChecker(), thread.getRootMessageId(),
683                                    ActionKeys.VIEW)) {
684    
685                            MessageCreateDateComparator comparator =
686                                    new MessageCreateDateComparator(false);
687    
688                            List<MBMessage> threadMessages =
689                                    mbMessageLocalService.getThreadMessages(
690                                            threadId, status, comparator);
691    
692                            for (MBMessage message : threadMessages) {
693                                    if (messages.size() >= max) {
694                                            break;
695                                    }
696    
697                                    if (MBMessagePermission.contains(
698                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
699    
700                                            messages.add(message);
701                                    }
702                            }
703    
704                            if (!messages.isEmpty()) {
705                                    MBMessage message = messages.get(messages.size() - 1);
706    
707                                    name = message.getSubject();
708                                    description = message.getSubject();
709                            }
710                    }
711    
712                    return exportToRSS(
713                            name, description, type, version, displayStyle, feedURL, entryURL,
714                            messages, themeDisplay);
715            }
716    
717            @Override
718            public void restoreMessageAttachmentFromTrash(
719                            long messageId, String fileName)
720                    throws PortalException {
721    
722                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
723    
724                    MBCategoryPermission.check(
725                            getPermissionChecker(), message.getGroupId(),
726                            message.getCategoryId(), ActionKeys.ADD_FILE);
727    
728                    mbMessageLocalService.restoreMessageAttachmentFromTrash(
729                            getUserId(), messageId, fileName);
730            }
731    
732            @Override
733            public void subscribeMessage(long messageId) throws PortalException {
734                    MBMessagePermission.check(
735                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
736    
737                    mbMessageLocalService.subscribeMessage(getUserId(), messageId);
738            }
739    
740            @Override
741            public void unsubscribeMessage(long messageId) throws PortalException {
742                    MBMessagePermission.check(
743                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
744    
745                    mbMessageLocalService.unsubscribeMessage(getUserId(), messageId);
746            }
747    
748            @Override
749            public void updateAnswer(long messageId, boolean answer, boolean cascade)
750                    throws PortalException {
751    
752                    mbMessageLocalService.updateAnswer(messageId, answer, cascade);
753            }
754    
755            @Override
756            public MBMessage updateDiscussionMessage(
757                            String className, long classPK, long messageId, String subject,
758                            String body, ServiceContext serviceContext)
759                    throws PortalException {
760    
761                    MBDiscussionPermission.check(
762                            getPermissionChecker(), messageId, ActionKeys.UPDATE_DISCUSSION);
763    
764                    return mbMessageLocalService.updateDiscussionMessage(
765                            getUserId(), messageId, className, classPK, subject, body,
766                            serviceContext);
767            }
768    
769            @Override
770            public MBMessage updateMessage(
771                            long messageId, String subject, String body,
772                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
773                            List<String> existingFiles, double priority, boolean allowPingbacks,
774                            ServiceContext serviceContext)
775                    throws PortalException {
776    
777                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
778    
779                    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");
780    
781                    if (preview &&
782                            MBMessagePermission.contains(
783                                    getPermissionChecker(), message, ActionKeys.UPDATE)) {
784    
785                            checkReplyToPermission(
786                                    message.getGroupId(), message.getCategoryId(),
787                                    message.getParentMessageId());
788                    }
789                    else {
790                            MBMessagePermission.check(
791                                    getPermissionChecker(), messageId, ActionKeys.UPDATE);
792                    }
793    
794                    if (LockManagerUtil.isLocked(
795                                    MBThread.class.getName(), message.getThreadId())) {
796    
797                            StringBundler sb = new StringBundler(4);
798    
799                            sb.append("Thread is locked for class name ");
800                            sb.append(MBThread.class.getName());
801                            sb.append(" and class PK ");
802                            sb.append(message.getThreadId());
803    
804                            throw new LockedThreadException(sb.toString());
805                    }
806    
807                    if (!MBCategoryPermission.contains(
808                                    getPermissionChecker(), message.getGroupId(),
809                                    message.getCategoryId(), ActionKeys.ADD_FILE)) {
810    
811                            inputStreamOVPs = Collections.emptyList();
812                    }
813    
814                    if (!MBCategoryPermission.contains(
815                                    getPermissionChecker(), message.getGroupId(),
816                                    message.getCategoryId(), ActionKeys.UPDATE_THREAD_PRIORITY)) {
817    
818                            MBThread thread = mbThreadLocalService.getThread(
819                                    message.getThreadId());
820    
821                            priority = thread.getPriority();
822                    }
823    
824                    return mbMessageLocalService.updateMessage(
825                            getGuestOrUserId(), messageId, subject, body, inputStreamOVPs,
826                            existingFiles, priority, allowPingbacks, serviceContext);
827            }
828    
829            protected void checkReplyToPermission(
830                            long groupId, long categoryId, long parentMessageId)
831                    throws PortalException {
832    
833                    PermissionChecker permissionChecker = getPermissionChecker();
834    
835                    if (parentMessageId > 0) {
836                            if (MBCategoryPermission.contains(
837                                            permissionChecker, groupId, categoryId,
838                                            ActionKeys.ADD_MESSAGE)) {
839    
840                                    return;
841                            }
842    
843                            if (!MBCategoryPermission.contains(
844                                            permissionChecker, groupId, categoryId,
845                                            ActionKeys.REPLY_TO_MESSAGE)) {
846    
847                                    throw new PrincipalException.MustHavePermission(
848                                            permissionChecker, MBCategory.class.getName(), categoryId,
849                                            ActionKeys.REPLY_TO_MESSAGE);
850                            }
851                    }
852                    else {
853                            MBCategoryPermission.check(
854                                    permissionChecker, groupId, categoryId, ActionKeys.ADD_MESSAGE);
855                    }
856            }
857    
858            protected String exportToRSS(
859                    String name, String description, String type, double version,
860                    String displayStyle, String feedURL, String entryURL,
861                    List<MBMessage> messages, ThemeDisplay themeDisplay) {
862    
863                    SyndFeed syndFeed = new SyndFeedImpl();
864    
865                    syndFeed.setDescription(description);
866    
867                    List<SyndEntry> syndEntries = new ArrayList<>();
868    
869                    syndFeed.setEntries(syndEntries);
870    
871                    for (MBMessage message : messages) {
872                            SyndEntry syndEntry = new SyndEntryImpl();
873    
874                            if (!message.isAnonymous()) {
875                                    String author = PortalUtil.getUserName(message);
876    
877                                    syndEntry.setAuthor(author);
878                            }
879    
880                            SyndContent syndContent = new SyndContentImpl();
881    
882                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
883    
884                            String value = null;
885    
886                            if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
887                                    value = StringUtil.shorten(
888                                            HtmlUtil.extractText(message.getBody()),
889                                            PropsValues.MESSAGE_BOARDS_RSS_ABSTRACT_LENGTH,
890                                            StringPool.BLANK);
891                            }
892                            else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
893                                    value = StringPool.BLANK;
894                            }
895                            else if (message.isFormatBBCode()) {
896                                    value = BBCodeTranslatorUtil.getHTML(message.getBody());
897    
898                                    value = MBUtil.replaceMessageBodyPaths(themeDisplay, value);
899                            }
900                            else {
901                                    value = message.getBody();
902                            }
903    
904                            syndContent.setValue(value);
905    
906                            syndEntry.setDescription(syndContent);
907    
908                            syndEntry.setLink(
909                                    entryURL + "&messageId=" + message.getMessageId());
910                            syndEntry.setPublishedDate(message.getCreateDate());
911                            syndEntry.setTitle(message.getSubject());
912                            syndEntry.setUpdatedDate(message.getModifiedDate());
913                            syndEntry.setUri(syndEntry.getLink());
914    
915                            syndEntries.add(syndEntry);
916                    }
917    
918                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
919    
920                    List<SyndLink> syndLinks = new ArrayList<>();
921    
922                    syndFeed.setLinks(syndLinks);
923    
924                    SyndLink selfSyndLink = new SyndLinkImpl();
925    
926                    syndLinks.add(selfSyndLink);
927    
928                    selfSyndLink.setHref(feedURL);
929                    selfSyndLink.setRel("self");
930    
931                    syndFeed.setPublishedDate(new Date());
932                    syndFeed.setTitle(name);
933                    syndFeed.setUri(feedURL);
934    
935                    try {
936                            return RSSUtil.export(syndFeed);
937                    }
938                    catch (FeedException fe) {
939                            throw new SystemException(fe);
940                    }
941            }
942    
943    }