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.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, String threadView,
602                            boolean includePrevAndNext)
603                    throws PortalException {
604    
605                    MBMessagePermission.check(
606                            getPermissionChecker(), messageId, ActionKeys.VIEW);
607    
608                    return mbMessageLocalService.getMessageDisplay(
609                            getGuestOrUserId(), messageId, status, threadView,
610                            includePrevAndNext);
611            }
612    
613            @Override
614            public int getThreadAnswersCount(
615                    long groupId, long categoryId, long threadId) {
616    
617                    return mbMessagePersistence.filterCountByG_C_T_A(
618                            groupId, categoryId, threadId, true);
619            }
620    
621            @Override
622            public List<MBMessage> getThreadMessages(
623                    long groupId, long categoryId, long threadId, int status, int start,
624                    int end) {
625    
626                    if (status == WorkflowConstants.STATUS_ANY) {
627                            return mbMessagePersistence.filterFindByG_C_T(
628                                    groupId, categoryId, threadId, start, end);
629                    }
630                    else {
631                            return mbMessagePersistence.filterFindByG_C_T_S(
632                                    groupId, categoryId, threadId, status, start, end);
633                    }
634            }
635    
636            @Override
637            public int getThreadMessagesCount(
638                    long groupId, long categoryId, long threadId, int status) {
639    
640                    if (status == WorkflowConstants.STATUS_ANY) {
641                            return mbMessagePersistence.filterCountByG_C_T(
642                                    groupId, categoryId, threadId);
643                    }
644                    else {
645                            return mbMessagePersistence.filterCountByG_C_T_S(
646                                    groupId, categoryId, threadId, status);
647                    }
648            }
649    
650            @Override
651            public String getThreadMessagesRSS(
652                            long threadId, int status, int max, String type, double version,
653                            String displayStyle, String feedURL, String entryURL,
654                            ThemeDisplay themeDisplay)
655                    throws PortalException {
656    
657                    String name = StringPool.BLANK;
658                    String description = StringPool.BLANK;
659    
660                    List<MBMessage> messages = new ArrayList<>();
661    
662                    MBThread thread = mbThreadLocalService.getThread(threadId);
663    
664                    if (MBMessagePermission.contains(
665                                    getPermissionChecker(), thread.getRootMessageId(),
666                                    ActionKeys.VIEW)) {
667    
668                            MessageCreateDateComparator comparator =
669                                    new MessageCreateDateComparator(false);
670    
671                            List<MBMessage> threadMessages =
672                                    mbMessageLocalService.getThreadMessages(
673                                            threadId, status, comparator);
674    
675                            for (MBMessage message : threadMessages) {
676                                    if (messages.size() >= max) {
677                                            break;
678                                    }
679    
680                                    if (MBMessagePermission.contains(
681                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
682    
683                                            messages.add(message);
684                                    }
685                            }
686    
687                            if (!messages.isEmpty()) {
688                                    MBMessage message = messages.get(messages.size() - 1);
689    
690                                    name = message.getSubject();
691                                    description = message.getSubject();
692                            }
693                    }
694    
695                    return exportToRSS(
696                            name, description, type, version, displayStyle, feedURL, entryURL,
697                            messages, themeDisplay);
698            }
699    
700            @Override
701            public void restoreMessageAttachmentFromTrash(
702                            long messageId, String fileName)
703                    throws PortalException {
704    
705                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
706    
707                    MBCategoryPermission.check(
708                            getPermissionChecker(), message.getGroupId(),
709                            message.getCategoryId(), ActionKeys.ADD_FILE);
710    
711                    mbMessageLocalService.restoreMessageAttachmentFromTrash(
712                            getUserId(), messageId, fileName);
713            }
714    
715            @Override
716            public void subscribeMessage(long messageId) throws PortalException {
717                    MBMessagePermission.check(
718                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
719    
720                    mbMessageLocalService.subscribeMessage(getUserId(), messageId);
721            }
722    
723            @Override
724            public void unsubscribeMessage(long messageId) throws PortalException {
725                    MBMessagePermission.check(
726                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
727    
728                    mbMessageLocalService.unsubscribeMessage(getUserId(), messageId);
729            }
730    
731            @Override
732            public void updateAnswer(long messageId, boolean answer, boolean cascade)
733                    throws PortalException {
734    
735                    mbMessageLocalService.updateAnswer(messageId, answer, cascade);
736            }
737    
738            @Override
739            public MBMessage updateDiscussionMessage(
740                            String className, long classPK, long messageId, String subject,
741                            String body, ServiceContext serviceContext)
742                    throws PortalException {
743    
744                    MBDiscussionPermission.check(
745                            getPermissionChecker(), messageId, ActionKeys.UPDATE_DISCUSSION);
746    
747                    return mbMessageLocalService.updateDiscussionMessage(
748                            getUserId(), messageId, className, classPK, subject, body,
749                            serviceContext);
750            }
751    
752            @Override
753            public MBMessage updateMessage(
754                            long messageId, String subject, String body,
755                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
756                            List<String> existingFiles, double priority, boolean allowPingbacks,
757                            ServiceContext serviceContext)
758                    throws PortalException {
759    
760                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
761    
762                    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");
763    
764                    if (preview &&
765                            MBMessagePermission.contains(
766                                    getPermissionChecker(), message, ActionKeys.UPDATE)) {
767    
768                            checkReplyToPermission(
769                                    message.getGroupId(), message.getCategoryId(),
770                                    message.getParentMessageId());
771                    }
772                    else {
773                            MBMessagePermission.check(
774                                    getPermissionChecker(), messageId, ActionKeys.UPDATE);
775                    }
776    
777                    if (LockManagerUtil.isLocked(
778                                    MBThread.class.getName(), message.getThreadId())) {
779    
780                            StringBundler sb = new StringBundler(5);
781    
782                            sb.append("Thread is locked for class name ");
783                            sb.append(MBThread.class.getName());
784                            sb.append(" and class PK ");
785                            sb.append(message.getThreadId());
786    
787                            throw new LockedThreadException(sb.toString());
788                    }
789    
790                    if (!MBCategoryPermission.contains(
791                                    getPermissionChecker(), message.getGroupId(),
792                                    message.getCategoryId(), ActionKeys.ADD_FILE)) {
793    
794                            inputStreamOVPs = Collections.emptyList();
795                    }
796    
797                    if (!MBCategoryPermission.contains(
798                                    getPermissionChecker(), message.getGroupId(),
799                                    message.getCategoryId(), ActionKeys.UPDATE_THREAD_PRIORITY)) {
800    
801                            MBThread thread = mbThreadLocalService.getThread(
802                                    message.getThreadId());
803    
804                            priority = thread.getPriority();
805                    }
806    
807                    return mbMessageLocalService.updateMessage(
808                            getGuestOrUserId(), messageId, subject, body, inputStreamOVPs,
809                            existingFiles, priority, allowPingbacks, serviceContext);
810            }
811    
812            protected void checkReplyToPermission(
813                            long groupId, long categoryId, long parentMessageId)
814                    throws PortalException {
815    
816                    PermissionChecker permissionChecker = getPermissionChecker();
817    
818                    if (parentMessageId > 0) {
819                            if (MBCategoryPermission.contains(
820                                            permissionChecker, groupId, categoryId,
821                                            ActionKeys.ADD_MESSAGE)) {
822    
823                                    return;
824                            }
825    
826                            if (!MBCategoryPermission.contains(
827                                            permissionChecker, groupId, categoryId,
828                                            ActionKeys.REPLY_TO_MESSAGE)) {
829    
830                                    throw new PrincipalException.MustHavePermission(
831                                            permissionChecker, MBCategory.class.getName(), categoryId,
832                                            ActionKeys.REPLY_TO_MESSAGE);
833                            }
834                    }
835                    else {
836                            MBCategoryPermission.check(
837                                    permissionChecker, groupId, categoryId, ActionKeys.ADD_MESSAGE);
838                    }
839            }
840    
841            protected String exportToRSS(
842                    String name, String description, String type, double version,
843                    String displayStyle, String feedURL, String entryURL,
844                    List<MBMessage> messages, ThemeDisplay themeDisplay) {
845    
846                    SyndFeed syndFeed = new SyndFeedImpl();
847    
848                    syndFeed.setDescription(description);
849    
850                    List<SyndEntry> syndEntries = new ArrayList<>();
851    
852                    syndFeed.setEntries(syndEntries);
853    
854                    for (MBMessage message : messages) {
855                            SyndEntry syndEntry = new SyndEntryImpl();
856    
857                            if (!message.isAnonymous()) {
858                                    String author = PortalUtil.getUserName(message);
859    
860                                    syndEntry.setAuthor(author);
861                            }
862    
863                            SyndContent syndContent = new SyndContentImpl();
864    
865                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
866    
867                            String value = null;
868    
869                            if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
870                                    value = StringUtil.shorten(
871                                            HtmlUtil.extractText(message.getBody()),
872                                            PropsValues.MESSAGE_BOARDS_RSS_ABSTRACT_LENGTH,
873                                            StringPool.BLANK);
874                            }
875                            else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
876                                    value = StringPool.BLANK;
877                            }
878                            else if (message.isFormatBBCode()) {
879                                    value = BBCodeTranslatorUtil.getHTML(message.getBody());
880    
881                                    value = MBUtil.replaceMessageBodyPaths(themeDisplay, value);
882                            }
883                            else {
884                                    value = message.getBody();
885                            }
886    
887                            syndContent.setValue(value);
888    
889                            syndEntry.setDescription(syndContent);
890    
891                            syndEntry.setLink(
892                                    entryURL + "&messageId=" + message.getMessageId());
893                            syndEntry.setPublishedDate(message.getCreateDate());
894                            syndEntry.setTitle(message.getSubject());
895                            syndEntry.setUpdatedDate(message.getModifiedDate());
896                            syndEntry.setUri(syndEntry.getLink());
897    
898                            syndEntries.add(syndEntry);
899                    }
900    
901                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
902    
903                    List<SyndLink> syndLinks = new ArrayList<>();
904    
905                    syndFeed.setLinks(syndLinks);
906    
907                    SyndLink selfSyndLink = new SyndLinkImpl();
908    
909                    syndLinks.add(selfSyndLink);
910    
911                    selfSyndLink.setHref(feedURL);
912                    selfSyndLink.setRel("self");
913    
914                    syndFeed.setPublishedDate(new Date());
915                    syndFeed.setTitle(name);
916                    syndFeed.setUri(feedURL);
917    
918                    try {
919                            return RSSUtil.export(syndFeed);
920                    }
921                    catch (FeedException fe) {
922                            throw new SystemException(fe);
923                    }
924            }
925    
926    }