2323import java .io .File ;
2424import java .io .IOException ;
2525import java .io .RandomAccessFile ;
26+ import java .util .ArrayList ;
2627import java .util .Arrays ;
28+ import java .util .Comparator ;
2729import java .util .Iterator ;
30+ import java .util .List ;
2831import java .util .concurrent .TimeUnit ;
2932
3033import static ratismal .drivebackup .config .Localization .intl ;
@@ -336,19 +339,7 @@ private FQID getRootFolder(@NotNull String folder) throws IOException, GraphApiE
336339 */
337340 @ Nullable
338341 private FQID getFolder (@ NotNull FQID root , @ NotNull String folder ) throws IOException , GraphApiErrorException {
339- Request request = new Request .Builder ()
340- .addHeader ("Authorization" , "Bearer " + accessToken )
341- .url ("https://graph.microsoft.com/v1.0/drives/" + root .driveId + "/items/" + root .itemId + "/children" )
342- .build ();
343- JSONArray children ;
344- try (Response response = DriveBackup .httpClient .newCall (request ).execute ()) {
345- if (!response .isSuccessful ()) {
346- throw new GraphApiErrorException (response );
347- }
348- children = new JSONObject (response .body ().string ()).getJSONArray ("value" );
349- }
350- for (int i = 0 ; i < children .length (); i ++) {
351- JSONObject childItem = children .getJSONObject (i );
342+ for (JSONObject childItem : getChildren (root , "?select=name,id,parentReference,remoteItem" )) {
352343 String folderName = childItem .getString ("name" ); // TODO filter non folders
353344 if (folder .equals (folderName )) {
354345 if (childItem .has ("remoteItem" )) {
@@ -359,10 +350,45 @@ private FQID getFolder(@NotNull FQID root, @NotNull String folder) throws IOExce
359350 return new FQID (driveId , itemId );
360351 }
361352 }
362- // TODO handle @odata.nextLink
363353 return null ;
364354 }
365355
356+ /**
357+ * gets all children for a given folder
358+ * @param folder to query
359+ * @param queryParams line like "?$select=name"
360+ * @throws IOException on request execution failure
361+ * @throws GraphApiErrorException if the children could not be retrieved
362+ * @throws JSONException if the response does not contain the expected items
363+ */
364+ @ NotNull
365+ private List <JSONObject > getChildren (@ NotNull FQID folder , @ NotNull String queryParams ) throws IOException , GraphApiErrorException {
366+ ArrayList <JSONObject > allChildren = new ArrayList <>();
367+ String targetUrl = "https://graph.microsoft.com/v1.0/me/drives/" + folder .driveId
368+ + "/items/" + folder .itemId + "/children" + queryParams ;
369+ while (true ) {
370+ Request request = new Request .Builder ()
371+ .addHeader ("Authorization" , "Bearer " + accessToken )
372+ .url (targetUrl )
373+ .build ();
374+ try (Response response = DriveBackup .httpClient .newCall (request ).execute ()) {
375+ if (!response .isSuccessful ()) {
376+ throw new GraphApiErrorException (response );
377+ }
378+ JSONObject parsedResponse = new JSONObject (response .body ().string ());
379+ JSONArray someChildren = parsedResponse .getJSONArray ("value" );
380+ allChildren .ensureCapacity (parsedResponse .getInt ("@odata.count" ));
381+ for (int i = 0 ; i < someChildren .length (); i ++) {
382+ allChildren .add (someChildren .getJSONObject (i ));
383+ }
384+ if (!parsedResponse .has ("@odata.nextLink" )) {
385+ return allChildren ;
386+ }
387+ targetUrl = parsedResponse .getString ("@odata.nextLink" );
388+ }
389+ }
390+ }
391+
366392 /**
367393 * moves an item to the recycle bin
368394 *
@@ -499,31 +525,21 @@ private void pruneBackups(@NotNull FQID parent) throws IOException, GraphApiErro
499525 if (fileLimit == -1 ) {
500526 return ;
501527 }
502- Request childItemRequest = new Request .Builder ()
503- .addHeader ("Authorization" , "Bearer " + accessToken )
504- .url ("https://graph.microsoft.com/v1.0/drives/" + parent .driveId + "/items/" + parent .itemId + "/children?sort_by=createdDateTime" )
505- .build ();
506- JSONArray items ;
507- try (Response childItemResponse = DriveBackup .httpClient .newCall (childItemRequest ).execute ()) {
508- if (!childItemResponse .isSuccessful ()) {
509- throw new GraphApiErrorException (childItemResponse );
510- }
511- items = new JSONObject (childItemResponse .body ().string ()).getJSONArray ("value" );
512- }
513- if (fileLimit >= items .length ()) { // TODO filter non backup files (folders & files not created by plugin)
528+ List <JSONObject > childItems = getChildren (parent , "?$select=id,createdDateTime" );
529+ if (fileLimit >= childItems .size ()) {
514530 return ;
515531 }
516532 logger .info (
517533 intl ("backup-method-limit-reached" ),
518- "file-count" , String .valueOf (items . length ()),
534+ "file-count" , String .valueOf (childItems . size ()),
519535 "upload-method" , getName (),
520536 "file-limit" , String .valueOf (fileLimit ));
521- int itemsToDelete = items .length () - fileLimit ;
537+ childItems .sort (Comparator .comparing (item -> item .getString ("createdDateTime" )));
538+ int itemsToDelete = childItems .size () - fileLimit ;
522539 for (int i = 0 ; i < itemsToDelete ; i ++) {
523- String itemId = items . getJSONObject (i ).getString ("id" );
540+ String itemId = childItems . get (i ).getString ("id" );
524541 recycleItem (parent .driveId , itemId );
525542 }
526- // TODO handle @odata.nextLink
527543 }
528544
529545 /**
0 commit comments