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.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  public class MBMessageServiceImpl extends MBMessageServiceBaseImpl {
72  
73      public MBMessage addDiscussionMessage(
74              String className, long classPK, long threadId, long parentMessageId,
75              String subject, String body, ServiceContext serviceContext)
76          throws PortalException, SystemException {
77  
78          User user = getUser();
79  
80          MBDiscussionPermission.check(
81              getPermissionChecker(), user.getCompanyId(),
82              serviceContext.getScopeGroupId(), className, classPK,
83              user.getUserId(), ActionKeys.ADD_DISCUSSION);
84  
85          return mbMessageLocalService.addDiscussionMessage(
86              getUserId(), null, className, classPK, threadId, parentMessageId,
87              subject, body, serviceContext);
88      }
89  
90      public MBMessage addMessage(
91              long categoryId, long threadId, long parentMessageId,
92              String subject, String body,
93              List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
94              double priority, ServiceContext serviceContext)
95          throws PortalException, SystemException {
96  
97          checkReplyToPermission(categoryId, parentMessageId);
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         MessageCreateDateComparator comparator =
415             new MessageCreateDateComparator(false);
416 
417         Iterator<MBMessage> itr = mbMessageLocalService.getThreadMessages(
418             threadId, comparator).iterator();
419 
420         while (itr.hasNext() && (messages.size() < max)) {
421             MBMessage message = itr.next();
422 
423             if (MBMessagePermission.contains(
424                     getPermissionChecker(), message, ActionKeys.VIEW)) {
425 
426                 messages.add(message);
427             }
428         }
429 
430         if (messages.size() > 0) {
431             MBMessage message = messages.get(messages.size() - 1);
432 
433             name = message.getSubject();
434             description = message.getSubject();
435         }
436 
437         return exportToRSS(
438             name, description, type, version, displayStyle, feedURL, entryURL,
439             messages, themeDisplay);
440     }
441 
442     public void subscribeMessage(long messageId)
443         throws PortalException, SystemException {
444 
445         MBMessagePermission.check(
446             getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
447 
448         mbMessageLocalService.subscribeMessage(getUserId(), messageId);
449     }
450 
451     public void unsubscribeMessage(long messageId)
452         throws PortalException, SystemException {
453 
454         MBMessagePermission.check(
455             getPermissionChecker(), messageId, ActionKeys.SUBSCRIBE);
456 
457         mbMessageLocalService.unsubscribeMessage(getUserId(), messageId);
458     }
459 
460     public MBMessage updateDiscussionMessage(
461             String className, long classPK, long messageId, String subject,
462             String body, ServiceContext serviceContext)
463         throws PortalException, SystemException {
464 
465         User user = getUser();
466 
467         MBDiscussionPermission.check(
468             getPermissionChecker(), user.getCompanyId(),
469             serviceContext.getScopeGroupId(), className, classPK, messageId,
470             user.getUserId(), ActionKeys.UPDATE_DISCUSSION);
471 
472         return mbMessageLocalService.updateDiscussionMessage(
473             getUserId(), messageId, subject, body);
474     }
475 
476     public MBMessage updateMessage(
477             long messageId, String subject, String body,
478             List<ObjectValuePair<String, byte[]>> files,
479             List<String> existingFiles, double priority,
480             ServiceContext serviceContext)
481         throws PortalException, SystemException {
482 
483         MBMessage message = mbMessageLocalService.getMessage(messageId);
484 
485         MBMessagePermission.check(
486             getPermissionChecker(), messageId, ActionKeys.UPDATE);
487 
488         if (!MBCategoryPermission.contains(
489                 getPermissionChecker(), message.getCategoryId(),
490                 ActionKeys.ADD_FILE)) {
491 
492             files.clear();
493         }
494 
495         if (!MBCategoryPermission.contains(
496                 getPermissionChecker(), message.getCategoryId(),
497                 ActionKeys.UPDATE_THREAD_PRIORITY)) {
498 
499             MBThread thread = mbThreadLocalService.getThread(
500                 message.getThreadId());
501 
502             priority = thread.getPriority();
503         }
504 
505         return mbMessageLocalService.updateMessage(
506             getUserId(), messageId, subject, body, files, existingFiles,
507             priority, serviceContext);
508     }
509 
510     protected void checkReplyToPermission(long categoryId, long parentMessageId)
511         throws PortalException, SystemException {
512 
513         if (parentMessageId > 0) {
514             if (MBCategoryPermission.contains(
515                     getPermissionChecker(), categoryId,
516                     ActionKeys.ADD_MESSAGE)) {
517 
518                 return;
519             }
520 
521             MBMessage parentMessage = mbMessagePersistence.fetchByPrimaryKey(
522                 parentMessageId);
523 
524             if ((parentMessage == null) ||
525                 !MBCategoryPermission.contains(
526                     getPermissionChecker(), categoryId,
527                     ActionKeys.REPLY_TO_MESSAGE)) {
528 
529                 throw new PrincipalException();
530             }
531         }
532         else {
533             MBCategoryPermission.check(
534                 getPermissionChecker(), categoryId, ActionKeys.ADD_MESSAGE);
535         }
536     }
537 
538     protected String exportToRSS(
539             String name, String description, String type, double version,
540             String displayStyle, String feedURL, String entryURL,
541             List<MBMessage> messages, ThemeDisplay themeDisplay)
542         throws SystemException {
543 
544         SyndFeed syndFeed = new SyndFeedImpl();
545 
546         syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
547         syndFeed.setTitle(name);
548         syndFeed.setLink(feedURL);
549         syndFeed.setDescription(description);
550 
551         List<SyndEntry> entries = new ArrayList<SyndEntry>();
552 
553         syndFeed.setEntries(entries);
554 
555         Iterator<MBMessage> itr = messages.iterator();
556 
557         while (itr.hasNext()) {
558             MBMessage message = itr.next();
559 
560             String author = PortalUtil.getUserName(
561                 message.getUserId(), message.getUserName());
562 
563             String value = null;
564 
565             if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
566                 value = StringUtil.shorten(
567                     HtmlUtil.extractText(message.getBody()),
568                     _RSS_ABSTRACT_LENGTH, StringPool.BLANK);
569             }
570             else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
571                 value = StringPool.BLANK;
572             }
573             else {
574                 value = BBCodeUtil.getHTML(message);
575 
576                 value = StringUtil.replace(
577                     value,
578                     new String[] {
579                         "@theme_images_path@",
580                         "href=\"/",
581                         "src=\"/"
582                     },
583                     new String[] {
584                         themeDisplay.getURLPortal() +
585                             themeDisplay.getPathThemeImages(),
586                         "href=\"" + themeDisplay.getURLPortal() + "/",
587                         "src=\"" + themeDisplay.getURLPortal() + "/"
588                     });
589             }
590 
591             SyndEntry syndEntry = new SyndEntryImpl();
592 
593             if (!message.isAnonymous()) {
594                 syndEntry.setAuthor(author);
595             }
596 
597             syndEntry.setTitle(message.getSubject());
598             syndEntry.setLink(
599                 entryURL + "&messageId=" + message.getMessageId());
600             syndEntry.setUri(syndEntry.getLink());
601             syndEntry.setPublishedDate(message.getCreateDate());
602             syndEntry.setUpdatedDate(message.getModifiedDate());
603 
604             SyndContent syndContent = new SyndContentImpl();
605 
606             syndContent.setType(RSSUtil.DEFAULT_ENTRY_TYPE);
607             syndContent.setValue(value);
608 
609             syndEntry.setDescription(syndContent);
610 
611             entries.add(syndEntry);
612         }
613 
614         try {
615             return RSSUtil.export(syndFeed);
616         }
617         catch (FeedException fe) {
618             throw new SystemException(fe);
619         }
620     }
621 
622     private static final int _RSS_ABSTRACT_LENGTH = GetterUtil.getInteger(
623         PropsUtil.get(PropsKeys.MESSAGE_BOARDS_RSS_ABSTRACT_LENGTH));
624 
625 }