Implement Feature: Create shareable link (#1061)

* Implement feature request to create a shareable file link. Default is to create a read-only anonymous link

Co-authored-by: Norbert Preining <norbert@preining.info>
This commit is contained in:
abraunegg 2020-09-14 17:49:50 +10:00 committed by GitHub
parent 4ddad0c350
commit 0c770efa96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 4 deletions

View file

@ -689,6 +689,8 @@ Options:
Set the directory used to store the configuration files
--create-directory ARG
Create a directory on OneDrive - no sync will be performed.
--create-share-link ARG
Create a shareable link for an existing file on OneDrive
--debug-https
Debug OneDrive HTTPS communication.
--destination-directory ARG

View file

@ -44,6 +44,9 @@ Set the directory used to store the configuration files
\fB\-\-create\-directory\fP ARG
Create a directory on OneDrive \- no sync will be performed.
.TP
\fB\-\-create\-share\-link\fP ARG
Create a shareable link for an existing file on OneDrive
.TP
\fB\-\-debug\-https\fP
Debug OneDrive HTTPS communication.
.br

View file

@ -249,6 +249,7 @@ final class Config
{
// Add additional options that are NOT configurable via config file
stringValues["create_directory"] = "";
stringValues["create_share_link"] = "";
stringValues["destination_directory"] = "";
stringValues["get_file_link"] = "";
stringValues["get_o365_drive_id"] = "";
@ -293,6 +294,9 @@ final class Config
"create-directory",
"Create a directory on OneDrive - no sync will be performed.",
&stringValues["create_directory"],
"create-share-link",
"Create a shareable link for an existing file on OneDrive",
&stringValues["create_share_link"],
"debug-https",
"Debug OneDrive HTTPS communication.",
&boolValues["debug_https"],
@ -591,7 +595,9 @@ void outputLongHelp(Option[] opt)
auto argsNeedingOptions = [
"--confdir",
"--create-directory",
"--create-share-link",
"--destination-directory",
"--get-file-link",
"--get-O365-drive-id",
"--log-dir",
"--min-notify-changes",

View file

@ -565,7 +565,7 @@ int main(string[] args)
// create-directory, remove-directory, source-directory, destination-directory
// these are activities that dont perform a sync, so to not generate an error message for these items either
if (((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) || ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) || (cfg.getValueString("get_file_link") != "") || (cfg.getValueString("get_o365_drive_id") != "") || cfg.getValueBool("display_sync_status") || cfg.getValueBool("list_business_shared_folders")) {
if (((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) || ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) || (cfg.getValueString("get_file_link") != "") || (cfg.getValueString("create_share_link") != "") || (cfg.getValueString("get_o365_drive_id") != "") || cfg.getValueBool("display_sync_status") || cfg.getValueBool("list_business_shared_folders")) {
performSyncOK = true;
}
@ -700,8 +700,8 @@ int main(string[] args)
// Use exit scopes to shutdown API
return EXIT_FAILURE;
} else {
if (cfg.getValueString("get_file_link") == "") {
// Print out that we are initializing the engine only if we are not grabbing the file link
if ((cfg.getValueString("get_file_link") == "") && (cfg.getValueString("create_share_link") == "")) {
// Print out that we are initializing the engine only if we are not grabbing the file link or creating a shareable link
log.logAndNotify("Initializing the Synchronization Engine ...");
}
}
@ -790,8 +790,18 @@ int main(string[] args)
return EXIT_SUCCESS;
}
// Are we createing an anonymous read-only shareable link for an existing file on OneDrive?
if (cfg.getValueString("create_share_link") != "") {
// Query OneDrive for the file, and if valid, create a shareable link for the file
sync.createShareableLinkForFile(cfg.getValueString("create_share_link"));
// Exit application
// Use exit scopes to shutdown API
return EXIT_SUCCESS;
}
// Are we obtaining the URL path for a synced file?
if (cfg.getValueString("get_file_link") != "") {
// Query OneDrive for the file link
sync.queryOneDriveForFileURL(cfg.getValueString("get_file_link"), syncDir);
// Exit application
// Use exit scopes to shutdown API

View file

@ -567,7 +567,6 @@ final class OneDriveApi
return get(url);
}
// Return the requested details of the specified id
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get
JSONValue getFileDetails(const(char)[] driveId, const(char)[] id)
@ -579,6 +578,17 @@ final class OneDriveApi
return get(url);
}
// Create an anonymous read-only shareable link for an existing file on OneDrive
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createlink
JSONValue createShareableLink(const(char)[] driveId, const(char)[] id, JSONValue accessScope)
{
checkAccessTokenExpired();
const(char)[] url;
url = driveByIdUrl ~ driveId ~ "/items/" ~ id ~ "/createLink";
http.addRequestHeader("Content-Type", "application/json");
return post(url, accessScope.toString());
}
// https://dev.onedrive.com/items/move.htm
JSONValue moveByPath(const(char)[] sourcePath, JSONValue moveData)
{

View file

@ -5173,6 +5173,83 @@ final class SyncEngine
}
}
// Create an anonymous read-only shareable link for an existing file on OneDrive
void createShareableLinkForFile(string filePath)
{
JSONValue onedrivePathDetails;
JSONValue createShareableLinkResponse;
string driveId;
string itemId;
string fileShareLink;
// Get the path details from OneDrive
try {
onedrivePathDetails = onedrive.getPathDetails(filePath); // Returns a JSON String for the OneDrive Path
} catch (OneDriveException e) {
log.vdebug("onedrivePathDetails = onedrive.getPathDetails(filePath); generated a OneDriveException");
if (e.httpStatusCode == 404) {
// Requested path could not be found
log.error("ERROR: The requested path to query was not found on OneDrive");
return;
}
if (e.httpStatusCode == 429) {
// HTTP request returned status code 429 (Too Many Requests). We need to leverage the response Retry-After HTTP header to ensure minimum delay until the throttle is removed.
handleOneDriveThrottleRequest();
// Retry original request by calling function again to avoid replicating any further error handling
log.vdebug("Retrying original request that generated the OneDrive HTTP 429 Response Code (Too Many Requests) - calling queryDriveForChanges(path);");
createShareableLinkForFile(filePath);
// return back to original call
return;
}
if (e.httpStatusCode == 504) {
// HTTP request returned status code 504 (Gateway Timeout)
log.log("OneDrive returned a 'HTTP 504 - Gateway Timeout' - retrying request");
// Retry original request by calling function again to avoid replicating any further error handling
createShareableLinkForFile(filePath);
// return back to original call
return;
} else {
// display what the error is
displayOneDriveErrorMessage(e.msg);
return;
}
}
// Was a valid JSON response received?
if (onedrivePathDetails.type() == JSONType.object) {
// valid JSON response for the file was received
// Configure the required variables
driveId = onedrivePathDetails["parentReference"]["driveId"].str;
itemId = onedrivePathDetails["id"].str;
// configure the access scope
JSONValue accessScope = [
"type": "view",
"scope": "anonymous"
];
// Create the shareable file link
createShareableLinkResponse = onedrive.createShareableLink(driveId, itemId, accessScope);
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);
} else {
// not a valid JSON object
log.error("ERROR: There was an error performing this operation on OneDrive");
log.error("ERROR: Increase logging verbosity to assist determining why.");
return;
}
} else {
// not a valid JSON object
log.error("ERROR: There was an error performing this operation on OneDrive");
log.error("ERROR: Increase logging verbosity to assist determining why.");
return;
}
}
// Query OneDrive for a URL path of a file
void queryOneDriveForFileURL(string localFilePath, string syncDir)
{