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