001/* 002 * Copyright 2013 Anyware Services 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 */ 016package org.ametys.plugins.queriesdirectory; 017 018import java.util.Optional; 019import java.util.Set; 020 021import org.ametys.core.group.GroupIdentity; 022import org.ametys.core.user.UserIdentity; 023import org.ametys.plugins.repository.AmetysObjectResolver; 024import org.ametys.plugins.repository.AmetysRepositoryException; 025import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 026import org.ametys.plugins.repository.RepositoryConstants; 027 028/** 029 * Helper for manipulating {@link Query} 030 * 031 */ 032public final class QueryHelper 033{ 034 private static final String __PLUGIN_NODE_NAME = "queriesdirectory"; 035 private static final String __ROOT_QUERY_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":queries"; 036 037 private QueryHelper() 038 { 039 // Private 040 } 041 042 /** 043 * Get the root plugin storage object. 044 * @param resolver The Ametys object resolver 045 * @return the root plugin storage object. 046 * @throws AmetysRepositoryException if a repository error occurs. 047 */ 048 public static ModifiableTraversableAmetysObject getQueriesRootNode(AmetysObjectResolver resolver) throws AmetysRepositoryException 049 { 050 try 051 { 052 ModifiableTraversableAmetysObject pluginsNode = resolver.resolveByPath("/ametys:plugins"); 053 054 ModifiableTraversableAmetysObject pluginNode = getOrCreateNode(pluginsNode, __PLUGIN_NODE_NAME, "ametys:unstructured"); 055 056 return getOrCreateNode(pluginNode, "ametys:queries", __ROOT_QUERY_NODETYPE); 057 } 058 catch (AmetysRepositoryException e) 059 { 060 throw new AmetysRepositoryException("Unable to get the queries root node", e); 061 } 062 } 063 064 private static ModifiableTraversableAmetysObject getOrCreateNode(ModifiableTraversableAmetysObject parentNode, String nodeName, String nodeType) throws AmetysRepositoryException 065 { 066 ModifiableTraversableAmetysObject definitionsNode; 067 if (parentNode.hasChild(nodeName)) 068 { 069 definitionsNode = parentNode.getChild(nodeName); 070 } 071 else 072 { 073 definitionsNode = parentNode.createChild(nodeName, nodeType); 074 parentNode.saveChanges(); 075 } 076 return definitionsNode; 077 } 078 079 /** 080 * Creates the XPath query to get all queries for administrator 081 * @param type The query type 082 * @return The XPath query 083 */ 084 public static String getXPathQueryForAdministrator(Optional<String> type) 085 { 086 return _getXPathQuery(null, false/*admin*/, null, type, null); 087 } 088 089 /** 090 * Creates the XPath query to get all queries in READ access 091 * @param user The user 092 * @param groups The user's groups 093 * @param type The query type 094 * @return The XPath query 095 */ 096 public static String getXPathQueryForReadAccess(UserIdentity user, Set<GroupIdentity> groups, Optional<String> type) 097 { 098 return _getXPathQuery(user, true, groups, type, true); 099 } 100 101 /** 102 * Creates the XPath query to get all queries in WRITE access 103 * @param user The user 104 * @param groups The user's groups 105 * @param type The query type 106 * @return The XPath query 107 */ 108 public static String getXPathQueryForWriteAccess(UserIdentity user, Set<GroupIdentity> groups, Optional<String> type) 109 { 110 return _getXPathQuery(user, true, groups, type, false); 111 } 112 113 private static String _getXPathQuery(UserIdentity user, boolean checkVisibility, Set<GroupIdentity> groups, Optional<String> type, Boolean readAccess) 114 { 115 StringBuilder query = new StringBuilder("//element(*, ") 116 .append(QueryFactory.QUERY_NODETYPE) 117 .append(")"); 118 if (checkVisibility || type.isPresent()) 119 { 120 query.append('['); 121 } 122 123 type.ifPresent(t -> query.append("@").append(Query.TYPE).append("='").append(t).append("'")); 124 125 if (checkVisibility) 126 { 127 type.ifPresent(t -> query.append(" and (")); 128 129 _appendPublicPredicate(query); 130 131 String login = user.getLogin(); 132 String populationId = user.getPopulationId(); 133 _appendPrivatePredicate(query, login, populationId); 134 135 _appendSharedPredicate(query, login, populationId, groups, readAccess); 136 137 type.ifPresent(t -> query.append(')')); 138 } 139 140 141 if (checkVisibility || type.isPresent()) 142 { 143 query.append(']'); 144 } 145 146 return query.toString(); 147 } 148 149 private static void _appendPublicPredicate(StringBuilder query) 150 { 151 query.append("(@").append(Query.VISIBILITY).append("='").append(Query.Visibility.PUBLIC.name()) 152 .append("') or "); 153 } 154 155 private static void _appendPrivatePredicate(StringBuilder query, String login, String populationId) 156 { 157 query.append("(@").append(Query.VISIBILITY).append("='").append(Query.Visibility.PRIVATE.name()) 158 .append("' and "); 159 _appendUserCondition(query, login, populationId); 160 query.append(") or "); 161 } 162 163 private static void _appendSharedPredicate(StringBuilder query, String login, String populationId, Set<GroupIdentity> groups, boolean readAccess) 164 { 165 query.append("(@").append(Query.VISIBILITY).append("='").append(Query.Visibility.SHARED.name()) 166 .append("' and ("); 167 query.append("("); 168 _appendUserCondition(query, login, populationId); 169 query.append(") or "); 170 171 if (readAccess) 172 { 173 _appendUserAccessCondition(query, login, populationId, Query.PROFILE_READ_ACCESS); 174 query.append(" or "); 175 } 176 _appendUserAccessCondition(query, login, populationId, Query.PROFILE_WRITE_ACCESS); 177 178 _appendGroupsCondition(query, groups, readAccess); 179 query.append("))"); 180 } 181 182 private static void _appendUserCondition(StringBuilder query, String login, String populationId) 183 { 184 query.append('@').append(Query.AUTHOR).append("/ametys:login='").append(login) 185 .append("' and @").append(Query.AUTHOR).append("/ametys:population='").append(populationId) 186 .append('\''); 187 } 188 189 private static void _appendGroupsCondition(StringBuilder query, Set<GroupIdentity> groups, boolean readAccess) 190 { 191 for (GroupIdentity group : groups) 192 { 193 String groupId = group.getId(); 194 String groupDirectory = group.getDirectoryId(); 195 196 if (readAccess) 197 { 198 query.append(" or "); 199 _appendGroupAccessCondition(query, groupId, groupDirectory, Query.PROFILE_READ_ACCESS); 200 } 201 query.append(" or "); 202 _appendGroupAccessCondition(query, groupId, groupDirectory, Query.PROFILE_WRITE_ACCESS); 203 } 204 } 205 206 private static void _appendUserAccessCondition(StringBuilder query, String login, String populationId, String accessNodeName) 207 { 208 query.append("(").append(accessNodeName).append("/").append(Query.USERS).append("/ametys:login='").append(login) 209 .append("' and ").append(accessNodeName).append("/").append(Query.USERS).append("/ametys:population='").append(populationId) 210 .append("')"); 211 } 212 213 private static void _appendGroupAccessCondition(StringBuilder query, String groupId, String groupDirectory, String accessNodeName) 214 { 215 query.append("(").append(accessNodeName).append("/").append(Query.GROUPS).append("/ametys:groupId='").append(groupId) 216 .append("' and ").append(accessNodeName).append("/").append(Query.GROUPS).append("/ametys:groupDirectory='").append(groupDirectory) 217 .append("')"); 218 } 219}