content: /*
   *  Copyright (C) 2014 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.io.IOException;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import com.google.appengine.api.datastore.DatastoreService;
  import com.google.appengine.api.datastore.DatastoreServiceFactory;
  import com.google.appengine.api.datastore.Key;
  import com.google.appengine.api.datastore.PreparedQuery;
  import com.google.appengine.api.datastore.Query;
  import com.google.appengine.api.datastore.Entity;
  import com.google.appengine.api.datastore.Query.FilterOperator;
  import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
  import com.google.appengine.tools.remoteapi.RemoteApiOptions;
  
  /**
   * Run this application to create two default user roles (admin and user), and to grant existing
   * users the authorization to view, modify and delete all surveys groups and surveys that exist on
   * an instance
   *
   * @author emmanuel
   */
  public class DefaultUserRoles {
  
      private static String ADMIN_ROLE_NAME = "admin";
  
      private static String USER_ROLE_NAME = "user";
  
      private static List<String> allPermissionsList = Arrays.asList("PROJECT_FOLDER_CREATE",
              "PROJECT_FOLDER_READ", "PROJECT_FOLDER_UPDATE", "PROJECT_FOLDER_DELETE", "FORM_CREATE",
              "FORM_READ", "FORM_UPDATE", "FORM_DELETE");
  
      private static Entity createAuthorizationEntity(Key userKey, Key roleKey) {
          Entity authorizationEntity = new Entity("UserAuthorization");
          authorizationEntity.setProperty("userId", userKey.getId());
          authorizationEntity.setProperty("roleId", roleKey.getId());
          authorizationEntity.setProperty("objectPath", "/");
          return authorizationEntity;
      }
  
      public static String anonymizeEmail(String email) {
          return email.replaceAll(".{4}@.{2}", "**@**");
      }
  
      public static void main(String[] args) {
          if (args.length < 3 || args.length > 4) {
              System.out
                      .println(
                      "Usage: java org.akvo.gae.remoteapi.DefaultUserRoles <appid> <user> '<passwd>' [port]");
              System.exit(1);
          }
  
          final String instanceUrl = "localhost".equals(args[0]) ? "localhost" : args[0]
                  + ".appspot.com";
          final String userEmail = args[1];
          final String passwd = args[2];
          final int port = args.length == 4 ? Integer.parseInt(args[3]) : 443;
  
          final RemoteApiOptions options = new RemoteApiOptions().server(instanceUrl, port)
                  .credentials(
                          userEmail, passwd);
  
          final RemoteApiInstaller installer = new RemoteApiInstaller();
  
          try {
              installer.install(options);
  
              DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
  
              // create / retrieve defaultroles + retrieve key ids
  
              Query rolesQuery = new Query("UserRole").setFilter(new Query.FilterPredicate("name",
                      FilterOperator.IN, Arrays.asList(ADMIN_ROLE_NAME, USER_ROLE_NAME)));
              PreparedQuery rolesPq = ds.prepare(rolesQuery);
              Entity defaultAdminRole = null;
              Entity defaultUserRole = null;
  
              for (Entity role : rolesPq.asIterable()) {
                  String roleName = (String) role.getProperty("name");
                  if (ADMIN_ROLE_NAME.equals(roleName)) {
                      defaultAdminRole = role;
                  } else {
                      defaultUserRole = role;
                  }
              }
  
              Key adminRoleKey = null;
              if (defaultAdminRole == null) {
                  defaultAdminRole = new Entity("UserRole");
                  defaultAdminRole.setProperty("name", "admin");
                  defaultAdminRole.setProperty("permissions", allPermissionsList);
                  adminRoleKey = ds.put(defaultAdminRole);
                  System.out.println(ADMIN_ROLE_NAME + " role created");
              } else {
                  adminRoleKey = defaultAdminRole.getKey();
                  System.out.println(ADMIN_ROLE_NAME + " role already exists");
              }
  
              Key userRoleKey = null;
              if (defaultUserRole == null) {
                  defaultUserRole = new Entity("UserRole");
                  defaultUserRole.setProperty("name", "user");
                  defaultUserRole.setProperty("permissions", allPermissionsList);
                  userRoleKey = ds.put(defaultUserRole);
                  System.out.println(USER_ROLE_NAME + " role created");
              } else {
                  userRoleKey = defaultUserRole.getKey();
                  System.out.println(USER_ROLE_NAME + " role already exists");
              }
  
              // for each user create authorization
  
              // retrieve existing authorization
              Query userAuthQuery = new Query("UserAuthorization");
              userAuthQuery.setFilter(new Query.FilterPredicate(
                      "objectPath", FilterOperator.EQUAL, "/"));
  
              PreparedQuery userAuthPq = ds.prepare(userAuthQuery);
              Map<Long, Long> userAuthMap = new HashMap<Long, Long>();
              for (Entity authorization : userAuthPq.asIterable()) {
                  Long userId = (Long) authorization.getProperty("userId");
                  Long roleId = (Long) authorization.getProperty("roleId");
                  userAuthMap.put(userId, roleId);
              }
  
              List<Entity> userAuthorizationList = new ArrayList<Entity>();
              Query userQuery = new Query("User");
              // ignore superadmin users
              userQuery.setFilter(new Query.FilterPredicate(
                      "permissionList", FilterOperator.IN, Arrays.asList("10", "20")));
              PreparedQuery userPq = ds.prepare(userQuery);
  
              for (Entity user : userPq.asIterable()) {
                  String permissionList = (String) user.getProperty("permissionList");
                  String email = (String) user.getProperty("emailAddress");
                  Long userId = user.getKey().getId();
  
                  if (permissionList.trim().equals("10")) {
                      if (userAuthMap.containsKey(userId)
                              && userAuthMap.get(userId).equals(adminRoleKey.getId())) {
                          System.out.println("Admin authorization for user " + anonymizeEmail(email)
                                  + " already exists");
                          continue;
                      }
                      userAuthorizationList
                              .add(createAuthorizationEntity(user.getKey(), adminRoleKey));
                      System.out.println("Creating Admin user authorization for: "
                              + anonymizeEmail(email));
                  } else {
                      if (userAuthMap.containsKey(userId)
                              && userAuthMap.get(userId).equals(userRoleKey.getId())) {
                          System.out.println("User authorization for user " + anonymizeEmail(email)
                                  + " already exists");
                          continue;
                      }
                      userAuthorizationList
                              .add(createAuthorizationEntity(user.getKey(), userRoleKey));
                      System.out.println("Creating user authorization for: " + anonymizeEmail(email));
                  }
              }
  
              ds.put(userAuthorizationList);
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
              installer.uninstall();
          }
      }
  }
  