Skip to content

Commit 4cfc84e

Browse files
add new logic for path creation
1 parent b9d225d commit 4cfc84e

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

DriveBackup/src/main/java/ratismal/drivebackup/uploaders/onedrive/OneDriveUploader.java

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,181 @@ public void uploadFile(java.io.File file, String type) throws IOException {
228228
public void close() {
229229
// nothing needs to be done
230230
}
231+
232+
/**
233+
* fully qualified item id
234+
*/
235+
private static class FQID {
236+
public final String driveId;
237+
public final String itemId;
238+
239+
public FQID(String driveId, String itemId) {
240+
this.driveId = driveId;
241+
this.itemId = itemId;
242+
}
243+
}
244+
245+
/**
246+
* removes "." and ".." segments from the path
247+
* @param path to normalize
248+
* @return the normalized path
249+
*/
250+
@NotNull
251+
private String normalizePath(String path) {
252+
StringBuilder normalized = new StringBuilder();
253+
for (String part : path.split("[/\\\\]")) {
254+
if (".".equals(part) || "..".equals(part)) {
255+
continue;
256+
}
257+
normalized.append('/').append(part);
258+
}
259+
return normalized.substring(1);
260+
}
261+
262+
/**
263+
* creates all folders in the path if they don't already exist
264+
* @param path to create the folders for
265+
* @return FQID of the last folder in the path
266+
* @throws IOException if the folder could not be created;
267+
* or if the api request could not be executed due to cancellation, a connectivity problem or timeout.
268+
*/
269+
@NotNull
270+
private FQID createPath(String path) throws IOException {
271+
Iterator<String> parts = Arrays.stream(path.split("/")).iterator();
272+
FQID root = createRootFolder(parts.next());
273+
for (; parts.hasNext(); ) {
274+
String folder = parts.next();
275+
root = createFolder(root, folder);
276+
}
277+
return root;
278+
}
279+
280+
/**
281+
* creates a folder at the root if it doesn't already exist
282+
* @param root of where to create the folder
283+
* @param folder name to create
284+
* @return FQID of the folder
285+
* @throws IOException if the folder could not be created;
286+
* or if the api request could not be executed due to cancellation, a connectivity problem or timeout.
287+
*/
288+
@NotNull
289+
private FQID createFolder(FQID root, String folder) throws IOException {
290+
FQID item = getFolder(root, folder);
291+
if (item != null) {
292+
return item;
293+
}
294+
RequestBody requestBody = RequestBody.create("{ \"name\": \"" + folder
295+
+ "\", \"folder\": {}, \"@microsoft.graph.conflictBehavior\": \"fail\" }", jsonMediaType);
296+
Request request = new Request.Builder()
297+
.addHeader("Authorization", "Bearer " + accessToken)
298+
.url("https://graph.microsoft.com/v1.0/me/drive/root/children")
299+
.post(requestBody)
300+
.build();
301+
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
302+
if (!response.isSuccessful()) {
303+
throw new IOException("Couldn't create folder " + folder);
304+
}
305+
JSONObject parsedResponse = new JSONObject(response.body().string());
306+
String driveId = parsedResponse.getJSONObject("parentReference").getString("driveId");
307+
String itemId = parsedResponse.getString("id");
308+
return new FQID(driveId, itemId);
309+
}
310+
}
311+
312+
/**
313+
* creates a folder at the drive root if it doesn't already exist
314+
* @param folder name to create
315+
* @return FQID of the folder
316+
* @throws IOException if the folder could not be created;
317+
* or if the api request could not be executed due to cancellation, a connectivity problem or timeout.
318+
*/
319+
@NotNull
320+
private FQID createRootFolder(String folder) throws IOException {
321+
FQID item = getRootFolder(folder);
322+
if (item != null) {
323+
return item;
324+
}
325+
RequestBody requestBody = RequestBody.create("{ \"name\": \""
326+
+ folder + "\", \"folder\": {}, \"@name.conflictBehavior\": \"fail\" }", jsonMediaType);
327+
Request request = new Request.Builder()
328+
.addHeader("Authorization", "Bearer " + accessToken)
329+
.url("https://graph.microsoft.com/v1.0/me/drive/root/children")
330+
.post(requestBody)
331+
.build();
332+
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
333+
if (!response.isSuccessful()) {
334+
throw new IOException("Couldn't create folder " + folder);
335+
}
336+
JSONObject parsedResponse = new JSONObject(response.body().string());
337+
String driveId = parsedResponse.getJSONObject("parentReference").getString("driveId");
338+
String itemId = parsedResponse.getString("id");
339+
return new FQID(driveId, itemId);
340+
}
341+
}
342+
343+
/**
344+
* tries to find folder in the drive root
345+
* @param folder to search
346+
* @return FQID or null if not found
347+
*/
348+
@Nullable
349+
private FQID getRootFolder(String folder) {
350+
try {
351+
Request request = new Request.Builder()
352+
.addHeader("Authorization", "Bearer " + accessToken)
353+
.url("https://graph.microsoft.com/v1.0/me/drive/root:/" + folder + "?$select=id,parentReference,remoteItem")
354+
.build();
355+
JSONObject parsedResponse;
356+
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
357+
parsedResponse = new JSONObject(response.body().string());
358+
}
359+
if (parsedResponse.has("remoteItem")) {
360+
parsedResponse = parsedResponse.optJSONObject("remoteItem");
361+
}
362+
String driveId = parsedResponse.getJSONObject("parentReference").getString("driveId");
363+
String itemId = parsedResponse.getString("id");
364+
return new FQID(driveId, itemId);
365+
} catch (Exception exception) {
366+
return null;
367+
}
368+
}
369+
370+
/**
371+
* tries to find a folder under root
372+
* @param root to search
373+
* @param folder to look for
374+
* @return FQID or null if not found
375+
*/
376+
@Nullable
377+
private FQID getFolder(FQID root, String folder) {
378+
try {
379+
Request request = new Request.Builder()
380+
.addHeader("Authorization", "Bearer " + accessToken)
381+
.url("https://graph.microsoft.com/v1.0/me/drives/" + root.driveId + "/items/" + root.itemId + "/children")
382+
.build();
383+
JSONObject parsedResponse;
384+
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
385+
parsedResponse = new JSONObject(response.body().string());
386+
}
387+
JSONArray children = parsedResponse.getJSONArray("value");
388+
for (int i = 0; i < children.length(); i++) {
389+
JSONObject childItem = children.getJSONObject(i);
390+
String folderName = childItem.getString("name");
391+
if (folder.equals(folderName)) {
392+
if (childItem.has("remoteItem")) {
393+
childItem = childItem.optJSONObject("remoteItem");
394+
}
395+
String driveId = childItem.getJSONObject("parentReference").getString("driveId");
396+
String itemId = childItem.getString("id");
397+
return new FQID(driveId, itemId);
398+
}
399+
}
400+
// TODO handle @odata.nextLink
401+
} catch (Exception exception) {
402+
return null;
403+
}
404+
return null;
405+
}
231406

232407
/**
233408
* Creates a folder with the specified name in the specified parent folder in the authenticated user's OneDrive.

0 commit comments

Comments
 (0)