/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.vertical.adminweb; import java.util.Collection; import java.util.Date; import org.w3c.dom.Document; import com.enonic.esl.containers.ExtendedMap; import com.enonic.esl.util.DateUtil; import com.enonic.esl.util.StringUtil; import com.enonic.esl.xml.XMLTool; import com.enonic.cms.framework.xml.XMLDocument; import com.enonic.cms.core.content.ContentService; import com.enonic.cms.core.content.ContentStatus; import com.enonic.cms.core.content.ContentXMLCreator; import com.enonic.cms.core.content.access.ContentAccessResolver; import com.enonic.cms.core.content.category.CategoryAccessResolver; import com.enonic.cms.core.content.category.CategoryKey; import com.enonic.cms.core.content.contenttype.ContentTypeKey; import com.enonic.cms.core.content.query.OpenContentQuery; import com.enonic.cms.core.content.query.RelatedContentQuery; import com.enonic.cms.core.content.resultset.ContentResultSet; import com.enonic.cms.core.content.resultset.RelatedContentResultSet; import com.enonic.cms.core.security.SecurityService; import com.enonic.cms.core.security.user.User; import com.enonic.cms.core.security.user.UserEntity; import com.enonic.cms.core.security.user.UserKey; import com.enonic.cms.core.security.user.UserSpecification; import com.enonic.cms.store.dao.GroupDao; import com.enonic.cms.store.dao.UserDao; /** * This class contains common methods used to search for content. */ public final class SearchUtility { private UserDao userDao; private ContentService contentService; private SecurityService securityService; private GroupDao groupDao; /** * Private constructor. */ public SearchUtility( UserDao userDao, GroupDao groupDao, SecurityService securityService, ContentService contentService ) { this.userDao = userDao; this.groupDao = groupDao; this.securityService = securityService; this.contentService = contentService; } /** * Return the simple search string. */ private static String parseSimpleSearch( ExtendedMap items ) { boolean scopeAll = items.getString( "scope", "" ).equals( "all" ); String search = items.getString( "searchtext", "" ); return SearchBuilder.buildFromUserInput( search, true, scopeAll, false ).toString(); } /** * Return the advanced search string. */ private String parseAdvancedSearch( ExtendedMap items ) { SearchStringBuffer search = new SearchStringBuffer(); String key = items.getString( "acontentkey", null ); if ( key != null ) { search.appendKey( key ); } if ( items.containsKey( "owner.key" ) ) { search.appendOwner( "'" + items.getString( "owner.key" ) + "'" ); } if ( items.containsKey( "modifier.key" ) ) { search.appendModifier( "'" + items.getString( "modifier.key" ) + "'" ); } boolean assigneeOrAssignerSet = false; if ( items.containsKey( "_assignee" ) ) { UserSpecification userSpec = new UserSpecification(); userSpec.setKey( new UserKey( items.getString( "_assignee" ) ) ); UserEntity assigneeUser = userDao.findSingleBySpecification( userSpec ); search.appendAssigneeQualifiedName( "'" + assigneeUser.getQualifiedName().toString() + "'" ); assigneeOrAssignerSet = true; } if ( items.containsKey( "_assigner" ) ) { UserSpecification userSpec = new UserSpecification(); userSpec.setKey( new UserKey( items.getString( "_assigner" ) ) ); UserEntity assignerUser = userDao.findSingleBySpecification( userSpec ); search.appendAssignerQualifiedName( "'" + assignerUser.getQualifiedName().toString() + "'" ); assigneeOrAssignerSet = true; } if ( items.containsKey( "date_assignmentDueDate" ) ) { String assignmentDueDateOperator = items.getString( "_assignmentDueDate.op" ); String assignmentDueDate = items.getString( "date_assignmentDueDate" ); String assigmentDueDateQueryValue = parseDatetime( assignmentDueDate ); search.appendAssignmentDueDate( parseDatetimeOperator( assignmentDueDateOperator ), assigmentDueDateQueryValue ); search.appendNotEmpty( "assignmentDueDate" ); if ( !assigneeOrAssignerSet ) { search.appendNotEmpty( "assignee/qualifiedName" ); } } if ( items.containsKey( "state" ) ) { String nowDate = DateUtil.formatISODateTime( new Date() ); if ( items.getString( "state" ).equals( "4" ) ) { search.appendStatus( "" + ContentStatus.APPROVED.getKey() ); search.appendPublishFrom( " > ", "date(\"" + nowDate + "\")" ); } else if ( items.getString( "state" ).equals( "5" ) ) { // nothing to do, handled outside this function with publishedOnly flag } else if ( items.getString( "state" ).equals( "6" ) ) { search.appendStatus( "" + ContentStatus.APPROVED.getKey() ); search.appendPublishTo( " < ", "date(\"" + nowDate + "\")" ); } else { search.appendStatus( items.getString( "state" ) ); } } if ( items.containsKey( "datecreated" ) ) { search.appendCreated( parseDatetimeOperator( items.getString( "created.op" ) ), parseDatetime( items.getString( "datecreated" ) ) ); } if ( items.containsKey( "datemodified" ) ) { search.appendTimestamp( parseDatetimeOperator( items.getString( "modified.op" ) ), parseDatetime( items.getString( "datemodified" ) ) ); } String filter = items.getString( "filter", "" ).trim(); if ( filter.length() > 0 ) { search.appendRaw( filter ); } final String scopeStr = items.getString( "ascope", "" ); search.appendRaw( SearchBuilder.buildFromUserInput( items.getString( "asearchtext", "" ), true, scopeStr.equals( "all" ), scopeStr.equals( "fileAttachments" ) ) ); return search.toString(); } public XMLDocument simpleSearch( User user, ExtendedMap formItems, CategoryKey categoryKey, int[] contentTypeKeys, String orderBy, int index, int count ) throws VerticalAdminException { String query = parseSimpleSearch( formItems ); boolean publishedOnly = false; return findContent( user, categoryKey, contentTypeKeys, query, true, orderBy, publishedOnly, index, count, true, true ); } public String simpleReport( User user, ExtendedMap formItems, int cat ) throws VerticalAdminException { String query = parseSimpleSearch( formItems ); boolean publishedOnly = false; int[] categoryKeys = null; if ( cat != -1 ) { categoryKeys = new int[]{cat}; } return findContent( user, categoryKeys, null, query, publishedOnly, true, 0, Integer.MAX_VALUE, 1, 1, 0, true, true, true, true ); } public XMLDocument advancedSearch( User user, ExtendedMap formItems, int[] contentTypeKeys, String orderBy, int index, int count ) throws VerticalAdminException { boolean includeSubCategories = formItems.getString( "subcategories", "0" ).equals( "1" ); boolean publishedOnly = formItems.getString( "state", "" ).equals( "5" ); // if status = Online => search with publishedOnly flag String query = parseAdvancedSearch( formItems ); int submittetCategoryKey = formItems.getInt( "categorykey", -1 ); if ( submittetCategoryKey == -1 ) { submittetCategoryKey = formItems.getInt( "cat", -1 ); } CategoryKey categoryKey = CategoryKey.parse( submittetCategoryKey ); return findContent( user, categoryKey, contentTypeKeys, query, includeSubCategories, orderBy, publishedOnly, index, count, true, true ); } private static String parseDatetimeOperator( String op ) { if ( op.equals( "lte" ) ) { return " <= "; } else if ( op.equals( "gte" ) ) { return " >= "; } else { return " = "; } } private static String parseDatetime( String date ) { StringBuffer str = new StringBuffer(); str.append( " date(\"" ); String[] fields = StringUtil.splitString( date, '.' ); str.append( fields[2] ).append( "-" ); str.append( fields[1] ).append( "-" ); str.append( fields[0] ); str.append( "\")" ); return str.toString(); } public String advancedReport( User user, ExtendedMap formItems, int[] contentTypeKeys ) throws VerticalAdminException { boolean includeSubCategories = formItems.getString( "subcategories", "0" ).equals( "1" ); boolean publishedOnly = formItems.getString( "state", "" ).equals( "5" ); // if status = Online => search with publishedOnly flag String query = parseAdvancedSearch( formItems ); int[] categoryKeys = null; if ( formItems.getInt( "cat", -1 ) != -1 ) { categoryKeys = new int[]{formItems.getInt( "cat" )}; } return findContent( user, categoryKeys, contentTypeKeys, query, publishedOnly, includeSubCategories, 0, Integer.MAX_VALUE, 1, 1, 0, true, true, true, true ); } private XMLDocument findContent( User user, CategoryKey categoryKey, int[] contentTypeKeys, String criteria, boolean subCategories, String orderBy, boolean publishedOnly, int index, int count, boolean includeUserRights, boolean adminReadOnly ) { int[] categoryKeys = null; if ( categoryKey != null ) { categoryKeys = new int[]{categoryKey.toInt()}; } return doFindContent( user, categoryKeys, contentTypeKeys, criteria, orderBy, publishedOnly, subCategories, index, count, false, 0, 0, 0, false, includeUserRights, adminReadOnly, true ); } private String findContent( User user, int[] categoryKeys, int[] contentTypeKeys, String criteria, boolean publishedOnly, boolean subCategories, int index, int count, int childrenLevel, int parentLevel, int parentChildrenLevel, boolean includeContentOwners, boolean includeRelatedContentOwners, boolean includeUserRights, boolean adminReadOnly ) { Document result = doFindContent( user, categoryKeys, contentTypeKeys, criteria, null, publishedOnly, subCategories, index, count, false, childrenLevel, parentLevel, parentChildrenLevel, false, includeUserRights, adminReadOnly, ( includeContentOwners || includeRelatedContentOwners ) ).getAsDOMDocument(); return XMLTool.documentToString( result ); } /** * Find content, based on given criteria. * * @param user The logged in user. * @param categoryKeysInt One or more categories to search in. * @param contentTypeKeys One or more content types to search in. * @param criteria The search string from the user. * @param orderBy The requested ordering. * @param publishedOnly Whether or not to limit the search to currently published documents. * @param includeSubCategories Whether or not to include subcategories for the defined <code>categoryKeys</code>. * @param index The start index in the search list. * @param count The number of items in the search list. * @param titlesOnly Whether or not to limit the resulting XML to titles only. * @param childrenLevel The level of children to include. * @param parentLevel The level of parents to include. * @param parentChildrenLevel The level of children for parents to include. * @param relatedTitlesOnly Whether or not to limit related contents to titles only. * @param includeUserRight Whether or not to include user rights in the resulting XML. * @param adminReadOnly Return only the doucuments that have the admin read only property set. * @param includeOwnerAndModifierInfo Decides whether or not to include owner and modifier info in the resulting XML. * @return An XML Document with the result of the search. */ private XMLDocument doFindContent( User user, int[] categoryKeysInt, int[] contentTypeKeys, String criteria, String orderBy, boolean publishedOnly, boolean includeSubCategories, int index, int count, boolean titlesOnly, int childrenLevel, int parentLevel, int parentChildrenLevel, boolean relatedTitlesOnly, boolean includeUserRight, boolean adminReadOnly, boolean includeOwnerAndModifierInfo ) { UserEntity userEntity = securityService.getUser( user.getKey() ); Collection<CategoryKey> categories = CategoryKey.convertToList( categoryKeysInt ); Collection<ContentTypeKey> contentTypeFilter = ContentTypeKey.convertToList( contentTypeKeys ); final Date now = new Date(); OpenContentQuery openContentQuery = new OpenContentQuery(); openContentQuery.setUser( userEntity ); openContentQuery.setCategoryKeyFilter( categories, includeSubCategories ? Integer.MAX_VALUE : 1 ); openContentQuery.setQuery( criteria ); openContentQuery.setOrderBy( orderBy ); openContentQuery.setContentTypeFilter( contentTypeFilter ); openContentQuery.setIndex( index ); openContentQuery.setCount( count ); if ( publishedOnly ) { openContentQuery.setFilterContentOnlineAt( now ); } else { openContentQuery.setFilterIncludeOfflineContent(); } openContentQuery.setFilterAdminBrowseOnly( adminReadOnly ); ContentResultSet contents = contentService.queryContent( openContentQuery ); RelatedContentQuery relatedContentQuery = new RelatedContentQuery( now ); relatedContentQuery.setUser( userEntity ); relatedContentQuery.setContentResultSet( contents ); relatedContentQuery.setParentLevel( parentLevel ); relatedContentQuery.setChildrenLevel( childrenLevel ); relatedContentQuery.setParentChildrenLevel( parentChildrenLevel ); relatedContentQuery.setIncludeOnlyMainVersions( true ); RelatedContentResultSet relatedContents = contentService.queryRelatedContent( relatedContentQuery ); ContentXMLCreator xmlCreator = new ContentXMLCreator(); xmlCreator.setResultIndexing( index, count ); xmlCreator.setIncludeCategoryData( !titlesOnly ); xmlCreator.setIncludeContentData( !titlesOnly ); xmlCreator.setIncludeOwnerAndModifierData( !titlesOnly ); xmlCreator.setIncludeOwnerAndModifierData( includeOwnerAndModifierInfo ); xmlCreator.setIncludeRelatedContentData( !relatedTitlesOnly ); xmlCreator.setIncludeUserRightsInfo( includeUserRight, new CategoryAccessResolver( groupDao ), new ContentAccessResolver( groupDao ) ); xmlCreator.setIncludeRepositoryPathInfo( true ); xmlCreator.setIncludeVersionsInfoForAdmin( true ); return xmlCreator.createContentsDocument( userEntity, contents, relatedContents ); } }