From c551203f4c2bf0de8254015da107f53cc0936aae Mon Sep 17 00:00:00 2001 From: abraunegg Date: Wed, 11 Oct 2023 05:48:22 +1100 Subject: [PATCH] Update PR * Add --create-share-link --- docs/application-config-options.md | 12 ++-- src/main.d | 14 ++++ src/onedrive.d | 10 +++ src/sync.d | 109 ++++++++++++++++++++++------- 4 files changed, 115 insertions(+), 30 deletions(-) diff --git a/docs/application-config-options.md b/docs/application-config-options.md index 5cfadcb8e..1a266080f 100644 --- a/docs/application-config-options.md +++ b/docs/application-config-options.md @@ -838,9 +838,11 @@ _**Description:**_ _**Usage Example:**_ ### CLI Option: --create-share-link -_**Description:**_ +_**Description:**_ This CLI option enables the creation of a shareable file link that can be provided to users to access the file that is stored on Microsoft OneDrive. By default, the permissions for the file will be 'read-only'. -_**Usage Example:**_ +_**Usage Example:**_ `onedrive --create-share-link 'relative/path/to/your/file.txt'` + +_**Additional Usage Notes:**_ If writable access to the file is required, you must add `--with-editing-perms` to your command. See below for details. ### CLI Option: --destination-directory _**Description:**_ @@ -951,9 +953,11 @@ _**Description:**_ This CLI option controls the verbosity of the application out _**Usage Example:**_ `onedrive --sync --verbose` or `onedrive --monitor --verbose` ### CLI Option: --with-editing-perms -_**Description:**_ +_**Description:**_ This CLI option enables the creation of a writable shareable file link that can be provided to users to access the file that is stored on Microsoft OneDrive. This option can only be used in conjunction with `--create-share-link` -_**Usage Example:**_ +_**Usage Example:**_ `onedrive --create-share-link 'relative/path/to/your/file.txt' --with-editing-perms` + +_**Additional Usage Notes:**_ Placement of `--with-editing-perms` is critical. It *must* be placed after the file path as per the example above. ## Depreciated Configuration File and CLI Options The following configuration options are no longer supported diff --git a/src/main.d b/src/main.d index 3ea942304..2d60a479c 100644 --- a/src/main.d +++ b/src/main.d @@ -441,6 +441,20 @@ int main(string[] cliArgs) { return EXIT_SUCCESS; } + // --create-share-link - Are we createing a shareable link for an existing file on OneDrive? + if (appConfig.getValueString("create_share_link") != "") { + // Query OneDrive for the file, and if valid, create a shareable link for the file + + // By default, the shareable link will be read-only. + // If the user adds: + // --with-editing-perms + // this will create a writeable link + syncEngineInstance.queryOneDriveForFileDetails(appConfig.getValueString("create_share_link"), runtimeSyncDirectory, "ShareableLink"); + // Exit application + // Use exit scopes to shutdown API + return EXIT_SUCCESS; + } + // If we get to this point, we have not performed a 'no-sync' task .. log.error("\n --sync or --monitor switches missing from your command line input. Please add one (not both) of these switches to your command line or use 'onedrive --help' for further assistance.\n"); log.error("No OneDrive sync will be performed without one of these two arguments being present.\n"); diff --git a/src/onedrive.d b/src/onedrive.d index f978e85f3..e4b76ad55 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -483,6 +483,16 @@ class OneDriveApi { return get(url); } + // Create a shareable link for an existing file on OneDrive based on the accessScope JSON permissions + // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createlink + JSONValue createShareableLink(string driveId, string id, JSONValue accessScope) { + checkAccessTokenExpired(); + string url; + url = driveByIdUrl ~ driveId ~ "/items/" ~ id ~ "/createLink"; + curlEngine.http.addRequestHeader("Content-Type", "application/json"); + return post(url, accessScope.toString()); + } + // Return the requested details of the specified path on the specified drive id and path // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get JSONValue getPathDetailsByDriveId(string driveId, string path) { diff --git a/src/sync.d b/src/sync.d index 2cdd6aca2..c9cb5ac88 100644 --- a/src/sync.d +++ b/src/sync.d @@ -6671,14 +6671,14 @@ class SyncEngine { if (exists(fullLocalFilePath)) { // search drive_id list string[] distinctDriveIds = itemDB.selectDistinctDriveIds(); - bool fileInDB = false; + bool pathInDB = false; Item dbItem; foreach (searchDriveId; distinctDriveIds) { // Does this path exist in the database, use the 'inputFilePath' if (itemDB.selectByPath(inputFilePath, searchDriveId, dbItem)) { // item is in the database - fileInDB = true; + pathInDB = true; JSONValue fileDetailsFromOneDrive; // Create a new API Instance for this thread and initialise it @@ -6694,43 +6694,100 @@ class SyncEngine { return; } - // debug output of response - log.vdebug("API Response: ", fileDetailsFromOneDrive); + // Is the API response a valid JSON file? + if (fileDetailsFromOneDrive.type() == JSONType.object) { - // What sort of response to we generate - // --get-file-link response - if (outputType == "URL") { - if ((fileDetailsFromOneDrive.type() == JSONType.object) && ("webUrl" in fileDetailsFromOneDrive)) { - // Valid JSON object - writeln(); - writeln("WebURL: ", fileDetailsFromOneDrive["webUrl"].str); + // debug output of response + log.vdebug("API Response: ", fileDetailsFromOneDrive); + + // What sort of response to we generate + // --get-file-link response + if (outputType == "URL") { + if ((fileDetailsFromOneDrive.type() == JSONType.object) && ("webUrl" in fileDetailsFromOneDrive)) { + // Valid JSON object + writeln(); + writeln("WebURL: ", fileDetailsFromOneDrive["webUrl"].str); + } } - } - - // --modified-by response - if (outputType == "ModifiedBy") { - if ((fileDetailsFromOneDrive.type() == JSONType.object) && ("lastModifiedBy" in fileDetailsFromOneDrive)) { - // Valid JSON object - writeln(); - writeln("Last modified: ", fileDetailsFromOneDrive["lastModifiedDateTime"].str); - writeln("Last modified by: ", fileDetailsFromOneDrive["lastModifiedBy"]["user"]["displayName"].str); - // if 'email' provided, add this to the output - if ("email" in fileDetailsFromOneDrive["lastModifiedBy"]["user"]) { - writeln("Email Address: ", fileDetailsFromOneDrive["lastModifiedBy"]["user"]["email"].str); + + // --modified-by response + if (outputType == "ModifiedBy") { + if ((fileDetailsFromOneDrive.type() == JSONType.object) && ("lastModifiedBy" in fileDetailsFromOneDrive)) { + // Valid JSON object + writeln(); + writeln("Last modified: ", fileDetailsFromOneDrive["lastModifiedDateTime"].str); + writeln("Last modified by: ", fileDetailsFromOneDrive["lastModifiedBy"]["user"]["displayName"].str); + // if 'email' provided, add this to the output + if ("email" in fileDetailsFromOneDrive["lastModifiedBy"]["user"]) { + writeln("Email Address: ", fileDetailsFromOneDrive["lastModifiedBy"]["user"]["email"].str); + } + } + } + + // --create-share-link response + if (outputType == "ShareableLink") { + + JSONValue accessScope; + JSONValue createShareableLinkResponse; + string thisDriveId = fileDetailsFromOneDrive["parentReference"]["driveId"].str; + string thisItemId = fileDetailsFromOneDrive["id"].str; + string fileShareLink; + bool writeablePermissions = appConfig.getValueBool("with_editing_perms"); + + // What sort of shareable link is required? + if (writeablePermissions) { + // configure the read-write access scope + accessScope = [ + "type": "edit", + "scope": "anonymous" + ]; + } else { + // configure the read-only access scope (default) + accessScope = [ + "type": "view", + "scope": "anonymous" + ]; + } + + // Try and create the shareable file link + try { + createShareableLinkResponse = queryOneDriveForFileDetailsApiInstance.createShareableLink(thisDriveId, thisItemId, accessScope); + } catch (OneDriveException exception) { + // display what the error is + displayOneDriveErrorMessage(exception.msg, getFunctionName!({})); + return; + } + + // Is the API response a valid JSON file? + if ((createShareableLinkResponse.type() == JSONType.object) && ("link" in createShareableLinkResponse)) { + // Extract the file share link from the JSON response + fileShareLink = createShareableLinkResponse["link"]["webUrl"].str; + writeln("File Shareable Link: ", fileShareLink); + if (writeablePermissions) { + writeln("Shareable Link has read-write permissions - use and provide with caution"); + } } } } + + // Shutdown the API access + queryOneDriveForFileDetailsApiInstance.shutdown(); + // Free object and memory + object.destroy(queryOneDriveForFileDetailsApiInstance); } } // was path found? - if (!fileInDB) { + if (!pathInDB) { // File has not been synced with OneDrive - log.error("Path has not been synced with OneDrive: ", inputFilePath); + log.error("Selected path has not been synced with OneDrive: ", inputFilePath); } } else { // File does not exist locally - log.error("Path not found on local system: ", inputFilePath); + log.error("Selected path not found on local system: ", inputFilePath); } } + + + } \ No newline at end of file