Added simple sorting support to backend

This commit is contained in:
Kenneth Skovhede
2025-03-26 15:58:06 +01:00
parent ddbf0eac56
commit 2b06faaf4f
2 changed files with 85 additions and 5 deletions
@@ -73,6 +73,7 @@ namespace Duplicati.Server.Database
public const string PAUSED_UNTIL = "paused-until";
public const string LAST_UPDATE_CHECK_VERSION = "last-update-check-version";
public const string ADDITIONAL_REPORT_URL = "additional-report-url";
public const string BACKUP_LIST_SORT_ORDER = "backup-list-sort-order";
}
private readonly Dictionary<string, string?> settings;
@@ -874,6 +875,21 @@ namespace Duplicati.Server.Database
SaveSettings();
}
}
public string? BackupListSortOrder
{
get
{
return settings[CONST.BACKUP_LIST_SORT_ORDER];
}
set
{
lock (databaseConnection.m_lock)
settings[CONST.BACKUP_LIST_SORT_ORDER] = value;
SaveSettings();
}
}
}
}
@@ -30,8 +30,8 @@ public class Backups : IEndpointV1
{
public static void Map(RouteGroupBuilder group)
{
group.MapGet("/backups", ([FromServices] Connection connection)
=> ExecuteGet(connection))
group.MapGet("/backups", ([FromServices] Connection connection, [FromQuery] string? sort = null)
=> ExecuteGet(connection, sort))
.RequireAuthorization();
group.MapPost("/backups", ([FromServices] Connection connection, [FromBody] Dto.BackupAndScheduleInputDto input, [FromQuery] bool? temporary, [FromQuery] bool? existingdb)
@@ -48,10 +48,62 @@ public class Backups : IEndpointV1
}).RequireAuthorization();
}
private static IEnumerable<Dto.BackupAndScheduleOutputDto> ExecuteGet(Connection connection)
private static IEnumerable<Dto.BackupAndScheduleOutputDto> ExecuteGet(Connection connection, string? sort)
{
var schedules = connection.Schedules;
var backups = connection.Backups;
var backups = connection.Backups.AsEnumerable();
IEnumerable<Dto.BackupAndScheduleOutputDto> ApplySorting(IEnumerable<Dto.BackupAndScheduleOutputDto> backups, string sort)
{
var asc = true;
if (sort.StartsWith("-"))
{
asc = false;
sort = sort.Substring(1);
}
else if (sort.StartsWith("+"))
{
asc = true;
sort = sort.Substring(1);
}
Func<Dto.BackupAndScheduleOutputDto, object?>? selector = sort switch
{
"name" => x => x.Backup.Name,
"id" => x => x.Backup.ID,
"lastrun" => x =>
{
if (x.Backup.Metadata == null)
return null;
x.Backup.Metadata.TryGetValue("LastSuccessfulRun", out var res);
return res;
}
,
"nextrun" => x => x.Schedule?.Time,
"schedule" => x => string.IsNullOrWhiteSpace(x.Schedule?.Repeat),
"destination" => x => Library.Utility.Utility.GuessScheme(x.Backup.TargetURL),
_ => null
};
// Ignore unknown sort fields
if (selector != null)
{
if (backups is IOrderedEnumerable<Dto.BackupAndScheduleOutputDto> backupsOrdered)
{
return asc
? backupsOrdered.ThenBy(selector)
: backupsOrdered.ThenByDescending(selector);
}
else
{
return asc
? backups.OrderBy(selector)
: backups.OrderByDescending(selector);
}
}
return backups;
}
var all = backups.Select(n => new
{
@@ -60,7 +112,7 @@ public class Backups : IEndpointV1
Schedule = schedules.FirstOrDefault(x => x.Tags != null && x.Tags.Contains("ID=" + n.ID))
});
return all.Select(x => new Dto.BackupAndScheduleOutputDto()
var res = all.Select(x => new Dto.BackupAndScheduleOutputDto()
{
Backup = new Dto.BackupDto()
{
@@ -99,7 +151,19 @@ public class Backups : IEndpointV1
AllowedDays = x.Schedule.AllowedDays
}
});
// Use DB setting if not set
if (string.IsNullOrWhiteSpace(sort))
sort = connection.ApplicationSettings.BackupListSortOrder;
// Apply sorting, if any
if (!string.IsNullOrWhiteSpace(sort))
foreach (var direction in sort.Split(","))
res = ApplySorting(res, direction);
return res;
}
private static Dto.ImportBackupOutputDto ExecuteImport(Connection connection, bool cmdline, bool import_metadata, bool direct, string passphrase, string tempfile)
{
try