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