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