content: /*
   *  Copyright (C) 2015 Stichting Akvo (Akvo Foundation)
   *
   *  This file is part of Akvo FLOW.
   *
   *  Akvo FLOW is free software: you can redistribute it and modify it under the terms of
   *  the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
   *  either version 3 of the License or any later version.
   *
   *  Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
   *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   *  See the GNU Affero General Public License included below for more details.
   *
   *  The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>.
   */
  
  package org.akvo.gae.remoteapi;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import com.google.appengine.api.datastore.DatastoreService;
  import com.google.appengine.api.datastore.Entity;
  import com.google.appengine.api.datastore.Query;
  import com.google.appengine.api.datastore.Query.Filter;
  import com.google.appengine.api.datastore.Query.FilterOperator;
  import com.google.appengine.api.datastore.Query.FilterPredicate;
  
  /**
   * Data script to assign a new permission to a role
   */
  public class AddPermission implements Process {
  
      private final static String USER_ROLE = "user";
      private final static String ADMIN_ROLE = "admin";
      private final static Set<String> PERMISSIONS = new HashSet<String>(Arrays.asList(
              "PROJECT_FOLDER_CREATE",
              "PROJECT_FOLDER_READ",
              "PROJECT_FOLDER_UPDATE",
              "PROJECT_FOLDER_DELETE",
              "FORM_CREATE",
              "FORM_READ",
              "FORM_UPDATE",
              "FORM_DELETE",
              "DATA_CLEANING",
              "DATA_DELETE"));
  
      @SuppressWarnings("unchecked")
      @Override
      public void execute(DatastoreService ds, String[] args) throws Exception {
          if (args.length < 1) {
              System.err
                      .println("Usage: "
                              + RemoteAPI.class.getName()
                              + "AddPermission <appid> <username> <password> [--role=<comma separated list of roles>] --permission=<comma separated list of permissions>");
              System.exit(1);
          }
  
          List<String> rolesList = null;
          List<String> permissionsList = null;
  
          boolean useDefaultRoles = args.length < 2;
          if (useDefaultRoles) {
              rolesList = new ArrayList<String>(Arrays.asList(USER_ROLE, ADMIN_ROLE));
              permissionsList = splitArgumentList(args[0]);
          } else {
              rolesList = splitArgumentList(args[0]);
              permissionsList = splitArgumentList(args[1]);
  
              if (rolesList.isEmpty()) {
                  System.err.println("No roles specified");
                  System.exit(1);
              }
          }
  
          if (!isValidPermissionsList(permissionsList)) {
              System.exit(1);
          }
  
          // update roles
          Filter roleNameFilter = new FilterPredicate("name",
                  FilterOperator.IN, rolesList);
          Query roleQuery = new Query("UserRole").setFilter(roleNameFilter);
  
          List<Entity> roles = new ArrayList<Entity>();
          for (Entity role : ds.prepare(roleQuery).asIterable()) {
              roles.add(role);
              List<String> permissions = (List<String>) role.getProperty("permissions");
              if (permissions == null) {
                  role.setProperty("permissions", new HashSet<String>(permissionsList));
              } else {
                  Set<String> permissionSet = new HashSet<String>(permissions);
                  permissionSet.addAll(permissionsList);
                  role.setProperty("permissions", permissionSet);
              }
          }
          ds.put(roles);
      }
  
      private List<String> splitArgumentList(String argument) {
          if (argument == null || argument.indexOf("=") == -1) {
              return new ArrayList<String>();
          }
  
          String[] parts = argument.split("=");
          String[] entities = parts.length == 2 ? parts[1].split(",") : null;
  
          if (entities == null) {
              return new ArrayList<String>();
          }
  
          List<String> argumentList = new ArrayList<String>();
          for (String entity : entities) {
              if (entity != null) {
                  argumentList.add(entity);
              }
          }
          return argumentList;
      }
  
      private boolean isValidPermissionsList(List<String> permissionsList) {
          boolean valid = true;
          for (String permission : permissionsList) {
              if (!PERMISSIONS.contains(permission)) {
                  System.err.println("Invalid permission: " + permission);
                  valid = false;
              }
          }
          return valid;
      }
  }
  