001    /**
002     * Copyright (c) 2000-2013 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.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.increment.BufferedIncrement;
021    import com.liferay.portal.kernel.increment.NumberIncrement;
022    import com.liferay.portal.kernel.json.JSONFactoryUtil;
023    import com.liferay.portal.kernel.json.JSONObject;
024    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
025    import com.liferay.portal.kernel.search.Field;
026    import com.liferay.portal.kernel.search.Hits;
027    import com.liferay.portal.kernel.search.Indexer;
028    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
029    import com.liferay.portal.kernel.search.SearchContext;
030    import com.liferay.portal.kernel.search.Sort;
031    import com.liferay.portal.kernel.systemevent.SystemEvent;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.workflow.WorkflowConstants;
035    import com.liferay.portal.model.Group;
036    import com.liferay.portal.model.ResourceConstants;
037    import com.liferay.portal.model.SystemEventConstants;
038    import com.liferay.portal.model.User;
039    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
040    import com.liferay.portal.service.ServiceContext;
041    import com.liferay.portal.util.PortletKeys;
042    import com.liferay.portlet.asset.model.AssetEntry;
043    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
044    import com.liferay.portlet.messageboards.NoSuchCategoryException;
045    import com.liferay.portlet.messageboards.SplitThreadException;
046    import com.liferay.portlet.messageboards.model.MBCategory;
047    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
048    import com.liferay.portlet.messageboards.model.MBMessage;
049    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
050    import com.liferay.portlet.messageboards.model.MBThread;
051    import com.liferay.portlet.messageboards.model.MBThreadConstants;
052    import com.liferay.portlet.messageboards.model.MBTreeWalker;
053    import com.liferay.portlet.messageboards.service.base.MBThreadLocalServiceBaseImpl;
054    import com.liferay.portlet.messageboards.util.MBUtil;
055    import com.liferay.portlet.social.model.SocialActivityConstants;
056    import com.liferay.portlet.trash.model.TrashEntry;
057    import com.liferay.portlet.trash.model.TrashVersion;
058    
059    import java.util.ArrayList;
060    import java.util.Date;
061    import java.util.HashSet;
062    import java.util.List;
063    import java.util.Set;
064    
065    /**
066     * @author Brian Wing Shun Chan
067     * @author Shuyang Zhou
068     */
069    public class MBThreadLocalServiceImpl extends MBThreadLocalServiceBaseImpl {
070    
071            @Override
072            public MBThread addThread(
073                            long categoryId, MBMessage message, ServiceContext serviceContext)
074                    throws PortalException, SystemException {
075    
076                    // Thread
077    
078                    Date now = new Date();
079    
080                    long threadId = message.getThreadId();
081    
082                    if (!message.isRoot() || (threadId <= 0)) {
083                            threadId = counterLocalService.increment();
084                    }
085    
086                    MBThread thread = mbThreadPersistence.create(threadId);
087    
088                    thread.setUuid(serviceContext.getUuid());
089                    thread.setGroupId(message.getGroupId());
090                    thread.setCompanyId(message.getCompanyId());
091                    thread.setUserId(message.getUserId());
092                    thread.setUserName(message.getUserName());
093                    thread.setCreateDate(serviceContext.getCreateDate(now));
094                    thread.setModifiedDate(serviceContext.getModifiedDate(now));
095                    thread.setCategoryId(categoryId);
096                    thread.setRootMessageId(message.getMessageId());
097                    thread.setRootMessageUserId(message.getUserId());
098    
099                    if (message.isAnonymous()) {
100                            thread.setLastPostByUserId(0);
101                    }
102                    else {
103                            thread.setLastPostByUserId(message.getUserId());
104                    }
105    
106                    thread.setLastPostDate(message.getCreateDate());
107    
108                    if (message.getPriority() != MBThreadConstants.PRIORITY_NOT_GIVEN) {
109                            thread.setPriority(message.getPriority());
110                    }
111    
112                    thread.setStatus(message.getStatus());
113                    thread.setStatusByUserId(message.getStatusByUserId());
114                    thread.setStatusByUserName(message.getStatusByUserName());
115                    thread.setStatusDate(message.getStatusDate());
116    
117                    mbThreadPersistence.update(thread);
118    
119                    // Asset
120    
121                    if (categoryId >= 0) {
122                            assetEntryLocalService.updateEntry(
123                                    message.getUserId(), message.getGroupId(),
124                                    thread.getStatusDate(), thread.getLastPostDate(),
125                                    MBThread.class.getName(), thread.getThreadId(),
126                                    thread.getUuid(), 0, new long[0], new String[0], false, null,
127                                    null, null, null, String.valueOf(thread.getRootMessageId()),
128                                    null, null, null, null, 0, 0, null, false);
129                    }
130    
131                    return thread;
132            }
133    
134            @Override
135            public void deleteThread(long threadId)
136                    throws PortalException, SystemException {
137    
138                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
139    
140                    mbThreadLocalService.deleteThread(thread);
141            }
142    
143            @Override
144            @SystemEvent(
145                    action = SystemEventConstants.ACTION_SKIP, send = false,
146                    type = SystemEventConstants.TYPE_DELETE)
147            public void deleteThread(MBThread thread)
148                    throws PortalException, SystemException {
149    
150                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
151                            thread.getRootMessageId());
152    
153                    // Indexer
154    
155                    Indexer messageIndexer = IndexerRegistryUtil.nullSafeGetIndexer(
156                            MBMessage.class);
157    
158                    messageIndexer.delete(thread);
159    
160                    // Attachments
161    
162                    long folderId = thread.getAttachmentsFolderId();
163    
164                    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
165                            PortletFileRepositoryUtil.deleteFolder(folderId);
166                    }
167    
168                    // Subscriptions
169    
170                    subscriptionLocalService.deleteSubscriptions(
171                            thread.getCompanyId(), MBThread.class.getName(),
172                            thread.getThreadId());
173    
174                    // Thread flags
175    
176                    mbThreadFlagPersistence.removeByThreadId(thread.getThreadId());
177    
178                    // Messages
179    
180                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
181                            thread.getThreadId());
182    
183                    for (MBMessage message : messages) {
184    
185                            // Ratings
186    
187                            ratingsStatsLocalService.deleteStats(
188                                    message.getWorkflowClassName(), message.getMessageId());
189    
190                            // Asset
191    
192                            assetEntryLocalService.deleteEntry(
193                                    message.getWorkflowClassName(), message.getMessageId());
194    
195                            // Resources
196    
197                            if (!message.isDiscussion()) {
198                                    resourceLocalService.deleteResource(
199                                            message.getCompanyId(), message.getWorkflowClassName(),
200                                            ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
201                            }
202    
203                            // Message
204    
205                            mbMessagePersistence.remove(message);
206    
207                            // Statistics
208    
209                            if (!message.isDiscussion()) {
210                                    mbStatsUserLocalService.updateStatsUser(
211                                            message.getGroupId(), message.getUserId());
212                            }
213    
214                            // Workflow
215    
216                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
217                                    message.getCompanyId(), message.getGroupId(),
218                                    message.getWorkflowClassName(), message.getMessageId());
219                    }
220    
221                    // Category
222    
223                    if ((rootMessage.getCategoryId() !=
224                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
225                            (rootMessage.getCategoryId() !=
226                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
227    
228                            try {
229                                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
230                                            thread.getCategoryId());
231    
232                                    MBUtil.updateCategoryStatistics(
233                                            category.getCompanyId(), category.getCategoryId());
234                            }
235                            catch (NoSuchCategoryException nsce) {
236                                    if (!thread.isInTrash()) {
237                                            throw nsce;
238                                    }
239                            }
240                    }
241    
242                    // Thread Asset
243    
244                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
245                            MBThread.class.getName(), thread.getThreadId());
246    
247                    if (assetEntry != null) {
248                            assetEntry.setTitle(rootMessage.getSubject());
249    
250                            assetEntryLocalService.updateAssetEntry(assetEntry);
251                    }
252    
253                    assetEntryLocalService.deleteEntry(
254                            MBThread.class.getName(), thread.getThreadId());
255    
256                    // Trash
257    
258                    trashEntryLocalService.deleteEntry(
259                            MBThread.class.getName(), thread.getThreadId());
260    
261                    // Indexer
262    
263                    Indexer threadIndexer = IndexerRegistryUtil.nullSafeGetIndexer(
264                            MBThread.class);
265    
266                    threadIndexer.delete(thread);
267    
268                    // Thread
269    
270                    mbThreadPersistence.remove(thread);
271            }
272    
273            @Override
274            public void deleteThreads(long groupId, long categoryId)
275                    throws PortalException, SystemException {
276    
277                    deleteThreads(groupId, categoryId, true);
278            }
279    
280            @Override
281            public void deleteThreads(
282                            long groupId, long categoryId, boolean includeTrashedEntries)
283                    throws PortalException, SystemException {
284    
285                    List<MBThread> threads = mbThreadPersistence.findByG_C(
286                            groupId, categoryId);
287    
288                    for (MBThread thread : threads) {
289                            if (includeTrashedEntries || !thread.isInTrash()) {
290                                    mbThreadLocalService.deleteThread(thread);
291                            }
292                    }
293    
294                    if (mbThreadPersistence.countByGroupId(groupId) == 0) {
295                            PortletFileRepositoryUtil.deletePortletRepository(
296                                    groupId, PortletKeys.MESSAGE_BOARDS);
297                    }
298            }
299    
300            @Override
301            public MBThread fetchThread(long threadId) throws SystemException {
302                    return mbThreadPersistence.fetchByPrimaryKey(threadId);
303            }
304    
305            @Override
306            public int getCategoryThreadsCount(
307                            long groupId, long categoryId, int status)
308                    throws SystemException {
309    
310                    if (status == WorkflowConstants.STATUS_ANY) {
311                            return mbThreadPersistence.countByG_C(groupId, categoryId);
312                    }
313                    else {
314                            return mbThreadPersistence.countByG_C_S(
315                                    groupId, categoryId, status);
316                    }
317            }
318    
319            /**
320             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreads(long,
321             *             QueryDefinition)}
322             */
323            @Override
324            public List<MBThread> getGroupThreads(
325                            long groupId, int status, int start, int end)
326                    throws SystemException {
327    
328                    QueryDefinition queryDefinition = new QueryDefinition(
329                            status, start, end, null);
330    
331                    return getGroupThreads(groupId, queryDefinition);
332            }
333    
334            @Override
335            public List<MBThread> getGroupThreads(
336                            long groupId, long userId, boolean subscribed,
337                            boolean includeAnonymous, QueryDefinition queryDefinition)
338                    throws SystemException {
339    
340                    if (userId <= 0) {
341                            return getGroupThreads(groupId, queryDefinition);
342                    }
343    
344                    if (subscribed) {
345                            return mbThreadFinder.findByS_G_U_C(
346                                    groupId, userId, null, queryDefinition);
347                    }
348                    else {
349                            if (includeAnonymous) {
350                                    return mbThreadFinder.findByG_U_C(
351                                            groupId, userId, null, queryDefinition);
352                            }
353                            else {
354                                    return mbThreadFinder.findByG_U_C_A(
355                                            groupId, userId, null, false, queryDefinition);
356                            }
357                    }
358            }
359    
360            @Override
361            public List<MBThread> getGroupThreads(
362                            long groupId, long userId, boolean subscribed,
363                            QueryDefinition queryDefinition)
364                    throws SystemException {
365    
366                    return getGroupThreads(
367                            groupId, userId, subscribed, true, queryDefinition);
368            }
369    
370            /**
371             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreads(long, long,
372             *             boolean, boolean, QueryDefinition)}
373             */
374            @Override
375            public List<MBThread> getGroupThreads(
376                            long groupId, long userId, int status, boolean subscribed,
377                            boolean includeAnonymous, int start, int end)
378                    throws SystemException {
379    
380                    QueryDefinition queryDefinition = new QueryDefinition(
381                            status, start, end, null);
382    
383                    return getGroupThreads(
384                            groupId, userId, subscribed, includeAnonymous, queryDefinition);
385            }
386    
387            /**
388             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreads(long, long,
389             *             boolean, QueryDefinition)}
390             */
391            @Override
392            public List<MBThread> getGroupThreads(
393                            long groupId, long userId, int status, boolean subscribed,
394                            int start, int end)
395                    throws SystemException {
396    
397                    QueryDefinition queryDefinition = new QueryDefinition(
398                            status, start, end, null);
399    
400                    return getGroupThreads(groupId, userId, subscribed, queryDefinition);
401            }
402    
403            /**
404             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreads(long, long,
405             *             QueryDefinition)}
406             */
407            @Override
408            public List<MBThread> getGroupThreads(
409                            long groupId, long userId, int status, int start, int end)
410                    throws SystemException {
411    
412                    QueryDefinition queryDefinition = new QueryDefinition(
413                            status, start, end, null);
414    
415                    return getGroupThreads(groupId, userId, false, queryDefinition);
416            }
417    
418            @Override
419            public List<MBThread> getGroupThreads(
420                            long groupId, long userId, QueryDefinition queryDefinition)
421                    throws SystemException {
422    
423                    return getGroupThreads(groupId, userId, false, queryDefinition);
424            }
425    
426            @Override
427            public List<MBThread> getGroupThreads(
428                            long groupId, QueryDefinition queryDefinition)
429                    throws SystemException {
430    
431                    if (queryDefinition.isExcludeStatus()) {
432                            return mbThreadPersistence.findByG_NotC_NotS(
433                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
434                                    queryDefinition.getStatus(), queryDefinition.getStart(),
435                                    queryDefinition.getEnd());
436                    }
437                    else {
438                            return mbThreadPersistence.findByG_NotC_S(
439                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
440                                    queryDefinition.getStatus(), queryDefinition.getStart(),
441                                    queryDefinition.getEnd());
442                    }
443            }
444    
445            /**
446             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreadsCount(long,
447             *             QueryDefinition)}
448             */
449            @Override
450            public int getGroupThreadsCount(long groupId, int status)
451                    throws SystemException {
452    
453                    QueryDefinition queryDefinition = new QueryDefinition(status);
454    
455                    return getGroupThreadsCount(groupId, queryDefinition);
456            }
457    
458            @Override
459            public int getGroupThreadsCount(
460                            long groupId, long userId, boolean subscribed,
461                            boolean includeAnonymous, QueryDefinition queryDefinition)
462                    throws SystemException {
463    
464                    if (userId <= 0) {
465                            return getGroupThreadsCount(groupId, queryDefinition);
466                    }
467    
468                    if (subscribed) {
469                            return mbThreadFinder.countByS_G_U_C(
470                                    groupId, userId, null, queryDefinition);
471                    }
472                    else {
473                            if (includeAnonymous) {
474                                    return mbThreadFinder.countByG_U_C(
475                                            groupId, userId, null, queryDefinition);
476                            }
477                            else {
478                                    return mbThreadFinder.countByG_U_C_A(
479                                            groupId, userId, null, false, queryDefinition);
480                            }
481                    }
482            }
483    
484            @Override
485            public int getGroupThreadsCount(
486                            long groupId, long userId, boolean subscribed,
487                            QueryDefinition queryDefinition)
488                    throws SystemException {
489    
490                    return getGroupThreadsCount(
491                            groupId, userId, subscribed, true, queryDefinition);
492            }
493    
494            /**
495             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreadsCount(long,
496             *             long, QueryDefinition)}
497             */
498            @Override
499            public int getGroupThreadsCount(long groupId, long userId, int status)
500                    throws SystemException {
501    
502                    QueryDefinition queryDefinition = new QueryDefinition(status);
503    
504                    return getGroupThreadsCount(groupId, userId, false, queryDefinition);
505            }
506    
507            /**
508             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreadsCount(long,
509             *             long, boolean, QueryDefinition)}
510             */
511            @Override
512            public int getGroupThreadsCount(
513                            long groupId, long userId, int status, boolean subscribed)
514                    throws SystemException {
515    
516                    QueryDefinition queryDefinition = new QueryDefinition(status);
517    
518                    return getGroupThreadsCount(
519                            groupId, userId, subscribed, true, queryDefinition);
520            }
521    
522            /**
523             * @deprecated As of 6.2.0, replaced by {@link #getGroupThreadsCount(long,
524             *             long, boolean, boolean, QueryDefinition)}
525             */
526            @Override
527            public int getGroupThreadsCount(
528                            long groupId, long userId, int status, boolean subscribed,
529                            boolean includeAnonymous)
530                    throws SystemException {
531    
532                    QueryDefinition queryDefinition = new QueryDefinition(status);
533    
534                    return getGroupThreadsCount(
535                            groupId, userId, subscribed, includeAnonymous, queryDefinition);
536            }
537    
538            @Override
539            public int getGroupThreadsCount(
540                            long groupId, long userId, QueryDefinition queryDefinition)
541                    throws SystemException {
542    
543                    return getGroupThreadsCount(groupId, userId, false, queryDefinition);
544            }
545    
546            @Override
547            public int getGroupThreadsCount(
548                            long groupId, QueryDefinition queryDefinition)
549                    throws SystemException {
550    
551                    if (queryDefinition.isExcludeStatus()) {
552                            return mbThreadPersistence.countByG_NotC_NotS(
553                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
554                                    queryDefinition.getStatus());
555                    }
556                    else {
557                            return mbThreadPersistence.countByG_NotC_S(
558                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
559                                    queryDefinition.getStatus());
560                    }
561            }
562    
563            @Override
564            public List<MBThread> getNoAssetThreads() throws SystemException {
565                    return mbThreadFinder.findByNoAssets();
566            }
567    
568            @Override
569            public List<MBThread> getPriorityThreads(long categoryId, double priority)
570                    throws PortalException, SystemException {
571    
572                    return getPriorityThreads(categoryId, priority, false);
573            }
574    
575            @Override
576            public List<MBThread> getPriorityThreads(
577                            long categoryId, double priority, boolean inherit)
578                    throws PortalException, SystemException {
579    
580                    if (!inherit) {
581                            return mbThreadPersistence.findByC_P(categoryId, priority);
582                    }
583    
584                    List<MBThread> threads = new ArrayList<MBThread>();
585    
586                    while ((categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
587                               (categoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
588    
589                            threads.addAll(
590                                    0, mbThreadPersistence.findByC_P(categoryId, priority));
591    
592                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
593                                    categoryId);
594    
595                            categoryId = category.getParentCategoryId();
596                    }
597    
598                    return threads;
599            }
600    
601            @Override
602            public MBThread getThread(long threadId)
603                    throws PortalException, SystemException {
604    
605                    return mbThreadPersistence.findByPrimaryKey(threadId);
606            }
607    
608            @Override
609            public List<MBThread> getThreads(
610                            long groupId, long categoryId, int status, int start, int end)
611                    throws SystemException {
612    
613                    if (status == WorkflowConstants.STATUS_ANY) {
614                            return mbThreadPersistence.findByG_C(
615                                    groupId, categoryId, start, end);
616                    }
617                    else {
618                            return mbThreadPersistence.findByG_C_S(
619                                    groupId, categoryId, status, start, end);
620                    }
621            }
622    
623            @Override
624            public int getThreadsCount(long groupId, long categoryId, int status)
625                    throws SystemException {
626    
627                    if (status == WorkflowConstants.STATUS_ANY) {
628                            return mbThreadPersistence.countByG_C(groupId, categoryId);
629                    }
630                    else {
631                            return mbThreadPersistence.countByG_C_S(
632                                    groupId, categoryId, status);
633                    }
634            }
635    
636            @Override
637            public boolean hasAnswerMessage(long threadId) throws SystemException {
638                    int count = mbMessagePersistence.countByT_A(threadId, true);
639    
640                    if (count > 0) {
641                            return true;
642                    }
643                    else {
644                            return false;
645                    }
646            }
647    
648            @BufferedIncrement(
649                    configuration = "MBThread", incrementClass = NumberIncrement.class)
650            @Override
651            public MBThread incrementViewCounter(long threadId, int increment)
652                    throws PortalException, SystemException {
653    
654                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
655    
656                    if (ExportImportThreadLocal.isImportInProcess()) {
657                            return thread;
658                    }
659    
660                    thread.setViewCount(thread.getViewCount() + increment);
661    
662                    mbThreadPersistence.update(thread);
663    
664                    return thread;
665            }
666    
667            @Override
668            public void moveDependentsToTrash(
669                            long groupId, long threadId, long trashEntryId)
670                    throws PortalException, SystemException {
671    
672                    Set<Long> userIds = new HashSet<Long>();
673    
674                    List<MBMessage> messages = mbMessageLocalService.getThreadMessages(
675                            threadId, WorkflowConstants.STATUS_ANY);
676    
677                    for (MBMessage message : messages) {
678    
679                            // Message
680    
681                            if (message.isDiscussion()) {
682                                    continue;
683                            }
684    
685                            int oldStatus = message.getStatus();
686    
687                            message.setStatus(WorkflowConstants.STATUS_IN_TRASH);
688    
689                            mbMessagePersistence.update(message);
690    
691                            userIds.add(message.getUserId());
692    
693                            // Trash
694    
695                            int status = oldStatus;
696    
697                            if (oldStatus == WorkflowConstants.STATUS_PENDING) {
698                                    status = WorkflowConstants.STATUS_DRAFT;
699                            }
700    
701                            if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
702                                    trashVersionLocalService.addTrashVersion(
703                                            trashEntryId, MBMessage.class.getName(),
704                                            message.getMessageId(), status);
705                            }
706    
707                            // Asset
708    
709                            if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
710                                    assetEntryLocalService.updateVisible(
711                                            MBMessage.class.getName(), message.getMessageId(), false);
712                            }
713    
714                            // Indexer
715    
716                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
717                                    MBMessage.class);
718    
719                            indexer.reindex(message);
720    
721                            // Workflow
722    
723                            if (oldStatus == WorkflowConstants.STATUS_PENDING) {
724                                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
725                                            message.getCompanyId(), message.getGroupId(),
726                                            MBMessage.class.getName(), message.getMessageId());
727                            }
728                    }
729    
730                    // Statistics
731    
732                    for (long userId : userIds) {
733                            mbStatsUserLocalService.updateStatsUser(groupId, userId);
734                    }
735            }
736    
737            @Override
738            public MBThread moveThread(long groupId, long categoryId, long threadId)
739                    throws PortalException, SystemException {
740    
741                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
742    
743                    long oldCategoryId = thread.getCategoryId();
744    
745                    MBCategory oldCategory = null;
746    
747                    if (oldCategoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
748                            oldCategory = mbCategoryPersistence.fetchByPrimaryKey(
749                                    oldCategoryId);
750                    }
751    
752                    MBCategory category = null;
753    
754                    if (categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
755                            category = mbCategoryPersistence.fetchByPrimaryKey(categoryId);
756                    }
757    
758                    // Thread
759    
760                    thread.setModifiedDate(new Date());
761                    thread.setCategoryId(categoryId);
762    
763                    mbThreadPersistence.update(thread);
764    
765                    // Messages
766    
767                    List<MBMessage> messages = mbMessagePersistence.findByG_C_T(
768                            groupId, oldCategoryId, thread.getThreadId());
769    
770                    for (MBMessage message : messages) {
771                            message.setCategoryId(categoryId);
772    
773                            mbMessagePersistence.update(message);
774    
775                            // Indexer
776    
777                            if (!message.isDiscussion()) {
778                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
779                                            MBMessage.class);
780    
781                                    indexer.reindex(message);
782                            }
783                    }
784    
785                    // Category
786    
787                    if ((oldCategory != null) && (categoryId != oldCategoryId)) {
788                            MBUtil.updateCategoryStatistics(
789                                    oldCategory.getCompanyId(), oldCategory.getCategoryId());
790                    }
791    
792                    if ((category != null) && (categoryId != oldCategoryId)) {
793                            MBUtil.updateCategoryStatistics(
794                                    category.getCompanyId(), category.getCategoryId());
795                    }
796    
797                    // Indexer
798    
799                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
800                            MBThread.class);
801    
802                    indexer.reindex(thread);
803    
804                    return thread;
805            }
806    
807            @Override
808            public MBThread moveThreadFromTrash(
809                            long userId, long categoryId, long threadId)
810                    throws PortalException, SystemException {
811    
812                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
813    
814                    TrashEntry trashEntry = thread.getTrashEntry();
815    
816                    if (trashEntry.isTrashEntry(MBThread.class, threadId)) {
817                            restoreThreadFromTrash(userId, threadId);
818                    }
819                    else {
820    
821                            // Thread
822    
823                            TrashVersion trashVersion =
824                                    trashVersionLocalService.fetchVersion(
825                                            trashEntry.getEntryId(), MBThread.class.getName(),
826                                            thread.getThreadId());
827    
828                            int status = WorkflowConstants.STATUS_APPROVED;
829    
830                            if (trashVersion != null) {
831                                    status = trashVersion.getStatus();
832                            }
833    
834                            updateStatus(userId, threadId, status);
835    
836                            // Trash
837    
838                            if (trashVersion != null) {
839                                    trashVersionLocalService.deleteTrashVersion(trashVersion);
840                            }
841    
842                            // Messages
843    
844                            restoreDependentsFromTrash(
845                                    thread.getGroupId(), threadId, trashEntry.getEntryId());
846                    }
847    
848                    return moveThread(thread.getGroupId(), categoryId, threadId);
849            }
850    
851            @Override
852            public void moveThreadsToTrash(long groupId, long userId)
853                    throws PortalException, SystemException {
854    
855                    List<MBThread> threads = mbThreadPersistence.findByGroupId(groupId);
856    
857                    for (MBThread thread : threads) {
858                            moveThreadToTrash(userId, thread);
859                    }
860            }
861    
862            @Override
863            public MBThread moveThreadToTrash(long userId, long threadId)
864                    throws PortalException, SystemException {
865    
866                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
867    
868                    return moveThreadToTrash(userId, thread);
869            }
870    
871            @Override
872            public MBThread moveThreadToTrash(long userId, MBThread thread)
873                    throws PortalException, SystemException {
874    
875                    // Thread
876    
877                    if (thread.getCategoryId() ==
878                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
879    
880                            return thread;
881                    }
882    
883                    int oldStatus = thread.getStatus();
884    
885                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
886                            thread.setStatus(WorkflowConstants.STATUS_DRAFT);
887    
888                            mbThreadPersistence.update(thread);
889                    }
890    
891                    thread = updateStatus(
892                            userId, thread.getThreadId(), WorkflowConstants.STATUS_IN_TRASH);
893    
894                    // Trash
895    
896                    TrashEntry trashEntry = trashEntryLocalService.addTrashEntry(
897                            userId, thread.getGroupId(), MBThread.class.getName(),
898                            thread.getThreadId(), thread.getUuid(), null, oldStatus, null,
899                            null);
900    
901                    // Messages
902    
903                    moveDependentsToTrash(
904                            thread.getGroupId(), thread.getThreadId(), trashEntry.getEntryId());
905    
906                    // Social
907    
908                    MBMessage message = mbMessageLocalService.getMBMessage(
909                            thread.getRootMessageId());
910    
911                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
912    
913                    extraDataJSONObject.put("rootMessageId", thread.getRootMessageId());
914                    extraDataJSONObject.put("title", message.getSubject());
915    
916                    socialActivityLocalService.addActivity(
917                            userId, thread.getGroupId(), MBThread.class.getName(),
918                            thread.getThreadId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
919                            extraDataJSONObject.toString(), 0);
920    
921                    return thread;
922            }
923    
924            @Override
925            public void restoreDependentsFromTrash(
926                            long groupId, long threadId, long trashEntryId)
927                    throws PortalException, SystemException {
928    
929                    Set<Long> userIds = new HashSet<Long>();
930    
931                    List<MBMessage> messages = mbMessageLocalService.getThreadMessages(
932                            threadId, WorkflowConstants.STATUS_ANY);
933    
934                    for (MBMessage message : messages) {
935    
936                            // Message
937    
938                            if (message.isDiscussion()) {
939                                    continue;
940                            }
941    
942                            TrashVersion trashVersion = trashVersionLocalService.fetchVersion(
943                                    trashEntryId, MBMessage.class.getName(),
944                                    message.getMessageId());
945    
946                            int oldStatus = WorkflowConstants.STATUS_APPROVED;
947    
948                            if (trashVersion != null) {
949                                    oldStatus = trashVersion.getStatus();
950                            }
951    
952                            message.setStatus(oldStatus);
953    
954                            mbMessagePersistence.update(message);
955    
956                            userIds.add(message.getUserId());
957    
958                            // Trash
959    
960                            if (trashVersion != null) {
961                                    trashVersionLocalService.deleteTrashVersion(trashVersion);
962                            }
963    
964                            // Asset
965    
966                            if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
967                                    assetEntryLocalService.updateVisible(
968                                            MBMessage.class.getName(), message.getMessageId(), true);
969                            }
970    
971                            // Indexer
972    
973                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
974                                    MBMessage.class);
975    
976                            indexer.reindex(message);
977                    }
978    
979                    // Statistics
980    
981                    for (long userId : userIds) {
982                            mbStatsUserLocalService.updateStatsUser(groupId, userId);
983                    }
984            }
985    
986            @Override
987            public void restoreThreadFromTrash(long userId, long threadId)
988                    throws PortalException, SystemException {
989    
990                    // Thread
991    
992                    MBThread thread = getThread(threadId);
993    
994                    if (thread.getCategoryId() ==
995                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
996    
997                            return;
998                    }
999    
1000                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
1001                            MBThread.class.getName(), threadId);
1002    
1003                    updateStatus(userId, threadId, trashEntry.getStatus());
1004    
1005                    // Messages
1006    
1007                    restoreDependentsFromTrash(
1008                            thread.getGroupId(), threadId, trashEntry.getEntryId());
1009    
1010                    // Trash
1011    
1012                    trashEntryLocalService.deleteEntry(trashEntry.getEntryId());
1013    
1014                    // Social
1015    
1016                    MBMessage message = mbMessageLocalService.getMBMessage(
1017                            thread.getRootMessageId());
1018    
1019                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1020    
1021                    extraDataJSONObject.put("rootMessageId", thread.getRootMessageId());
1022                    extraDataJSONObject.put("title", message.getSubject());
1023    
1024                    socialActivityLocalService.addActivity(
1025                            userId, thread.getGroupId(), MBThread.class.getName(),
1026                            thread.getThreadId(),
1027                            SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
1028                            extraDataJSONObject.toString(), 0);
1029            }
1030    
1031            @Override
1032            public Hits search(
1033                            long groupId, long userId, long creatorUserId, int status,
1034                            int start, int end)
1035                    throws PortalException, SystemException {
1036    
1037                    return search(groupId, userId, creatorUserId, 0, 0, status, start, end);
1038            }
1039    
1040            @Override
1041            public Hits search(
1042                            long groupId, long userId, long creatorUserId, long startDate,
1043                            long endDate, int status, int start, int end)
1044                    throws PortalException, SystemException {
1045    
1046                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1047                            MBThread.class.getName());
1048    
1049                    SearchContext searchContext = new SearchContext();
1050    
1051                    searchContext.setAttribute(Field.STATUS, status);
1052    
1053                    if (endDate > 0) {
1054                            searchContext.setAttribute("endDate", endDate);
1055                    }
1056    
1057                    searchContext.setAttribute("paginationType", "none");
1058    
1059                    if (creatorUserId > 0) {
1060                            searchContext.setAttribute(
1061                                    "participantUserId", String.valueOf(creatorUserId));
1062                    }
1063    
1064                    if (startDate > 0) {
1065                            searchContext.setAttribute("startDate", startDate);
1066                    }
1067    
1068                    Group group = groupLocalService.getGroup(groupId);
1069    
1070                    searchContext.setCompanyId(group.getCompanyId());
1071    
1072                    searchContext.setEnd(end);
1073                    searchContext.setGroupIds(new long[] {groupId});
1074                    searchContext.setSorts(new Sort("lastPostDate", true));
1075                    searchContext.setStart(start);
1076                    searchContext.setUserId(userId);
1077    
1078                    return indexer.search(searchContext);
1079            }
1080    
1081            @Override
1082            public MBThread splitThread(
1083                            long messageId, String subject, ServiceContext serviceContext)
1084                    throws PortalException, SystemException {
1085    
1086                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
1087    
1088                    if (message.isRoot()) {
1089                            throw new SplitThreadException();
1090                    }
1091    
1092                    MBCategory category = message.getCategory();
1093                    MBThread oldThread = message.getThread();
1094                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
1095                            oldThread.getRootMessageId());
1096    
1097                    // Message flags
1098    
1099                    mbMessageLocalService.updateAnswer(message, false, true);
1100    
1101                    // Create new thread
1102    
1103                    MBThread thread = addThread(
1104                            message.getCategoryId(), message, serviceContext);
1105    
1106                    oldThread.setModifiedDate(serviceContext.getModifiedDate(new Date()));
1107    
1108                    mbThreadPersistence.update(oldThread);
1109    
1110                    // Update messages
1111    
1112                    if (Validator.isNotNull(subject)) {
1113                            MBMessageDisplay messageDisplay =
1114                                    mbMessageService.getMessageDisplay(
1115                                            messageId, WorkflowConstants.STATUS_ANY,
1116                                            MBThreadConstants.THREAD_VIEW_TREE, false);
1117    
1118                            MBTreeWalker treeWalker = messageDisplay.getTreeWalker();
1119    
1120                            List<MBMessage> messages = treeWalker.getMessages();
1121    
1122                            int[] range = treeWalker.getChildrenRange(message);
1123    
1124                            for (int i = range[0]; i < range[1]; i++) {
1125                                    MBMessage curMessage = messages.get(i);
1126    
1127                                    String oldSubject = message.getSubject();
1128                                    String curSubject = curMessage.getSubject();
1129    
1130                                    if (oldSubject.startsWith("RE: ")) {
1131                                            curSubject = StringUtil.replace(
1132                                                    curSubject, rootMessage.getSubject(), subject);
1133                                    }
1134                                    else {
1135                                            curSubject = StringUtil.replace(
1136                                                    curSubject, oldSubject, subject);
1137                                    }
1138    
1139                                    curMessage.setSubject(curSubject);
1140    
1141                                    mbMessagePersistence.update(curMessage);
1142                            }
1143    
1144                            message.setSubject(subject);
1145                    }
1146    
1147                    message.setThreadId(thread.getThreadId());
1148                    message.setRootMessageId(thread.getRootMessageId());
1149                    message.setParentMessageId(0);
1150    
1151                    mbMessagePersistence.update(message);
1152    
1153                    // Indexer
1154    
1155                    if (!message.isDiscussion()) {
1156                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1157                                    MBMessage.class);
1158    
1159                            indexer.reindex(message);
1160                    }
1161    
1162                    // Update children
1163    
1164                    moveChildrenMessages(message, category, oldThread.getThreadId());
1165    
1166                    // Update new thread
1167    
1168                    MBUtil.updateThreadMessageCount(
1169                            thread.getCompanyId(), thread.getThreadId());
1170    
1171                    // Update old thread
1172    
1173                    MBUtil.updateThreadMessageCount(
1174                            oldThread.getCompanyId(), oldThread.getThreadId());
1175    
1176                    // Category
1177    
1178                    if ((message.getCategoryId() !=
1179                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
1180                            (message.getCategoryId() !=
1181                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
1182    
1183                            MBUtil.updateCategoryThreadCount(
1184                                    category.getCompanyId(), category.getCategoryId());
1185                    }
1186    
1187                    // Indexer
1188    
1189                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1190                            MBThread.class);
1191    
1192                    indexer.reindex(oldThread);
1193                    indexer.reindex(message.getThread());
1194    
1195                    return thread;
1196            }
1197    
1198            @Override
1199            public void updateQuestion(long threadId, boolean question)
1200                    throws PortalException, SystemException {
1201    
1202                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
1203    
1204                    if (thread.isQuestion() == question) {
1205                            return;
1206                    }
1207    
1208                    thread.setQuestion(question);
1209    
1210                    mbThreadPersistence.update(thread);
1211    
1212                    if (!question) {
1213                            MBMessage message = mbMessagePersistence.findByPrimaryKey(
1214                                    thread.getRootMessageId());
1215    
1216                            mbMessageLocalService.updateAnswer(message, false, true);
1217                    }
1218            }
1219    
1220            @Override
1221            public MBThread updateStatus(long userId, long threadId, int status)
1222                    throws PortalException, SystemException {
1223    
1224                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
1225    
1226                    // Thread
1227    
1228                    User user = userPersistence.findByPrimaryKey(userId);
1229    
1230                    Date now = new Date();
1231    
1232                    thread.setModifiedDate(now);
1233                    thread.setStatus(status);
1234                    thread.setStatusByUserId(user.getUserId());
1235                    thread.setStatusByUserName(user.getFullName());
1236                    thread.setStatusDate(now);
1237    
1238                    mbThreadPersistence.update(thread);
1239    
1240                    // Messages
1241    
1242                    if (thread.getCategoryId() !=
1243                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
1244    
1245                            // Category
1246    
1247                            MBCategory category = mbCategoryPersistence.fetchByPrimaryKey(
1248                                    thread.getCategoryId());
1249    
1250                            if (category != null) {
1251                                    MBUtil.updateCategoryStatistics(
1252                                            category.getCompanyId(), category.getCategoryId());
1253                            }
1254                    }
1255    
1256                    // Indexer
1257    
1258                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1259                            MBThread.class);
1260    
1261                    indexer.reindex(thread);
1262    
1263                    return thread;
1264            }
1265    
1266            /**
1267             * @deprecated As of 6.2.0, replaced by {@link #incrementViewCounter(long,
1268             *             int)}
1269             */
1270            @Override
1271            public MBThread updateThread(long threadId, int viewCount)
1272                    throws PortalException, SystemException {
1273    
1274                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
1275    
1276                    thread.setViewCount(viewCount);
1277    
1278                    mbThreadPersistence.update(thread);
1279    
1280                    return thread;
1281            }
1282    
1283            protected void moveChildrenMessages(
1284                            MBMessage parentMessage, MBCategory category, long oldThreadId)
1285                    throws PortalException, SystemException {
1286    
1287                    List<MBMessage> messages = mbMessagePersistence.findByT_P(
1288                            oldThreadId, parentMessage.getMessageId());
1289    
1290                    for (MBMessage message : messages) {
1291                            message.setCategoryId(parentMessage.getCategoryId());
1292                            message.setThreadId(parentMessage.getThreadId());
1293                            message.setRootMessageId(parentMessage.getRootMessageId());
1294    
1295                            mbMessagePersistence.update(message);
1296    
1297                            if (!message.isDiscussion()) {
1298                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1299                                            MBMessage.class);
1300    
1301                                    indexer.reindex(message);
1302                            }
1303    
1304                            moveChildrenMessages(message, category, oldThreadId);
1305                    }
1306            }
1307    
1308    }