Automatic Delete OXObjects Per User

From Open-Xchange
Revision as of 13:48, 29 June 2016 by Martin.schneider (talk | contribs) (Move to https://documentation.open-xchange.com/)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
How to automatically delete all objects of one user

I just wrote the following quick&dirty hack to delete all objects and folders created by an OXHE User. It can be useful to clean up a context or to just delete all data from one user. The following JAVA file contains the logic which is needed to login/search/delete via the Open-Xchange HTTP API.

package com.openexchange.tools.cleaner;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 *
 * @author cutmasta
 */
public class Start {

    Log LOG = LogFactory.getLog(Start.class);
    private SessionObject so = null;
    private String username = null;
    private String password = null;
    private String host = "localhost";
    private String protocol = "http";
    private static String CONTENT_TYPE_JSCRIPT = "text/javascript";
    private static String CHARSET_JSCRIPT = "UTF-8";
    private String TASK_SEARCH = "tasks";
    private String CONTACT_SEARCH = "contacts";
    private String CALENDAR_SEARCH = "calendar";
    private String INFOSTORE_SEARCH = "infostore";

    public static void main(String[] args) {
        new Start(args);
    }

    private Start(String[] args) {

        if (args.length != 4) {
            LOG.info("Arguments needed: <host> <protocol> <username> <password>");
            LOG.info("Example: test.org https test@sp4.com test");
            exitApp();
        }

        host = args[0].trim();
        protocol = args[1].trim();
        username = args[2].trim();
        password = args[3].trim();

        if (protocol.equals("https")) {
            Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
            Protocol.registerProtocol("https", easyhttps);
        }

        doLogin();

        try {

            // search all modules and fetch the id arrays
            doSearch();
        } catch (IOException ex) {
            LOG.error(ex);
        } catch (JSONException ex) {
            LOG.error("Error in process", ex);
        }


    }

    public String getSessionID() {
        return getSessionObject().getSessionid();
    }

    public SessionObject getSessionObject() {
        return so;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public String getHost() {
        return host;
    }

    private void doDeleteCreatedFolders(JSONArray rootfolders, String timestamp) throws JSONException, IOException {

        /* 
         * In this method here we delete all folders        
         * 
         */


        // loop through all root folders
        for (int i = 0; i < rootfolders.length(); i++) {
            
            // for each root/system folder , loop and delete its subfolders
            JSONObject subfolders_of_rootfolder_response = doGetSubFolders(rootfolders.getJSONArray(i).getInt(0));
            JSONArray subfolders_of_rootfolder = subfolders_of_rootfolder_response.getJSONArray("data");            
            for (int b = 0; b < subfolders_of_rootfolder.length(); b++) {
                JSONArray tmp_folder = subfolders_of_rootfolder.getJSONArray(b);
                if (!tmp_folder.getString(0).equalsIgnoreCase("default")) {
                    LOG.debug("Deleting recursive all private folders with array: " + tmp_folder);
                    deleteRecursiveFolder(tmp_folder);
                }
            }

        }



    }

    /**
     * This delete the subfolders of the given folder and the folder itself!
     * @param my_private_folder_array
     * @throws java.io.IOException
     * @throws org.json.JSONException
     */
    private void deleteRecursiveFolder(JSONArray my_private_folder_array) throws IOException, JSONException {

        JSONObject my_private_subfolders_response = doGetSubFolders(my_private_folder_array.getInt(0));

        // only delete if subfolders exists
        //if (my_private_subfolders_response.length() > 0) {
        if (my_private_subfolders_response.getJSONArray("data").length() > 0) {

            LOG.debug(my_private_subfolders_response);

            JSONArray my_private_subfolders = my_private_subfolders_response.getJSONArray("data");

            String my_private_subfolders_timestamp = my_private_subfolders_response.getString("timestamp");

            //LOG.info("Private folders list: " +my_private_subfolders);
            for (int i = 0; i < my_private_subfolders.length(); i++) {
                JSONArray folder_data = my_private_subfolders.getJSONArray(i);
                LOG.debug("Deleting folder with ID " + folder_data.getInt(0) + " and parent ID " + folder_data.getInt(1) + " - Tstamp " + my_private_subfolders_timestamp);
                doDeleteFolder(folder_data.getInt(0), folder_data.getInt(1), my_private_subfolders_timestamp);
            }
        }


        /* Now delete the folder itself , which could contain the subfolders before!
         * We must "get" the folder data because we need the correct timestamp for deleting!
         */
        JSONObject top_level_folder_data = doGetSingleFolder(my_private_folder_array.getInt(0));
        if(!my_private_folder_array.isNull(0) && !my_private_folder_array.isNull(1) && !top_level_folder_data.isNull("timestamp")){
            // execute delete
            doDeleteFolder(my_private_folder_array.getInt(0), my_private_folder_array.getInt(1), top_level_folder_data.getString("timestamp"));
        }   
        
        

    }

    private void doDeleteFolder(int folder_id, int parent_id, String tstamp) {

        try {

            PutMethod deleteMethod = new PutMethod(getProtocol() + "://" + getHost() + "/ajax/folders?action=delete&timestamp=" + tstamp + "&session=" + getSessionObject().getSessionid());

            RequestEntity data = new StringRequestEntity("[" + folder_id + "]", CONTENT_TYPE_JSCRIPT, CHARSET_JSCRIPT);
            deleteMethod.setRequestEntity(data);
            getSessionObject().getOxClient().executeMethod(deleteMethod);

            JSONObject responseObject = ResponseTools.reponse2JsonObject(deleteMethod);

            LOG.debug("Delete folder response is: " + responseObject);

        } catch (Exception ex) {
            LOG.error("Error deleting folder with ID " + folder_id + " and parent ID " + parent_id, ex);
        }
    }

    private JSONObject doGetSubFolders(int parent_folder) throws IOException, JSONException {

        // 1 = id
        // 20 = Object ID of the parent folder.
        // 300 = Name of this folder.
        // 301 = Name of the module which implements this folder.
        // 302 = type    // 1 	 private
        //2 	public
        //3 	shared
        // 5 	system folder
        // 304 =  true if this folder has subfolders.
        // 305 = own_rights

        try {


            GetMethod folder_search = new GetMethod(getProtocol() + "://" + getHost() + "/ajax/folders?action=list&columns=1,20,300,301,302,304,305&parent=" + parent_folder + "&session=" + getSessionObject().getSessionid());


            getSessionObject().getOxClient().executeMethod(folder_search);

            JSONObject responseObject = ResponseTools.reponse2JsonObject(folder_search);

            return responseObject;

        } catch (IOException ex) {
            LOG.error("Generic IO error while searching folders", ex);
            throw ex;
        } catch (JSONException ex) {
            LOG.error("JSON error while searching folders", ex);
            throw ex;
        }
    }

    private JSONObject doGetSingleFolder(int folder_id) throws IOException, JSONException {

        // 1 = id
        // 20 = Object ID of the parent folder.
        // 300 = Name of this folder.
        // 301 = Name of the module which implements this folder.
        // 302 = type    // 1 	 private
        //2 	public
        //3 	shared
        // 5 	system folder
        // 304 =  true if this folder has subfolders.
        // 305 = own_rights

        try {


            GetMethod folder_search = new GetMethod(getProtocol() + "://" + getHost() + "/ajax/folders?action=get&id=" + folder_id + "&columns=1,20,300,301,302,304,305&session=" + getSessionObject().getSessionid());


            getSessionObject().getOxClient().executeMethod(folder_search);

            JSONObject responseObject = ResponseTools.reponse2JsonObject(folder_search);

            return responseObject;

        } catch (IOException ex) {
            LOG.error("Generic IO error while searching folders", ex);
            throw ex;
        } catch (JSONException ex) {
            LOG.error("JSON error while searching folders", ex);
            throw ex;
        }
    }

    private void doLogin() {

        LOG.info("Using " + getProtocol() + "://" + getUsername() + "@" + getHost() + " for connections!");

        HttpClient client = new HttpClient();


        PostMethod login_post = new PostMethod(getProtocol() + "://" + getHost() + "/ajax/login?action=login");
        login_post.addParameter("name", getUsername());
        login_post.addParameter("password", getPassword());

        try {

            client.executeMethod(login_post);

            JSONObject loginObject = ResponseTools.reponse2JsonObject(login_post);

            if (loginObject.has("session")) {
                so = new SessionObject();
                getSessionObject().setCookies(client.getState().getCookies());
                getSessionObject().setSessionid((String) loginObject.get("session"));
                getSessionObject().setOxClient(client);
                LOG.info("Login successfull!");
            } else {
                String errmsg = (String) loginObject.get("error");
                LOG.info("Error login into system!\n" + errmsg);
                exitApp();
            }
        } catch (Exception exp) {
            LOG.error("LOGIN ERROR", exp);
        } finally {
            login_post.releaseConnection();
        }
    }

    private void doSearch() throws JSONException, IOException {

        LOG.info("Starting search for objects...");

        JSONObject task_objects = doSearchInModule(TASK_SEARCH);
        JSONObject contact_objects = doSearchInModule(CONTACT_SEARCH);
        JSONObject calendar_objects = doSearchInModule(CALENDAR_SEARCH);
        JSONObject store_objects = doSearchInModule(INFOSTORE_SEARCH);

        LOG.info("Search done!");

        //LOG.info("Found " + task_objects.getJSONArray("data").length() + " task items");
        //LOG.info("Found " + contact_objects.getJSONArray("data").length() + " contact items");
        //LOG.info("Found " + calendar_objects.getJSONArray("data").length() + " calendar items");
        //LOG.info("Found " + store_objects.getJSONArray("data").length() + " infostore items");

        LOG.info("Starting delete process...");

        doDeleteMultiple(task_objects, contact_objects, calendar_objects, store_objects);

        LOG.info("Deleting Objects done!");


        LOG.info("Starting delete process for folders...");

        // search all folders and delete them
        JSONObject rootfolders_response = doGetRootFolders();

        JSONArray rootfolders = rootfolders_response.getJSONArray("data");

        doDeleteCreatedFolders(rootfolders, rootfolders_response.getString("timestamp"));

        LOG.info("Deleting folders done!");

    }

    private JSONArray buildDeleteArray(JSONObject module_objects, String MODULE) throws JSONException {

        JSONArray dat_array = new JSONArray();

        LOG.debug("Building delete array from json object: " + module_objects);

        if (module_objects.has("data") && module_objects.has("timestamp")) {

            String tstamp = module_objects.getString("timestamp");
            JSONArray srv_data_ids = module_objects.getJSONArray("data");
            for (int i = 0; i < srv_data_ids.length(); i++) {
                JSONArray ids = (JSONArray) srv_data_ids.get(i);
                JSONObject js = new JSONObject();
                js.put("module", MODULE);
                js.put("timestamp", tstamp);
                js.put("action", "delete");



                JSONObject del_ids = new JSONObject();
                del_ids.put("id", ids.getInt(0));
                del_ids.put("folder", ids.getInt(1));

                // workaround because infostore expects an array with a 1 json object which contains the ids
                if (MODULE.equals(INFOSTORE_SEARCH)) {
                    // send array with object
                    JSONArray tmp = new JSONArray();
                    tmp.put(del_ids);
                    js.put("data", tmp);
                } else {
                    // send normal id 
                    js.put("data", del_ids);
                }
                dat_array.put(js);
            }
        }


        return dat_array;
    }

    private void doDeleteMultiple(JSONObject task_objects, JSONObject contact_objects, JSONObject calendar_objects, JSONObject store_objects) throws JSONException {

        LOG.info("Deleting tasks...");
        fireDeleteMultiple(buildDeleteArray(task_objects, TASK_SEARCH));
        LOG.info("Deleting contacts...");
        fireDeleteMultiple(buildDeleteArray(contact_objects, CONTACT_SEARCH));
        LOG.info("Deleting appointments...");
        fireDeleteMultiple(buildDeleteArray(calendar_objects, CALENDAR_SEARCH));
        LOG.info("Deleting infostore objects...");
        fireDeleteMultiple(buildDeleteArray(store_objects, INFOSTORE_SEARCH));
    }

    private JSONObject doGetRootFolders() throws IOException, JSONException {

        // 1 = id
        // 20 = Object ID of the parent folder.
        // 300 = Name of this folder.
        // 301 = Name of the module which implements this folder.
        // 302 = type    // 1 	 private
        //2 	public
        //3 	shared
        // 5 	system folder
        // 304 =  true if this folder has subfolders.
        // 305 = own_rights

        try {


            GetMethod folder_search = new GetMethod(getProtocol() + "://" + getHost() + "/ajax/folders?action=root&columns=1,20,300,301,302,304,305&session=" + getSessionObject().getSessionid());


            getSessionObject().getOxClient().executeMethod(folder_search);

            return ResponseTools.reponse2JsonObject(folder_search);

        } catch (IOException ex) {
            LOG.error("Generic IO error while searching folders", ex);
            throw ex;
        } catch (JSONException ex) {
            LOG.error("JSON error while searching folders", ex);
            throw ex;
        }






    }

    private void fireDeleteMultiple(JSONArray del_data_array) {

        try {

            //LOG.info("Sending delete array: " + del_data_array);

            PutMethod deleteMethod = new PutMethod(getProtocol() + "://" + getHost() + "/ajax/multiple?continue=true&session=" + getSessionObject().getSessionid());

            RequestEntity data = new StringRequestEntity(del_data_array.toString(), CONTENT_TYPE_JSCRIPT, CHARSET_JSCRIPT);
            deleteMethod.setRequestEntity(data);
            getSessionObject().getOxClient().executeMethod(deleteMethod);

            JSONArray responseObject = ResponseTools.reponse2JsonArray(deleteMethod);

        //LOG.info(responseObject);

        } catch (Exception ex) {
            LOG.error("Error deleting items", ex);
        }
    }

    private JSONObject doSearchInModule(String MODULE) {

        // FETCH ALL OBJECT IDS FROM ALL FOLDERS 
        // EXCLUDING PUBLIC ADRESSBOOK WHICH HAS ID 6        
        PutMethod searchMethod = new PutMethod(getProtocol() + "://" + getHost() + "/ajax/" + MODULE + "?action=search&columns=1,20&session=" + getSessionObject().getSessionid());

        try {

            RequestEntity data = new StringRequestEntity("{\"pattern\":\"*\"}", CONTENT_TYPE_JSCRIPT, CHARSET_JSCRIPT);
            searchMethod.setRequestEntity(data);
            getSessionObject().getOxClient().executeMethod(searchMethod);

            return ResponseTools.reponse2JsonObject(searchMethod);
        } catch (Exception ex) {
            LOG.error("Error searching " + MODULE, ex);
            return null;
        }
    }

    private void exitApp() {
        System.exit(1);
    }

    public String getProtocol() {
        return protocol;
    }
}