From 58429ce0c4ddd99b56669c6a3c9363d8e74831b4 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 19 Aug 2025 17:40:22 +0200 Subject: [PATCH 1/2] attempt to fix app folder issue by creating it by an upload --- .../Io/OneDrive2FileStorage.cs | 102 +++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs index 132981dd..81198e71 100644 --- a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs @@ -1125,9 +1125,58 @@ namespace keepass2android.Io } } + public static async Task GetOrCreateAppRootAsync(GraphServiceClient client, string dummyFileName = "welcome_at_kp2a.txt") + { - private async Task> ListShares(OneDrive2ItemLocation parentPath, GraphServiceClient client) + try + { + return await client.RequestAdapter.SendAsync( + new Microsoft.Graph.Drives.Item.Items.Item.DriveItemItemRequestBuilder( + new Dictionary { + { "drive%2Did", "me" }, + { "driveItem%2Did", "special/approot" } + }, + client.RequestAdapter + ).ToGetRequestInformation(), + static (p) => DriveItem.CreateFromDiscriminatorValue(p) + ); + } + catch (Microsoft.Kiota.Abstractions.ApiException ex) when (ex.ResponseStatusCode == 404) + { + // App folder doesn’t exist yet → create it by uploading a dummy file + using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("init")); + + var uploadRequest = new RequestInformation + { + HttpMethod = Method.PUT, + UrlTemplate = "{+baseurl}/me/drive/special/approot:/{filename}:/content", + PathParameters = new Dictionary + { + { "baseurl", client.RequestAdapter.BaseUrl }, + { "filename", dummyFileName } + }, + Content = stream + }; + + var uploadedItem = await client.RequestAdapter.SendAsync( + uploadRequest, + DriveItem.CreateFromDiscriminatorValue + ); + + // Use WithUrl() to hit that endpoint + var parentId = uploadedItem.ParentReference.Id; + + var parentItemRequest = new DriveItemRequestBuilder( + $"{client.RequestAdapter.BaseUrl}/me/drive/items/{parentId}", + client.RequestAdapter + ); + + return await parentItemRequest.GetAsync(); + } + } + + protected virtual async Task> ListShares(OneDrive2ItemLocation parentPath, GraphServiceClient client) { List result = []; @@ -1345,6 +1394,8 @@ namespace keepass2android.Io } } + + protected override async Task GetSpecialFolder( OneDrive2ItemLocation itemLocation, GraphServiceClient client) @@ -1363,7 +1414,7 @@ namespace keepass2android.Io Console.WriteLine(e); throw; } - + } return _specialFolderIdByDriveId[itemLocation.DriveId]; @@ -1378,8 +1429,55 @@ namespace keepass2android.Io { return drive.Name ?? MyOneDriveDisplayName; } + public static async Task GetOrCreateAppRootAsync(GraphServiceClient client, string dummyFileName = "welcome_at_kp2a_app_folder.txt") + { + try + { + await client.RequestAdapter.SendAsync( + new Microsoft.Graph.Drives.Item.Items.Item.DriveItemItemRequestBuilder( + new Dictionary { + { "drive%2Did", "me" }, + { "driveItem%2Did", "special/approot" } + }, + client.RequestAdapter + ).ToGetRequestInformation(), + static (p) => DriveItem.CreateFromDiscriminatorValue(p) + ); + //if this is successful, approot seems to exist + } + catch (Microsoft.Kiota.Abstractions.ApiException ex) when (ex.ResponseStatusCode == 404) + { + // App folder doesn’t exist yet → create it by uploading a dummy file + using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("init")); + + var uploadRequest = new RequestInformation + { + HttpMethod = Method.PUT, + UrlTemplate = "{+baseurl}/me/drive/special/approot:/{filename}:/content", + PathParameters = new Dictionary + { + { "baseurl", client.RequestAdapter.BaseUrl }, + { "filename", dummyFileName } + }, + Content = stream + }; + + await client.RequestAdapter.SendAsync( + uploadRequest, + DriveItem.CreateFromDiscriminatorValue + ); + + } + } + + protected override async Task> ListShares(OneDrive2ItemLocation parentPath, GraphServiceClient client) + { + await GetOrCreateAppRootAsync(client); + return await base.ListShares(parentPath, client); + } + public override bool CanListShares { get { return false; } } protected override string MyOneDriveDisplayName => "Keepass2Android App Folder"; } From b7276d13641aa283fe639d82f25e631be0ace82c Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 19 Aug 2025 18:00:38 +0200 Subject: [PATCH 2/2] remove no-longer-sensible comment --- src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs index 81198e71..e73c7bea 100644 --- a/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/OneDrive2FileStorage.cs @@ -1164,7 +1164,6 @@ namespace keepass2android.Io DriveItem.CreateFromDiscriminatorValue ); - // Use WithUrl() to hit that endpoint var parentId = uploadedItem.ParentReference.Id; var parentItemRequest = new DriveItemRequestBuilder(