/clientapi/admin/backups (owner decision 2026-10-07, approving these endpoints in production): the list with what runs, the restore waiting and the last restore's report; back up now; delete; a download for the password, through a ticket good for ten minutes in the link's path, as one tar whose length is known first and which honours Range (BackupTar); an upload in pieces of at most 32 MB, each at the offset already received or refused with it, so a broken upload resumes, read into a backup only when it holds nothing but plain files under one backup's folder; and a restore for the password and the host typed out. Every call checks the administrator against the database. nginx streams downloads for an hour and takes upload pieces unbuffered, rate-limited. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
104 lines
3.7 KiB
C#
104 lines
3.7 KiB
C#
using PrivaPub.ClientModels.Resources;
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
namespace PrivaPub.ClientModels.Admin
|
|
{
|
|
// the server's backups as the administrator's page shows them, with what is running and the last restore
|
|
public class ViewBackups
|
|
{
|
|
public List<ViewBackup> Backups { get; set; } = [];
|
|
public string Running { get; set; }//"backup" or "restore" while one runs
|
|
public ViewRestoreWaiting Waiting { get; set; }
|
|
public ViewRestore LastRestore { get; set; }
|
|
public string Host { get; set; }//what a restore asks to be typed
|
|
public long FreeBytes { get; set; }
|
|
}
|
|
|
|
public class ViewBackup
|
|
{
|
|
public string Id { get; set; }
|
|
public string Kind { get; set; }//nightly, manual, pre-deploy, pre-restore, uploaded
|
|
public DateTime CreatedAt { get; set; }
|
|
public long Bytes { get; set; }//the database's files
|
|
public long MediaBytes { get; set; }
|
|
public int MediaFiles { get; set; }
|
|
public int MediaMissing { get; set; }
|
|
public bool DbOnly { get; set; }
|
|
public bool Consistent { get; set; }
|
|
public int Collections { get; set; }
|
|
public long Documents { get; set; }
|
|
public string AppCommit { get; set; }
|
|
public int MigrationNumber { get; set; }
|
|
public int RootsDeletedSince { get; set; }//logins deleted after it, which a restore deletes again
|
|
public string NotRestorable { get; set; }//why not, from its manifest; hashes are checked when asked
|
|
}
|
|
|
|
public class ViewRestoreWaiting
|
|
{
|
|
public string Backup { get; set; }
|
|
public string State { get; set; }
|
|
public int Attempts { get; set; }
|
|
public string RequestedBy { get; set; }
|
|
public DateTime RequestedAt { get; set; }
|
|
public string Error { get; set; }
|
|
}
|
|
|
|
public class ViewRestore
|
|
{
|
|
public string Backup { get; set; }
|
|
public DateTime BackupCreatedAt { get; set; }
|
|
public string PreRestore { get; set; }
|
|
public string RequestedBy { get; set; }
|
|
public DateTime RestoredAt { get; set; }
|
|
public bool Abandoned { get; set; }
|
|
public string Error { get; set; }
|
|
public long Documents { get; set; }
|
|
public int Collections { get; set; }
|
|
public int MediaRestored { get; set; }
|
|
public int MediaMissing { get; set; }
|
|
public int RootsDeleted { get; set; }
|
|
public int PersonasDeleted { get; set; }
|
|
public int GroupsDeleted { get; set; }
|
|
public int PostsDeleted { get; set; }
|
|
public List<string> RootsTombstoned { get; set; } = [];
|
|
public List<string> PersonasTombstoned { get; set; } = [];
|
|
public List<string> GroupsTombstoned { get; set; } = [];
|
|
public int PostsGone { get; set; }
|
|
public int MediaTrashed { get; set; }
|
|
public int ProtectiveKept { get; set; }
|
|
public int SessionsEnded { get; set; }
|
|
}
|
|
|
|
// a backup downloaded or restored: the administrator's password again, and for a restore the server's host typed out
|
|
public class BackupPasswordForm
|
|
{
|
|
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
|
|
StringLength(200, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
|
|
public string Password { get; set; }
|
|
}
|
|
|
|
public class RestoreBackupForm : BackupPasswordForm
|
|
{
|
|
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
|
|
StringLength(253, ErrorMessageResourceName = "MaxLengthString", ErrorMessageResourceType = typeof(ErrorsResource))]
|
|
public string Host { get; set; }
|
|
}
|
|
|
|
// a download link good for a while, for one backup
|
|
public class ViewBackupTicket
|
|
{
|
|
public string Url { get; set; }
|
|
public DateTime ExpiresAt { get; set; }
|
|
public long Bytes { get; set; }
|
|
}
|
|
|
|
// a backup being uploaded in pieces: how much has arrived
|
|
public class ViewBackupUpload
|
|
{
|
|
public string Id { get; set; }
|
|
public long Received { get; set; }
|
|
public long ChunkBytes { get; set; }//the largest piece accepted
|
|
}
|
|
}
|