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.security.auth.PrincipalException;
022    import com.liferay.portal.kernel.security.permission.ActionKeys;
023    import com.liferay.portal.kernel.security.permission.PermissionChecker;
024    import com.liferay.portal.kernel.util.HtmlUtil;
025    import com.liferay.portal.kernel.util.ObjectValuePair;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.workflow.WorkflowConstants;
031    import com.liferay.portal.model.Company;
032    import com.liferay.portal.model.Group;
033    import com.liferay.portal.model.User;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.PropsValues;
038    import com.liferay.portlet.messageboards.exception.LockedThreadException;
039    import com.liferay.portlet.messageboards.model.MBCategory;
040    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
041    import com.liferay.portlet.messageboards.model.MBMessage;
042    import com.liferay.portlet.messageboards.model.MBMessageConstants;
043    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
044    import com.liferay.portlet.messageboards.model.MBThread;
045    import com.liferay.portlet.messageboards.model.MBThreadConstants;
046    import com.liferay.portlet.messageboards.service.base.MBMessageServiceBaseImpl;
047    import com.liferay.portlet.messageboards.service.permission.MBCategoryPermission;
048    import com.liferay.portlet.messageboards.service.permission.MBDiscussionPermission;
049    import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
050    import com.liferay.portlet.messageboards.util.MBUtil;
051    import com.liferay.portlet.messageboards.util.comparator.MessageCreateDateComparator;
052    import com.liferay.util.RSSUtil;
053    
054    import com.sun.syndication.feed.synd.SyndContent;
055    import com.sun.syndication.feed.synd.SyndContentImpl;
056    import com.sun.syndication.feed.synd.SyndEntry;
057    import com.sun.syndication.feed.synd.SyndEntryImpl;
058    import com.sun.syndication.feed.synd.SyndFeed;
059    import com.sun.syndication.feed.synd.SyndFeedImpl;
060    import com.sun.syndication.feed.synd.SyndLink;
061    import com.sun.syndication.feed.synd.SyndLinkImpl;
062    import com.sun.syndication.io.FeedException;
063    
064    import java.io.File;
065    import java.io.FileInputStream;
066    import java.io.FileNotFoundException;
067    import java.io.InputStream;
068    
069    import java.util.ArrayList;
070    import java.util.Collections;
071    import java.util.Date;
072    import java.util.List;
073    
074    /**
075     * @author Brian Wing Shun Chan
076     * @author Mika Koivisto
077     * @author Shuyang Zhou
078     */
079    public class MBMessageServiceImpl extends MBMessageServiceBaseImpl {
080    
081            @Override
082            public MBMessage addDiscussionMessage(
083                            long groupId, String className, long classPK, long threadId,
084                            long parentMessageId, String subject, String body,
085                            ServiceContext serviceContext)
086                    throws PortalException {
087    
088                    User user = getGuestOrUser();
089    
090                    MBDiscussionPermission.check(
091                            getPermissionChecker(), user.getCompanyId(),
092                            serviceContext.getScopeGroupId(), className, classPK,
093                            ActionKeys.ADD_DISCUSSION);
094    
095                    return mbMessageLocalService.addDiscussionMessage(
096                            user.getUserId(), null, groupId, className, classPK, threadId,
097                            parentMessageId, subject, body, serviceContext);
098            }
099    
100            @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(
581                            long messageId, int status, boolean includePrevAndNext)
582                    throws PortalException {
583    
584                    MBMessagePermission.check(
585                            getPermissionChecker(), messageId, ActionKeys.VIEW);
586    
587                    return mbMessageLocalService.getMessageDisplay(
588                            getGuestOrUserId(), messageId, status, includePrevAndNext);
589            }
590    
591            /**
592             * @deprecated As of 7.0.0, replaced by {@link #getMessageDisplay(long, int,
593             *             boolean)}
594             */
595            @Deprecated
596            @Override
597            public MBMessageDisplay getMessageDisplay(
598                            long messageId, int status, String threadView,
599                            boolean includePrevAndNext)
600                    throws PortalException {
601    
602                    MBMessagePermission.check(
603                            getPermissionChecker(), messageId, ActionKeys.VIEW);
604    
605                    return mbMessageLocalService.getMessageDisplay(
606                            getGuestOrUserId(), messageId, status, threadView,
607                            includePrevAndNext);
608            }
609    
610            @Override
611            public int getThreadAnswersCount(
612                    long groupId, long categoryId, long threadId) {
613    
614                    return mbMessagePersistence.filterCountByG_C_T_A(
615                            groupId, categoryId, threadId, true);
616            }
617    
618            @Override
619            public List<MBMessage> getThreadMessages(
620                    long groupId, long categoryId, long threadId, int status, int start,
621                    int end) {
622    
623                    if (status == WorkflowConstants.STATUS_ANY) {
624                            return mbMessagePersistence.filterFindByG_C_T(
625                                    groupId, categoryId, threadId, start, end);
626                    }
627                    else {
628                            return mbMessagePersistence.filterFindByG_C_T_S(
629                                    groupId, categoryId, threadId, status, start, end);
630                    }
631            }
632    
633            @Override
634            public int getThreadMessagesCount(
635                    long groupId, long categoryId, long threadId, int status) {
636    
637                    if (status == WorkflowConstants.STATUS_ANY) {
638                            return mbMessagePersistence.filterCountByG_C_T(
639                                    groupId, categoryId, threadId);
640                    }
641                    else {
642                            return mbMessagePersistence.filterCountByG_C_T_S(
643                                    groupId, categoryId, threadId, status);
644                    }
645            }
646    
647            @Override
648            public String getThreadMessagesRSS(
649                            long threadId, int status, int max, String type, double version,
650                            String displayStyle, String feedURL, String entryURL,
651                            ThemeDisplay themeDisplay)
652                    throws PortalException {
653    
654                    String name = StringPool.BLANK;
655                    String description = StringPool.BLANK;
656    
657                    List<MBMessage> messages = new ArrayList<>();
658    
659                    MBThread thread = mbThreadLocalService.getThread(threadId);
660    
661                    if (MBMessagePermission.contains(
662                                    getPermissionChecker(), thread.getRootMessageId(),
663                                    ActionKeys.VIEW)) {
664    
665                            MessageCreateDateComparator comparator =
666                                    new MessageCreateDateComparator(false);
667    
668                            List<MBMessage> threadMessages =
669                                    mbMessageLocalService.getThreadMessages(
670                                            threadId, status, comparator);
671    
672                            for (MBMessage message : threadMessages) {
673                                    if (messages.size() >= max) {
674                                            break;
675                                    }
676    
677                                    if (MBMessagePermission.contains(
678                                                    getPermissionChecker(), message, ActionKeys.VIEW)) {
679    
680                                            messages.add(message);
681                                    }
682                            }
683    
684                            if (!messages.isEmpty()) {
685                                    MBMessage message = messages.get(messages.size() - 1);
686    
687                                    name = message.getSubject();
688                                    description = message.getSubject();
689                            }
690                    }
691    
692                    return exportToRSS(
693                            name, description, type, version, displayStyle, feedURL, entryURL,
694                            messages, themeDisplay);
695            }
696    
697            @Override
698            public void restoreMessageAttachmentFromTrash(
699                            long messageId, String fileName)
700                    throws PortalException {
701    
702                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
703    
704                    MBCategoryPermission.check(
705                            getPermissionChecker(), message.getGroupId(),
706                            message.getCategoryId(), ActionKeys.ADD_FILE);
707    
708                    mbMessageLocalService.restoreMessageAttachmentFromTrash(
709                            getUserId(), messageId, fileName);
710            }
711    
712            @Override
713            public void subscribeMessage(long messageId) throws PortalException {
714                    MBMessagePermission.check(
715                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
716    
717                    mbMessageLocalService.subscribeMessage(getUserId(), messageId);
718            }
719    
720            @Override
721            public void unsubscribeMessage(long messageId) throws PortalException {
722                    MBMessagePermission.check(
723                            getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
724    
725                    mbMessageLocalService.unsubscribeMessage(getUserId(), messageId);
726            }
727    
728            @Override
729            public void updateAnswer(long messageId, boolean answer, boolean cascade)
730                    throws PortalException {
731    
732                    mbMessageLocalService.updateAnswer(messageId, answer, cascade);
733            }
734    
735            @Override
736            public MBMessage updateDiscussionMessage(
737                            String className, long classPK, long messageId, String subject,
738                            String body, ServiceContext serviceContext)
739                    throws PortalException {
740    
741                    MBDiscussionPermission.check(
742                            getPermissionChecker(), messageId, ActionKeys.UPDATE_DISCUSSION);
743    
744                    return mbMessageLocalService.updateDiscussionMessage(
745                            getUserId(), messageId, className, classPK, subject, body,
746                            serviceContext);
747            }
748    
749            @Override
750            public MBMessage updateMessage(
751                            long messageId, String subject, String body,
752                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
753                            List<String> existingFiles, double priority, boolean allowPingbacks,
754                            ServiceContext serviceContext)
755                    throws PortalException {
756    
757                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
758    
759                    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");
760    
761                    if (preview &&
762                            MBMessagePermission.contains(
763                                    getPermissionChecker(), message, ActionKeys.UPDATE)) {
764    
765                            checkReplyToPermission(
766                                    message.getGroupId(), message.getCategoryId(),
767                                    message.getParentMessageId());
768                    }
769                    else {
770                            MBMessagePermission.check(
771                                    getPermissionChecker(), messageId, ActionKeys.UPDATE);
772                    }
773    
774                    if (LockManagerUtil.isLocked(
775                                    MBThread.class.getName(), message.getThreadId())) {
776    
777                            StringBundler sb = new StringBundler(4);
778    
779                            sb.append("Thread is locked for class name ");
780                            sb.append(MBThread.class.getName());
781                            sb.append(" and class PK ");
782                            sb.append(message.getThreadId());
783    
784                            throw new LockedThreadException(sb.toString());
785                    }
786    
787                    if (!MBCategoryPermission.contains(
788                                    getPermissionChecker(), message.getGroupId(),
789                                    message.getCategoryId(), ActionKeys.ADD_FILE)) {
790    
791                            inputStreamOVPs = Collections.emptyList();
792                    }
793    
794                    if (!MBCategoryPermission.contains(
795                                    getPermissionChecker(), message.getGroupId(),
796                                    message.getCategoryId(), ActionKeys.UPDATE_THREAD_PRIORITY)) {
797    
798                            MBThread thread = mbThreadLocalService.getThread(
799                                    message.getThreadId());
800    
801                            priority = thread.getPriority();
802                    }
803    
804                    return mbMessageLocalService.updateMessage(
805                            getGuestOrUserId(), messageId, subject, body, inputStreamOVPs,
806                            existingFiles, priority, allowPingbacks, serviceContext);
807            }
808    
809            protected void checkReplyToPermission(
810                            long groupId, long categoryId, long parentMessageId)
811                    throws PortalException {
812    
813                    PermissionChecker permissionChecker = getPermissionChecker();
814    
815                    if (parentMessageId > 0) {
816                            if (MBCategoryPermission.contains(
817                                            permissionChecker, groupId, categoryId,
818                                            ActionKeys.ADD_MESSAGE)) {
819    
820                                    return;
821                            }
822    
823                            if (!MBCategoryPermission.contains(
824                                            permissionChecker, groupId, categoryId,
825                                            ActionKeys.REPLY_TO_MESSAGE)) {
826    
827                                    throw new PrincipalException.MustHavePermission(
828                                            permissionChecker, MBCategory.class.getName(), categoryId,
829                                            ActionKeys.REPLY_TO_MESSAGE);
830                            }
831                    }
832                    else {
833                            MBCategoryPermission.check(
834                                    permissionChecker, groupId, categoryId, ActionKeys.ADD_MESSAGE);
835                    }
836            }
837    
838            protected String exportToRSS(
839                    String name, String description, String type, double version,
840                    String displayStyle, String feedURL, String entryURL,
841                    List<MBMessage> messages, ThemeDisplay themeDisplay) {
842    
843                    SyndFeed syndFeed = new SyndFeedImpl();
844    
845                    syndFeed.setDescription(description);
846    
847                    List<SyndEntry> syndEntries = new ArrayList<>();
848    
849                    syndFeed.setEntries(syndEntries);
850    
851                    for (MBMessage message : messages) {
852                            SyndEntry syndEntry = new SyndEntryImpl();
853    
854                            if (!message.isAnonymous()) {
855                                    String author = PortalUtil.getUserName(message);
856    
857                                    syndEntry.setAuthor(author);
858                            }
859    
860                            SyndContent syndContent = new SyndContentImpl();
861    
862                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
863    
864                            String value = null;
865    
866                            if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
867                                    value = StringUtil.shorten(
868                                            HtmlUtil.extractText(message.getBody()),
869                                            PropsValues.MESSAGE_BOARDS_RSS_ABSTRACT_LENGTH,
870                                            StringPool.BLANK);
871                            }
872                            else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
873                                    value = StringPool.BLANK;
874                            }
875                            else if (message.isFormatBBCode()) {
876                                    value = BBCodeTranslatorUtil.getHTML(message.getBody());
877    
878                                    value = MBUtil.replaceMessageBodyPaths(themeDisplay, value);
879                            }
880                            else {
881                                    value = message.getBody();
882                            }
883    
884                            syndContent.setValue(value);
885    
886                            syndEntry.setDescription(syndContent);
887    
888                            syndEntry.setLink(
889                                    entryURL + "&messageId=" + message.getMessageId());
890                            syndEntry.setPublishedDate(message.getCreateDate());
891                            syndEntry.setTitle(message.getSubject());
892                            syndEntry.setUpdatedDate(message.getModifiedDate());
893                            syndEntry.setUri(syndEntry.getLink());
894    
895                            syndEntries.add(syndEntry);
896                    }
897    
898                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
899    
900                    List<SyndLink> syndLinks = new ArrayList<>();
901    
902                    syndFeed.setLinks(syndLinks);
903    
904                    SyndLink selfSyndLink = new SyndLinkImpl();
905    
906                    syndLinks.add(selfSyndLink);
907    
908                    selfSyndLink.setHref(feedURL);
909                    selfSyndLink.setRel("self");
910    
911                    syndFeed.setPublishedDate(new Date());
912                    syndFeed.setTitle(name);
913                    syndFeed.setUri(feedURL);
914    
915                    try {
916                            return RSSUtil.export(syndFeed);
917                    }
918                    catch (FeedException fe) {
919                            throw new SystemException(fe);
920                    }
921            }
922    
923    }