001package com.box.sdk; 002 003import static com.box.sdk.PagingParameters.DEFAULT_LIMIT; 004import static com.box.sdk.PagingParameters.marker; 005import static com.box.sdk.SortParameters.none; 006 007import com.eclipsesource.json.Json; 008import com.eclipsesource.json.JsonObject; 009import java.net.URL; 010import java.util.Iterator; 011 012/** 013 * Provides methods for deleting, recovering, and viewing a user's trashed files and folders. 014 * 015 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 016 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 017 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p> 018 */ 019public class BoxTrash implements Iterable<BoxItem.Info> { 020 021 /** 022 * Get Item URL Template. 023 */ 024 public static final URLTemplate GET_ITEMS_URL = new URLTemplate("folders/trash/items/"); 025 /** 026 * Folder Info URL Template. 027 */ 028 public static final URLTemplate FOLDER_INFO_URL_TEMPLATE = new URLTemplate("folders/%s/trash"); 029 /** 030 * File Info URL Template. 031 */ 032 public static final URLTemplate FILE_INFO_URL_TEMPLATE = new URLTemplate("files/%s/trash"); 033 /** 034 * Restore File URL Template. 035 */ 036 public static final URLTemplate RESTORE_FILE_URL_TEMPLATE = new URLTemplate("files/%s"); 037 /** 038 * Restore Folder URL Template. 039 */ 040 public static final URLTemplate RESTORE_FOLDER_URL_TEMPLATE = new URLTemplate("folders/%s"); 041 042 private final BoxAPIConnection api; 043 044 /** 045 * Constructs a BoxTrash using a given API connection. 046 * 047 * @param api the API connection to be used by the trash. 048 */ 049 public BoxTrash(BoxAPIConnection api) { 050 this.api = api; 051 } 052 053 /** 054 * Permanently deletes a trashed folder. 055 * 056 * @param folderID the ID of the trashed folder to permanently delete. 057 */ 058 public void deleteFolder(String folderID) { 059 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.api.getBaseURL(), folderID); 060 BoxAPIRequest request = new BoxAPIRequest(this.api, url, "DELETE"); 061 request.send().close(); 062 } 063 064 /** 065 * Gets information about a trashed folder. 066 * 067 * @param folderID the ID of the trashed folder. 068 * @return info about the trashed folder. 069 */ 070 public BoxFolder.Info getFolderInfo(String folderID) { 071 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.api.getBaseURL(), folderID); 072 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "GET"); 073 try (BoxJSONResponse response = request.send()) { 074 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 075 076 BoxFolder folder = new BoxFolder(this.api, jsonObject.get("id").asString()); 077 return folder.new Info(response.getJSON()); 078 } 079 } 080 081 /** 082 * Gets information about a trashed folder that's limited to a list of specified fields. 083 * 084 * @param folderID the ID of the trashed folder. 085 * @param fields the fields to retrieve. 086 * @return info about the trashed folder containing only the specified fields. 087 */ 088 public BoxFolder.Info getFolderInfo(String folderID, String... fields) { 089 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 090 URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.api.getBaseURL(), queryString, folderID); 091 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "GET"); 092 try (BoxJSONResponse response = request.send()) { 093 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 094 095 BoxFolder folder = new BoxFolder(this.api, jsonObject.get("id").asString()); 096 return folder.new Info(response.getJSON()); 097 } 098 } 099 100 /** 101 * Restores a trashed folder back to its original location. 102 * 103 * @param folderID the ID of the trashed folder. 104 * @return info about the restored folder. 105 */ 106 public BoxFolder.Info restoreFolder(String folderID) { 107 URL url = RESTORE_FOLDER_URL_TEMPLATE.build(this.api.getBaseURL(), folderID); 108 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "POST"); 109 JsonObject requestJSON = new JsonObject() 110 .add("", ""); 111 request.setBody(requestJSON.toString()); 112 try (BoxJSONResponse response = request.send()) { 113 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 114 115 BoxFolder restoredFolder = new BoxFolder(this.api, responseJSON.get("id").asString()); 116 return restoredFolder.new Info(responseJSON); 117 } 118 } 119 120 /** 121 * Restores a trashed folder to a new location with a new name. 122 * 123 * @param folderID the ID of the trashed folder. 124 * @param newName an optional new name to give the folder. This can be null to use the folder's original name. 125 * @param newParentID an optional new parent ID for the folder. This can be null to use the folder's original 126 * parent. 127 * @return info about the restored folder. 128 */ 129 public BoxFolder.Info restoreFolder(String folderID, String newName, String newParentID) { 130 JsonObject requestJSON = new JsonObject(); 131 132 if (newName != null) { 133 requestJSON.add("name", newName); 134 } 135 136 if (newParentID != null) { 137 JsonObject parent = new JsonObject(); 138 parent.add("id", newParentID); 139 requestJSON.add("parent", parent); 140 } 141 142 URL url = RESTORE_FOLDER_URL_TEMPLATE.build(this.api.getBaseURL(), folderID); 143 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "POST"); 144 request.setBody(requestJSON.toString()); 145 try (BoxJSONResponse response = request.send()) { 146 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 147 148 BoxFolder restoredFolder = new BoxFolder(this.api, responseJSON.get("id").asString()); 149 return restoredFolder.new Info(responseJSON); 150 } 151 } 152 153 /** 154 * Permanently deletes a trashed file. 155 * 156 * @param fileID the ID of the trashed folder to permanently delete. 157 */ 158 public void deleteFile(String fileID) { 159 URL url = FILE_INFO_URL_TEMPLATE.build(this.api.getBaseURL(), fileID); 160 BoxAPIRequest request = new BoxAPIRequest(this.api, url, "DELETE"); 161 request.send().close(); 162 } 163 164 /** 165 * Gets information about a trashed file. 166 * 167 * @param fileID the ID of the trashed file. 168 * @return info about the trashed file. 169 */ 170 public BoxFile.Info getFileInfo(String fileID) { 171 URL url = FILE_INFO_URL_TEMPLATE.build(this.api.getBaseURL(), fileID); 172 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "GET"); 173 try (BoxJSONResponse response = request.send()) { 174 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 175 176 BoxFile file = new BoxFile(this.api, jsonObject.get("id").asString()); 177 return file.new Info(response.getJSON()); 178 } 179 } 180 181 /** 182 * Gets information about a trashed file that's limited to a list of specified fields. 183 * 184 * @param fileID the ID of the trashed file. 185 * @param fields the fields to retrieve. 186 * @return info about the trashed file containing only the specified fields. 187 */ 188 public BoxFile.Info getFileInfo(String fileID, String... fields) { 189 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 190 URL url = FILE_INFO_URL_TEMPLATE.buildWithQuery(this.api.getBaseURL(), queryString, fileID); 191 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "GET"); 192 try (BoxJSONResponse response = request.send()) { 193 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 194 195 BoxFile file = new BoxFile(this.api, jsonObject.get("id").asString()); 196 return file.new Info(response.getJSON()); 197 } 198 } 199 200 /** 201 * Restores a trashed file back to its original location. 202 * 203 * @param fileID the ID of the trashed file. 204 * @return info about the restored file. 205 */ 206 public BoxFile.Info restoreFile(String fileID) { 207 URL url = RESTORE_FILE_URL_TEMPLATE.build(this.api.getBaseURL(), fileID); 208 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "POST"); 209 JsonObject requestJSON = new JsonObject() 210 .add("", ""); 211 return getInfo(requestJSON, request); 212 } 213 214 /** 215 * Restores a trashed file to a new location with a new name. 216 * 217 * @param fileID the ID of the trashed file. 218 * @param newName an optional new name to give the file. This can be null to use the file's original name. 219 * @param newParentID an optional new parent ID for the file. This can be null to use the file's original 220 * parent. 221 * @return info about the restored file. 222 */ 223 public BoxFile.Info restoreFile(String fileID, String newName, String newParentID) { 224 JsonObject requestJSON = new JsonObject(); 225 226 if (newName != null) { 227 requestJSON.add("name", newName); 228 } 229 230 if (newParentID != null) { 231 JsonObject parent = new JsonObject(); 232 parent.add("id", newParentID); 233 requestJSON.add("parent", parent); 234 } 235 236 URL url = RESTORE_FILE_URL_TEMPLATE.build(this.api.getBaseURL(), fileID); 237 BoxJSONRequest request = new BoxJSONRequest(this.api, url, "POST"); 238 return getInfo(requestJSON, request); 239 } 240 241 /** 242 * Returns an iterator over the items in the trash. 243 * 244 * @return an iterator over the items in the trash. 245 */ 246 public Iterator<BoxItem.Info> iterator() { 247 return items(none(), marker(DEFAULT_LIMIT)).iterator(); 248 } 249 250 /** 251 * Returns an iterable containing the items in trash. You can specify sort order, limit of files requested, ofset 252 * or use marker based pagination. 253 * 254 * @param sortParameters describes sorting parameters. 255 * Sort parameters are supported only with offset based pagination. 256 * Use {@link SortParameters#none()} to ignore sorting. 257 * @param pagingParameters describes paging parameters 258 * @param fields the fields to retrieve. 259 * @return an iterable containing the items in the trash. 260 */ 261 public Iterable<BoxItem.Info> items( 262 SortParameters sortParameters, 263 PagingParameters pagingParameters, 264 String... fields 265 ) { 266 QueryStringBuilder builder = sortParameters.asQueryStringBuilder(); 267 validateSortIsSelectedWithOffsetPaginationOnly(pagingParameters, builder); 268 269 if (fields.length > 0) { 270 builder.appendParam("fields", fields); 271 } 272 final String query = builder.toString(); 273 return () -> { 274 URL url = GET_ITEMS_URL.buildWithQuery(this.api.getBaseURL(), query); 275 if (pagingParameters == null) { 276 return new BoxItemIterator(this.api, url, marker(DEFAULT_LIMIT)); 277 } else { 278 return new BoxItemIterator(this.api, url, pagingParameters); 279 } 280 }; 281 } 282 283 private BoxFile.Info getInfo(JsonObject requestJSON, BoxJSONRequest request) { 284 request.setBody(requestJSON.toString()); 285 try (BoxJSONResponse response = request.send()) { 286 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 287 288 BoxFile restoredFile = new BoxFile(this.api, responseJSON.get("id").asString()); 289 return restoredFile.new Info(responseJSON); 290 } 291 } 292 293 /** 294 * Throws IllegalArgumentException exception when sorting and marker pagination is selected. 295 * 296 * @param pagingParameters paging definition to check 297 * @param sortQuery builder containing sort query 298 */ 299 private void validateSortIsSelectedWithOffsetPaginationOnly( 300 PagingParameters pagingParameters, 301 QueryStringBuilder sortQuery 302 ) { 303 if (pagingParameters != null && pagingParameters.isMarkerBasedPaging() && sortQuery.toString().length() > 0) { 304 throw new IllegalArgumentException("Sorting is not supported when using marker based pagination."); 305 } 306 } 307}