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