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