Automatic Delete OXObjects Per User
From Open-Xchange
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×tamp=" + 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; } }