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