001/* 002 * Copyright 2016 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.ArrayList; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.LinkedList; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.lang3.StringUtils; 032 033import org.ametys.cms.FilterNameHelper; 034import org.ametys.core.group.GroupIdentity; 035import org.ametys.core.right.RightManager; 036import org.ametys.core.right.RightManager.RightResult; 037import org.ametys.core.ui.Callable; 038import org.ametys.core.user.CurrentUserProvider; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.plugins.core.user.UserHelper; 041import org.ametys.plugins.queriesdirectory.Query.QueryProfile; 042import org.ametys.plugins.queriesdirectory.Query.Visibility; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 045import org.ametys.plugins.repository.UnknownAmetysObjectException; 046import org.ametys.runtime.parameter.ParameterHelper; 047import org.ametys.runtime.plugin.component.AbstractLogEnabled; 048 049/** 050 * DAO for manipulating queries 051 */ 052public class QueryDAO extends AbstractLogEnabled implements Serviceable, Component 053{ 054 /** The Avalon role */ 055 public static final String ROLE = QueryDAO.class.getName(); 056 057 /** The current user provider */ 058 protected CurrentUserProvider _userProvider; 059 060 /** The Ametys object resolver */ 061 private AmetysObjectResolver _resolver; 062 063 private UserHelper _userHelper; 064 065 private RightManager _rightManager; 066 067 @Override 068 public void service(ServiceManager serviceManager) throws ServiceException 069 { 070 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 071 _userProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 072 _userHelper = (UserHelper) serviceManager.lookup(UserHelper.ROLE); 073 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 074 } 075 076 /** 077 * Get queries' properties 078 * @param queryIds The ids of queries to retrieve 079 * @return The queries' properties 080 */ 081 @Callable 082 public Map<String, Object> getQueriesProperties(List<String> queryIds) 083 { 084 Map<String, Object> result = new HashMap<>(); 085 086 List<Map<String, Object>> queries = new LinkedList<>(); 087 List<Map<String, Object>> notAllowedQueries = new LinkedList<>(); 088 Set<String> unknownQueries = new HashSet<>(); 089 090 091 for (String id : queryIds) 092 { 093 try 094 { 095 Query query = _resolver.resolveById(id); 096 097 if (_hasRight(query)) 098 { 099 queries.add(getQueryProperties(query)); 100 } 101 else 102 { 103 notAllowedQueries.add(getQueryProperties(query)); 104 } 105 } 106 catch (UnknownAmetysObjectException e) 107 { 108 unknownQueries.add(id); 109 } 110 } 111 112 result.put("queries", queries); 113 result.put("unknownQueries", unknownQueries); 114 result.put("unknownQueries", unknownQueries); 115 116 return result; 117 } 118 119 /** 120 * Get the query properties 121 * @param query The query 122 * @return The query properties 123 */ 124 public Map<String, Object> getQueryProperties (Query query) 125 { 126 Map<String, Object> infos = new HashMap<>(); 127 128 infos.put("id", query.getId()); 129 infos.put("title", query.getTitle()); 130 infos.put("type", query.getType()); 131 infos.put("description", query.getDescription()); 132 infos.put("author", _userHelper.user2json(query.getAuthor())); 133 infos.put("visibility", query.getVisibility().toString()); 134 infos.put("content", query.getContent()); 135 infos.put("lastModificationDate", ParameterHelper.valueToString(query.getLastModificationDate())); 136 137 boolean isAdministrator = isAdministrator(); 138 infos.put("isAdministrator", isAdministrator); 139 140 UserIdentity currentUser = _userProvider.getUser(); 141 infos.put("canRead", isAdministrator || query.canRead(currentUser)); 142 infos.put("canWrite", isAdministrator || query.canWrite(currentUser)); 143 144 return infos; 145 } 146 147 /** 148 * Creates a new {@link Query} 149 * @param title The title of the query 150 * @param desc The description of the query 151 * @param type The type of the query 152 * @param content The content of the query 153 * @return The id of created query 154 */ 155 @Callable 156 public String createQuery(String title, String desc, String type, String content) 157 { 158 ModifiableTraversableAmetysObject queriesNode = QueryHelper.getQueriesRootNode(_resolver); 159 160 String name = FilterNameHelper.filterName(title); 161 162 // Find unique name 163 String uniqueName = name; 164 int index = 2; 165 while (queriesNode.hasChild(uniqueName)) 166 { 167 uniqueName = name + "-" + (index++); 168 } 169 170 Query query = queriesNode.createChild(uniqueName, QueryFactory.QUERY_NODETYPE); 171 query.setTitle(title); 172 query.setDescription(desc); 173 query.setAuthor(_userProvider.getUser()); 174 query.setType(type); 175 query.setContent(content); 176 query.setVisibility(Visibility.PRIVATE); 177 query.setLastModificationDate(new Date()); 178 179 queriesNode.saveChanges(); 180 181 return query.getId(); 182 } 183 184 /** 185 * Edits a {@link Query} 186 * @param id The id of the query 187 * @param title The title of the query 188 * @param desc The description of the query 189 * @return A result map 190 */ 191 @Callable 192 public Map<String, Object> updateQuery(String id, String title, String desc) 193 { 194 Map<String, Object> results = new HashMap<>(); 195 196 Query query = _resolver.resolveById(id); 197 198 if (query.canWrite(_userProvider.getUser())) 199 { 200 query.setTitle(title); 201 query.setDescription(desc); 202 query.saveChanges(); 203 } 204 else 205 { 206 results.put("message", "not-allowed"); 207 } 208 209 results.put("id", query.getId()); 210 211 return results; 212 } 213 214 /** 215 * Saves a {@link Query} 216 * @param id The id of the query 217 * @param type The type of the query 218 * @param content The content of the query 219 * @return A result map 220 */ 221 @Callable 222 public Map<String, Object> saveQuery(String id, String type, String content) 223 { 224 Map<String, Object> results = new HashMap<>(); 225 226 Query query = _resolver.resolveById(id); 227 228 if (query.canWrite(_userProvider.getUser())) 229 { 230 query.setType(type); 231 query.setContent(content); 232 query.saveChanges(); 233 } 234 else 235 { 236 results.put("message", "not-allowed"); 237 } 238 239 results.put("id", query.getId()); 240 241 return results; 242 } 243 244 /** 245 * Deletes {@link Query}(ies) 246 * @param ids The ids of the queries to delete 247 * @return A result map 248 */ 249 @Callable 250 public Map<String, Object> deleteQuery(List<String> ids) 251 { 252 Map<String, Object> results = new HashMap<>(); 253 254 List<String> deletedQueries = new ArrayList<>(); 255 List<String> unknownQueries = new ArrayList<>(); 256 List<String> notallowedQueries = new ArrayList<>(); 257 258 for (String id : ids) 259 { 260 try 261 { 262 Query query = _resolver.resolveById(id); 263 264 UserIdentity author = query.getAuthor(); 265 if (author != null && author.equals(_userProvider.getUser())) 266 { 267 query.remove(); 268 query.saveChanges(); 269 deletedQueries.add(id); 270 } 271 else 272 { 273 notallowedQueries.add(query.getTitle()); 274 } 275 } 276 catch (UnknownAmetysObjectException e) 277 { 278 unknownQueries.add(id); 279 getLogger().error("Unable to delete query. The query of id '" + id + " doesn't exist", e); 280 } 281 } 282 283 results.put("deletedQueries", deletedQueries); 284 results.put("notallowedQueries", notallowedQueries); 285 results.put("unknownQueries", unknownQueries); 286 287 return results; 288 } 289 290 /** 291 * Changes the visibility of a {@link Query} 292 * @param queryId The id of the query 293 * @param visibilityStr The new visibility 294 * @return A result map 295 */ 296 @Callable 297 public Map<String, Object> changeVisibility(String queryId, String visibilityStr) 298 { 299 Map<String, Object> results = new HashMap<>(); 300 301 // Parameter checks. 302 Query query = null; 303 if (StringUtils.isNotEmpty(queryId)) 304 { 305 query = _resolver.resolveById(queryId); 306 } 307 else 308 { 309 throw new IllegalArgumentException("Mandatory query id parameter is missing."); 310 } 311 312 Visibility visibility = Visibility.valueOf(visibilityStr.toUpperCase()); 313 314 UserIdentity author = query.getAuthor(); 315 if (author != null && author.equals(_userProvider.getUser())) 316 { 317 query.setVisibility(visibility); 318 query.saveChanges(); 319 } 320 else 321 { 322 results.put("message", "not-allowed"); 323 } 324 325 return results; 326 } 327 328 /** 329 * Assign rights to the given users on the given query 330 * @param queryId The query id 331 * @param profileId The profile id 332 * @param users The users to grant 333 * @return A result map 334 */ 335 @Callable 336 public Map<String, Object> addGrantedUsers(String queryId, String profileId, List<Map<String, String>> users) 337 { 338 return _assignRights(queryId, profileId, "users", users, null); 339 } 340 341 /** 342 * Assign rigths to the given groups on the given query 343 * @param queryId The query id 344 * @param profileId The profile id 345 * @param groups The groups to grant 346 * @return A result map 347 */ 348 @Callable 349 public Map<String, Object> addGrantedGroups(String queryId, String profileId, List<Map<String, String>> groups) 350 { 351 return _assignRights(queryId, profileId, "groups", null, groups); 352 } 353 354 private Map<String, Object> _assignRights(String queryId, String profileId, String type, List<Map<String, String>> users, List<Map<String, String>> groups) 355 { 356 HashMap<String, Object> results = new HashMap<>(); 357 358 // Parameter checks. 359 Query query = null; 360 if (StringUtils.isNotEmpty(queryId)) 361 { 362 query = _resolver.resolveById(queryId); 363 } 364 else 365 { 366 throw new IllegalArgumentException("Mandatory query id parameter is missing."); 367 } 368 369 if (!"users".equals(type) && !"groups".equals(type)) 370 { 371 throw new IllegalArgumentException("Unexpected type parameter : " + type); 372 } 373 374 if (!"read_access".equals(profileId) && !"write_access".equals(profileId)) 375 { 376 throw new IllegalArgumentException("Unexpected profile identifier : " + profileId); 377 } 378 379 UserIdentity author = query.getAuthor(); 380 if (author != null && author.equals(_userProvider.getUser())) 381 { 382 QueryProfile profile = QueryProfile.valueOf(profileId.toUpperCase()); 383 384 // Set new values 385 if ("users".equals(type)) 386 { 387 Set<UserIdentity> allEntries = query.getGrantedUsers(profile); 388 389 for (Map<String, String> user : users) 390 { 391 UserIdentity userIdentity = new UserIdentity(user.get("login"), user.get("populationId")); 392 if (!allEntries.contains(userIdentity)) 393 { 394 allEntries.add(userIdentity); 395 } 396 } 397 398 query.setGrantedUsers(profile, allEntries); 399 } 400 else 401 { 402 Set<GroupIdentity> allEntries = query.getGrantedGroups(profile); 403 404 for (Map<String, String> group : groups) 405 { 406 GroupIdentity groupIdentity = new GroupIdentity(group.get("id"), group.get("groupDirectory")); 407 if (!allEntries.contains(groupIdentity)) 408 { 409 allEntries.add(groupIdentity); 410 } 411 } 412 413 query.setGrantedGroups(profile, allEntries); 414 } 415 416 // Save 417 query.saveChanges(); 418 } 419 else 420 { 421 results.put("message", "not-allowed"); 422 } 423 424 return results; 425 } 426 427 /** 428 * Remove rights to the given users on the given query 429 * @param queryId The query id 430 * @param profileId The profile id 431 * @param users The users to remove 432 * @param groups The groups to remove 433 * @return A result map 434 */ 435 @Callable 436 public Map<String, Object> removeAssignment(String queryId, String profileId, List<Map<String, String>> users, List<Map<String, String>> groups) 437 { 438 HashMap<String, Object> results = new HashMap<>(); 439 440 // Parameter checks. 441 Query query = null; 442 if (StringUtils.isNotEmpty(queryId)) 443 { 444 query = _resolver.resolveById(queryId); 445 } 446 else 447 { 448 throw new IllegalArgumentException("Mandatory query id parameter is missing."); 449 } 450 if (!"read_access".equals(profileId) && !"write_access".equals(profileId)) 451 { 452 throw new IllegalArgumentException("Unexpected profile identifier : " + profileId); 453 } 454 455 UserIdentity author = query.getAuthor(); 456 if (author != null && author.equals(_userProvider.getUser())) 457 { 458 QueryProfile profile = QueryProfile.valueOf(profileId.toUpperCase()); 459 460 if (!users.isEmpty()) 461 { 462 Set<UserIdentity> grantedUsers = query.getGrantedUsers(profile); 463 for (Map<String, String> user : users) 464 { 465 UserIdentity userIdentity = new UserIdentity(user.get("login"), user.get("populationId")); 466 grantedUsers.remove(userIdentity); 467 } 468 469 query.setGrantedUsers(profile, grantedUsers); 470 } 471 472 if (!groups.isEmpty()) 473 { 474 Set<GroupIdentity> grantedGroups = query.getGrantedGroups(profile); 475 for (Map<String, String> group : groups) 476 { 477 GroupIdentity groupIdentity = new GroupIdentity(group.get("id"), group.get("groupDirectory")); 478 grantedGroups.remove(groupIdentity); 479 } 480 481 query.setGrantedGroups(profile, grantedGroups); 482 } 483 484 // Save 485 query.saveChanges(); 486 } 487 else 488 { 489 results.put("message", "not-allowed"); 490 } 491 492 return results; 493 } 494 495 /** 496 * Determines if the current user is administrator of queries 497 * @return <code>true</code> if current user is administrator 498 */ 499 public boolean isAdministrator() 500 { 501 return _rightManager.hasRight(_userProvider.getUser(), "QueriesDirectory_Rights_Admin", "/cms") == RightResult.RIGHT_ALLOW; 502 } 503 504 /** 505 * Test if the current user has the right required to access the query 506 * @param query The query 507 * @return true if the user has the right needed, false otherwise. 508 */ 509 protected boolean _hasRight(Query query) 510 { 511 UserIdentity user = _userProvider.getUser(); 512 return query.canRead(user) || isAdministrator(); 513 } 514}