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.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.search.Indexer;
021    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
022    import com.liferay.portal.kernel.systemevent.SystemEvent;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.kernel.workflow.WorkflowConstants;
025    import com.liferay.portal.model.ResourceConstants;
026    import com.liferay.portal.model.SystemEventConstants;
027    import com.liferay.portal.model.User;
028    import com.liferay.portal.service.ServiceContext;
029    import com.liferay.portlet.messageboards.CategoryNameException;
030    import com.liferay.portlet.messageboards.model.MBCategory;
031    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
032    import com.liferay.portlet.messageboards.model.MBMailingList;
033    import com.liferay.portlet.messageboards.model.MBMessage;
034    import com.liferay.portlet.messageboards.model.MBThread;
035    import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
036    import com.liferay.portlet.messageboards.service.base.MBCategoryLocalServiceBaseImpl;
037    import com.liferay.portlet.trash.model.TrashEntry;
038    import com.liferay.portlet.trash.model.TrashVersion;
039    
040    import java.util.ArrayList;
041    import java.util.Date;
042    import java.util.List;
043    
044    /**
045     * @author Brian Wing Shun Chan
046     * @author Wesley Gong
047     */
048    public class MBCategoryLocalServiceImpl extends MBCategoryLocalServiceBaseImpl {
049    
050            @Override
051            public MBCategory addCategory(
052                            long userId, long parentCategoryId, String name, String description,
053                            ServiceContext serviceContext)
054                    throws PortalException {
055    
056                    return addCategory(
057                            userId, parentCategoryId, name, description,
058                            MBCategoryConstants.DEFAULT_DISPLAY_STYLE, null, null, null, 0,
059                            false, null, null, 0, null, false, null, 0, false, null, null,
060                            false, false, serviceContext);
061            }
062    
063            @Override
064            public MBCategory addCategory(
065                            long userId, long parentCategoryId, String name, String description,
066                            String displayStyle, String emailAddress, String inProtocol,
067                            String inServerName, int inServerPort, boolean inUseSSL,
068                            String inUserName, String inPassword, int inReadInterval,
069                            String outEmailAddress, boolean outCustom, String outServerName,
070                            int outServerPort, boolean outUseSSL, String outUserName,
071                            String outPassword, boolean allowAnonymous,
072                            boolean mailingListActive, ServiceContext serviceContext)
073                    throws PortalException {
074    
075                    // Category
076    
077                    User user = userPersistence.findByPrimaryKey(userId);
078                    long groupId = serviceContext.getScopeGroupId();
079                    parentCategoryId = getParentCategoryId(groupId, parentCategoryId);
080    
081                    validate(name);
082    
083                    long categoryId = counterLocalService.increment();
084    
085                    MBCategory category = mbCategoryPersistence.create(categoryId);
086    
087                    category.setUuid(serviceContext.getUuid());
088                    category.setGroupId(groupId);
089                    category.setCompanyId(user.getCompanyId());
090                    category.setUserId(user.getUserId());
091                    category.setUserName(user.getFullName());
092                    category.setParentCategoryId(parentCategoryId);
093                    category.setName(name);
094                    category.setDescription(description);
095                    category.setDisplayStyle(displayStyle);
096                    category.setExpandoBridgeAttributes(serviceContext);
097    
098                    mbCategoryPersistence.update(category);
099    
100                    // Resources
101    
102                    if (serviceContext.isAddGroupPermissions() ||
103                            serviceContext.isAddGuestPermissions()) {
104    
105                            addCategoryResources(
106                                    category, serviceContext.isAddGroupPermissions(),
107                                    serviceContext.isAddGuestPermissions());
108                    }
109                    else {
110                            addCategoryResources(
111                                    category, serviceContext.getGroupPermissions(),
112                                    serviceContext.getGuestPermissions());
113                    }
114    
115                    // Mailing list
116    
117                    mbMailingListLocalService.addMailingList(
118                            userId, groupId, category.getCategoryId(), emailAddress, inProtocol,
119                            inServerName, inServerPort, inUseSSL, inUserName, inPassword,
120                            inReadInterval, outEmailAddress, outCustom, outServerName,
121                            outServerPort, outUseSSL, outUserName, outPassword, allowAnonymous,
122                            mailingListActive, serviceContext);
123    
124                    return category;
125            }
126    
127            @Override
128            public void addCategoryResources(
129                            long categoryId, boolean addGroupPermissions,
130                            boolean addGuestPermissions)
131                    throws PortalException {
132    
133                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
134                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
135    
136                            return;
137                    }
138    
139                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
140                            categoryId);
141    
142                    addCategoryResources(
143                            category, addGroupPermissions, addGuestPermissions);
144            }
145    
146            @Override
147            public void addCategoryResources(
148                            long categoryId, String[] groupPermissions,
149                            String[] guestPermissions)
150                    throws PortalException {
151    
152                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
153                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
154    
155                            return;
156                    }
157    
158                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
159                            categoryId);
160    
161                    addCategoryResources(category, groupPermissions, guestPermissions);
162            }
163    
164            @Override
165            public void addCategoryResources(
166                            MBCategory category, boolean addGroupPermissions,
167                            boolean addGuestPermissions)
168                    throws PortalException {
169    
170                    resourceLocalService.addResources(
171                            category.getCompanyId(), category.getGroupId(),
172                            category.getUserId(), MBCategory.class.getName(),
173                            category.getCategoryId(), false, addGroupPermissions,
174                            addGuestPermissions);
175            }
176    
177            @Override
178            public void addCategoryResources(
179                            MBCategory category, String[] groupPermissions,
180                            String[] guestPermissions)
181                    throws PortalException {
182    
183                    resourceLocalService.addModelResources(
184                            category.getCompanyId(), category.getGroupId(),
185                            category.getUserId(), MBCategory.class.getName(),
186                            category.getCategoryId(), groupPermissions, guestPermissions);
187            }
188    
189            @Override
190            public void deleteCategories(long groupId) throws PortalException {
191                    List<MBCategory> categories = mbCategoryPersistence.findByGroupId(
192                            groupId);
193    
194                    for (MBCategory category : categories) {
195                            mbCategoryLocalService.deleteCategory(category);
196                    }
197            }
198    
199            @Override
200            public void deleteCategory(long categoryId) throws PortalException {
201                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
202                            categoryId);
203    
204                    mbCategoryLocalService.deleteCategory(category);
205            }
206    
207            @Override
208            public void deleteCategory(MBCategory category) throws PortalException {
209                    mbCategoryLocalService.deleteCategory(category, true);
210            }
211    
212            @Override
213            @SystemEvent(
214                    action = SystemEventConstants.ACTION_SKIP,
215                    type = SystemEventConstants.TYPE_DELETE
216            )
217            public void deleteCategory(
218                            MBCategory category, boolean includeTrashedEntries)
219                    throws PortalException {
220    
221                    // Categories
222    
223                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
224                            category.getGroupId(), category.getCategoryId());
225    
226                    for (MBCategory curCategory : categories) {
227                            if (includeTrashedEntries || !curCategory.isInTrashExplicitly()) {
228                                    mbCategoryLocalService.deleteCategory(
229                                            curCategory, includeTrashedEntries);
230                            }
231                    }
232    
233                    // Threads
234    
235                    mbThreadLocalService.deleteThreads(
236                            category.getGroupId(), category.getCategoryId(),
237                            includeTrashedEntries);
238    
239                    // Mailing list
240    
241                    MBMailingList mbMailingList =
242                            mbMailingListLocalService.fetchCategoryMailingList(
243                                    category.getGroupId(), category.getCategoryId());
244    
245                    if (mbMailingList != null) {
246                            mbMailingListLocalService.deleteMailingList(mbMailingList);
247                    }
248    
249                    // Subscriptions
250    
251                    subscriptionLocalService.deleteSubscriptions(
252                            category.getCompanyId(), MBCategory.class.getName(),
253                            category.getCategoryId());
254    
255                    // Expando
256    
257                    expandoRowLocalService.deleteRows(category.getCategoryId());
258    
259                    // Resources
260    
261                    resourceLocalService.deleteResource(
262                            category.getCompanyId(), MBCategory.class.getName(),
263                            ResourceConstants.SCOPE_INDIVIDUAL, category.getCategoryId());
264    
265                    // Trash
266    
267                    if (category.isInTrashExplicitly()) {
268                            trashEntryLocalService.deleteEntry(
269                                    MBCategory.class.getName(), category.getCategoryId());
270                    }
271                    else {
272                            trashVersionLocalService.deleteTrashVersion(
273                                    MBCategory.class.getName(), category.getCategoryId());
274                    }
275    
276                    // Category
277    
278                    mbCategoryPersistence.remove(category);
279            }
280    
281            @Override
282            public List<MBCategory> getCategories(long groupId) {
283                    return mbCategoryPersistence.findByGroupId(groupId);
284            }
285    
286            @Override
287            public List<MBCategory> getCategories(long groupId, int status) {
288                    return mbCategoryPersistence.findByG_S(groupId, status);
289            }
290    
291            @Override
292            public List<MBCategory> getCategories(
293                    long groupId, long parentCategoryId, int start, int end) {
294    
295                    return mbCategoryPersistence.findByG_P(
296                            groupId, parentCategoryId, start, end);
297            }
298    
299            @Override
300            public List<MBCategory> getCategories(
301                    long groupId, long parentCategoryId, int status, int start, int end) {
302    
303                    if (status == WorkflowConstants.STATUS_ANY) {
304                            return mbCategoryPersistence.findByG_P(
305                                    groupId, parentCategoryId, start, end);
306                    }
307    
308                    return mbCategoryPersistence.findByG_P_S(
309                            groupId, parentCategoryId, status, start, end);
310            }
311    
312            @Override
313            public List<MBCategory> getCategories(
314                    long groupId, long excludedCategoryId, long parentCategoryId,
315                    int status, int start, int end) {
316    
317                    if (status == WorkflowConstants.STATUS_ANY) {
318                            return mbCategoryPersistence.findByNotC_G_P(
319                                    excludedCategoryId, groupId, parentCategoryId, start, end);
320                    }
321    
322                    return mbCategoryPersistence.findByNotC_G_P_S(
323                            excludedCategoryId, groupId, parentCategoryId, status, start, end);
324            }
325    
326            @Override
327            public List<MBCategory> getCategories(
328                    long groupId, long[] parentCategoryIds, int start, int end) {
329    
330                    return mbCategoryPersistence.findByG_P(
331                            groupId, parentCategoryIds, start, end);
332            }
333    
334            @Override
335            public List<MBCategory> getCategories(
336                    long groupId, long[] parentCategoryIds, int status, int start,
337                    int end) {
338    
339                    if (status == WorkflowConstants.STATUS_ANY) {
340                            return mbCategoryPersistence.findByG_P(
341                                    groupId, parentCategoryIds, start, end);
342                    }
343    
344                    return mbCategoryPersistence.findByG_P_S(
345                            groupId, parentCategoryIds, status, start, end);
346            }
347    
348            @Override
349            public List<MBCategory> getCategories(
350                    long groupId, long[] excludedCategoryIds, long[] parentCategoryIds,
351                    int status, int start, int end) {
352    
353                    if (status == WorkflowConstants.STATUS_ANY) {
354                            return mbCategoryPersistence.findByNotC_G_P(
355                                    excludedCategoryIds, groupId, parentCategoryIds, start, end);
356                    }
357    
358                    return mbCategoryPersistence.findByNotC_G_P_S(
359                            excludedCategoryIds, groupId, parentCategoryIds, status, start,
360                            end);
361            }
362    
363            @Override
364            public List<Object> getCategoriesAndThreads(long groupId, long categoryId) {
365                    List<Object> categoriesAndThreads = new ArrayList<>();
366    
367                    List<MBCategory> categories = getCategories(
368                            groupId, categoryId, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
369    
370                    categoriesAndThreads.addAll(categories);
371    
372                    List<MBThread> threads = mbThreadLocalService.getThreads(
373                            groupId, categoryId, WorkflowConstants.STATUS_ANY,
374                            QueryUtil.ALL_POS, QueryUtil.ALL_POS);
375    
376                    categoriesAndThreads.addAll(threads);
377    
378                    return categoriesAndThreads;
379            }
380    
381            @Override
382            public int getCategoriesCount(long groupId) {
383                    return mbCategoryPersistence.countByGroupId(groupId);
384            }
385    
386            @Override
387            public int getCategoriesCount(long groupId, int status) {
388                    return mbCategoryPersistence.countByG_S(groupId, status);
389            }
390    
391            @Override
392            public int getCategoriesCount(long groupId, long parentCategoryId) {
393                    return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
394            }
395    
396            @Override
397            public int getCategoriesCount(
398                    long groupId, long parentCategoryId, int status) {
399    
400                    if (status == WorkflowConstants.STATUS_ANY) {
401                            return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
402                    }
403    
404                    return mbCategoryPersistence.countByG_P_S(
405                            groupId, parentCategoryId, status);
406            }
407    
408            @Override
409            public int getCategoriesCount(
410                    long groupId, long excludedCategoryId, long parentCategoryId,
411                    int status) {
412    
413                    if (status == WorkflowConstants.STATUS_ANY) {
414                            return mbCategoryPersistence.countByNotC_G_P(
415                                    excludedCategoryId, groupId, parentCategoryId);
416                    }
417    
418                    return mbCategoryPersistence.countByNotC_G_P_S(
419                            excludedCategoryId, groupId, parentCategoryId, status);
420            }
421    
422            @Override
423            public int getCategoriesCount(long groupId, long[] parentCategoryIds) {
424                    return mbCategoryPersistence.countByG_P(groupId, parentCategoryIds);
425            }
426    
427            @Override
428            public int getCategoriesCount(
429                    long groupId, long[] parentCategoryIds, int status) {
430    
431                    if (status == WorkflowConstants.STATUS_ANY) {
432                            return mbCategoryPersistence.countByG_P(groupId, parentCategoryIds);
433                    }
434    
435                    return mbCategoryPersistence.countByG_P_S(
436                            groupId, parentCategoryIds, status);
437            }
438    
439            @Override
440            public int getCategoriesCount(
441                    long groupId, long[] excludedCategoryIds, long[] parentCategoryIds,
442                    int status) {
443    
444                    if (status == WorkflowConstants.STATUS_ANY) {
445                            return mbCategoryPersistence.countByNotC_G_P(
446                                    excludedCategoryIds, groupId, parentCategoryIds);
447                    }
448    
449                    return mbCategoryPersistence.countByNotC_G_P_S(
450                            excludedCategoryIds, groupId, parentCategoryIds, status);
451            }
452    
453            @Override
454            public MBCategory getCategory(long categoryId) throws PortalException {
455                    MBCategory category = null;
456    
457                    if ((categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
458                            (categoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
459    
460                            category = mbCategoryPersistence.findByPrimaryKey(categoryId);
461                    }
462                    else {
463                            category = new MBCategoryImpl();
464    
465                            category.setCategoryId(categoryId);
466                            category.setParentCategoryId(categoryId);
467                    }
468    
469                    return category;
470            }
471    
472            @Override
473            public List<MBCategory> getCompanyCategories(
474                    long companyId, int start, int end) {
475    
476                    return mbCategoryPersistence.findByCompanyId(companyId, start, end);
477            }
478    
479            @Override
480            public int getCompanyCategoriesCount(long companyId) {
481                    return mbCategoryPersistence.countByCompanyId(companyId);
482            }
483    
484            @Override
485            public List<Long> getSubcategoryIds(
486                    List<Long> categoryIds, long groupId, long categoryId) {
487    
488                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
489                            groupId, categoryId);
490    
491                    for (MBCategory category : categories) {
492                            categoryIds.add(category.getCategoryId());
493    
494                            getSubcategoryIds(
495                                    categoryIds, category.getGroupId(), category.getCategoryId());
496                    }
497    
498                    return categoryIds;
499            }
500    
501            @Override
502            public List<MBCategory> getSubscribedCategories(
503                    long groupId, long userId, int start, int end) {
504    
505                    QueryDefinition<MBCategory> queryDefinition = new QueryDefinition<>(
506                            WorkflowConstants.STATUS_ANY, start, end, null);
507    
508                    return mbCategoryFinder.findByS_G_U_P(
509                            groupId, userId, null, queryDefinition);
510            }
511    
512            @Override
513            public int getSubscribedCategoriesCount(long groupId, long userId) {
514                    QueryDefinition<MBCategory> queryDefinition = new QueryDefinition<>(
515                            WorkflowConstants.STATUS_ANY);
516    
517                    return mbCategoryFinder.countByS_G_U_P(
518                            groupId, userId, null, queryDefinition);
519            }
520    
521            @Override
522            public void moveCategoriesToTrash(long groupId, long userId)
523                    throws PortalException {
524    
525                    List<MBCategory> categories = mbCategoryPersistence.findByGroupId(
526                            groupId);
527    
528                    for (MBCategory category : categories) {
529                            moveCategoryToTrash(userId, category.getCategoryId());
530                    }
531            }
532    
533            @Override
534            public MBCategory moveCategory(
535                            long categoryId, long parentCategoryId,
536                            boolean mergeWithParentCategory)
537                    throws PortalException {
538    
539                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
540                            categoryId);
541    
542                    parentCategoryId = getParentCategoryId(category, parentCategoryId);
543    
544                    if (mergeWithParentCategory && (categoryId != parentCategoryId) &&
545                            (parentCategoryId !=
546                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
547                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
548    
549                            mergeCategories(category, parentCategoryId);
550    
551                            return category;
552                    }
553    
554                    category.setParentCategoryId(parentCategoryId);
555    
556                    return mbCategoryPersistence.update(category);
557            }
558    
559            @Override
560            public MBCategory moveCategoryFromTrash(
561                            long userId, long categoryId, long newCategoryId)
562                    throws PortalException {
563    
564                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
565                            categoryId);
566    
567                    if (category.isInTrashExplicitly()) {
568                            restoreCategoryFromTrash(userId, categoryId);
569                    }
570                    else {
571    
572                            // Category
573    
574                            TrashVersion trashVersion = trashVersionLocalService.fetchVersion(
575                                    MBCategory.class.getName(), category.getCategoryId());
576    
577                            int status = WorkflowConstants.STATUS_APPROVED;
578    
579                            if (trashVersion != null) {
580                                    status = trashVersion.getStatus();
581                            }
582    
583                            updateStatus(userId, categoryId, status);
584    
585                            // Trash
586    
587                            if (trashVersion != null) {
588                                    trashVersionLocalService.deleteTrashVersion(trashVersion);
589                            }
590    
591                            // Categories and threads
592    
593                            User user = userPersistence.findByPrimaryKey(userId);
594    
595                            List<Object> categoriesAndThreads = getCategoriesAndThreads(
596                                    category.getGroupId(), categoryId);
597    
598                            restoreDependentsFromTrash(user, categoriesAndThreads);
599                    }
600    
601                    return moveCategory(categoryId, newCategoryId, false);
602            }
603    
604            @Override
605            public MBCategory moveCategoryToTrash(long userId, long categoryId)
606                    throws PortalException {
607    
608                    // Category
609    
610                    MBCategory category = updateStatus(
611                            userId, categoryId, WorkflowConstants.STATUS_IN_TRASH);
612    
613                    // Trash
614    
615                    TrashEntry trashEntry = trashEntryLocalService.addTrashEntry(
616                            userId, category.getGroupId(), MBCategory.class.getName(),
617                            categoryId, category.getUuid(), null,
618                            WorkflowConstants.STATUS_APPROVED, null, null);
619    
620                    // Categories and threads
621    
622                    User user = userPersistence.findByPrimaryKey(userId);
623    
624                    List<Object> categoriesAndThreads = getCategoriesAndThreads(
625                            category.getGroupId(), categoryId);
626    
627                    moveDependentsToTrash(
628                            user, categoriesAndThreads, trashEntry.getEntryId());
629    
630                    return category;
631            }
632    
633            @Override
634            public void restoreCategoryFromTrash(long userId, long categoryId)
635                    throws PortalException {
636    
637                    // Category
638    
639                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
640                            MBCategory.class.getName(), categoryId);
641    
642                    MBCategory category = updateStatus(
643                            userId, categoryId, WorkflowConstants.STATUS_APPROVED);
644    
645                    // Categories and threads
646    
647                    User user = userPersistence.findByPrimaryKey(userId);
648    
649                    List<Object> categoriesAndThreads = getCategoriesAndThreads(
650                            category.getGroupId(), categoryId);
651    
652                    restoreDependentsFromTrash(user, categoriesAndThreads);
653    
654                    // Trash
655    
656                    trashEntryLocalService.deleteEntry(trashEntry.getEntryId());
657            }
658    
659            @Override
660            public void subscribeCategory(long userId, long groupId, long categoryId)
661                    throws PortalException {
662    
663                    if (categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
664                            categoryId = groupId;
665                    }
666    
667                    subscriptionLocalService.addSubscription(
668                            userId, groupId, MBCategory.class.getName(), categoryId);
669            }
670    
671            @Override
672            public void unsubscribeCategory(long userId, long groupId, long categoryId)
673                    throws PortalException {
674    
675                    if (categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
676                            categoryId = groupId;
677                    }
678    
679                    subscriptionLocalService.deleteSubscription(
680                            userId, MBCategory.class.getName(), categoryId);
681            }
682    
683            @Override
684            public MBCategory updateCategory(
685                            long categoryId, long parentCategoryId, String name,
686                            String description, String displayStyle, String emailAddress,
687                            String inProtocol, String inServerName, int inServerPort,
688                            boolean inUseSSL, String inUserName, String inPassword,
689                            int inReadInterval, String outEmailAddress, boolean outCustom,
690                            String outServerName, int outServerPort, boolean outUseSSL,
691                            String outUserName, String outPassword, boolean allowAnonymous,
692                            boolean mailingListActive, boolean mergeWithParentCategory,
693                            ServiceContext serviceContext)
694                    throws PortalException {
695    
696                    // Merge categories
697    
698                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
699                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
700    
701                            return null;
702                    }
703    
704                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
705                            categoryId);
706    
707                    parentCategoryId = getParentCategoryId(category, parentCategoryId);
708    
709                    if (mergeWithParentCategory && (categoryId != parentCategoryId) &&
710                            (parentCategoryId !=
711                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
712                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
713    
714                            mergeCategories(category, parentCategoryId);
715    
716                            return category;
717                    }
718    
719                    // Category
720    
721                    validate(name);
722    
723                    category.setParentCategoryId(parentCategoryId);
724                    category.setName(name);
725                    category.setDescription(description);
726    
727                    if (!displayStyle.equals(category.getDisplayStyle())) {
728                            category.setDisplayStyle(displayStyle);
729    
730                            updateChildCategoriesDisplayStyle(category, displayStyle);
731                    }
732    
733                    category.setExpandoBridgeAttributes(serviceContext);
734    
735                    mbCategoryPersistence.update(category);
736    
737                    // Mailing list
738    
739                    MBMailingList mailingList = mbMailingListPersistence.fetchByG_C(
740                            category.getGroupId(), category.getCategoryId());
741    
742                    if (mailingList != null) {
743                            mbMailingListLocalService.updateMailingList(
744                                    mailingList.getMailingListId(), emailAddress, inProtocol,
745                                    inServerName, inServerPort, inUseSSL, inUserName, inPassword,
746                                    inReadInterval, outEmailAddress, outCustom, outServerName,
747                                    outServerPort, outUseSSL, outUserName, outPassword,
748                                    allowAnonymous, mailingListActive, serviceContext);
749                    }
750                    else {
751                            mbMailingListLocalService.addMailingList(
752                                    category.getUserId(), category.getGroupId(),
753                                    category.getCategoryId(), emailAddress, inProtocol,
754                                    inServerName, inServerPort, inUseSSL, inUserName, inPassword,
755                                    inReadInterval, outEmailAddress, outCustom, outServerName,
756                                    outServerPort, outUseSSL, outUserName, outPassword,
757                                    allowAnonymous, mailingListActive, serviceContext);
758                    }
759    
760                    return category;
761            }
762    
763            @Override
764            public MBCategory updateStatus(long userId, long categoryId, int status)
765                    throws PortalException {
766    
767                    // Category
768    
769                    User user = userPersistence.findByPrimaryKey(userId);
770    
771                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
772                            categoryId);
773    
774                    category.setStatus(status);
775                    category.setStatusByUserId(user.getUserId());
776                    category.setStatusByUserName(user.getFullName());
777                    category.setStatusDate(new Date());
778    
779                    mbCategoryPersistence.update(category);
780    
781                    return category;
782            }
783    
784            protected long getParentCategoryId(long groupId, long parentCategoryId) {
785                    if ((parentCategoryId !=
786                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
787                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
788    
789                            MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
790                                    parentCategoryId);
791    
792                            if ((parentCategory == null) ||
793                                    (groupId != parentCategory.getGroupId())) {
794    
795                                    parentCategoryId =
796                                            MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
797                            }
798                    }
799    
800                    return parentCategoryId;
801            }
802    
803            protected long getParentCategoryId(
804                    MBCategory category, long parentCategoryId) {
805    
806                    if ((parentCategoryId ==
807                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
808                            (parentCategoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
809    
810                            return parentCategoryId;
811                    }
812    
813                    if (category.getCategoryId() == parentCategoryId) {
814                            return category.getParentCategoryId();
815                    }
816    
817                    MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
818                            parentCategoryId);
819    
820                    if ((parentCategory == null) ||
821                            (category.getGroupId() != parentCategory.getGroupId())) {
822    
823                            return category.getParentCategoryId();
824                    }
825    
826                    List<Long> subcategoryIds = new ArrayList<>();
827    
828                    getSubcategoryIds(
829                            subcategoryIds, category.getGroupId(), category.getCategoryId());
830    
831                    if (subcategoryIds.contains(parentCategoryId)) {
832                            return category.getParentCategoryId();
833                    }
834    
835                    return parentCategoryId;
836            }
837    
838            protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
839                    throws PortalException {
840    
841                    if ((toCategoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
842                            (toCategoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
843    
844                            return;
845                    }
846    
847                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
848                            fromCategory.getGroupId(), fromCategory.getCategoryId());
849    
850                    for (MBCategory category : categories) {
851                            mergeCategories(category, toCategoryId);
852                    }
853    
854                    List<MBThread> threads = mbThreadPersistence.findByG_C(
855                            fromCategory.getGroupId(), fromCategory.getCategoryId());
856    
857                    for (MBThread thread : threads) {
858    
859                            // Thread
860    
861                            thread.setCategoryId(toCategoryId);
862    
863                            mbThreadPersistence.update(thread);
864    
865                            List<MBMessage> messages = mbMessagePersistence.findByThreadId(
866                                    thread.getThreadId());
867    
868                            for (MBMessage message : messages) {
869    
870                                    // Message
871    
872                                    message.setCategoryId(toCategoryId);
873    
874                                    mbMessagePersistence.update(message);
875    
876                                    // Indexer
877    
878                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
879                                            MBMessage.class);
880    
881                                    indexer.reindex(message);
882                            }
883                    }
884    
885                    MBCategory toCategory = mbCategoryPersistence.findByPrimaryKey(
886                            toCategoryId);
887    
888                    toCategory.setThreadCount(
889                            fromCategory.getThreadCount() + toCategory.getThreadCount());
890                    toCategory.setMessageCount(
891                            fromCategory.getMessageCount() + toCategory.getMessageCount());
892    
893                    mbCategoryPersistence.update(toCategory);
894    
895                    mbCategoryLocalService.deleteCategory(fromCategory);
896            }
897    
898            protected void moveDependentsToTrash(
899                            User user, List<Object> categoriesAndThreads, long trashEntryId)
900                    throws PortalException {
901    
902                    for (Object object : categoriesAndThreads) {
903                            if (object instanceof MBThread) {
904    
905                                    // Thread
906    
907                                    MBThread thread = (MBThread)object;
908    
909                                    int oldStatus = thread.getStatus();
910    
911                                    if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
912                                            continue;
913                                    }
914    
915                                    thread.setStatus(WorkflowConstants.STATUS_IN_TRASH);
916    
917                                    mbThreadPersistence.update(thread);
918    
919                                    // Trash
920    
921                                    if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
922                                            trashVersionLocalService.addTrashVersion(
923                                                    trashEntryId, MBThread.class.getName(),
924                                                    thread.getThreadId(), oldStatus, null);
925                                    }
926    
927                                    // Threads
928    
929                                    mbThreadLocalService.moveDependentsToTrash(
930                                            user.getUserId(), thread.getThreadId(), trashEntryId);
931    
932                                    // Indexer
933    
934                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
935                                            MBThread.class);
936    
937                                    indexer.reindex(thread);
938                            }
939                            else if (object instanceof MBCategory) {
940    
941                                    // Category
942    
943                                    MBCategory category = (MBCategory)object;
944    
945                                    if (category.isInTrash()) {
946                                            continue;
947                                    }
948    
949                                    int oldStatus = category.getStatus();
950    
951                                    category.setStatus(WorkflowConstants.STATUS_IN_TRASH);
952    
953                                    mbCategoryPersistence.update(category);
954    
955                                    // Trash
956    
957                                    if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
958                                            trashVersionLocalService.addTrashVersion(
959                                                    trashEntryId, MBCategory.class.getName(),
960                                                    category.getCategoryId(), oldStatus, null);
961                                    }
962    
963                                    // Categories and threads
964    
965                                    moveDependentsToTrash(
966                                            user,
967                                            getCategoriesAndThreads(
968                                                    category.getGroupId(), category.getCategoryId()),
969                                            trashEntryId);
970                            }
971                    }
972            }
973    
974            protected void restoreDependentsFromTrash(
975                            User user, List<Object> categoriesAndThreads)
976                    throws PortalException {
977    
978                    for (Object object : categoriesAndThreads) {
979                            if (object instanceof MBThread) {
980    
981                                    // Thread
982    
983                                    MBThread thread = (MBThread)object;
984    
985                                    if (!thread.isInTrashImplicitly()) {
986                                            continue;
987                                    }
988    
989                                    TrashVersion trashVersion =
990                                            trashVersionLocalService.fetchVersion(
991                                                    MBThread.class.getName(), thread.getThreadId());
992    
993                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
994    
995                                    if (trashVersion != null) {
996                                            oldStatus = trashVersion.getStatus();
997                                    }
998    
999                                    thread.setStatus(oldStatus);
1000    
1001                                    mbThreadPersistence.update(thread);
1002    
1003                                    // Threads
1004    
1005                                    mbThreadLocalService.restoreDependentsFromTrash(
1006                                            user.getUserId(), thread.getThreadId());
1007    
1008                                    // Trash
1009    
1010                                    if (trashVersion != null) {
1011                                            trashVersionLocalService.deleteTrashVersion(trashVersion);
1012                                    }
1013    
1014                                    // Indexer
1015    
1016                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1017                                            MBThread.class);
1018    
1019                                    indexer.reindex(thread);
1020                            }
1021                            else if (object instanceof MBCategory) {
1022    
1023                                    // Category
1024    
1025                                    MBCategory category = (MBCategory)object;
1026    
1027                                    if (!category.isInTrashImplicitly()) {
1028                                            continue;
1029                                    }
1030    
1031                                    TrashVersion trashVersion =
1032                                            trashVersionLocalService.fetchVersion(
1033                                                    MBCategory.class.getName(), category.getCategoryId());
1034    
1035                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
1036    
1037                                    if (trashVersion != null) {
1038                                            oldStatus = trashVersion.getStatus();
1039                                    }
1040    
1041                                    category.setStatus(oldStatus);
1042    
1043                                    mbCategoryPersistence.update(category);
1044    
1045                                    // Categories and threads
1046    
1047                                    restoreDependentsFromTrash(
1048                                            user,
1049                                            getCategoriesAndThreads(
1050                                                    category.getGroupId(), category.getCategoryId()));
1051    
1052                                    // Trash
1053    
1054                                    if (trashVersion != null) {
1055                                            trashVersionLocalService.deleteTrashVersion(trashVersion);
1056                                    }
1057                            }
1058                    }
1059            }
1060    
1061            protected void updateChildCategoriesDisplayStyle(
1062                            MBCategory category, String displayStyle)
1063                    throws PortalException {
1064    
1065                    List<MBCategory> categories = getCategories(
1066                            category.getGroupId(), category.getCategoryId(), QueryUtil.ALL_POS,
1067                            QueryUtil.ALL_POS);
1068    
1069                    for (MBCategory curCategory : categories) {
1070                            updateChildCategoriesDisplayStyle(curCategory, displayStyle);
1071    
1072                            curCategory.setDisplayStyle(displayStyle);
1073    
1074                            mbCategoryPersistence.update(curCategory);
1075                    }
1076            }
1077    
1078            protected void validate(String name) throws PortalException {
1079                    if (Validator.isNull(name)) {
1080                            throw new CategoryNameException();
1081                    }
1082            }
1083    
1084    }