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.portal.service.impl;
016    
017    import com.liferay.portal.DuplicateUserGroupException;
018    import com.liferay.portal.NoSuchUserGroupException;
019    import com.liferay.portal.RequiredUserGroupException;
020    import com.liferay.portal.UserGroupNameException;
021    import com.liferay.portal.kernel.dao.orm.QueryUtil;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.search.BaseModelSearchResult;
025    import com.liferay.portal.kernel.search.Hits;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.QueryConfig;
029    import com.liferay.portal.kernel.search.SearchContext;
030    import com.liferay.portal.kernel.search.SearchException;
031    import com.liferay.portal.kernel.search.Sort;
032    import com.liferay.portal.kernel.systemevent.SystemEvent;
033    import com.liferay.portal.kernel.util.CharPool;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.MapUtil;
036    import com.liferay.portal.kernel.util.OrderByComparator;
037    import com.liferay.portal.kernel.util.SetUtil;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.kernel.workflow.WorkflowConstants;
040    import com.liferay.portal.model.Group;
041    import com.liferay.portal.model.GroupConstants;
042    import com.liferay.portal.model.ResourceConstants;
043    import com.liferay.portal.model.SystemEventConstants;
044    import com.liferay.portal.model.Team;
045    import com.liferay.portal.model.User;
046    import com.liferay.portal.model.UserGroup;
047    import com.liferay.portal.model.UserGroupConstants;
048    import com.liferay.portal.security.auth.PrincipalThreadLocal;
049    import com.liferay.portal.security.exportimport.UserGroupImportTransactionThreadLocal;
050    import com.liferay.portal.security.permission.PermissionCacheUtil;
051    import com.liferay.portal.service.ServiceContext;
052    import com.liferay.portal.service.base.UserGroupLocalServiceBaseImpl;
053    import com.liferay.portal.util.PropsValues;
054    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationConstants;
055    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationSettingsMapFactory;
056    import com.liferay.portlet.exportimport.lar.ExportImportHelperUtil;
057    import com.liferay.portlet.exportimport.lar.PortletDataHandlerKeys;
058    import com.liferay.portlet.exportimport.lar.UserIdStrategy;
059    import com.liferay.portlet.exportimport.model.ExportImportConfiguration;
060    import com.liferay.portlet.usersadmin.util.UsersAdminUtil;
061    
062    import java.io.File;
063    import java.io.Serializable;
064    
065    import java.util.ArrayList;
066    import java.util.Collections;
067    import java.util.HashMap;
068    import java.util.LinkedHashMap;
069    import java.util.List;
070    import java.util.Map;
071    import java.util.Set;
072    
073    /**
074     * Provides the local service for accessing, adding, deleting, and updating user
075     * groups.
076     *
077     * @author Charles May
078     */
079    public class UserGroupLocalServiceImpl extends UserGroupLocalServiceBaseImpl {
080    
081            /**
082             * Adds the user groups to the group.
083             *
084             * @param groupId the primary key of the group
085             * @param userGroupIds the primary keys of the user groups
086             */
087            @Override
088            public void addGroupUserGroups(long groupId, long[] userGroupIds) {
089                    groupPersistence.addUserGroups(groupId, userGroupIds);
090    
091                    PermissionCacheUtil.clearCache();
092            }
093    
094            /**
095             * Adds the user groups to the team.
096             *
097             * @param teamId the primary key of the team
098             * @param userGroupIds the primary keys of the user groups
099             */
100            @Override
101            public void addTeamUserGroups(long teamId, long[] userGroupIds) {
102                    teamPersistence.addUserGroups(teamId, userGroupIds);
103    
104                    PermissionCacheUtil.clearCache();
105            }
106    
107            /**
108             * Adds a user group.
109             *
110             * <p>
111             * This method handles the creation and bookkeeping of the user group,
112             * including its resources, metadata, and internal data structures. It is
113             * not necessary to make subsequent calls to setup default groups and
114             * resources for the user group.
115             * </p>
116             *
117             * @param      userId the primary key of the user
118             * @param      companyId the primary key of the user group's company
119             * @param      name the user group's name
120             * @param      description the user group's description
121             * @return     the user group
122             * @throws     PortalException if the user group's information was invalid
123             * @deprecated As of 6.2.0, replaced by {@link #addUserGroup(long, long,
124             *             String, String, ServiceContext)}
125             */
126            @Deprecated
127            @Override
128            public UserGroup addUserGroup(
129                            long userId, long companyId, String name, String description)
130                    throws PortalException {
131    
132                    return addUserGroup(userId, companyId, name, description, null);
133            }
134    
135            /**
136             * Adds a user group.
137             *
138             * <p>
139             * This method handles the creation and bookkeeping of the user group,
140             * including its resources, metadata, and internal data structures. It is
141             * not necessary to make subsequent calls to setup default groups and
142             * resources for the user group.
143             * </p>
144             *
145             * @param  userId the primary key of the user
146             * @param  companyId the primary key of the user group's company
147             * @param  name the user group's name
148             * @param  description the user group's description
149             * @param  serviceContext the service context to be applied (optionally
150             *         <code>null</code>). Can set expando bridge attributes for the
151             *         user group.
152             * @return the user group
153             * @throws PortalException if the user group's information was invalid
154             */
155            @Override
156            public UserGroup addUserGroup(
157                            long userId, long companyId, String name, String description,
158                            ServiceContext serviceContext)
159                    throws PortalException {
160    
161                    // User group
162    
163                    validate(0, companyId, name);
164    
165                    User user = userPersistence.findByPrimaryKey(userId);
166    
167                    long userGroupId = counterLocalService.increment();
168    
169                    UserGroup userGroup = userGroupPersistence.create(userGroupId);
170    
171                    if (serviceContext != null) {
172                            userGroup.setUuid(serviceContext.getUuid());
173                    }
174    
175                    userGroup.setCompanyId(companyId);
176                    userGroup.setUserId(user.getUserId());
177                    userGroup.setUserName(user.getFullName());
178                    userGroup.setParentUserGroupId(
179                            UserGroupConstants.DEFAULT_PARENT_USER_GROUP_ID);
180                    userGroup.setName(name);
181                    userGroup.setDescription(description);
182                    userGroup.setAddedByLDAPImport(
183                            UserGroupImportTransactionThreadLocal.isOriginatesFromImport());
184                    userGroup.setExpandoBridgeAttributes(serviceContext);
185    
186                    userGroupPersistence.update(userGroup);
187    
188                    // Group
189    
190                    groupLocalService.addGroup(
191                            userId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
192                            UserGroup.class.getName(), userGroup.getUserGroupId(),
193                            GroupConstants.DEFAULT_LIVE_GROUP_ID,
194                            getLocalizationMap(String.valueOf(userGroupId)), null, 0, true,
195                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, null, false, true,
196                            null);
197    
198                    // Resources
199    
200                    resourceLocalService.addResources(
201                            companyId, 0, userId, UserGroup.class.getName(),
202                            userGroup.getUserGroupId(), false, false, false);
203    
204                    // Indexer
205    
206                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
207                            UserGroup.class);
208    
209                    indexer.reindex(userGroup);
210    
211                    return userGroup;
212            }
213    
214            /**
215             * Clears all associations between the user and its user groups and clears
216             * the permissions cache.
217             *
218             * <p>
219             * This method is called from {@link #deleteUserGroup(UserGroup)}.
220             * </p>
221             *
222             * @param userId the primary key of the user
223             */
224            @Override
225            public void clearUserUserGroups(long userId) {
226                    userPersistence.clearUserGroups(userId);
227    
228                    PermissionCacheUtil.clearCache(userId);
229            }
230    
231            /**
232             * Copies the user group's layout to the user.
233             *
234             * @param      userGroupId the primary key of the user group
235             * @param      userId the primary key of the user
236             * @throws     PortalException if a user with the primary key could not be
237             *             found or if a portal exception occurred
238             * @deprecated As of 6.2.0
239             */
240            @Deprecated
241            @Override
242            public void copyUserGroupLayouts(long userGroupId, long userId)
243                    throws PortalException {
244    
245                    Map<String, String[]> parameterMap = getLayoutTemplatesParameters();
246    
247                    File[] files = exportLayouts(userGroupId, parameterMap);
248    
249                    try {
250                            importLayouts(userId, parameterMap, files[0], files[1]);
251                    }
252                    finally {
253                            if (files[0] != null) {
254                                    files[0].delete();
255                            }
256    
257                            if (files[1] != null) {
258                                    files[1].delete();
259                            }
260                    }
261            }
262    
263            /**
264             * Copies the user group's layouts to the users who are not already members
265             * of the user group.
266             *
267             * @param      userGroupId the primary key of the user group
268             * @param      userIds the primary keys of the users
269             * @throws     PortalException if any one of the users could not be found or
270             *             if a portal exception occurred
271             * @deprecated As of 6.1.0
272             */
273            @Deprecated
274            @Override
275            public void copyUserGroupLayouts(long userGroupId, long[] userIds)
276                    throws PortalException {
277    
278                    Map<String, String[]> parameterMap = getLayoutTemplatesParameters();
279    
280                    File[] files = exportLayouts(userGroupId, parameterMap);
281    
282                    try {
283                            for (long userId : userIds) {
284                                    if (!userGroupPersistence.containsUser(userGroupId, userId)) {
285                                            importLayouts(userId, parameterMap, files[0], files[1]);
286                                    }
287                            }
288                    }
289                    finally {
290                            if (files[0] != null) {
291                                    files[0].delete();
292                            }
293    
294                            if (files[1] != null) {
295                                    files[1].delete();
296                            }
297                    }
298            }
299    
300            /**
301             * Copies the user groups' layouts to the user.
302             *
303             * @param      userGroupIds the primary keys of the user groups
304             * @param      userId the primary key of the user
305             * @throws     PortalException if a user with the primary key could not be
306             *             found or if a portal exception occurred
307             * @deprecated As of 6.1.0
308             */
309            @Deprecated
310            @Override
311            public void copyUserGroupLayouts(long[] userGroupIds, long userId)
312                    throws PortalException {
313    
314                    for (long userGroupId : userGroupIds) {
315                            if (!userGroupPersistence.containsUser(userGroupId, userId)) {
316                                    copyUserGroupLayouts(userGroupId, userId);
317                            }
318                    }
319            }
320    
321            /**
322             * Deletes the user group.
323             *
324             * @param  userGroupId the primary key of the user group
325             * @return the deleted user group
326             * @throws PortalException if a user group with the primary key could not be
327             *         found or if the user group had a workflow in approved status
328             */
329            @Override
330            public UserGroup deleteUserGroup(long userGroupId) throws PortalException {
331                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
332                            userGroupId);
333    
334                    return userGroupLocalService.deleteUserGroup(userGroup);
335            }
336    
337            /**
338             * Deletes the user group.
339             *
340             * @param  userGroup the user group
341             * @return the deleted user group
342             * @throws PortalException if the organization had a workflow in approved
343             *         status
344             */
345            @Override
346            @SystemEvent(
347                    action = SystemEventConstants.ACTION_SKIP,
348                    type = SystemEventConstants.TYPE_DELETE
349            )
350            public UserGroup deleteUserGroup(UserGroup userGroup)
351                    throws PortalException {
352    
353                    int count = userLocalService.getUserGroupUsersCount(
354                            userGroup.getUserGroupId(), WorkflowConstants.STATUS_APPROVED);
355    
356                    if (count > 0) {
357                            throw new RequiredUserGroupException();
358                    }
359    
360                    // Expando
361    
362                    expandoRowLocalService.deleteRows(userGroup.getUserGroupId());
363    
364                    // Users
365    
366                    clearUserUserGroups(userGroup.getUserId());
367    
368                    // Group
369    
370                    Group group = userGroup.getGroup();
371    
372                    groupLocalService.deleteGroup(group);
373    
374                    // User group roles
375    
376                    userGroupGroupRoleLocalService.deleteUserGroupGroupRolesByUserGroupId(
377                            userGroup.getUserGroupId());
378    
379                    // Resources
380    
381                    resourceLocalService.deleteResource(
382                            userGroup.getCompanyId(), UserGroup.class.getName(),
383                            ResourceConstants.SCOPE_INDIVIDUAL, userGroup.getUserGroupId());
384    
385                    // User group
386    
387                    userGroupPersistence.remove(userGroup);
388    
389                    // Permission cache
390    
391                    PermissionCacheUtil.clearCache();
392    
393                    return userGroup;
394            }
395    
396            @Override
397            public void deleteUserGroups(long companyId) throws PortalException {
398                    List<UserGroup> userGroups = userGroupPersistence.findByCompanyId(
399                            companyId);
400    
401                    for (UserGroup userGroup : userGroups) {
402                            userGroupLocalService.deleteUserGroup(userGroup);
403                    }
404            }
405    
406            @Override
407            public UserGroup fetchUserGroup(long companyId, String name) {
408                    return userGroupPersistence.fetchByC_N(companyId, name);
409            }
410    
411            @Override
412            public List<UserGroup> getGroupUserUserGroups(long groupId, long userId)
413                    throws PortalException {
414    
415                    long[] groupUserGroupIds = groupPersistence.getUserGroupPrimaryKeys(
416                            groupId);
417    
418                    if (groupUserGroupIds.length == 0) {
419                            return Collections.emptyList();
420                    }
421    
422                    long[] userUserGroupIds = userPersistence.getUserGroupPrimaryKeys(
423                            userId);
424    
425                    if (userUserGroupIds.length == 0) {
426                            return Collections.emptyList();
427                    }
428    
429                    Set<Long> userGroupIds = SetUtil.intersect(
430                            groupUserGroupIds, userUserGroupIds);
431    
432                    if (userGroupIds.isEmpty()) {
433                            return Collections.emptyList();
434                    }
435    
436                    List<UserGroup> userGroups = new ArrayList<>(userGroupIds.size());
437    
438                    for (Long userGroupId : userGroupIds) {
439                            userGroups.add(userGroupPersistence.findByPrimaryKey(userGroupId));
440                    }
441    
442                    return userGroups;
443            }
444    
445            /**
446             * Returns the user group with the name.
447             *
448             * @param  companyId the primary key of the user group's company
449             * @param  name the user group's name
450             * @return Returns the user group with the name
451             * @throws PortalException if a user group with the name could not be found
452             */
453            @Override
454            public UserGroup getUserGroup(long companyId, String name)
455                    throws PortalException {
456    
457                    return userGroupPersistence.findByC_N(companyId, name);
458            }
459    
460            /**
461             * Returns all the user groups belonging to the company.
462             *
463             * @param  companyId the primary key of the user groups' company
464             * @return the user groups belonging to the company
465             */
466            @Override
467            public List<UserGroup> getUserGroups(long companyId) {
468                    return userGroupPersistence.findByCompanyId(companyId);
469            }
470    
471            /**
472             * Returns all the user groups with the primary keys.
473             *
474             * @param  userGroupIds the primary keys of the user groups
475             * @return the user groups with the primary keys
476             * @throws PortalException if any one of the user groups could not be found
477             */
478            @Override
479            public List<UserGroup> getUserGroups(long[] userGroupIds)
480                    throws PortalException {
481    
482                    List<UserGroup> userGroups = new ArrayList<>(userGroupIds.length);
483    
484                    for (long userGroupId : userGroupIds) {
485                            UserGroup userGroup = getUserGroup(userGroupId);
486    
487                            userGroups.add(userGroup);
488                    }
489    
490                    return userGroups;
491            }
492    
493            /**
494             * Returns an ordered range of all the user groups that match the keywords.
495             *
496             * <p>
497             * Useful when paginating results. Returns a maximum of <code>end -
498             * start</code> instances. <code>start</code> and <code>end</code> are not
499             * primary keys, they are indexes in the result set. Thus, <code>0</code>
500             * refers to the first result in the set. Setting both <code>start</code>
501             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
502             * result set.
503             * </p>
504             *
505             * @param  companyId the primary key of the user group's company
506             * @param  keywords the keywords (space separated), which may occur in the
507             *         user group's name or description (optionally <code>null</code>)
508             * @param  params the finder params (optionally <code>null</code>). For more
509             *         information see {@link
510             *         com.liferay.portal.service.persistence.UserGroupFinder}
511             * @param  start the lower bound of the range of user groups to return
512             * @param  end the upper bound of the range of user groups to return (not
513             *         inclusive)
514             * @param  obc the comparator to order the user groups (optionally
515             *         <code>null</code>)
516             * @return the matching user groups ordered by comparator <code>obc</code>
517             * @see    com.liferay.portal.service.persistence.UserGroupFinder
518             */
519            @Override
520            public List<UserGroup> search(
521                    long companyId, String keywords, LinkedHashMap<String, Object> params,
522                    int start, int end, OrderByComparator<UserGroup> obc) {
523    
524                    return userGroupFinder.findByKeywords(
525                            companyId, keywords, params, start, end, obc);
526            }
527    
528            /**
529             * Returns an ordered range of all the user groups that match the keywords,
530             * using the indexer. It is preferable to use this method instead of the
531             * non-indexed version whenever possible for performance reasons.
532             *
533             * <p>
534             * Useful when paginating results. Returns a maximum of <code>end -
535             * start</code> instances. <code>start</code> and <code>end</code> are not
536             * primary keys, they are indexes in the result set. Thus, <code>0</code>
537             * refers to the first result in the set. Setting both <code>start</code>
538             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
539             * result set.
540             * </p>
541             *
542             * @param  companyId the primary key of the user group's company
543             * @param  keywords the keywords (space separated), which may occur in the
544             *         user group's name or description (optionally <code>null</code>)
545             * @param  params the finder params (optionally <code>null</code>). For more
546             *         information see {@link
547             *         com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer}
548             * @param  start the lower bound of the range of user groups to return
549             * @param  end the upper bound of the range of user groups to return (not
550             *         inclusive)
551             * @param  sort the field and direction by which to sort (optionally
552             *         <code>null</code>)
553             * @return the matching user groups ordered by sort
554             * @see    com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer
555             */
556            @Override
557            public Hits search(
558                    long companyId, String keywords, LinkedHashMap<String, Object> params,
559                    int start, int end, Sort sort) {
560    
561                    String name = null;
562                    String description = null;
563                    boolean andOperator = false;
564    
565                    if (Validator.isNotNull(keywords)) {
566                            name = keywords;
567                            description = keywords;
568                    }
569                    else {
570                            andOperator = true;
571                    }
572    
573                    if (params != null) {
574                            params.put("keywords", keywords);
575                    }
576    
577                    return search(
578                            companyId, name, description, params, andOperator, start, end,
579                            sort);
580            }
581    
582            /**
583             * Returns an ordered range of all the user groups that match the name and
584             * description.
585             *
586             * <p>
587             * Useful when paginating results. Returns a maximum of <code>end -
588             * start</code> instances. <code>start</code> and <code>end</code> are not
589             * primary keys, they are indexes in the result set. Thus, <code>0</code>
590             * refers to the first result in the set. Setting both <code>start</code>
591             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
592             * result set.
593             * </p>
594             *
595             * @param  companyId the primary key of the user group's company
596             * @param  name the user group's name (optionally <code>null</code>)
597             * @param  description the user group's description (optionally
598             *         <code>null</code>)
599             * @param  params the finder params (optionally <code>null</code>). For more
600             *         information see {@link
601             *         com.liferay.portal.service.persistence.UserGroupFinder}
602             * @param  andOperator whether every field must match its keywords or just
603             *         one field
604             * @param  start the lower bound of the range of user groups to return
605             * @param  end the upper bound of the range of user groups to return (not
606             *         inclusive)
607             * @param  obc the comparator to order the user groups (optionally
608             *         <code>null</code>)
609             * @return the matching user groups ordered by comparator <code>obc</code>
610             * @see    com.liferay.portal.service.persistence.UserGroupFinder
611             */
612            @Override
613            public List<UserGroup> search(
614                    long companyId, String name, String description,
615                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
616                    int end, OrderByComparator<UserGroup> obc) {
617    
618                    return userGroupFinder.findByC_N_D(
619                            companyId, name, description, params, andOperator, start, end, obc);
620            }
621    
622            /**
623             * Returns an ordered range of all the user groups that match the name and
624             * description. It is preferable to use this method instead of the
625             * non-indexed version whenever possible for performance reasons.
626             *
627             * <p>
628             * Useful when paginating results. Returns a maximum of <code>end -
629             * start</code> instances. <code>start</code> and <code>end</code> are not
630             * primary keys, they are indexes in the result set. Thus, <code>0</code>
631             * refers to the first result in the set. Setting both <code>start</code>
632             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
633             * result set.
634             * </p>
635             *
636             * @param  companyId the primary key of the user group's company
637             * @param  name the user group's name (optionally <code>null</code>)
638             * @param  description the user group's description (optionally
639             *         <code>null</code>)
640             * @param  params the finder params (optionally <code>null</code>). For more
641             *         information see {@link
642             *         com.liferay.portlet.usergroupsadmin.util.UserGroupIndexer}
643             * @param  andSearch whether every field must match its keywords or just one
644             *         field
645             * @param  start the lower bound of the range of user groups to return
646             * @param  end the upper bound of the range of user groups to return (not
647             *         inclusive)
648             * @param  sort the field and direction by which to sort (optionally
649             *         <code>null</code>)
650             * @return the matching user groups ordered by sort
651             * @see    com.liferay.portal.service.persistence.UserGroupFinder
652             */
653            @Override
654            public Hits search(
655                    long companyId, String name, String description,
656                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
657                    int end, Sort sort) {
658    
659                    try {
660                            Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
661                                    UserGroup.class);
662    
663                            SearchContext searchContext = buildSearchContext(
664                                    companyId, name, description, params, andSearch, start, end,
665                                    sort);
666    
667                            return indexer.search(searchContext);
668                    }
669                    catch (Exception e) {
670                            throw new SystemException(e);
671                    }
672            }
673    
674            /**
675             * Returns the number of user groups that match the keywords
676             *
677             * @param  companyId the primary key of the user group's company
678             * @param  keywords the keywords (space separated), which may occur in the
679             *         user group's name or description (optionally <code>null</code>)
680             * @param  params the finder params (optionally <code>null</code>). For more
681             *         information see {@link
682             *         com.liferay.portal.service.persistence.UserGroupFinder}
683             * @return the number of matching user groups
684             * @see    com.liferay.portal.service.persistence.UserGroupFinder
685             */
686            @Override
687            public int searchCount(
688                    long companyId, String keywords, LinkedHashMap<String, Object> params) {
689    
690                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
691                            UserGroup.class);
692    
693                    if (!indexer.isIndexerEnabled() ||
694                            !PropsValues.USER_GROUPS_SEARCH_WITH_INDEX ||
695                            isUseCustomSQL(params)) {
696    
697                            return userGroupFinder.countByKeywords(companyId, keywords, params);
698                    }
699    
700                    String name = null;
701                    String description = null;
702                    boolean andOperator = false;
703    
704                    if (Validator.isNotNull(keywords)) {
705                            name = keywords;
706                            description = keywords;
707                    }
708                    else {
709                            andOperator = true;
710                    }
711    
712                    if (params != null) {
713                            params.put("keywords", keywords);
714                    }
715    
716                    try {
717                            SearchContext searchContext = buildSearchContext(
718                                    companyId, name, description, params, andOperator,
719                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
720    
721                            return (int)indexer.searchCount(searchContext);
722                    }
723                    catch (Exception e) {
724                            throw new SystemException(e);
725                    }
726            }
727    
728            /**
729             * Returns the number of user groups that match the name and description.
730             *
731             * @param  companyId the primary key of the user group's company
732             * @param  name the user group's name (optionally <code>null</code>)
733             * @param  description the user group's description (optionally
734             *         <code>null</code>)
735             * @param  params the finder params (optionally <code>null</code>). For more
736             *         information see {@link
737             *         com.liferay.portal.service.persistence.UserGroupFinder}
738             * @param  andOperator whether every field must match its keywords or just
739             *         one field
740             * @return the number of matching user groups
741             * @see    com.liferay.portal.service.persistence.UserGroupFinder
742             */
743            @Override
744            public int searchCount(
745                    long companyId, String name, String description,
746                    LinkedHashMap<String, Object> params, boolean andOperator) {
747    
748                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
749                            UserGroup.class);
750    
751                    if (!indexer.isIndexerEnabled() ||
752                            !PropsValues.USER_GROUPS_SEARCH_WITH_INDEX ||
753                            isUseCustomSQL(params)) {
754    
755                            return userGroupFinder.countByC_N_D(
756                                    companyId, name, description, params, andOperator);
757                    }
758    
759                    try {
760                            SearchContext searchContext = buildSearchContext(
761                                    companyId, name, description, params, true, QueryUtil.ALL_POS,
762                                    QueryUtil.ALL_POS, null);
763    
764                            return (int)indexer.searchCount(searchContext);
765                    }
766                    catch (Exception e) {
767                            throw new SystemException(e);
768                    }
769            }
770    
771            @Override
772            public BaseModelSearchResult<UserGroup> searchUserGroups(
773                            long companyId, String keywords,
774                            LinkedHashMap<String, Object> params, int start, int end, Sort sort)
775                    throws PortalException {
776    
777                    String name = null;
778                    String description = null;
779                    boolean andOperator = false;
780    
781                    if (Validator.isNotNull(keywords)) {
782                            name = keywords;
783                            description = keywords;
784                    }
785                    else {
786                            andOperator = true;
787                    }
788    
789                    if (params != null) {
790                            params.put("keywords", keywords);
791                    }
792    
793                    return searchUserGroups(
794                            companyId, name, description, params, andOperator, start, end,
795                            sort);
796            }
797    
798            @Override
799            public BaseModelSearchResult<UserGroup> searchUserGroups(
800                            long companyId, String name, String description,
801                            LinkedHashMap<String, Object> params, boolean andSearch, int start,
802                            int end, Sort sort)
803                    throws PortalException {
804    
805                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
806                            UserGroup.class);
807    
808                    SearchContext searchContext = buildSearchContext(
809                            companyId, name, description, params, andSearch, start, end, sort);
810    
811                    for (int i = 0; i < 10; i++) {
812                            Hits hits = indexer.search(searchContext);
813    
814                            List<UserGroup> userGroups = UsersAdminUtil.getUserGroups(hits);
815    
816                            if (userGroups != null) {
817                                    return new BaseModelSearchResult<>(
818                                            userGroups, hits.getLength());
819                            }
820                    }
821    
822                    throw new SearchException(
823                            "Unable to fix the search index after 10 attempts");
824            }
825    
826            /**
827             * Sets the user groups associated with the user copying the user group
828             * layouts and removing and adding user group associations for the user as
829             * necessary.
830             *
831             * @param  userId the primary key of the user
832             * @param  userGroupIds the primary keys of the user groups
833             * @throws PortalException if a portal exception occurred
834             */
835            @Override
836            public void setUserUserGroups(long userId, long[] userGroupIds)
837                    throws PortalException {
838    
839                    if (PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
840                            copyUserGroupLayouts(userGroupIds, userId);
841                    }
842    
843                    userPersistence.setUserGroups(userId, userGroupIds);
844    
845                    Indexer<User> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
846                            User.class);
847    
848                    User user = userLocalService.fetchUser(userId);
849    
850                    indexer.reindex(user);
851    
852                    PermissionCacheUtil.clearCache(userId);
853            }
854    
855            /**
856             * Removes the user groups from the group.
857             *
858             * @param groupId the primary key of the group
859             * @param userGroupIds the primary keys of the user groups
860             */
861            @Override
862            public void unsetGroupUserGroups(long groupId, long[] userGroupIds) {
863                    List<Team> teams = teamPersistence.findByGroupId(groupId);
864    
865                    for (Team team : teams) {
866                            teamPersistence.removeUserGroups(team.getTeamId(), userGroupIds);
867                    }
868    
869                    userGroupGroupRoleLocalService.deleteUserGroupGroupRoles(
870                            userGroupIds, groupId);
871    
872                    groupPersistence.removeUserGroups(groupId, userGroupIds);
873    
874                    PermissionCacheUtil.clearCache();
875            }
876    
877            /**
878             * Removes the user groups from the team.
879             *
880             * @param teamId the primary key of the team
881             * @param userGroupIds the primary keys of the user groups
882             */
883            @Override
884            public void unsetTeamUserGroups(long teamId, long[] userGroupIds) {
885                    teamPersistence.removeUserGroups(teamId, userGroupIds);
886    
887                    PermissionCacheUtil.clearCache();
888            }
889    
890            /**
891             * Updates the user group.
892             *
893             * @param      companyId the primary key of the user group's company
894             * @param      userGroupId the primary key of the user group
895             * @param      name the user group's name
896             * @param      description the user group's description
897             * @return     the user group
898             * @throws     PortalException if a user group with the primary key could
899             *             not be found or if the new information was invalid
900             * @deprecated As of 6.2.0, replaced by {@link #updateUserGroup(long, long,
901             *             String, String, ServiceContext)}
902             */
903            @Deprecated
904            @Override
905            public UserGroup updateUserGroup(
906                            long companyId, long userGroupId, String name, String description)
907                    throws PortalException {
908    
909                    return updateUserGroup(companyId, userGroupId, name, description, null);
910            }
911    
912            /**
913             * Updates the user group.
914             *
915             * @param  companyId the primary key of the user group's company
916             * @param  userGroupId the primary key of the user group
917             * @param  name the user group's name
918             * @param  description the user group's description
919             * @param  serviceContext the service context to be applied (optionally
920             *         <code>null</code>). Can set expando bridge attributes for the
921             *         user group.
922             * @return the user group
923             * @throws PortalException if a user group with the primary key could not be
924             *         found or if the new information was invalid
925             */
926            @Override
927            public UserGroup updateUserGroup(
928                            long companyId, long userGroupId, String name, String description,
929                            ServiceContext serviceContext)
930                    throws PortalException {
931    
932                    // User group
933    
934                    validate(userGroupId, companyId, name);
935    
936                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
937                            userGroupId);
938    
939                    userGroup.setName(name);
940                    userGroup.setDescription(description);
941                    userGroup.setExpandoBridgeAttributes(serviceContext);
942    
943                    userGroupPersistence.update(userGroup);
944    
945                    // Indexer
946    
947                    Indexer<UserGroup> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
948                            UserGroup.class);
949    
950                    indexer.reindex(userGroup);
951    
952                    return userGroup;
953            }
954    
955            protected SearchContext buildSearchContext(
956                    long companyId, String name, String description,
957                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
958                    int end, Sort sort) {
959    
960                    SearchContext searchContext = new SearchContext();
961    
962                    searchContext.setAndSearch(andSearch);
963    
964                    Map<String, Serializable> attributes = new HashMap<>();
965    
966                    attributes.put("description", description);
967                    attributes.put("name", name);
968    
969                    searchContext.setAttributes(attributes);
970    
971                    searchContext.setCompanyId(companyId);
972                    searchContext.setEnd(end);
973    
974                    if (params != null) {
975                            String keywords = (String)params.remove("keywords");
976    
977                            if (Validator.isNotNull(keywords)) {
978                                    searchContext.setKeywords(keywords);
979                            }
980                    }
981    
982                    if (sort != null) {
983                            searchContext.setSorts(sort);
984                    }
985    
986                    searchContext.setStart(start);
987    
988                    QueryConfig queryConfig = searchContext.getQueryConfig();
989    
990                    queryConfig.setHighlightEnabled(false);
991                    queryConfig.setScoreEnabled(false);
992    
993                    return searchContext;
994            }
995    
996            protected File[] exportLayouts(
997                            long userGroupId, Map<String, String[]> parameterMap)
998                    throws PortalException {
999    
1000                    File[] files = new File[2];
1001    
1002                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
1003                            userGroupId);
1004    
1005                    User user = userLocalService.getUser(
1006                            GetterUtil.getLong(PrincipalThreadLocal.getName()));
1007    
1008                    Group group = userGroup.getGroup();
1009    
1010                    if (userGroup.hasPrivateLayouts()) {
1011                            Map<String, Serializable> exportLayoutSettingsMap =
1012                                    ExportImportConfigurationSettingsMapFactory.
1013                                            buildExportLayoutSettingsMap(
1014                                                    user, group.getGroupId(), true,
1015                                                    ExportImportHelperUtil.getAllLayoutIds(
1016                                                            group.getGroupId(), true),
1017                                                    parameterMap);
1018    
1019                            ExportImportConfiguration exportImportConfiguration =
1020                                    exportImportConfigurationLocalService.
1021                                            addDraftExportImportConfiguration(
1022                                                    user.getUserId(),
1023                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1024                                                    exportLayoutSettingsMap);
1025    
1026                            files[0] = exportImportLocalService.exportLayoutsAsFile(
1027                                    exportImportConfiguration);
1028                    }
1029    
1030                    if (userGroup.hasPublicLayouts()) {
1031                            Map<String, Serializable> exportLayoutSettingsMap =
1032                                    ExportImportConfigurationSettingsMapFactory.
1033                                            buildExportLayoutSettingsMap(
1034                                                    user, group.getGroupId(), false,
1035                                                    ExportImportHelperUtil.getAllLayoutIds(
1036                                                            group.getGroupId(), false),
1037                                                    parameterMap);
1038    
1039                            ExportImportConfiguration exportImportConfiguration =
1040                                    exportImportConfigurationLocalService.
1041                                            addDraftExportImportConfiguration(
1042                                                    user.getUserId(),
1043                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1044                                                    exportLayoutSettingsMap);
1045    
1046                            files[1] = exportImportLocalService.exportLayoutsAsFile(
1047                                    exportImportConfiguration);
1048                    }
1049    
1050                    return files;
1051            }
1052    
1053            protected Map<String, String[]> getLayoutTemplatesParameters() {
1054                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
1055    
1056                    parameterMap.put(
1057                            PortletDataHandlerKeys.DATA_STRATEGY,
1058                            new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1059                    parameterMap.put(
1060                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1061                            new String[] {Boolean.FALSE.toString()});
1062                    parameterMap.put(
1063                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1064                            new String[] {Boolean.FALSE.toString()});
1065                    parameterMap.put(
1066                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1067                            new String[] {Boolean.FALSE.toString()});
1068                    parameterMap.put(
1069                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1070                            new String[] {
1071                                    PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME
1072                            });
1073                    parameterMap.put(
1074                            PortletDataHandlerKeys.LOGO,
1075                            new String[] {Boolean.FALSE.toString()});
1076                    parameterMap.put(
1077                            PortletDataHandlerKeys.PERMISSIONS,
1078                            new String[] {Boolean.TRUE.toString()});
1079                    parameterMap.put(
1080                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
1081                            new String[] {Boolean.TRUE.toString()});
1082                    parameterMap.put(
1083                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
1084                            new String[] {Boolean.TRUE.toString()});
1085                    parameterMap.put(
1086                            PortletDataHandlerKeys.PORTLET_DATA,
1087                            new String[] {Boolean.TRUE.toString()});
1088                    parameterMap.put(
1089                            PortletDataHandlerKeys.PORTLET_DATA_ALL,
1090                            new String[] {Boolean.TRUE.toString()});
1091                    parameterMap.put(
1092                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1093                            new String[] {Boolean.TRUE.toString()});
1094                    parameterMap.put(
1095                            PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
1096                            new String[] {
1097                                    PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM
1098                            });
1099                    parameterMap.put(
1100                            PortletDataHandlerKeys.THEME_REFERENCE,
1101                            new String[] {Boolean.TRUE.toString()});
1102                    parameterMap.put(
1103                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1104                            new String[] {Boolean.FALSE.toString()});
1105                    parameterMap.put(
1106                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1107                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1108    
1109                    return parameterMap;
1110            }
1111    
1112            protected void importLayouts(
1113                            long userId, Map<String, String[]> parameterMap,
1114                            File privateLayoutsFile, File publicLayoutsFile)
1115                    throws PortalException {
1116    
1117                    User user = userPersistence.findByPrimaryKey(userId);
1118    
1119                    long groupId = user.getGroupId();
1120    
1121                    if (privateLayoutsFile != null) {
1122                            Map<String, Serializable> importLayoutSettingsMap =
1123                                    ExportImportConfigurationSettingsMapFactory.
1124                                            buildImportLayoutSettingsMap(
1125                                                    user, groupId, true, null, parameterMap);
1126    
1127                            ExportImportConfiguration exportImportConfiguration =
1128                                    exportImportConfigurationLocalService.
1129                                            addDraftExportImportConfiguration(
1130                                                    user.getUserId(),
1131                                                    ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1132                                                    importLayoutSettingsMap);
1133    
1134                            exportImportLocalService.importLayouts(
1135                                    exportImportConfiguration, privateLayoutsFile);
1136                    }
1137    
1138                    if (publicLayoutsFile != null) {
1139                            Map<String, Serializable> importLayoutSettingsMap =
1140                                    ExportImportConfigurationSettingsMapFactory.
1141                                            buildImportLayoutSettingsMap(
1142                                                    user, groupId, false, null, parameterMap);
1143    
1144                            ExportImportConfiguration exportImportConfiguration =
1145                                    exportImportConfigurationLocalService.
1146                                            addDraftExportImportConfiguration(
1147                                                    user.getUserId(),
1148                                                    ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1149                                                    importLayoutSettingsMap);
1150    
1151                            exportImportLocalService.importLayouts(
1152                                    exportImportConfiguration, publicLayoutsFile);
1153                    }
1154            }
1155    
1156            protected boolean isUseCustomSQL(LinkedHashMap<String, Object> params) {
1157                    if (MapUtil.isEmpty(params)) {
1158                            return false;
1159                    }
1160    
1161                    return true;
1162            }
1163    
1164            protected void validate(long userGroupId, long companyId, String name)
1165                    throws PortalException {
1166    
1167                    if (Validator.isNull(name) || (name.indexOf(CharPool.COMMA) != -1) ||
1168                            (name.indexOf(CharPool.STAR) != -1)) {
1169    
1170                            throw new UserGroupNameException();
1171                    }
1172    
1173                    if (Validator.isNumber(name) &&
1174                            !PropsValues.USER_GROUPS_NAME_ALLOW_NUMERIC) {
1175    
1176                            throw new UserGroupNameException();
1177                    }
1178    
1179                    try {
1180                            UserGroup userGroup = userGroupFinder.findByC_N(companyId, name);
1181    
1182                            if (userGroup.getUserGroupId() != userGroupId) {
1183                                    throw new DuplicateUserGroupException(
1184                                            "{userGroupId=" + userGroupId + "}");
1185                            }
1186                    }
1187                    catch (NoSuchUserGroupException nsuge) {
1188                    }
1189            }
1190    
1191    }