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.usersadmin.util;
016    
017    import com.liferay.portal.NoSuchContactException;
018    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.search.BaseIndexer;
021    import com.liferay.portal.kernel.search.BooleanClauseOccur;
022    import com.liferay.portal.kernel.search.BooleanQuery;
023    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
024    import com.liferay.portal.kernel.search.Document;
025    import com.liferay.portal.kernel.search.Field;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.SearchContext;
029    import com.liferay.portal.kernel.search.SearchEngineUtil;
030    import com.liferay.portal.kernel.search.Summary;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.kernel.workflow.WorkflowConstants;
034    import com.liferay.portal.model.Contact;
035    import com.liferay.portal.model.Organization;
036    import com.liferay.portal.model.User;
037    import com.liferay.portal.model.impl.ContactImpl;
038    import com.liferay.portal.security.auth.FullNameGenerator;
039    import com.liferay.portal.security.auth.FullNameGeneratorFactory;
040    import com.liferay.portal.service.OrganizationLocalServiceUtil;
041    import com.liferay.portal.service.UserLocalServiceUtil;
042    import com.liferay.portal.util.PortletKeys;
043    import com.liferay.portal.util.PropsValues;
044    
045    import java.util.ArrayList;
046    import java.util.Collection;
047    import java.util.HashMap;
048    import java.util.LinkedHashMap;
049    import java.util.List;
050    import java.util.Locale;
051    import java.util.Map;
052    
053    import javax.portlet.PortletRequest;
054    import javax.portlet.PortletResponse;
055    import javax.portlet.PortletURL;
056    
057    /**
058     * @author Raymond Aug??
059     * @author Zsigmond Rab
060     * @author Hugo Huijser
061     */
062    public class UserIndexer extends BaseIndexer {
063    
064            public static final String[] CLASS_NAMES = {User.class.getName()};
065    
066            public static final String PORTLET_ID = PortletKeys.USERS_ADMIN;
067    
068            public UserIndexer() {
069                    setCommitImmediately(true);
070                    setDefaultSelectedFieldNames(
071                            Field.COMPANY_ID, Field.UID, Field.USER_ID);
072                    setIndexerEnabled(PropsValues.USERS_INDEXER_ENABLED);
073                    setPermissionAware(true);
074                    setStagingAware(false);
075            }
076    
077            @Override
078            public String[] getClassNames() {
079                    return CLASS_NAMES;
080            }
081    
082            @Override
083            public String getPortletId() {
084                    return PORTLET_ID;
085            }
086    
087            @Override
088            public void postProcessContextQuery(
089                            BooleanQuery contextQuery, SearchContext searchContext)
090                    throws Exception {
091    
092                    int status = GetterUtil.getInteger(
093                            searchContext.getAttribute(Field.STATUS),
094                            WorkflowConstants.STATUS_APPROVED);
095    
096                    if (status != WorkflowConstants.STATUS_ANY) {
097                            contextQuery.addRequiredTerm(Field.STATUS, status);
098                    }
099    
100                    LinkedHashMap<String, Object> params =
101                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
102    
103                    if (params == null) {
104                            return;
105                    }
106    
107                    for (Map.Entry<String, Object> entry : params.entrySet()) {
108                            String key = entry.getKey();
109                            Object value = entry.getValue();
110    
111                            if (value == null) {
112                                    continue;
113                            }
114    
115                            Class<?> clazz = value.getClass();
116    
117                            if (clazz.isArray()) {
118                                    Object[] values = (Object[])value;
119    
120                                    if (values.length == 0) {
121                                            continue;
122                                    }
123                            }
124    
125                            addContextQueryParams(contextQuery, searchContext, key, value);
126                    }
127            }
128    
129            @Override
130            public void postProcessSearchQuery(
131                            BooleanQuery searchQuery, SearchContext searchContext)
132                    throws Exception {
133    
134                    addSearchTerm(searchQuery, searchContext, "city", false);
135                    addSearchTerm(searchQuery, searchContext, "country", false);
136                    addSearchTerm(searchQuery, searchContext, "emailAddress", false);
137                    addSearchTerm(searchQuery, searchContext, "firstName", false);
138                    addSearchTerm(searchQuery, searchContext, "fullName", false);
139                    addSearchTerm(searchQuery, searchContext, "lastName", false);
140                    addSearchTerm(searchQuery, searchContext, "middleName", false);
141                    addSearchTerm(searchQuery, searchContext, "region", false);
142                    addSearchTerm(searchQuery, searchContext, "screenName", false);
143                    addSearchTerm(searchQuery, searchContext, "street", false);
144                    addSearchTerm(searchQuery, searchContext, "zip", false);
145    
146                    LinkedHashMap<String, Object> params =
147                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
148    
149                    if (params != null) {
150                            String expandoAttributes = (String)params.get("expandoAttributes");
151    
152                            if (Validator.isNotNull(expandoAttributes)) {
153                                    addSearchExpando(searchQuery, searchContext, expandoAttributes);
154                            }
155                    }
156            }
157    
158            protected void addContextQueryParams(
159                            BooleanQuery contextQuery, SearchContext searchContext, String key,
160                            Object value)
161                    throws Exception {
162    
163                    if (key.equals("usersGroups")) {
164                            if (value instanceof Long[]) {
165                                    Long[] values = (Long[])value;
166    
167                                    BooleanQuery usersGroupsQuery = BooleanQueryFactoryUtil.create(
168                                            searchContext);
169    
170                                    for (long groupId : values) {
171                                            usersGroupsQuery.addTerm("groupIds", groupId);
172                                    }
173    
174                                    contextQuery.add(usersGroupsQuery, BooleanClauseOccur.MUST);
175                            }
176                            else {
177                                    contextQuery.addRequiredTerm("groupIds", String.valueOf(value));
178                            }
179                    }
180                    else if (key.equals("usersOrgs")) {
181                            if (value instanceof Long[]) {
182                                    Long[] values = (Long[])value;
183    
184                                    BooleanQuery usersOrgsQuery = BooleanQueryFactoryUtil.create(
185                                            searchContext);
186    
187                                    for (long organizationId : values) {
188                                            usersOrgsQuery.addTerm("organizationIds", organizationId);
189                                            usersOrgsQuery.addTerm(
190                                                    "ancestorOrganizationIds", organizationId);
191                                    }
192    
193                                    contextQuery.add(usersOrgsQuery, BooleanClauseOccur.MUST);
194                            }
195                            else {
196                                    contextQuery.addRequiredTerm(
197                                            "organizationIds", String.valueOf(value));
198                            }
199                    }
200                    else if (key.equals("usersOrgsCount")) {
201                            contextQuery.addRequiredTerm(
202                                    "organizationCount", String.valueOf(value));
203                    }
204                    else if (key.equals("usersRoles")) {
205                            contextQuery.addRequiredTerm("roleIds", String.valueOf(value));
206                    }
207                    else if (key.equals("usersTeams")) {
208                            contextQuery.addRequiredTerm("teamIds", String.valueOf(value));
209                    }
210                    else if (key.equals("usersUserGroups")) {
211                            contextQuery.addRequiredTerm("userGroupIds", String.valueOf(value));
212                    }
213            }
214    
215            @Override
216            protected void doDelete(Object obj) throws Exception {
217                    User user = (User)obj;
218    
219                    deleteDocument(user.getCompanyId(), user.getUserId());
220    
221                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(Contact.class);
222    
223                    Contact contact = new ContactImpl();
224    
225                    contact.setContactId(user.getContactId());
226                    contact.setCompanyId(user.getCompanyId());
227    
228                    indexer.delete(contact);
229            }
230    
231            @Override
232            protected Document doGetDocument(Object obj) throws Exception {
233                    User user = (User)obj;
234    
235                    Document document = getBaseModelDocument(PORTLET_ID, user);
236    
237                    long[] organizationIds = user.getOrganizationIds();
238    
239                    document.addKeyword(Field.COMPANY_ID, user.getCompanyId());
240                    document.addKeyword(Field.GROUP_ID, user.getGroupIds());
241                    document.addDate(Field.MODIFIED_DATE, user.getModifiedDate());
242                    document.addKeyword(Field.SCOPE_GROUP_ID, user.getGroupIds());
243                    document.addKeyword(Field.STATUS, user.getStatus());
244                    document.addKeyword(Field.USER_ID, user.getUserId());
245                    document.addKeyword(Field.USER_NAME, user.getFullName());
246    
247                    document.addKeyword(
248                            "ancestorOrganizationIds",
249                            getAncestorOrganizationIds(
250                                    user.getUserId(), user.getOrganizationIds()));
251                    document.addText("emailAddress", user.getEmailAddress());
252                    document.addText("firstName", user.getFirstName());
253                    document.addText("fullName", user.getFullName());
254                    document.addKeyword("groupIds", user.getGroupIds());
255                    document.addText("jobTitle", user.getJobTitle());
256                    document.addText("lastName", user.getLastName());
257                    document.addText("middleName", user.getMiddleName());
258                    document.addKeyword("organizationIds", organizationIds);
259                    document.addKeyword(
260                            "organizationCount", String.valueOf(organizationIds.length));
261                    document.addKeyword("roleIds", user.getRoleIds());
262                    document.addText("screenName", user.getScreenName());
263                    document.addKeyword("teamIds", user.getTeamIds());
264                    document.addKeyword("userGroupIds", user.getUserGroupIds());
265    
266                    populateAddresses(document, user.getAddresses(), 0, 0);
267    
268                    return document;
269            }
270    
271            @Override
272            protected String doGetSortField(String orderByCol) {
273                    if (orderByCol.equals("email-address")) {
274                            return "emailAddress";
275                    }
276                    else if (orderByCol.equals("first-name")) {
277                            return "firstName";
278                    }
279                    else if (orderByCol.equals("job-title")) {
280                            return "jobTitle";
281                    }
282                    else if (orderByCol.equals("last-name")) {
283                            return "lastName";
284                    }
285                    else if (orderByCol.equals("screen-name")) {
286                            return "screenName";
287                    }
288                    else {
289                            return orderByCol;
290                    }
291            }
292    
293            @Override
294            protected Summary doGetSummary(
295                    Document document, Locale locale, String snippet, PortletURL portletURL,
296                    PortletRequest portletRequest, PortletResponse portletResponse) {
297    
298                    String firstName = document.get("firstName");
299                    String middleName = document.get("middleName");
300                    String lastName = document.get("lastName");
301    
302                    FullNameGenerator fullNameGenerator =
303                            FullNameGeneratorFactory.getInstance();
304    
305                    String title = fullNameGenerator.getFullName(
306                            firstName, middleName, lastName);
307    
308                    String content = null;
309    
310                    String userId = document.get(Field.USER_ID);
311    
312                    portletURL.setParameter("struts_action", "/users_admin/edit_user");
313                    portletURL.setParameter("p_u_i_d", userId);
314    
315                    return new Summary(title, content, portletURL);
316            }
317    
318            @Override
319            protected void doReindex(Object obj) throws Exception {
320                    if (obj instanceof Long) {
321                            long userId = (Long)obj;
322    
323                            User user = UserLocalServiceUtil.getUserById(userId);
324    
325                            doReindex(user);
326                    }
327                    else if (obj instanceof long[]) {
328                            long[] userIds = (long[])obj;
329    
330                            Map<Long, Collection<Document>> documentsMap =
331                                    new HashMap<Long, Collection<Document>>();
332    
333                            for (long userId : userIds) {
334                                    User user = UserLocalServiceUtil.getUserById(userId);
335    
336                                    if (user.isDefaultUser()) {
337                                            continue;
338                                    }
339    
340                                    Document document = getDocument(user);
341    
342                                    long companyId = user.getCompanyId();
343    
344                                    Collection<Document> documents = documentsMap.get(companyId);
345    
346                                    if (documents == null) {
347                                            documents = new ArrayList<Document>();
348    
349                                            documentsMap.put(companyId, documents);
350                                    }
351    
352                                    documents.add(document);
353                            }
354    
355                            for (Map.Entry<Long, Collection<Document>> entry :
356                                            documentsMap.entrySet()) {
357    
358                                    long companyId = entry.getKey();
359                                    Collection<Document> documents = entry.getValue();
360    
361                                    SearchEngineUtil.updateDocuments(
362                                            getSearchEngineId(), companyId, documents,
363                                            isCommitImmediately());
364                            }
365                    }
366                    else if (obj instanceof User) {
367                            User user = (User)obj;
368    
369                            if (user.isDefaultUser()) {
370                                    return;
371                            }
372    
373                            Document document = getDocument(user);
374    
375                            SearchEngineUtil.updateDocument(
376                                    getSearchEngineId(), user.getCompanyId(), document,
377                                    isCommitImmediately());
378    
379                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
380                                    Contact.class);
381    
382                            try {
383                                    indexer.reindex(user.getContact());
384                            }
385                            catch (NoSuchContactException nscce) {
386    
387                                    // This is a temporary workaround for LPS-46825
388    
389                            }
390                    }
391            }
392    
393            @Override
394            protected void doReindex(String className, long classPK) throws Exception {
395                    User user = UserLocalServiceUtil.getUserById(classPK);
396    
397                    doReindex(user);
398            }
399    
400            @Override
401            protected void doReindex(String[] ids) throws Exception {
402                    long companyId = GetterUtil.getLong(ids[0]);
403    
404                    reindexUsers(companyId);
405            }
406    
407            protected long[] getAncestorOrganizationIds(
408                            long userId, long[] organizationIds)
409                    throws Exception {
410    
411                    List<Organization> ancestorOrganizations =
412                            new ArrayList<Organization>();
413    
414                    for (long organizationId : organizationIds) {
415                            Organization organization =
416                                    OrganizationLocalServiceUtil.getOrganization(organizationId);
417    
418                            ancestorOrganizations.addAll(organization.getAncestors());
419                    }
420    
421                    long[] ancestorOrganizationIds = new long[ancestorOrganizations.size()];
422    
423                    for (int i = 0; i < ancestorOrganizations.size(); i++) {
424                            Organization ancestorOrganization = ancestorOrganizations.get(i);
425    
426                            ancestorOrganizationIds[i] =
427                                    ancestorOrganization.getOrganizationId();
428                    }
429    
430                    return ancestorOrganizationIds;
431            }
432    
433            @Override
434            protected String getPortletId(SearchContext searchContext) {
435                    return PORTLET_ID;
436            }
437    
438            protected void reindexUsers(long companyId) throws PortalException {
439                    final ActionableDynamicQuery actionableDynamicQuery =
440                            UserLocalServiceUtil.getActionableDynamicQuery();
441    
442                    actionableDynamicQuery.setCompanyId(companyId);
443                    actionableDynamicQuery.setPerformActionMethod(
444                            new ActionableDynamicQuery.PerformActionMethod() {
445    
446                                    @Override
447                                    public void performAction(Object object)
448                                            throws PortalException {
449    
450                                            User user = (User)object;
451    
452                                            if (!user.isDefaultUser()) {
453                                                    Document document = getDocument(user);
454    
455                                                    actionableDynamicQuery.addDocument(document);
456                                            }
457                                    }
458    
459                            });
460                    actionableDynamicQuery.setSearchEngineId(getSearchEngineId());
461    
462                    actionableDynamicQuery.performActions();
463            }
464    
465    }