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