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