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