mirror of
https://github.com/abraunegg/onedrive
synced 2026-03-14 14:35:46 +01:00
Implement Feature Request: Support Permanent Delete on OneDrive (#2999)
* Implement Feature Request: Support Permanent Delete on OneDrive (#2803)
This commit is contained in:
parent
e5de5a29e7
commit
228e7db188
4 changed files with 127 additions and 8 deletions
|
|
@ -36,6 +36,7 @@ Before reading this document, please ensure you are running application version
|
|||
- [no_remote_delete](#no_remote_delete)
|
||||
- [notify_file_actions](#notify_file_actions)
|
||||
- [operation_timeout](#operation_timeout)
|
||||
- [permanent_delete](#permanent_delete)
|
||||
- [rate_limit](#rate_limit)
|
||||
- [read_only_auth_scope](#read_only_auth_scope)
|
||||
- [remove_source_files](#remove_source_files)
|
||||
|
|
@ -505,6 +506,38 @@ _**Default Value:**_ 3600
|
|||
|
||||
_**Config Example:**_ `operation_timeout = "3600"`
|
||||
|
||||
### permanent_delete
|
||||
_**Description:**_ Permanently delete an item online when it is removed locally. When using this method, they're permanently removed and aren't sent to the Microsoft OneDrive Recycle Bin. Therefore, permanently deleted drive items can't be restored afterward. Online data loss MAY occur in this scenario.
|
||||
|
||||
_**Value Type:**_ Boolean
|
||||
|
||||
_**Default Value:**_ False
|
||||
|
||||
_**Config Example:**_ `permanent_delete = "true"`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The Microsoft OneDrive API for this capability is also very narrow:
|
||||
> | Account Type | Config Option is Supported |
|
||||
> |--------------|------------------|
|
||||
> | Personal | ❌ |
|
||||
> | Business | ✔ |
|
||||
> | SharePoint | ✔ |
|
||||
> | Microsoft Cloud Germany | ✔ |
|
||||
> | Microsoft Cloud for US Government | ❌ |
|
||||
> | Azure and Office365 operated by VNET in China | ❌ |
|
||||
>
|
||||
> When using this config option against an unsupported Personal Accounts the following message will be generated:
|
||||
> ```
|
||||
> WARNING: The application is configured to permanently delete files online; however, this action is not supported by Microsoft OneDrive Personal Accounts.
|
||||
> ```
|
||||
>
|
||||
> When using this config option against a supported account the following message will be generated:
|
||||
> ```
|
||||
> WARNING: Application has been configured to permanently remove files online rather than send to the recycle bin. Permanently deleted items can't be restored.
|
||||
> WARNING: Online data loss MAY occur in this scenario.
|
||||
> ```
|
||||
>
|
||||
|
||||
### rate_limit
|
||||
_**Description:**_ This configuration option controls the bandwidth used by the application, per thread, when interacting with Microsoft OneDrive.
|
||||
|
||||
|
|
|
|||
|
|
@ -332,6 +332,8 @@ class ApplicationConfig {
|
|||
boolValues["read_only_auth_scope"] = false;
|
||||
// - Flag to cleanup local files when using --download-only
|
||||
boolValues["cleanup_local_files"] = false;
|
||||
// - Perform a permanentDelete on deletion activities
|
||||
boolValues["permanent_delete"] = false;
|
||||
|
||||
// Webhook Feature Options
|
||||
boolValues["webhook_enabled"] = false;
|
||||
|
|
@ -1411,6 +1413,7 @@ class ApplicationConfig {
|
|||
addLogEntry("Config option 'sync_dir_permissions' = " ~ to!string(getValueLong("sync_dir_permissions")));
|
||||
addLogEntry("Config option 'sync_file_permissions' = " ~ to!string(getValueLong("sync_file_permissions")));
|
||||
addLogEntry("Config option 'space_reservation' = " ~ to!string(getValueLong("space_reservation")));
|
||||
addLogEntry("Config option 'permanent_delete' = " ~ to!string(getValueBool("permanent_delete")));
|
||||
|
||||
// curl operations
|
||||
addLogEntry("Config option 'application_id' = " ~ getValueString("application_id"));
|
||||
|
|
|
|||
|
|
@ -630,6 +630,16 @@ class OneDriveApi {
|
|||
performDelete(url);
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/graph/api/driveitem-permanentdelete?view=graph-rest-1.0
|
||||
void permanentDeleteById(const(char)[] driveId, const(char)[] id, const(char)[] eTag = null) {
|
||||
// string[string] requestHeaders;
|
||||
const(char)[] url = driveByIdUrl ~ driveId ~ "/items/" ~ id ~ "/permanentDelete";
|
||||
//TODO: investigate why this always fail with 412 (Precondition Failed)
|
||||
// if (eTag) requestHeaders["If-Match"] = eTag;
|
||||
// as per documentation, a permanentDelete needs to be a HTTP POST
|
||||
performPermanentDelete(url);
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_post_children
|
||||
JSONValue createById(string parentDriveId, string parentId, JSONValue item) {
|
||||
string url = driveByIdUrl ~ parentDriveId ~ "/items/" ~ parentId ~ "/children";
|
||||
|
|
@ -962,6 +972,14 @@ class OneDriveApi {
|
|||
}, validateJSONResponse, callingFunction, lineno);
|
||||
}
|
||||
|
||||
private void performPermanentDelete(const(char)[] url, string[string] requestHeaders=null, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
|
||||
bool validateJSONResponse = false;
|
||||
oneDriveErrorHandlerWrapper((CurlResponse response) {
|
||||
connect(HTTP.Method.post, url, false, response, requestHeaders);
|
||||
return curlEngine.execute();
|
||||
}, validateJSONResponse, callingFunction, lineno);
|
||||
}
|
||||
|
||||
private void downloadFile(const(char)[] url, string filename, long fileSize, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
|
||||
// Threshold for displaying download bar
|
||||
long thresholdFileSize = 4 * 2^^20; // 4 MiB
|
||||
|
|
|
|||
81
src/sync.d
81
src/sync.d
|
|
@ -170,6 +170,8 @@ class SyncEngine {
|
|||
// Is bypass_data_preservation set via config file
|
||||
// Local data loss MAY occur in this scenario
|
||||
bool bypassDataPreservation = false;
|
||||
// Has the user configured to permanently delete files online rather than send to online recycle bin
|
||||
bool permanentDelete = false;
|
||||
// Maximum file size upload
|
||||
// https://support.microsoft.com/en-us/office/invalid-file-names-and-file-types-in-onedrive-and-sharepoint-64883a5d-228e-48f5-b3d2-eb39e07630fa?ui=en-us&rs=en-us&ad=us
|
||||
// July 2020, maximum file size for all accounts is 100GB
|
||||
|
|
@ -307,8 +309,10 @@ class SyncEngine {
|
|||
// Are we forcing the client to bypass any data preservation techniques to NOT rename any local files if there is a conflict?
|
||||
// The enabling of this function could lead to data loss
|
||||
if (appConfig.getValueBool("bypass_data_preservation")) {
|
||||
addLogEntry();
|
||||
addLogEntry("WARNING: Application has been configured to bypass local data preservation in the event of file conflict.");
|
||||
addLogEntry("WARNING: Local data loss MAY occur in this scenario.");
|
||||
addLogEntry();
|
||||
this.bypassDataPreservation = true;
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +412,46 @@ class SyncEngine {
|
|||
forceExit();
|
||||
}
|
||||
|
||||
// Has the client been configured to permanently delete files online rather than send these to the online recycle bin?
|
||||
if (appConfig.getValueBool("permanent_delete")) {
|
||||
// This can only be set if not using:
|
||||
// - US Government L4
|
||||
// - US Government L5 (DOD)
|
||||
// - Azure and Office365 operated by VNET in China
|
||||
//
|
||||
// Additionally, this is not supported by OneDrive Personal accounts:
|
||||
//
|
||||
// This is a doc bug. In fact, OneDrive personal accounts do not support the permanentDelete API, it only applies to OneDrive for Business and SharePoint document libraries.
|
||||
//
|
||||
// Reference: https://learn.microsoft.com/en-us/answers/questions/1501170/onedrive-permanently-delete-a-file
|
||||
string azureConfigValue = appConfig.getValueString("azure_ad_endpoint");
|
||||
|
||||
// Now that we know the 'accountType' we can configure this correctly
|
||||
if ((appConfig.accountType != "personal") && (azureConfigValue.empty || azureConfigValue == "DE")) {
|
||||
// Only supported for Global Service and DE based on https://learn.microsoft.com/en-us/graph/api/driveitem-permanentdelete?view=graph-rest-1.0
|
||||
addLogEntry();
|
||||
addLogEntry("WARNING: Application has been configured to permanently remove files online rather than send to the recycle bin. Permanently deleted items can't be restored.");
|
||||
addLogEntry("WARNING: Online data loss MAY occur in this scenario.");
|
||||
addLogEntry();
|
||||
this.permanentDelete = true;
|
||||
} else {
|
||||
// what error message do we present
|
||||
if (appConfig.accountType == "personal") {
|
||||
// personal account type - API not supported
|
||||
addLogEntry();
|
||||
addLogEntry("WARNING: The application is configured to permanently delete files online; however, this action is not supported by Microsoft OneDrive Personal Accounts.");
|
||||
addLogEntry();
|
||||
} else {
|
||||
// Not a personal account
|
||||
addLogEntry();
|
||||
addLogEntry("WARNING: The application is configured to permanently delete files online; however, this action is not supported by the National Cloud Deployment in use.");
|
||||
addLogEntry();
|
||||
}
|
||||
// ensure this is false regardless
|
||||
this.permanentDelete = false;
|
||||
}
|
||||
}
|
||||
|
||||
// API was initialised
|
||||
if (verboseLogging) {addLogEntry("Sync Engine Initialised with new Onedrive API instance", ["verbose"]);}
|
||||
return true;
|
||||
|
|
@ -6668,8 +6712,13 @@ class SyncEngine {
|
|||
uploadDeletedItemOneDriveApiInstance = new OneDriveApi(appConfig);
|
||||
uploadDeletedItemOneDriveApiInstance.initialise();
|
||||
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
uploadDeletedItemOneDriveApiInstance.deleteById(actualItemToDelete.driveId, actualItemToDelete.id);
|
||||
if (!permanentDelete) {
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
uploadDeletedItemOneDriveApiInstance.deleteById(actualItemToDelete.driveId, actualItemToDelete.id);
|
||||
} else {
|
||||
// Perform the permanent delete via the default OneDrive API instance
|
||||
uploadDeletedItemOneDriveApiInstance.permanentDeleteById(actualItemToDelete.driveId, actualItemToDelete.id);
|
||||
}
|
||||
|
||||
// OneDrive API Instance Cleanup - Shutdown API, free curl object and memory
|
||||
uploadDeletedItemOneDriveApiInstance.releaseCurlEngine();
|
||||
|
|
@ -6736,16 +6785,27 @@ class SyncEngine {
|
|||
// Log the action
|
||||
if (debugLogging) {addLogEntry("Attempting to delete this child item id: " ~ child.id ~ " from drive: " ~ child.driveId, ["debug"]);}
|
||||
|
||||
// perform the delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.deleteById(child.driveId, child.id, child.eTag);
|
||||
if (!permanentDelete) {
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.deleteById(child.driveId, child.id, child.eTag);
|
||||
} else {
|
||||
// Perform the permanent delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.permanentDeleteById(child.driveId, child.id, child.eTag);
|
||||
}
|
||||
|
||||
// delete the child reference in the local database
|
||||
itemDB.deleteById(child.driveId, child.id);
|
||||
}
|
||||
// Log the action
|
||||
if (debugLogging) {addLogEntry("Attempting to delete this parent item id: " ~ itemToDelete.id ~ " from drive: " ~ itemToDelete.driveId, ["debug"]);}
|
||||
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.deleteById(itemToDelete.driveId, itemToDelete.id, itemToDelete.eTag);
|
||||
if (!permanentDelete) {
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.deleteById(itemToDelete.driveId, itemToDelete.id, itemToDelete.eTag);
|
||||
} else {
|
||||
// Perform the permanent delete via the default OneDrive API instance
|
||||
performReverseDeletionOneDriveApiInstance.permanentDeleteById(itemToDelete.driveId, itemToDelete.id, itemToDelete.eTag);
|
||||
}
|
||||
|
||||
// OneDrive API Instance Cleanup - Shutdown API, free curl object and memory
|
||||
performReverseDeletionOneDriveApiInstance.releaseCurlEngine();
|
||||
|
|
@ -7734,8 +7794,13 @@ class SyncEngine {
|
|||
|
||||
// Try the online deletion
|
||||
try {
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
deleteByPathNoSyncAPIInstance.deleteById(deletionItem.driveId, deletionItem.id);
|
||||
if (!permanentDelete) {
|
||||
// Perform the delete via the default OneDrive API instance
|
||||
deleteByPathNoSyncAPIInstance.deleteById(deletionItem.driveId, deletionItem.id);
|
||||
} else {
|
||||
// Perform the permanent delete via the default OneDrive API instance
|
||||
deleteByPathNoSyncAPIInstance.permanentDeleteById(deletionItem.driveId, deletionItem.id);
|
||||
}
|
||||
// If we get here without error, directory was deleted
|
||||
addLogEntry("The requested directory to delete online has been deleted");
|
||||
} catch (OneDriveException exception) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue