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