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