Files
duplicati/proprietary/Office365/RestoreProvider/RestoreProvider.Site.cs
T

94 lines
3.5 KiB
C#

// Copyright (c) 2026 Duplicati Inc. All rights reserved.
using Duplicati.Library.Logging;
using Duplicati.Proprietary.Office365.SourceItems;
namespace Duplicati.Proprietary.Office365;
partial class RestoreProvider
{
internal SiteApiImpl SiteApi => new SiteApiImpl(_apiHelper);
internal class SiteApiImpl(APIHelper provider)
{
internal IAsyncEnumerable<GraphDrive> ListSiteDrivesAsync(string siteId, CancellationToken ct)
{
var baseUrl = provider.GraphBaseUrl.TrimEnd('/');
var select = GraphSelectBuilder.BuildSelect<GraphDrive>();
var site = Uri.EscapeDataString(siteId);
var url =
$"{baseUrl}/v1.0/sites/{site}/drives" +
$"?$select={Uri.EscapeDataString(select)}" +
$"&$top={APIHelper.GENERAL_PAGE_SIZE}";
return provider.GetAllGraphItemsAsync<GraphDrive>(url, ct);
}
}
private async Task RestoreSiteDrives(CancellationToken cancel)
{
if (RestoreTarget == null)
throw new InvalidOperationException("Restore target entry is not set");
// Only proceed if we are restoring to a Site
if (RestoreTarget.Type != SourceItemType.Site)
return;
var driveSources = GetMetadataByType(SourceItemType.Drive);
if (driveSources.Count == 0)
return;
var targetSiteId = RestoreTarget.Metadata.GetValueOrDefault("o365:Id");
if (string.IsNullOrWhiteSpace(targetSiteId))
{
Log.WriteWarningMessage(LOGTAG, "RestoreSiteDrivesMissingId", null, "Target site ID is missing, cannot restore site drives.");
return;
}
try
{
// List existing drives on the target site
var targetDrives = new List<GraphDrive>();
await foreach (var drive in SiteApi.ListSiteDrivesAsync(targetSiteId, cancel))
{
targetDrives.Add(drive);
}
foreach (var driveSource in driveSources)
{
var metadata = driveSource.Value;
var sourceName = metadata.GetValueOrDefault("o365:Name");
if (string.IsNullOrWhiteSpace(sourceName))
{
// Fallback to using the last part of the path if name is missing
sourceName = Path.GetFileName(driveSource.Key.TrimEnd(Path.DirectorySeparatorChar));
}
// Try to match by name
var match = targetDrives.FirstOrDefault(d =>
string.Equals(d.Name, sourceName, StringComparison.OrdinalIgnoreCase));
// Also try to match by "Documents" if source is "Documents" but target might be named differently in URL but same display name?
// Or if source is "Shared Documents" and target is "Documents" (common in SharePoint).
// But let's stick to exact name match for now.
if (match != null)
{
_restoredDriveMap[driveSource.Key] = match.Id;
}
else
{
Log.WriteWarningMessage(LOGTAG, "RestoreSiteDrivesNoMatch", null, $"Could not find matching drive for '{sourceName}' in target site. Creating new document libraries is not yet supported.");
}
}
}
catch (Exception ex)
{
Log.WriteErrorMessage(LOGTAG, "RestoreSiteDrivesFailed", ex, $"Failed to restore site drives");
}
}
}