001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     <a href="mailto:grenard@nuxeo.com">Guillaume</a>
016 */
017package org.nuxeo.ecm.platform.ui.select2.automation;
018
019import java.io.Serializable;
020import java.util.List;
021import java.util.Locale;
022
023import net.sf.json.JSONArray;
024import net.sf.json.JSONObject;
025
026import org.apache.commons.lang.StringUtils;
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.common.utils.i18n.I18NUtils;
030import org.nuxeo.ecm.automation.OperationContext;
031import org.nuxeo.ecm.automation.core.Constants;
032import org.nuxeo.ecm.automation.core.annotations.Context;
033import org.nuxeo.ecm.automation.core.annotations.Operation;
034import org.nuxeo.ecm.automation.core.annotations.OperationMethod;
035import org.nuxeo.ecm.automation.core.annotations.Param;
036import org.nuxeo.ecm.core.api.Blob;
037import org.nuxeo.ecm.core.api.Blobs;
038import org.nuxeo.ecm.core.api.DocumentModel;
039import org.nuxeo.ecm.core.api.DocumentModelList;
040import org.nuxeo.ecm.core.api.NuxeoGroup;
041import org.nuxeo.ecm.core.api.NuxeoPrincipal;
042import org.nuxeo.ecm.core.schema.SchemaManager;
043import org.nuxeo.ecm.core.schema.types.Field;
044import org.nuxeo.ecm.core.schema.types.QName;
045import org.nuxeo.ecm.core.schema.types.Schema;
046import org.nuxeo.ecm.directory.Directory;
047import org.nuxeo.ecm.directory.SizeLimitExceededException;
048import org.nuxeo.ecm.directory.api.DirectoryService;
049import org.nuxeo.ecm.platform.ui.select2.common.Select2Common;
050import org.nuxeo.ecm.platform.usermanager.UserAdapter;
051import org.nuxeo.ecm.platform.usermanager.UserManager;
052
053/**
054 * SuggestUser Operation.
055 *
056 * @since 5.7.3
057 */
058@Operation(id = SuggestUserEntries.ID, category = Constants.CAT_SERVICES, label = "Get user/group suggestion", description = "Get the user/group list of the running instance. This is returning a blob containing a serialized JSON array..", addToStudio = false)
059public class SuggestUserEntries {
060
061    @SuppressWarnings("unused")
062    private static final Log log = LogFactory.getLog(SuggestUserEntries.class);
063
064    public static final String ID = "UserGroup.Suggestion";
065
066    @Context
067    protected OperationContext ctx;
068
069    @Context
070    protected SchemaManager schemaManager;
071
072    @Param(name = "searchTerm", alias = "prefix", required = false)
073    protected String prefix;
074
075    @Param(name = "searchType", required = false)
076    protected String searchType;
077
078    @Param(name = "groupRestriction", required = false)
079    protected String groupRestriction;
080
081    @Param(name = "userSuggestionMaxSearchResults", required = false)
082    protected Integer userSuggestionMaxSearchResults;
083
084    @Param(name = "firstLabelField", required = false)
085    protected String firstLabelField;
086
087    @Param(name = "secondLabelField", required = false)
088    protected String secondLabelField;
089
090    @Param(name = "thirdLabelField", required = false)
091    protected String thirdLabelField;
092
093    @Param(name = "hideFirstLabel", required = false)
094    protected boolean hideFirstLabel = false;
095
096    @Param(name = "hideSecondLabel", required = false)
097    protected boolean hideSecondLabel = false;
098
099    @Param(name = "hideThirdLabel", required = false)
100    protected boolean hideThirdLabel;
101
102    @Param(name = "displayEmailInSuggestion", required = false)
103    protected boolean displayEmailInSuggestion;
104
105    @Param(name = "hideIcon", required = false)
106    protected boolean hideIcon;
107
108    @Context
109    protected UserManager userManager;
110
111    @Context
112    protected DirectoryService directoryService;
113
114    @Param(name = "lang", required = false)
115    protected String lang;
116
117    @OperationMethod
118    public Blob run() {
119        JSONArray result = new JSONArray();
120        boolean isGroupRestriction = !StringUtils.isBlank(groupRestriction);
121        boolean groupOnly = false;
122        boolean userOnly = isGroupRestriction;
123
124        if (!isGroupRestriction && searchType != null && !searchType.isEmpty()) {
125            if (searchType.equals(Select2Common.USER_TYPE)) {
126                userOnly = true;
127            } else if (searchType.equals(Select2Common.GROUP_TYPE)) {
128                groupOnly = true;
129            }
130        }
131        try {
132            DocumentModelList userList = null;
133            DocumentModelList groupList = null;
134            if (!groupOnly) {
135                Schema schema = schemaManager.getSchema(userManager.getUserSchemaName());
136                userList = userManager.searchUsers(prefix);
137                Directory userDir = directoryService.getDirectory(userManager.getUserDirectoryName());
138                for (DocumentModel user : userList) {
139                    JSONObject obj = new JSONObject();
140                    for (Field field : schema.getFields()) {
141                        QName fieldName = field.getName();
142                        String key = fieldName.getLocalName();
143                        Serializable value = user.getPropertyValue(fieldName.getPrefixedName());
144                        if (key.equals(userDir.getPasswordField())) {
145                            continue;
146                        }
147                        obj.element(key, value);
148                    }
149                    String userId = user.getId();
150                    obj.put(Select2Common.ID, userId);
151                    obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.USER_TYPE);
152                    obj.put(Select2Common.PREFIXED_ID_KEY_NAME, NuxeoPrincipal.PREFIX + userId);
153                    Select2Common.computeUserLabel(obj, firstLabelField, secondLabelField, thirdLabelField,
154                            hideFirstLabel, hideSecondLabel, hideThirdLabel, displayEmailInSuggestion, userId);
155                    Select2Common.computeUserGroupIcon(obj, hideIcon);
156                    if (isGroupRestriction) {
157                        // We need to load all data about the user particularly
158                        // its
159                        // groups.
160                        user = userManager.getUserModel(userId);
161                        UserAdapter userAdapter = user.getAdapter(UserAdapter.class);
162                        List<String> groups = userAdapter.getGroups();
163                        if (groups != null && groups.contains(groupRestriction)) {
164                            result.add(obj);
165                        }
166                    } else {
167                        result.add(obj);
168                    }
169                }
170            }
171            if (!userOnly) {
172                Schema schema = schemaManager.getSchema(userManager.getGroupSchemaName());
173                groupList = userManager.searchGroups(prefix);
174                for (DocumentModel group : groupList) {
175                    JSONObject obj = new JSONObject();
176                    for (Field field : schema.getFields()) {
177                        QName fieldName = field.getName();
178                        String key = fieldName.getLocalName();
179                        Serializable value = group.getPropertyValue(fieldName.getPrefixedName());
180                        obj.element(key, value);
181                    }
182                    String groupId = group.getId();
183                    obj.put(Select2Common.ID, groupId);
184                    // If the group hasn't an label, let's put the groupid
185                    Select2Common.computeGroupLabel(obj, groupId, userManager.getGroupLabelField(), hideFirstLabel);
186                    obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.GROUP_TYPE);
187                    obj.put(Select2Common.PREFIXED_ID_KEY_NAME, NuxeoGroup.PREFIX + groupId);
188                    Select2Common.computeUserGroupIcon(obj, hideIcon);
189                    result.add(obj);
190                }
191            }
192
193            // Limit size results.
194            int userSize = userList != null ? userList.size() : 0;
195            int groupSize = groupList != null ? groupList.size() : 0;
196            int totalSize = userSize + groupSize;
197            if (userSuggestionMaxSearchResults != null && userSuggestionMaxSearchResults > 0) {
198                if (userSize > userSuggestionMaxSearchResults || groupSize > userSuggestionMaxSearchResults
199                        || totalSize > userSuggestionMaxSearchResults) {
200                    throw new SizeLimitExceededException();
201                }
202            }
203
204        } catch (SizeLimitExceededException e) {
205            return searchOverflowMessage();
206        }
207
208        return Blobs.createBlob(result.toString(), "application/json");
209    }
210
211    /**
212     * @return searchOverflowMessage
213     * @since 5.7.3
214     */
215    private Blob searchOverflowMessage() {
216        JSONArray result = new JSONArray();
217        JSONObject obj = new JSONObject();
218        obj.put(Select2Common.LABEL,
219                I18NUtils.getMessageString("messages", "label.security.searchOverFlow", new Object[0], getLocale()));
220        result.add(obj);
221        return Blobs.createBlob(result.toString(), "application/json");
222    }
223
224    protected String getLang() {
225        if (lang == null) {
226            lang = (String) ctx.get("lang");
227            if (lang == null) {
228                lang = Select2Common.DEFAULT_LANG;
229            }
230        }
231        return lang;
232    }
233
234    protected Locale getLocale() {
235        return new Locale(getLang());
236    }
237
238}