001/*
002 * (C) Copyright 2016-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Michael Vachette
018 *     Florent Guillaume
019 */
020package org.nuxeo.ecm.automation.core.operations.users;
021
022import java.util.AbstractMap.SimpleEntry;
023import java.util.Arrays;
024import java.util.Map.Entry;
025
026import org.apache.commons.lang3.StringUtils;
027import org.nuxeo.ecm.automation.OperationException;
028import org.nuxeo.ecm.automation.core.Constants;
029import org.nuxeo.ecm.automation.core.annotations.Context;
030import org.nuxeo.ecm.automation.core.annotations.Operation;
031import org.nuxeo.ecm.automation.core.annotations.OperationMethod;
032import org.nuxeo.ecm.automation.core.annotations.Param;
033import org.nuxeo.ecm.automation.core.util.Properties;
034import org.nuxeo.ecm.automation.core.util.StringList;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.directory.BaseSession;
037import org.nuxeo.ecm.platform.usermanager.UserManager;
038
039/**
040 * Operation to create or update a group.
041 *
042 * @since 9.1
043 */
044@Operation(id = CreateOrUpdateGroup.ID, //
045        category = Constants.CAT_USERS_GROUPS, //
046        label = "Create or Update Group", //
047        description = "Create or Update Group")
048public class CreateOrUpdateGroup {
049
050    public static final String ID = "Group.CreateOrUpdate";
051
052    public static final String CREATE_OR_UPDATE = "createOrUpdate";
053
054    public static final String CREATE = "create";
055
056    public static final String UPDATE = "update";
057
058    public static final String GROUP_SCHEMA = "group";
059
060    protected static final String GROUP_COLON = GROUP_SCHEMA + ':';
061
062    public static final String GROUP_NAME = "groupname";
063
064    public static final String GROUP_LABEL = "grouplabel";
065
066    public static final String GROUP_DESCRIPTION = "description";
067
068    public static final String MEMBERS = "members";
069
070    public static final String SUB_GROUPS = "subGroups";
071
072    public static final String PARENT_GROUPS = "parentGroups";
073
074    public static final String GROUP_TENANTID = "tenantId";
075
076    @Context
077    protected UserManager userManager;
078
079    @Param(name = "groupname")
080    protected String groupName;
081
082    @Param(name = "tenantId", required = false)
083    protected String tenantId;
084
085    @Param(name = "grouplabel", required = false)
086    protected String groupLabel;
087
088    @Param(name = "description", required = false)
089    protected String groupDescription;
090
091    @Param(name = "members", required = false)
092    protected StringList members;
093
094    @Param(name = "subGroups", required = false)
095    protected StringList subGroups;
096
097    @Param(name = "parentGroups", required = false)
098    protected StringList parentGroups;
099
100    @Param(name = "properties", required = false)
101    protected Properties properties = new Properties();
102
103    @Param(name = "mode", required = false, values = { CREATE_OR_UPDATE, CREATE, UPDATE })
104    protected String mode;
105
106    @OperationMethod
107    public void run() throws OperationException {
108        String tenantGroupName = getTenantGroupName(groupName, tenantId);
109        boolean create;
110        DocumentModel groupDoc = userManager.getGroupModel(tenantGroupName);
111        if (groupDoc == null) {
112            if (UPDATE.equals(mode)) {
113                throw new OperationException("Cannot update non-existent group: " + groupName);
114            }
115            create = true;
116            groupDoc = userManager.getBareGroupModel();
117            groupDoc.setProperty(GROUP_SCHEMA, GROUP_NAME, tenantGroupName);
118        } else {
119            if (CREATE.equals(mode)) {
120                throw new OperationException("Cannot create already-existing group: " + groupName);
121            }
122            create = false;
123        }
124        if (members != null) {
125            groupDoc.setProperty(GROUP_SCHEMA, MEMBERS, members);
126        }
127        if (subGroups != null) {
128            groupDoc.setProperty(GROUP_SCHEMA, SUB_GROUPS, subGroups);
129        }
130        if (parentGroups != null) {
131            groupDoc.setProperty(GROUP_SCHEMA, PARENT_GROUPS, parentGroups);
132        }
133        for (Entry<String, String> entry : Arrays.asList( //
134                new SimpleEntry<>(GROUP_TENANTID, tenantId), //
135                new SimpleEntry<>(GROUP_LABEL, groupLabel), //
136                new SimpleEntry<>(GROUP_DESCRIPTION, groupDescription))) {
137            String key = entry.getKey();
138            String value = entry.getValue();
139            if (StringUtils.isNotBlank(value)) {
140                properties.put(key, value);
141            }
142        }
143        for (Entry<String, String> entry : properties.entrySet()) {
144            String key = entry.getKey();
145            String value = entry.getValue();
146            if (key.startsWith(GROUP_COLON)) {
147                key = key.substring(GROUP_COLON.length());
148            }
149            groupDoc.setProperty(GROUP_SCHEMA, key, value);
150        }
151        if (create) {
152            userManager.createGroup(groupDoc);
153        } else {
154            userManager.updateGroup(groupDoc);
155        }
156    }
157
158    /**
159     * Use tenant_mytenant_mygroup instead of mygroup for groups having a tenant id.
160     * <p>
161     * This is done explicitly instead of the implicit computation done in SQLSession.createEntry which is based on a
162     * tenant id deduced from the logged-in user.
163     */
164    public static String getTenantGroupName(String groupName, String tenantId) {
165        if (StringUtils.isBlank(tenantId)) {
166            return groupName;
167        }
168        return BaseSession.computeMultiTenantDirectoryId(tenantId, groupName);
169    }
170
171}