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