001/*
002 * (C) Copyright 2006-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 *     Bogdan Stefanescu
018 *     Ricardo Dias
019 *     Estelle Giuly
020 */
021package org.nuxeo.ecm.automation.features;
022
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.List;
026import java.util.Set;
027
028import org.apache.commons.lang3.StringUtils;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.apache.commons.text.StringEscapeUtils;
032import org.nuxeo.ecm.automation.core.scripting.CoreFunctions;
033import org.nuxeo.ecm.automation.core.util.StringList;
034import org.nuxeo.ecm.core.api.CoreSession;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.DocumentRef;
037import org.nuxeo.ecm.core.api.IdRef;
038import org.nuxeo.ecm.core.api.NuxeoPrincipal;
039import org.nuxeo.ecm.core.api.PathRef;
040import org.nuxeo.ecm.core.query.sql.NXQL;
041import org.nuxeo.ecm.core.uidgen.UIDGeneratorService;
042import org.nuxeo.ecm.core.uidgen.UIDSequencer;
043import org.nuxeo.ecm.directory.Session;
044import org.nuxeo.ecm.directory.api.DirectoryService;
045import org.nuxeo.ecm.platform.usermanager.UserManager;
046import org.nuxeo.runtime.api.Framework;
047import org.nuxeo.runtime.services.config.ConfigurationService;
048
049/**
050 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
051 */
052public class PlatformFunctions extends CoreFunctions {
053
054    private volatile DirectoryService dirService;
055
056    private static final Log log = LogFactory.getLog(PlatformFunctions.class);
057
058    private volatile UserManager userMgr;
059
060    public static final String HIBERNATE_SEQUENCER_PROPERTY = "org.nuxeo.ecm.core.uidgen.sequencer.hibernate";
061
062    public UserManager getUserManager() {
063        if (userMgr == null) {
064            userMgr = Framework.getService(UserManager.class);
065        }
066        return userMgr;
067    }
068
069    public DirectoryService getDirService() {
070        if (dirService == null) {
071            dirService = Framework.getService(DirectoryService.class);
072        }
073        return dirService;
074    }
075
076    public String getVocabularyLabel(String voc, String key) {
077        try (Session session = getDirService().open(voc)) {
078            if (!session.hasEntry(key)) {
079                log.debug("Unable to find the key '" + key + "' in the vocabulary '" + voc + "'.");
080                return key;
081            }
082            DocumentModel doc = session.getEntry(key);
083            return (String) doc.getPropertyValue("label"); // no schema prefix for vocabularies
084        }
085    }
086
087    public NuxeoPrincipal getPrincipal(String username) {
088        return getUserManager().getPrincipal(username);
089    }
090
091    protected String getEmail(NuxeoPrincipal principal, String userSchemaName, String userEmailFieldName) {
092        if (principal == null) {
093            return null;
094        }
095        return (String) principal.getModel().getProperty(userSchemaName, userEmailFieldName);
096    }
097
098    public String getEmail(String username) {
099        UserManager userManager = getUserManager();
100        return getEmail(userManager.getPrincipal(username), userManager.getUserSchemaName(),
101                userManager.getUserEmailField());
102    }
103
104    public Set<NuxeoPrincipal> getPrincipalsFromGroup(String group) {
105        return getPrincipalsFromGroup(group, false);
106    }
107
108    public Set<NuxeoPrincipal> getPrincipalsFromGroup(String group, boolean ignoreGroups) {
109        PrincipalHelper ph = new PrincipalHelper(getUserManager(), null);
110        return ph.getPrincipalsFromGroup(group, !ignoreGroups);
111    }
112
113    public StringList getEmailsFromGroup(String group) {
114        return getEmailsFromGroup(group, false);
115    }
116
117    public StringList getEmailsFromGroup(String group, boolean ignoreGroups) {
118        PrincipalHelper ph = new PrincipalHelper(getUserManager(), null);
119        Set<String> emails = ph.getEmailsFromGroup(group, !ignoreGroups);
120        return new StringList(emails);
121    }
122
123    public StringList getPrincipalEmails(List<NuxeoPrincipal> principals) {
124        StringList result = new StringList(principals.size());
125        String schemaName = getUserManager().getUserSchemaName();
126        String fieldName = getUserManager().getUserEmailField();
127        for (NuxeoPrincipal principal : principals) {
128            String email = getEmail(principal, schemaName, fieldName);
129            if (!StringUtils.isEmpty(email)) {
130                result.add(email);
131            }
132        }
133        return result;
134    }
135
136    public StringList getEmails(List<String> usernames) {
137        return getEmails(usernames, false);
138    }
139
140    /**
141     * Returns user emails
142     *
143     * @param usernames list of user names
144     * @param usePrefix indicates if user resolution takes into account nuxeo prefix <b>user:</b>
145     * @since 5.5
146     */
147    public StringList getEmails(List<String> usernames, boolean usePrefix) {
148        if (usernames == null) {
149            return new StringList(0);
150        }
151        UserManager userManager = getUserManager();
152        StringList result = new StringList(usernames.size());
153        String schemaName = getUserManager().getUserSchemaName();
154        String fieldName = getUserManager().getUserEmailField();
155        for (String username : usernames) {
156            NuxeoPrincipal principal = null;
157            if (usePrefix) {
158                if (username.startsWith(NuxeoPrincipal.PREFIX)) {
159                    principal = userManager.getPrincipal(username.replace(NuxeoPrincipal.PREFIX, ""));
160                }
161            } else {
162                principal = userManager.getPrincipal(username);
163            }
164            if (principal != null) {
165                String email = getEmail(principal, schemaName, fieldName);
166                if (!StringUtils.isEmpty(email)) {
167                    result.add(email);
168                }
169            }
170        }
171        return result;
172    }
173
174    public String getNextId(final String key) {
175        ConfigurationService configurationService = Framework.getService(ConfigurationService.class);
176        boolean useHibernate = configurationService.isBooleanPropertyTrue(HIBERNATE_SEQUENCER_PROPERTY);
177        return getNextId(key, useHibernate ? "hibernateSequencer" : null);
178    }
179
180    public String getNextId(final String key, final String sequencerName) {
181        UIDGeneratorService uidGeneratorService = Framework.getService(UIDGeneratorService.class);
182        UIDSequencer seq = uidGeneratorService.getSequencer(sequencerName);
183        return Long.toString(seq.getNextLong(key));
184    }
185
186    public static String htmlEscape(String str) {
187        return StringEscapeUtils.escapeHtml4(str);
188    }
189
190    /**
191     * Escapes a string according to NXQL escaping rules.
192     * <p>
193     * The resulting string is safe to include between single quotes in a NXQL expression.
194     *
195     * @param str the input string
196     * @return the escaped string
197     * @since 6.0-HF21, 7.10
198     */
199    public static String nxqlEscape(String str) {
200        return NXQL.escapeStringInner(str);
201    }
202
203    /**
204     * Concatenate into the list given as first argument other arguments. Other arguments will be explosed if it is a
205     * list of object. ex: concatenateInto(myList, a, anotherList) with a is scalar object and anotherList is a list of
206     * object will produced myList.add(a) and the same for each object contained into the anotherList list.
207     *
208     * @param <T>
209     * @param list List of values of type A
210     * @param values Value can be instance of java.util.Collection<Object> or an array of Objects or simply a scalar
211     *            Object. If Null, the parameter is ignored
212     * @return the list that contains the list contain and value (see value description)
213     * @exception xxxxx if in values there is at least one object type not compatible with the collection list
214     */
215    @SuppressWarnings("unchecked")
216    public <T> List<T> concatenateIntoList(List<T> list, Object... values) {
217
218        if (list == null) {
219            throw new IllegalArgumentException("First parameter must not be null");
220        }
221
222        for (Object value : values) {
223            if (value == null) {
224                continue;
225            }
226
227            if (value instanceof Object[]) {
228                for (Object subValue : (Object[]) value) {
229                    if (subValue != null) {
230                        list.add((T) subValue);
231                    }
232                }
233                continue;
234            }
235
236            if (value instanceof Collection) {
237                for (Object subValue : (Collection<Object>) value) {
238                    if (subValue != null) {
239                        list.add((T) subValue);
240                    }
241                }
242                continue;
243            }
244
245            list.add((T) value);
246
247        }
248        return list;
249    }
250
251    /**
252     * Idem than concatenateInto except that a new list is created.
253     */
254    public <T> List<T> concatenateValuesAsNewList(Object... values) {
255
256        List<T> result = new ArrayList<>();
257        return concatenateIntoList(result, values);
258    }
259
260    /**
261     * Checks if a document with the supplied id (or path) exists.
262     *
263     * @param session The CoreSession to obtain the document
264     * @param idOrPath The document Id or path
265     * @return true if the document exists, or false otherwise
266     */
267    public boolean documentExists(CoreSession session, String idOrPath) {
268        DocumentRef documentRef = idOrPath.startsWith("/") ? new PathRef(idOrPath) : new IdRef(idOrPath);
269        return session.exists(documentRef);
270    }
271
272}