1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.messageboards.service.impl;
16  
17  import com.liferay.portal.kernel.exception.PortalException;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.util.GetterUtil;
20  import com.liferay.portal.kernel.util.HtmlUtil;
21  import com.liferay.portal.kernel.util.ObjectValuePair;
22  import com.liferay.portal.kernel.util.PropsKeys;
23  import com.liferay.portal.kernel.util.StringPool;
24  import com.liferay.portal.kernel.util.StringUtil;
25  import com.liferay.portal.model.Company;
26  import com.liferay.portal.model.Group;
27  import com.liferay.portal.model.User;
28  import com.liferay.portal.security.auth.PrincipalException;
29  import com.liferay.portal.security.permission.ActionKeys;
30  import com.liferay.portal.service.ServiceContext;
31  import com.liferay.portal.theme.ThemeDisplay;
32  import com.liferay.portal.util.PortalUtil;
33  import com.liferay.portal.util.PropsUtil;
34  import com.liferay.portlet.messageboards.LockedThreadException;
35  import com.liferay.portlet.messageboards.NoSuchCategoryException;
36  import com.liferay.portlet.messageboards.model.MBCategory;
37  import com.liferay.portlet.messageboards.model.MBMessage;
38  import com.liferay.portlet.messageboards.model.MBMessageDisplay;
39  import com.liferay.portlet.messageboards.model.MBThread;
40  import com.liferay.portlet.messageboards.model.MBThreadConstants;
41  import com.liferay.portlet.messageboards.service.base.MBMessageServiceBaseImpl;
42  import com.liferay.portlet.messageboards.service.permission.MBCategoryPermission;
43  import com.liferay.portlet.messageboards.service.permission.MBDiscussionPermission;
44  import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
45  import com.liferay.portlet.messageboards.util.BBCodeUtil;
46  import com.liferay.portlet.messageboards.util.comparator.MessageCreateDateComparator;
47  import com.liferay.util.RSSUtil;
48  
49  import com.sun.syndication.feed.synd.SyndContent;
50  import com.sun.syndication.feed.synd.SyndContentImpl;
51  import com.sun.syndication.feed.synd.SyndEntry;
52  import com.sun.syndication.feed.synd.SyndEntryImpl;
53  import com.sun.syndication.feed.synd.SyndFeed;
54  import com.sun.syndication.feed.synd.SyndFeedImpl;
55  import com.sun.syndication.io.FeedException;
56  
57  import java.util.ArrayList;
58  import java.util.Iterator;
59  import java.util.List;
60  
61  /**
62   * <a href="MBMessageServiceImpl.java.html"><b><i>View Source</i></b></a>
63   *
64   * @author Brian Wing Shun Chan
65   * @author Mika Koivisto
66   */
67  public class MBMessageServiceImpl extends MBMessageServiceBaseImpl {
68  
69      public MBMessage addDiscussionMessage(
70              String className, long classPK, long threadId,
71              long parentMessageId, String subject, String body,
72              ServiceContext serviceContext)
73          throws PortalException, SystemException {
74  
75          User user = getUser();
76  
77          MBDiscussionPermission.check(
78              getPermissionChecker(), user.getCompanyId(),
79              serviceContext.getScopeGroupId(), className, classPK,
80              user.getUserId(), ActionKeys.ADD_DISCUSSION);
81  
82          return mbMessageLocalService.addDiscussionMessage(
83              getUserId(), null, className, classPK, threadId,
84              parentMessageId, subject, body, serviceContext);
85      }
86  
87      public MBMessage addMessage(
88              long groupId, long categoryId, String subject, String body,
89              List<ObjectValuePair<String, byte[]>> files,
90              boolean anonymous, double priority, boolean allowPingbacks,
91              ServiceContext serviceContext)
92          throws PortalException, SystemException {
93  
94          MBCategoryPermission.check(
95              getPermissionChecker(), groupId, categoryId,
96              ActionKeys.ADD_MESSAGE);
97  
98          if (!MBCategoryPermission.contains(
99                  getPermissionChecker(), groupId, categoryId,
100                 ActionKeys.ADD_FILE)) {
101 
102             files.clear();
103         }
104 
105         if (!MBCategoryPermission.contains(
106                 getPermissionChecker(), groupId, categoryId,
107                 ActionKeys.UPDATE_THREAD_PRIORITY)) {
108 
109             priority = MBThreadConstants.PRIORITY_NOT_GIVEN;
110         }
111 
112         return mbMessageLocalService.addMessage(
113             getGuestOrUserId(), null, groupId, categoryId, subject, body, files,
114             anonymous, priority, allowPingbacks, serviceContext);
115     }
116 
117     public MBMessage addMessage(
118             long groupId, long categoryId, long threadId, long parentMessageId,
119             String subject, String body,
120             List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
121             double priority, boolean allowPingbacks,
122             ServiceContext serviceContext)
123         throws PortalException, SystemException {
124 
125         checkReplyToPermission(groupId, categoryId, parentMessageId);
126 
127         if (lockLocalService.isLocked(
128                 MBThread.class.getName(), threadId)) {
129 
130             throw new LockedThreadException();
131         }
132 
133         if (!MBCategoryPermission.contains(
134                 getPermissionChecker(), groupId, categoryId,
135                 ActionKeys.ADD_FILE)) {
136 
137             files.clear();
138         }
139 
140         if (!MBCategoryPermission.contains(
141                 getPermissionChecker(), groupId, categoryId,
142                 ActionKeys.UPDATE_THREAD_PRIORITY)) {
143 
144             priority = MBThreadConstants.PRIORITY_NOT_GIVEN;
145         }
146 
147         return mbMessageLocalService.addMessage(
148             getGuestOrUserId(), null, groupId, categoryId, threadId,
149             parentMessageId, subject, body, files, anonymous, priority,
150             allowPingbacks, serviceContext);
151     }
152 
153     public void deleteDiscussionMessage(
154             long groupId, String className, long classPK, long messageId)
155         throws PortalException, SystemException {
156 
157         User user = getUser();
158 
159         MBDiscussionPermission.check(
160             getPermissionChecker(), user.getCompanyId(), groupId, className,
161             classPK, messageId, user.getUserId(), ActionKeys.DELETE_DISCUSSION);
162 
163         mbMessageLocalService.deleteDiscussionMessage(messageId);
164     }
165 
166     public void deleteMessage(long messageId)
167         throws PortalException, SystemException {
168 
169         MBMessagePermission.check(
170             getPermissionChecker(), messageId, ActionKeys.DELETE);
171 
172         mbMessageLocalService.deleteMessage(messageId);
173     }
174 
175     public List<MBMessage> getCategoryMessages(
176             long groupId, long categoryId, int status, int start, int end)
177         throws PortalException, SystemException {
178 
179         List<MBMessage> messages = new ArrayList<MBMessage>();
180 
181         Iterator<MBMessage> itr = mbMessageLocalService.getCategoryMessages(
182             groupId, categoryId, status, start, end).iterator();
183 
184         while (itr.hasNext()) {
185             MBMessage message = itr.next();
186 
187             if (MBMessagePermission.contains(
188                     getPermissionChecker(), message, ActionKeys.VIEW)) {
189 
190                 messages.add(message);
191             }
192         }
193 
194         return messages;
195     }
196 
197     public int getCategoryMessagesCount(
198             long groupId, long categoryId, int status)
199         throws SystemException {
200 
201         return mbMessageLocalService.getCategoryMessagesCount(
202             groupId, categoryId, status);
203     }
204 
205     public String getCategoryMessagesRSS(
206             long groupId, long categoryId, int status, int max, String type,
207             double version, String displayStyle, String feedURL,
208             String entryURL, ThemeDisplay themeDisplay)
209         throws PortalException, SystemException {
210 
211         String name = StringPool.BLANK;
212         String description = StringPool.BLANK;
213 
214         try {
215             MBCategory category = mbCategoryLocalService.getCategory(
216                 categoryId);
217 
218             name = category.getName();
219             description = category.getDescription();
220         }
221         catch (NoSuchCategoryException nsce) {
222             Group group = groupLocalService.getGroup(categoryId);
223 
224             name = group.getName();
225             description = group.getDescription();
226         }
227 
228         List<MBMessage> messages = new ArrayList<MBMessage>();
229 
230         int lastIntervalStart = 0;
231         boolean listNotExhausted = true;
232         MessageCreateDateComparator comparator =
233             new MessageCreateDateComparator(false);
234 
235         while ((messages.size() < max) && listNotExhausted) {
236             List<MBMessage> messageList =
237                 mbMessageLocalService.getCategoryMessages(
238                     groupId, categoryId, status, lastIntervalStart,
239                     lastIntervalStart + max, comparator);
240 
241             Iterator<MBMessage> itr = messageList.iterator();
242 
243             lastIntervalStart += max;
244             listNotExhausted = (messageList.size() == max);
245 
246             while (itr.hasNext() && (messages.size() < max)) {
247                 MBMessage message = itr.next();
248 
249                 if (MBMessagePermission.contains(
250                         getPermissionChecker(), message, ActionKeys.VIEW)) {
251 
252                     messages.add(message);
253                 }
254             }
255         }
256 
257         return exportToRSS(
258             name, description, type, version, displayStyle, feedURL, entryURL,
259             messages, themeDisplay);
260     }
261 
262     public String getCompanyMessagesRSS(
263             long companyId, int status, int max, String type, double version,
264             String displayStyle, String feedURL, String entryURL,
265             ThemeDisplay themeDisplay)
266         throws PortalException, SystemException {
267 
268         Company company = companyPersistence.findByPrimaryKey(companyId);
269 
270         String name = company.getName();
271         String description = company.getName();
272 
273         List<MBMessage> messages = new ArrayList<MBMessage>();
274 
275         int lastIntervalStart = 0;
276         boolean listNotExhausted = true;
277         MessageCreateDateComparator comparator =
278             new MessageCreateDateComparator(false);
279 
280         while ((messages.size() < max) && listNotExhausted) {
281             List<MBMessage> messageList =
282                 mbMessageLocalService.getCompanyMessages(
283                     companyId, status, lastIntervalStart,
284                     lastIntervalStart + max, comparator);
285 
286             Iterator<MBMessage> itr = messageList.iterator();
287 
288             lastIntervalStart += max;
289             listNotExhausted = (messageList.size() == max);
290 
291             while (itr.hasNext() && (messages.size() < max)) {
292                 MBMessage message = itr.next();
293 
294                 if (MBMessagePermission.contains(
295                         getPermissionChecker(), message, ActionKeys.VIEW)) {
296 
297                     messages.add(message);
298                 }
299             }
300         }
301 
302         return exportToRSS(
303             name, description, type, version, displayStyle, feedURL, entryURL,
304             messages, themeDisplay);
305     }
306 
307     public String getGroupMessagesRSS(
308             long groupId, int status, int max, String type, double version,
309             String displayStyle, String feedURL, String entryURL,
310             ThemeDisplay themeDisplay)
311         throws PortalException, SystemException {
312 
313         String name = StringPool.BLANK;
314         String description = StringPool.BLANK;
315 
316         List<MBMessage> messages = new ArrayList<MBMessage>();
317 
318         int lastIntervalStart = 0;
319         boolean listNotExhausted = true;
320         MessageCreateDateComparator comparator =
321             new MessageCreateDateComparator(false);
322 
323         while ((messages.size() < max) && listNotExhausted) {
324             List<MBMessage> messageList =
325                 mbMessageLocalService.getGroupMessages(
326                     groupId, status, lastIntervalStart, lastIntervalStart + max,
327                     comparator);
328 
329             Iterator<MBMessage> itr = messageList.iterator();
330 
331             lastIntervalStart += max;
332             listNotExhausted = (messageList.size() == max);
333 
334             while (itr.hasNext() && (messages.size() < max)) {
335                 MBMessage message = itr.next();
336 
337                 if (MBMessagePermission.contains(
338                         getPermissionChecker(), message, ActionKeys.VIEW)) {
339 
340                     messages.add(message);
341                 }
342             }
343         }
344 
345         if (messages.size() > 0) {
346             MBMessage message = messages.get(messages.size() - 1);
347 
348             name = message.getSubject();
349             description = message.getSubject();
350         }
351 
352         return exportToRSS(
353             name, description, type, version, displayStyle, feedURL, entryURL,
354             messages, themeDisplay);
355     }
356 
357     public String getGroupMessagesRSS(
358             long groupId, long userId, int status, int max, String type,
359             double version, String displayStyle, String feedURL,
360             String entryURL, ThemeDisplay themeDisplay)
361         throws PortalException, SystemException {
362 
363         String name = StringPool.BLANK;
364         String description = StringPool.BLANK;
365 
366         List<MBMessage> messages = new ArrayList<MBMessage>();
367 
368         int lastIntervalStart = 0;
369         boolean listNotExhausted = true;
370         MessageCreateDateComparator comparator =
371             new MessageCreateDateComparator(false);
372 
373         while ((messages.size() < max) && listNotExhausted) {
374             List<MBMessage> messageList =
375                 mbMessageLocalService.getGroupMessages(
376                     groupId, userId, status, lastIntervalStart,
377                     lastIntervalStart + max, comparator);
378 
379             Iterator<MBMessage> itr = messageList.iterator();
380 
381             lastIntervalStart += max;
382             listNotExhausted = (messageList.size() == max);
383 
384             while (itr.hasNext() && (messages.size() < max)) {
385                 MBMessage message = itr.next();
386 
387                 if (MBMessagePermission.contains(
388                         getPermissionChecker(), message, ActionKeys.VIEW)) {
389 
390                     messages.add(message);
391                 }
392             }
393         }
394 
395         if (messages.size() > 0) {
396             MBMessage message = messages.get(messages.size() - 1);
397 
398             name = message.getSubject();
399             description = message.getSubject();
400         }
401 
402         return exportToRSS(
403             name, description, type, version, displayStyle, feedURL, entryURL,
404             messages, themeDisplay);
405     }
406 
407     public MBMessage getMessage(long messageId)
408         throws PortalException, SystemException {
409 
410         MBMessagePermission.check(
411             getPermissionChecker(), messageId, ActionKeys.VIEW);
412 
413         return mbMessageLocalService.getMessage(messageId);
414     }
415 
416     public MBMessageDisplay getMessageDisplay(
417             long messageId, int status, String threadView)
418         throws PortalException, SystemException {
419 
420         MBMessagePermission.check(
421             getPermissionChecker(), messageId, ActionKeys.VIEW);
422 
423         return mbMessageLocalService.getMessageDisplay(
424             messageId, status, threadView);
425     }
426 
427     public String getThreadMessagesRSS(
428             long threadId, int status, int max, String type, double version,
429             String displayStyle, String feedURL, String entryURL,
430             ThemeDisplay themeDisplay)
431         throws PortalException, SystemException {
432 
433         String name = StringPool.BLANK;
434         String description = StringPool.BLANK;
435 
436         List<MBMessage> messages = new ArrayList<MBMessage>();
437 
438         MessageCreateDateComparator comparator =
439             new MessageCreateDateComparator(false);
440 
441         Iterator<MBMessage> itr = mbMessageLocalService.getThreadMessages(
442             threadId, status, comparator).iterator();
443 
444         while (itr.hasNext() && (messages.size() < max)) {
445             MBMessage message = itr.next();
446 
447             if (MBMessagePermission.contains(
448                     getPermissionChecker(), message, ActionKeys.VIEW)) {
449 
450                 messages.add(message);
451             }
452         }
453 
454         if (messages.size() > 0) {
455             MBMessage message = messages.get(messages.size() - 1);
456 
457             name = message.getSubject();
458             description = message.getSubject();
459         }
460 
461         return exportToRSS(
462             name, description, type, version, displayStyle, feedURL, entryURL,
463             messages, themeDisplay);
464     }
465 
466     public void subscribeMessage(long messageId)
467         throws PortalException, SystemException {
468 
469         MBMessagePermission.check(
470             getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
471 
472         mbMessageLocalService.subscribeMessage(getUserId(), messageId);
473     }
474 
475     public void unsubscribeMessage(long messageId)
476         throws PortalException, SystemException {
477 
478         MBMessagePermission.check(
479             getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
480 
481         mbMessageLocalService.unsubscribeMessage(getUserId(), messageId);
482     }
483 
484     public MBMessage updateDiscussionMessage(
485             String className, long classPK, long messageId, String subject,
486             String body, ServiceContext serviceContext)
487         throws PortalException, SystemException {
488 
489         User user = getUser();
490 
491         MBDiscussionPermission.check(
492             getPermissionChecker(), user.getCompanyId(),
493             serviceContext.getScopeGroupId(), className, classPK, messageId,
494             user.getUserId(), ActionKeys.UPDATE_DISCUSSION);
495 
496         return mbMessageLocalService.updateDiscussionMessage(
497             getUserId(), messageId, subject, body, serviceContext.getStatus());
498     }
499 
500     public MBMessage updateMessage(
501             long messageId, String subject, String body,
502             List<ObjectValuePair<String, byte[]>> files,
503             List<String> existingFiles, double priority, boolean allowPingbacks,
504             ServiceContext serviceContext)
505         throws PortalException, SystemException {
506 
507         MBMessage message = mbMessageLocalService.getMessage(messageId);
508 
509         MBMessagePermission.check(
510             getPermissionChecker(), messageId, ActionKeys.UPDATE);
511 
512         if (lockLocalService.isLocked(
513                 MBThread.class.getName(), message.getThreadId())) {
514 
515             throw new LockedThreadException();
516         }
517 
518         if (!MBCategoryPermission.contains(
519                 getPermissionChecker(), message.getGroupId(),
520                 message.getCategoryId(), ActionKeys.ADD_FILE)) {
521 
522             files.clear();
523         }
524 
525         if (!MBCategoryPermission.contains(
526                 getPermissionChecker(), message.getGroupId(),
527                 message.getCategoryId(), ActionKeys.UPDATE_THREAD_PRIORITY)) {
528 
529             MBThread thread = mbThreadLocalService.getThread(
530                 message.getThreadId());
531 
532             priority = thread.getPriority();
533         }
534 
535         return mbMessageLocalService.updateMessage(
536             getUserId(), messageId, subject, body, files, existingFiles,
537             priority, allowPingbacks, serviceContext);
538     }
539 
540     protected void checkReplyToPermission(
541             long groupId, long categoryId, long parentMessageId)
542         throws PortalException, SystemException {
543 
544         if (parentMessageId > 0) {
545             if (MBCategoryPermission.contains(
546                     getPermissionChecker(), groupId, categoryId,
547                     ActionKeys.ADD_MESSAGE)) {
548 
549                 return;
550             }
551 
552             MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(
553                 parentMessageId);
554 
555             if ((parentMessage == null) ||
556                 !MBCategoryPermission.contains(
557                     getPermissionChecker(), groupId, categoryId,
558                     ActionKeys.REPLY_TO_MESSAGE)) {
559 
560                 throw new PrincipalException();
561             }
562         }
563         else {
564             MBCategoryPermission.check(
565                 getPermissionChecker(), groupId, categoryId,
566                 ActionKeys.ADD_MESSAGE);
567         }
568     }
569 
570     protected String exportToRSS(
571             String name, String description, String type, double version,
572             String displayStyle, String feedURL, String entryURL,
573             List<MBMessage> messages, ThemeDisplay themeDisplay)
574         throws SystemException {
575 
576         SyndFeed syndFeed = new SyndFeedImpl();
577 
578         syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
579         syndFeed.setTitle(name);
580         syndFeed.setLink(feedURL);
581         syndFeed.setDescription(description);
582 
583         List<SyndEntry> entries = new ArrayList<SyndEntry>();
584 
585         syndFeed.setEntries(entries);
586 
587         Iterator<MBMessage> itr = messages.iterator();
588 
589         while (itr.hasNext()) {
590             MBMessage message = itr.next();
591 
592             String author = PortalUtil.getUserName(
593                 message.getUserId(), message.getUserName());
594 
595             String value = null;
596 
597             if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
598                 value = StringUtil.shorten(
599                     HtmlUtil.extractText(message.getBody()),
600                     _RSS_ABSTRACT_LENGTH, StringPool.BLANK);
601             }
602             else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
603                 value = StringPool.BLANK;
604             }
605             else {
606                 value = BBCodeUtil.getHTML(message);
607 
608                 value = StringUtil.replace(
609                     value,
610                     new String[] {
611                         "@theme_images_path@",
612                         "href=\"/",
613                         "src=\"/"
614                     },
615                     new String[] {
616                         themeDisplay.getURLPortal() +
617                             themeDisplay.getPathThemeImages(),
618                         "href=\"" + themeDisplay.getURLPortal() + "/",
619                         "src=\"" + themeDisplay.getURLPortal() + "/"
620                     });
621             }
622 
623             SyndEntry syndEntry = new SyndEntryImpl();
624 
625             if (!message.isAnonymous()) {
626                 syndEntry.setAuthor(author);
627             }
628 
629             syndEntry.setTitle(message.getSubject());
630             syndEntry.setLink(
631                 entryURL + "&messageId=" + message.getMessageId());
632             syndEntry.setUri(syndEntry.getLink());
633             syndEntry.setPublishedDate(message.getCreateDate());
634             syndEntry.setUpdatedDate(message.getModifiedDate());
635 
636             SyndContent syndContent = new SyndContentImpl();
637 
638             syndContent.setType(RSSUtil.DEFAULT_ENTRY_TYPE);
639             syndContent.setValue(value);
640 
641             syndEntry.setDescription(syndContent);
642 
643             entries.add(syndEntry);
644         }
645 
646         try {
647             return RSSUtil.export(syndFeed);
648         }
649         catch (FeedException fe) {
650             throw new SystemException(fe);
651         }
652     }
653 
654     private static final int _RSS_ABSTRACT_LENGTH = GetterUtil.getInteger(
655         PropsUtil.get(PropsKeys.MESSAGE_BOARDS_RSS_ABSTRACT_LENGTH));
656 
657 }