001
014
015 package com.liferay.portlet.messageboards.util;
016
017 import com.liferay.portal.kernel.dao.shard.ShardCallable;
018 import com.liferay.portal.kernel.exception.PortalException;
019 import com.liferay.portal.kernel.language.LanguageUtil;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslatorUtil;
023 import com.liferay.portal.kernel.portlet.LiferayWindowState;
024 import com.liferay.portal.kernel.sanitizer.Sanitizer;
025 import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
026 import com.liferay.portal.kernel.search.Document;
027 import com.liferay.portal.kernel.search.Field;
028 import com.liferay.portal.kernel.search.Hits;
029 import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
030 import com.liferay.portal.kernel.util.ArrayUtil;
031 import com.liferay.portal.kernel.util.CharPool;
032 import com.liferay.portal.kernel.util.ContentTypes;
033 import com.liferay.portal.kernel.util.GetterUtil;
034 import com.liferay.portal.kernel.util.HtmlUtil;
035 import com.liferay.portal.kernel.util.Http;
036 import com.liferay.portal.kernel.util.LocaleUtil;
037 import com.liferay.portal.kernel.util.ParamUtil;
038 import com.liferay.portal.kernel.util.PropsUtil;
039 import com.liferay.portal.kernel.util.StringBundler;
040 import com.liferay.portal.kernel.util.StringPool;
041 import com.liferay.portal.kernel.util.StringUtil;
042 import com.liferay.portal.kernel.util.Validator;
043 import com.liferay.portal.kernel.workflow.WorkflowConstants;
044 import com.liferay.portal.model.Company;
045 import com.liferay.portal.model.Group;
046 import com.liferay.portal.model.Organization;
047 import com.liferay.portal.model.ResourceConstants;
048 import com.liferay.portal.model.Role;
049 import com.liferay.portal.model.RoleConstants;
050 import com.liferay.portal.model.Subscription;
051 import com.liferay.portal.model.ThemeConstants;
052 import com.liferay.portal.model.UserGroup;
053 import com.liferay.portal.security.permission.ActionKeys;
054 import com.liferay.portal.security.permission.PermissionChecker;
055 import com.liferay.portal.security.permission.ResourceActionsUtil;
056 import com.liferay.portal.service.GroupLocalServiceUtil;
057 import com.liferay.portal.service.OrganizationLocalServiceUtil;
058 import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
059 import com.liferay.portal.service.RoleLocalServiceUtil;
060 import com.liferay.portal.service.ServiceContext;
061 import com.liferay.portal.service.SubscriptionLocalServiceUtil;
062 import com.liferay.portal.service.UserGroupLocalServiceUtil;
063 import com.liferay.portal.service.UserGroupRoleLocalServiceUtil;
064 import com.liferay.portal.service.UserLocalServiceUtil;
065 import com.liferay.portal.theme.ThemeDisplay;
066 import com.liferay.portal.util.PortalUtil;
067 import com.liferay.portal.util.PropsValues;
068 import com.liferay.portal.util.WebKeys;
069 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
070 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
071 import com.liferay.portlet.messageboards.MBSettings;
072 import com.liferay.portlet.messageboards.model.MBBan;
073 import com.liferay.portlet.messageboards.model.MBCategory;
074 import com.liferay.portlet.messageboards.model.MBCategoryConstants;
075 import com.liferay.portlet.messageboards.model.MBMessage;
076 import com.liferay.portlet.messageboards.model.MBStatsUser;
077 import com.liferay.portlet.messageboards.model.MBThread;
078 import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
079 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
080 import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
081 import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
082 import com.liferay.util.mail.JavaMailUtil;
083
084 import java.io.InputStream;
085
086 import java.util.ArrayList;
087 import java.util.Calendar;
088 import java.util.Collections;
089 import java.util.Date;
090 import java.util.HashMap;
091 import java.util.HashSet;
092 import java.util.LinkedHashMap;
093 import java.util.List;
094 import java.util.Map;
095 import java.util.Set;
096 import java.util.concurrent.Callable;
097
098 import javax.mail.BodyPart;
099 import javax.mail.Message;
100 import javax.mail.Part;
101 import javax.mail.internet.MimeMessage;
102 import javax.mail.internet.MimeMultipart;
103
104 import javax.portlet.PortletRequest;
105 import javax.portlet.PortletURL;
106 import javax.portlet.RenderResponse;
107
108 import javax.servlet.http.HttpServletRequest;
109
110
113 public class MBUtil {
114
115 public static final String BB_CODE_EDITOR_WYSIWYG_IMPL_KEY =
116 "editor.wysiwyg.portal-web.docroot.html.portlet.message_boards." +
117 "edit_message.bb_code.jsp";
118
119 public static final String EMOTICONS = "/emoticons";
120
121 public static final String MESSAGE_POP_PORTLET_PREFIX = "mb_message.";
122
123 public static void addPortletBreadcrumbEntries(
124 long categoryId, HttpServletRequest request,
125 RenderResponse renderResponse)
126 throws Exception {
127
128 if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
129 (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
130
131 return;
132 }
133
134 MBCategory category = MBCategoryLocalServiceUtil.getCategory(
135 categoryId);
136
137 addPortletBreadcrumbEntries(category, request, renderResponse);
138 }
139
140 public static void addPortletBreadcrumbEntries(
141 MBCategory category, HttpServletRequest request,
142 RenderResponse renderResponse)
143 throws Exception {
144
145 String strutsAction = ParamUtil.getString(request, "struts_action");
146
147 PortletURL portletURL = renderResponse.createRenderURL();
148
149 if (strutsAction.equals("/message_boards/select_category") ||
150 strutsAction.equals("/message_boards_admin/select_category")) {
151
152 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
153 WebKeys.THEME_DISPLAY);
154
155 portletURL.setParameter(
156 "struts_action", "/message_boards/select_category");
157 portletURL.setWindowState(LiferayWindowState.POP_UP);
158
159 PortalUtil.addPortletBreadcrumbEntry(
160 request, themeDisplay.translate("categories"),
161 portletURL.toString());
162 }
163 else {
164 portletURL.setParameter("struts_action", "/message_boards/view");
165 }
166
167 List<MBCategory> ancestorCategories = category.getAncestors();
168
169 Collections.reverse(ancestorCategories);
170
171 for (MBCategory curCategory : ancestorCategories) {
172 portletURL.setParameter(
173 "mbCategoryId", String.valueOf(curCategory.getCategoryId()));
174
175 PortalUtil.addPortletBreadcrumbEntry(
176 request, curCategory.getName(), portletURL.toString());
177 }
178
179 portletURL.setParameter(
180 "mbCategoryId", String.valueOf(category.getCategoryId()));
181
182 PortalUtil.addPortletBreadcrumbEntry(
183 request, category.getName(), portletURL.toString());
184 }
185
186 public static void addPortletBreadcrumbEntries(
187 MBMessage message, HttpServletRequest request,
188 RenderResponse renderResponse)
189 throws Exception {
190
191 if (message.getCategoryId() ==
192 MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
193
194 return;
195 }
196
197 if (message.getCategoryId() !=
198 MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
199
200 addPortletBreadcrumbEntries(
201 message.getCategory(), request, renderResponse);
202 }
203
204 PortletURL portletURL = renderResponse.createRenderURL();
205
206 portletURL.setParameter(
207 "struts_action", "/message_boards/view_message");
208 portletURL.setParameter(
209 "messageId", String.valueOf(message.getMessageId()));
210
211 PortalUtil.addPortletBreadcrumbEntry(
212 request, message.getSubject(), portletURL.toString());
213 }
214
215 public static void collectMultipartContent(
216 MimeMultipart multipart, MBMailMessage collector)
217 throws Exception {
218
219 for (int i = 0; i < multipart.getCount(); i++) {
220 BodyPart part = multipart.getBodyPart(i);
221
222 collectPartContent(part, collector);
223 }
224 }
225
226 public static void collectPartContent(
227 Part part, MBMailMessage mbMailMessage)
228 throws Exception {
229
230 Object partContent = part.getContent();
231
232 String contentType = StringUtil.toLowerCase(part.getContentType());
233
234 if ((part.getDisposition() != null) &&
235 StringUtil.equalsIgnoreCase(
236 part.getDisposition(), MimeMessage.ATTACHMENT)) {
237
238 if (_log.isDebugEnabled()) {
239 _log.debug("Processing attachment");
240 }
241
242 byte[] bytes = null;
243
244 if (partContent instanceof String) {
245 bytes = ((String)partContent).getBytes();
246 }
247 else if (partContent instanceof InputStream) {
248 bytes = JavaMailUtil.getBytes(part);
249 }
250
251 mbMailMessage.addBytes(part.getFileName(), bytes);
252 }
253 else {
254 if (partContent instanceof MimeMultipart) {
255 MimeMultipart mimeMultipart = (MimeMultipart)partContent;
256
257 collectMultipartContent(mimeMultipart, mbMailMessage);
258 }
259 else if (partContent instanceof String) {
260 Map<String, Object> options = new HashMap<String, Object>();
261
262 options.put("emailPartToMBMessageBody", Boolean.TRUE);
263
264 String messageBody = SanitizerUtil.sanitize(
265 0, 0, 0, MBMessage.class.getName(), 0, contentType,
266 Sanitizer.MODE_ALL, (String)partContent, options);
267
268 if (contentType.startsWith(ContentTypes.TEXT_HTML)) {
269 mbMailMessage.setHtmlBody(messageBody);
270 }
271 else {
272 mbMailMessage.setPlainBody(messageBody);
273 }
274 }
275 }
276 }
277
278 public static String getAbsolutePath(
279 PortletRequest portletRequest, long mbCategoryId)
280 throws PortalException {
281
282 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
283 WebKeys.THEME_DISPLAY);
284
285 if (mbCategoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
286 return themeDisplay.translate("home");
287 }
288
289 MBCategory mbCategory = MBCategoryLocalServiceUtil.fetchMBCategory(
290 mbCategoryId);
291
292 List<MBCategory> categories = mbCategory.getAncestors();
293
294 Collections.reverse(categories);
295
296 StringBundler sb = new StringBundler((categories.size() * 3) + 5);
297
298 sb.append(themeDisplay.translate("home"));
299 sb.append(StringPool.SPACE);
300
301 for (MBCategory curCategory : categories) {
302 sb.append(StringPool.RAQUO_CHAR);
303 sb.append(StringPool.SPACE);
304 sb.append(curCategory.getName());
305 }
306
307 sb.append(StringPool.RAQUO_CHAR);
308 sb.append(StringPool.SPACE);
309 sb.append(mbCategory.getName());
310
311 return sb.toString();
312 }
313
314 public static String getBBCodeHTML(String msgBody, String pathThemeImages) {
315 return StringUtil.replace(
316 BBCodeTranslatorUtil.getHTML(msgBody),
317 ThemeConstants.TOKEN_THEME_IMAGES_PATH + EMOTICONS,
318 pathThemeImages + EMOTICONS);
319 }
320
321 public static long getCategoryId(
322 HttpServletRequest request, MBCategory category) {
323
324 long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
325
326 if (category != null) {
327 categoryId = category.getCategoryId();
328 }
329
330 categoryId = ParamUtil.getLong(request, "mbCategoryId", categoryId);
331
332 return categoryId;
333 }
334
335 public static long getCategoryId(
336 HttpServletRequest request, MBMessage message) {
337
338 long categoryId = MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
339
340 if (message != null) {
341 categoryId = message.getCategoryId();
342 }
343
344 categoryId = ParamUtil.getLong(request, "mbCategoryId", categoryId);
345
346 return categoryId;
347 }
348
349 public static Set<Long> getCategorySubscriptionClassPKs(long userId) {
350 List<Subscription> subscriptions =
351 SubscriptionLocalServiceUtil.getUserSubscriptions(
352 userId, MBCategory.class.getName());
353
354 Set<Long> classPKs = new HashSet<Long>(subscriptions.size());
355
356 for (Subscription subscription : subscriptions) {
357 classPKs.add(subscription.getClassPK());
358 }
359
360 return classPKs;
361 }
362
363 public static Map<String, String> getEmailDefinitionTerms(
364 PortletRequest portletRequest, String emailFromAddress,
365 String emailFromName) {
366
367 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
368 WebKeys.THEME_DISPLAY);
369
370 Map<String, String> definitionTerms =
371 new LinkedHashMap<String, String>();
372
373 definitionTerms.put(
374 "[$CATEGORY_NAME$]",
375 LanguageUtil.get(
376 themeDisplay.getLocale(),
377 "the-category-in-which-the-message-has-been-posted"));
378 definitionTerms.put(
379 "[$COMPANY_ID$]",
380 LanguageUtil.get(
381 themeDisplay.getLocale(),
382 "the-company-id-associated-with-the-message-board"));
383 definitionTerms.put(
384 "[$COMPANY_MX$]",
385 LanguageUtil.get(
386 themeDisplay.getLocale(),
387 "the-company-mx-associated-with-the-message-board"));
388 definitionTerms.put(
389 "[$COMPANY_NAME$]",
390 LanguageUtil.get(
391 themeDisplay.getLocale(),
392 "the-company-name-associated-with-the-message-board"));
393 definitionTerms.put(
394 "[$FROM_ADDRESS$]", HtmlUtil.escape(emailFromAddress));
395 definitionTerms.put("[$FROM_NAME$]", HtmlUtil.escape(emailFromName));
396
397 if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
398 definitionTerms.put(
399 "[$MAILING_LIST_ADDRESS$]",
400 LanguageUtil.get(
401 themeDisplay.getLocale(),
402 "the-email-address-of-the-mailing-list"));
403 }
404
405 definitionTerms.put(
406 "[$MESSAGE_BODY$]",
407 LanguageUtil.get(themeDisplay.getLocale(), "the-message-body"));
408 definitionTerms.put(
409 "[$MESSAGE_ID$]",
410 LanguageUtil.get(themeDisplay.getLocale(), "the-message-id"));
411 definitionTerms.put(
412 "[$MESSAGE_SUBJECT$]",
413 LanguageUtil.get(themeDisplay.getLocale(), "the-message-subject"));
414 definitionTerms.put(
415 "[$MESSAGE_URL$]",
416 LanguageUtil.get(themeDisplay.getLocale(), "the-message-url"));
417 definitionTerms.put(
418 "[$MESSAGE_USER_ADDRESS$]",
419 LanguageUtil.get(
420 themeDisplay.getLocale(),
421 "the-email-address-of-the-user-who-added-the-message"));
422 definitionTerms.put(
423 "[$MESSAGE_USER_NAME$]",
424 LanguageUtil.get(
425 themeDisplay.getLocale(), "the-user-who-added-the-message"));
426
427 Company company = themeDisplay.getCompany();
428
429 definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());
430
431 definitionTerms.put(
432 "[$PORTLET_NAME$]", PortalUtil.getPortletTitle(portletRequest));
433 definitionTerms.put(
434 "[$SITE_NAME$]",
435 LanguageUtil.get(
436 themeDisplay.getLocale(),
437 "the-site-name-associated-with-the-message-board"));
438
439 if (!PropsValues.MESSAGE_BOARDS_EMAIL_BULK) {
440 definitionTerms.put(
441 "[$TO_ADDRESS$]",
442 LanguageUtil.get(
443 themeDisplay.getLocale(),
444 "the-address-of-the-email-recipient"));
445 definitionTerms.put(
446 "[$TO_NAME$]",
447 LanguageUtil.get(
448 themeDisplay.getLocale(),
449 "the-name-of-the-email-recipient"));
450 }
451
452 return definitionTerms;
453 }
454
455 public static Map<String, String> getEmailFromDefinitionTerms(
456 PortletRequest portletRequest) {
457
458 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
459 WebKeys.THEME_DISPLAY);
460
461 Map<String, String> definitionTerms =
462 new LinkedHashMap<String, String>();
463
464 definitionTerms.put(
465 "[$COMPANY_ID$]",
466 LanguageUtil.get(
467 themeDisplay.getLocale(),
468 "the-company-id-associated-with-the-message-board"));
469 definitionTerms.put(
470 "[$COMPANY_MX$]",
471 LanguageUtil.get(
472 themeDisplay.getLocale(),
473 "the-company-mx-associated-with-the-message-board"));
474 definitionTerms.put(
475 "[$COMPANY_NAME$]",
476 LanguageUtil.get(
477 themeDisplay.getLocale(),
478 "the-company-name-associated-with-the-message-board"));
479
480 if (PropsValues.POP_SERVER_NOTIFICATIONS_ENABLED) {
481 definitionTerms.put(
482 "[$MAILING_LIST_ADDRESS$]",
483 LanguageUtil.get(
484 themeDisplay.getLocale(),
485 "the-email-address-of-the-mailing-list"));
486 }
487
488 definitionTerms.put(
489 "[$MESSAGE_USER_ADDRESS$]",
490 LanguageUtil.get(
491 themeDisplay.getLocale(),
492 "the-email-address-of-the-user-who-added-the-message"));
493 definitionTerms.put(
494 "[$MESSAGE_USER_NAME$]",
495 LanguageUtil.get(
496 themeDisplay.getLocale(), "the-user-who-added-the-message"));
497 definitionTerms.put(
498 "[$PORTLET_NAME$]", PortalUtil.getPortletTitle(portletRequest));
499 definitionTerms.put(
500 "[$SITE_NAME$]",
501 LanguageUtil.get(
502 themeDisplay.getLocale(),
503 "the-site-name-associated-with-the-message-board"));
504
505 return definitionTerms;
506 }
507
508 public static List<Object> getEntries(Hits hits) {
509 List<Object> entries = new ArrayList<Object>();
510
511 for (Document document : hits.getDocs()) {
512 long categoryId = GetterUtil.getLong(
513 document.get(Field.CATEGORY_ID));
514
515 try {
516 MBCategoryLocalServiceUtil.getCategory(categoryId);
517 }
518 catch (Exception e) {
519 if (_log.isWarnEnabled()) {
520 _log.warn(
521 "Message boards search index is stale and contains " +
522 "category " + categoryId);
523 }
524
525 continue;
526 }
527
528 long threadId = GetterUtil.getLong(document.get("threadId"));
529
530 try {
531 MBThreadLocalServiceUtil.getThread(threadId);
532 }
533 catch (Exception e) {
534 if (_log.isWarnEnabled()) {
535 _log.warn(
536 "Message boards search index is stale and contains " +
537 "thread " + threadId);
538 }
539
540 continue;
541 }
542
543 String entryClassName = document.get(Field.ENTRY_CLASS_NAME);
544 long entryClassPK = GetterUtil.getLong(
545 document.get(Field.ENTRY_CLASS_PK));
546
547 Object obj = null;
548
549 try {
550 if (entryClassName.equals(DLFileEntry.class.getName())) {
551 long classPK = GetterUtil.getLong(
552 document.get(Field.CLASS_PK));
553
554 MBMessageLocalServiceUtil.getMessage(classPK);
555
556 obj = DLFileEntryLocalServiceUtil.getDLFileEntry(
557 entryClassPK);
558 }
559 else if (entryClassName.equals(MBMessage.class.getName())) {
560 obj = MBMessageLocalServiceUtil.getMessage(entryClassPK);
561 }
562
563 entries.add(obj);
564 }
565 catch (Exception e) {
566 if (_log.isWarnEnabled()) {
567 _log.warn(
568 "Message boards search index is stale and contains " +
569 "entry {className=" + entryClassName + ", " +
570 "classPK=" + entryClassPK + "}");
571 }
572
573 continue;
574 }
575 }
576
577 return entries;
578 }
579
580 public static long getMessageId(String mailId) {
581 int x = mailId.indexOf(CharPool.LESS_THAN) + 1;
582 int y = mailId.indexOf(CharPool.AT);
583
584 long messageId = 0;
585
586 if ((x > 0 ) && (y != -1)) {
587 String temp = mailId.substring(x, y);
588
589 int z = temp.lastIndexOf(CharPool.PERIOD);
590
591 if (z != -1) {
592 messageId = GetterUtil.getLong(temp.substring(z + 1));
593 }
594 }
595
596 return messageId;
597 }
598
599 public static long getParentMessageId(Message message) throws Exception {
600 long parentMessageId = -1;
601
602 String parentHeader = getParentMessageIdString(message);
603
604 if (parentHeader != null) {
605 if (_log.isDebugEnabled()) {
606 _log.debug("Parent header " + parentHeader);
607 }
608
609 parentMessageId = getMessageId(parentHeader);
610
611 if (_log.isDebugEnabled()) {
612 _log.debug("Previous message id " + parentMessageId);
613 }
614 }
615
616 return parentMessageId;
617 }
618
619 public static String getParentMessageIdString(Message message)
620 throws Exception {
621
622
623
624
625
626
627 String parentHeader = null;
628
629 String[] references = message.getHeader("References");
630
631 if (ArrayUtil.isNotEmpty(references)) {
632 String reference = references[0];
633
634 int x = reference.lastIndexOf("<mb.");
635
636 if (x > -1) {
637 int y = reference.indexOf(">", x);
638
639 parentHeader = reference.substring(x, y);
640 }
641 }
642
643 if (parentHeader == null) {
644 String[] inReplyToHeaders = message.getHeader("In-Reply-To");
645
646 if (ArrayUtil.isNotEmpty(inReplyToHeaders)) {
647 parentHeader = inReplyToHeaders[0];
648 }
649 }
650
651 if (Validator.isNull(parentHeader) ||
652 !parentHeader.startsWith(MESSAGE_POP_PORTLET_PREFIX, 1)) {
653
654 parentHeader = _getParentMessageIdFromSubject(message);
655 }
656
657 return parentHeader;
658 }
659
660 public static String getReplyToAddress(
661 long categoryId, long messageId, String mx,
662 String defaultMailingListAddress) {
663
664 if (PropsValues.POP_SERVER_SUBDOMAIN.length() <= 0) {
665 return defaultMailingListAddress;
666 }
667
668 StringBundler sb = new StringBundler(8);
669
670 sb.append(MESSAGE_POP_PORTLET_PREFIX);
671 sb.append(categoryId);
672 sb.append(StringPool.PERIOD);
673 sb.append(messageId);
674 sb.append(StringPool.AT);
675 sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
676 sb.append(StringPool.PERIOD);
677 sb.append(mx);
678
679 return sb.toString();
680 }
681
682 public static String getSubjectForEmail(Message message) throws Exception {
683 long parentMessageId = getParentMessageId(message);
684
685 MBMessage parentMessage = MBMessageLocalServiceUtil.getMBMessage(
686 parentMessageId);
687
688 String subject = parentMessage.getSubject();
689
690 if (subject.startsWith("RE:")) {
691 return subject;
692 }
693 else {
694 return "RE: " + parentMessage.getSubject();
695 }
696 }
697
698 public static String getSubjectWithoutMessageId(Message message)
699 throws Exception {
700
701 String subject = message.getSubject();
702
703 String parentMessageId = _getParentMessageIdFromSubject(message);
704
705 if (Validator.isNotNull(parentMessageId)) {
706 int pos = subject.indexOf(parentMessageId);
707
708 if (pos != -1) {
709 subject = subject.substring(0, pos);
710 }
711 }
712
713 return subject;
714 }
715
716 public static String[] getThreadPriority(
717 MBSettings mbSettings, String languageId, double value,
718 ThemeDisplay themeDisplay)
719 throws Exception {
720
721 String[] priorities = mbSettings.getPriorities(languageId);
722
723 String[] priorityPair = _findThreadPriority(
724 value, themeDisplay, priorities);
725
726 if (priorityPair == null) {
727 String defaultLanguageId = LocaleUtil.toLanguageId(
728 LocaleUtil.getSiteDefault());
729
730 priorities = mbSettings.getPriorities(defaultLanguageId);
731
732 priorityPair = _findThreadPriority(value, themeDisplay, priorities);
733 }
734
735 return priorityPair;
736 }
737
738 public static Set<Long> getThreadSubscriptionClassPKs(long userId) {
739 List<Subscription> subscriptions =
740 SubscriptionLocalServiceUtil.getUserSubscriptions(
741 userId, MBThread.class.getName());
742
743 Set<Long> classPKs = new HashSet<Long>(subscriptions.size());
744
745 for (Subscription subscription : subscriptions) {
746 classPKs.add(subscription.getClassPK());
747 }
748
749 return classPKs;
750 }
751
752 public static Date getUnbanDate(MBBan ban, int expireInterval) {
753 Date banDate = ban.getCreateDate();
754
755 Calendar cal = Calendar.getInstance();
756
757 cal.setTime(banDate);
758
759 cal.add(Calendar.DATE, expireInterval);
760
761 return cal.getTime();
762 }
763
764 public static String getUserRank(
765 MBSettings mbSettings, String languageId, int posts)
766 throws Exception {
767
768 String rank = StringPool.BLANK;
769
770 String[] ranks = mbSettings.getRanks(languageId);
771
772 for (int i = 0; i < ranks.length; i++) {
773 String[] kvp = StringUtil.split(ranks[i], CharPool.EQUAL);
774
775 String kvpName = kvp[0];
776 int kvpPosts = GetterUtil.getInteger(kvp[1]);
777
778 if (posts >= kvpPosts) {
779 rank = kvpName;
780 }
781 else {
782 break;
783 }
784 }
785
786 return rank;
787 }
788
789 public static String[] getUserRank(
790 MBSettings mbSettings, String languageId, MBStatsUser statsUser)
791 throws Exception {
792
793 String[] rank = {StringPool.BLANK, StringPool.BLANK};
794
795 int maxPosts = 0;
796
797 Group group = GroupLocalServiceUtil.getGroup(statsUser.getGroupId());
798
799 long companyId = group.getCompanyId();
800
801 String[] ranks = mbSettings.getRanks(languageId);
802
803 for (int i = 0; i < ranks.length; i++) {
804 String[] kvp = StringUtil.split(ranks[i], CharPool.EQUAL);
805
806 String curRank = kvp[0];
807 String curRankValue = kvp[1];
808
809 String[] curRankValueKvp = StringUtil.split(
810 curRankValue, CharPool.COLON);
811
812 if (curRankValueKvp.length <= 1) {
813 int posts = GetterUtil.getInteger(curRankValue);
814
815 if ((posts <= statsUser.getMessageCount()) &&
816 (posts >= maxPosts)) {
817
818 rank[0] = curRank;
819 maxPosts = posts;
820 }
821 }
822 else {
823 String entityType = curRankValueKvp[0];
824 String entityValue = curRankValueKvp[1];
825
826 try {
827 if (_isEntityRank(
828 companyId, statsUser, entityType, entityValue)) {
829
830 rank[1] = curRank;
831
832 break;
833 }
834 }
835 catch (Exception e) {
836 if (_log.isWarnEnabled()) {
837 _log.warn(e);
838 }
839 }
840 }
841 }
842
843 return rank;
844 }
845
846 public static boolean hasMailIdHeader(Message message) throws Exception {
847 String[] messageIds = message.getHeader("Message-ID");
848
849 if (messageIds == null) {
850 return false;
851 }
852
853 for (String messageId : messageIds) {
854 if (Validator.isNotNull(PropsValues.POP_SERVER_SUBDOMAIN) &&
855 messageId.contains(PropsValues.POP_SERVER_SUBDOMAIN)) {
856
857 return true;
858 }
859 }
860
861 return false;
862 }
863
864 public static boolean isValidMessageFormat(String messageFormat) {
865 String editorImpl = PropsUtil.get(BB_CODE_EDITOR_WYSIWYG_IMPL_KEY);
866
867 if (messageFormat.equals("bbcode") &&
868 !(editorImpl.equals("bbcode") ||
869 editorImpl.equals("ckeditor_bbcode"))) {
870
871 return false;
872 }
873
874 return true;
875 }
876
877 public static boolean isViewableMessage(
878 ThemeDisplay themeDisplay, MBMessage message)
879 throws Exception {
880
881 return isViewableMessage(themeDisplay, message, message);
882 }
883
884 public static boolean isViewableMessage(
885 ThemeDisplay themeDisplay, MBMessage message,
886 MBMessage parentMessage)
887 throws Exception {
888
889 PermissionChecker permissionChecker =
890 themeDisplay.getPermissionChecker();
891
892 if (!MBMessagePermission.contains(
893 permissionChecker, parentMessage, ActionKeys.VIEW)) {
894
895 return false;
896 }
897
898 if ((message.getMessageId() != parentMessage.getMessageId()) &&
899 !MBMessagePermission.contains(
900 permissionChecker, message, ActionKeys.VIEW)) {
901
902 return false;
903 }
904
905 if (!message.isApproved() &&
906 !Validator.equals(message.getUserId(), themeDisplay.getUserId()) &&
907 !permissionChecker.isGroupAdmin(themeDisplay.getScopeGroupId())) {
908
909 return false;
910 }
911
912 return true;
913 }
914
915 public static void propagatePermissions(
916 long companyId, long groupId, long parentMessageId,
917 ServiceContext serviceContext)
918 throws PortalException {
919
920 MBMessage parentMessage = MBMessageLocalServiceUtil.getMBMessage(
921 parentMessageId);
922
923 Role defaultGroupRole = RoleLocalServiceUtil.getDefaultGroupRole(
924 groupId);
925 Role guestRole = RoleLocalServiceUtil.getRole(
926 companyId, RoleConstants.GUEST);
927
928 List<String> actionIds = ResourceActionsUtil.getModelResourceActions(
929 MBMessage.class.getName());
930
931 Map<Long, Set<String>> roleIdsToActionIds =
932 ResourcePermissionLocalServiceUtil.
933 getAvailableResourcePermissionActionIds(
934 companyId, MBMessage.class.getName(),
935 ResourceConstants.SCOPE_INDIVIDUAL,
936 String.valueOf(parentMessage.getMessageId()), actionIds);
937
938 Set<String> defaultGroupActionIds = roleIdsToActionIds.get(
939 defaultGroupRole.getRoleId());
940
941 if (defaultGroupActionIds == null) {
942 serviceContext.setGroupPermissions(new String[]{});
943 }
944 else {
945 serviceContext.setGroupPermissions(
946 defaultGroupActionIds.toArray(
947 new String[defaultGroupActionIds.size()]));
948 }
949
950 Set<String> guestActionIds = roleIdsToActionIds.get(
951 guestRole.getRoleId());
952
953 if (guestActionIds == null) {
954 serviceContext.setGuestPermissions(new String[]{});
955 }
956 else {
957 serviceContext.setGuestPermissions(
958 guestActionIds.toArray(new String[guestActionIds.size()]));
959 }
960 }
961
962 public static String replaceMessageBodyPaths(
963 ThemeDisplay themeDisplay, String messageBody) {
964
965 return StringUtil.replace(
966 messageBody,
967 new String[] {
968 ThemeConstants.TOKEN_THEME_IMAGES_PATH, "href=\"/", "src=\"/"
969 },
970 new String[] {
971 themeDisplay.getPathThemeImages(),
972 "href=\"" + themeDisplay.getURLPortal() + "/",
973 "src=\"" + themeDisplay.getURLPortal() + "/"
974 });
975 }
976
977 public static void updateCategoryMessageCount(
978 long companyId, final long categoryId) {
979
980 Callable<Void> callable = new ShardCallable<Void>(companyId) {
981
982 @Override
983 protected Void doCall() throws Exception {
984 MBCategory category =
985 MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
986
987 if (category == null) {
988 return null;
989 }
990
991 int messageCount = _getMessageCount(category);
992
993 category.setMessageCount(messageCount);
994
995 MBCategoryLocalServiceUtil.updateMBCategory(category);
996
997 return null;
998 }
999
1000 };
1001
1002 TransactionCommitCallbackRegistryUtil.registerCallback(callable);
1003 }
1004
1005 public static void updateCategoryStatistics(
1006 long companyId, final long categoryId) {
1007
1008 Callable<Void> callable = new ShardCallable<Void>(companyId) {
1009
1010 @Override
1011 protected Void doCall() throws Exception {
1012 MBCategory category =
1013 MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
1014
1015 if (category == null) {
1016 return null;
1017 }
1018
1019 int messageCount = _getMessageCount(category);
1020
1021 int threadCount =
1022 MBThreadLocalServiceUtil.getCategoryThreadsCount(
1023 category.getGroupId(), category.getCategoryId(),
1024 WorkflowConstants.STATUS_APPROVED);
1025
1026 category.setMessageCount(messageCount);
1027 category.setThreadCount(threadCount);
1028
1029 MBCategoryLocalServiceUtil.updateMBCategory(category);
1030
1031 return null;
1032 }
1033
1034 };
1035
1036 TransactionCommitCallbackRegistryUtil.registerCallback(callable);
1037 }
1038
1039 public static void updateCategoryThreadCount(
1040 long companyId, final long categoryId) {
1041
1042 Callable<Void> callable = new ShardCallable<Void>(companyId) {
1043
1044 @Override
1045 protected Void doCall() throws Exception {
1046 MBCategory category =
1047 MBCategoryLocalServiceUtil.fetchMBCategory(categoryId);
1048
1049 if (category == null) {
1050 return null;
1051 }
1052
1053 int threadCount =
1054 MBThreadLocalServiceUtil.getCategoryThreadsCount(
1055 category.getGroupId(), category.getCategoryId(),
1056 WorkflowConstants.STATUS_APPROVED);
1057
1058 category.setThreadCount(threadCount);
1059
1060 MBCategoryLocalServiceUtil.updateMBCategory(category);
1061
1062 return null;
1063 }
1064
1065 };
1066
1067 TransactionCommitCallbackRegistryUtil.registerCallback(callable);
1068 }
1069
1070 public static void updateThreadMessageCount(
1071 long companyId, final long threadId) {
1072
1073 Callable<Void> callable = new ShardCallable<Void>(companyId) {
1074
1075 @Override
1076 protected Void doCall() throws Exception {
1077 MBThread thread = MBThreadLocalServiceUtil.fetchThread(
1078 threadId);
1079
1080 if (thread == null) {
1081 return null;
1082 }
1083
1084 int messageCount =
1085 MBMessageLocalServiceUtil.getThreadMessagesCount(
1086 threadId, WorkflowConstants.STATUS_APPROVED);
1087
1088 thread.setMessageCount(messageCount);
1089
1090 MBThreadLocalServiceUtil.updateMBThread(thread);
1091
1092 return null;
1093 }
1094
1095 };
1096
1097 TransactionCommitCallbackRegistryUtil.registerCallback(callable);
1098 }
1099
1100 private static String[] _findThreadPriority(
1101 double value, ThemeDisplay themeDisplay, String[] priorities) {
1102
1103 for (int i = 0; i < priorities.length; i++) {
1104 String[] priority = StringUtil.split(
1105 priorities[i], StringPool.PIPE);
1106
1107 try {
1108 String priorityName = priority[0];
1109 String priorityImage = priority[1];
1110 double priorityValue = GetterUtil.getDouble(priority[2]);
1111
1112 if (value == priorityValue) {
1113 if (!priorityImage.startsWith(Http.HTTP)) {
1114 priorityImage =
1115 themeDisplay.getPathThemeImages() + priorityImage;
1116 }
1117
1118 return new String[] {priorityName, priorityImage};
1119 }
1120 }
1121 catch (Exception e) {
1122 _log.error("Unable to determine thread priority", e);
1123 }
1124 }
1125
1126 return null;
1127 }
1128
1129 private static int _getMessageCount(MBCategory category) {
1130 return MBMessageLocalServiceUtil.getCategoryMessagesCount(
1131 category.getGroupId(), category.getCategoryId(),
1132 WorkflowConstants.STATUS_APPROVED);
1133 }
1134
1135 private static String _getParentMessageIdFromSubject(Message message)
1136 throws Exception {
1137
1138 if (message.getSubject() == null) {
1139 return null;
1140 }
1141
1142 String parentMessageId = null;
1143
1144 String subject = StringUtil.reverse(message.getSubject());
1145
1146 int pos = subject.indexOf(CharPool.LESS_THAN);
1147
1148 if (pos != -1) {
1149 parentMessageId = StringUtil.reverse(subject.substring(0, pos + 1));
1150 }
1151
1152 return parentMessageId;
1153 }
1154
1155 private static boolean _isEntityRank(
1156 long companyId, MBStatsUser statsUser, String entityType,
1157 String entityValue)
1158 throws Exception {
1159
1160 long groupId = statsUser.getGroupId();
1161 long userId = statsUser.getUserId();
1162
1163 if (entityType.equals("organization-role") ||
1164 entityType.equals("site-role")) {
1165
1166 Role role = RoleLocalServiceUtil.getRole(companyId, entityValue);
1167
1168 if (UserGroupRoleLocalServiceUtil.hasUserGroupRole(
1169 userId, groupId, role.getRoleId(), true)) {
1170
1171 return true;
1172 }
1173 }
1174 else if (entityType.equals("organization")) {
1175 Organization organization =
1176 OrganizationLocalServiceUtil.getOrganization(
1177 companyId, entityValue);
1178
1179 if (OrganizationLocalServiceUtil.hasUserOrganization(
1180 userId, organization.getOrganizationId(), false, false)) {
1181
1182 return true;
1183 }
1184 }
1185 else if (entityType.equals("regular-role")) {
1186 if (RoleLocalServiceUtil.hasUserRole(
1187 userId, companyId, entityValue, true)) {
1188
1189 return true;
1190 }
1191 }
1192 else if (entityType.equals("user-group")) {
1193 UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
1194 companyId, entityValue);
1195
1196 if (UserLocalServiceUtil.hasUserGroupUser(
1197 userGroup.getUserGroupId(), userId)) {
1198
1199 return true;
1200 }
1201 }
1202
1203 return false;
1204 }
1205
1206 private static Log _log = LogFactoryUtil.getLog(MBUtil.class);
1207
1208 }