backups.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. declare(strict_types=1);
  3. require_once __DIR__ . "/../includes/auth.php";
  4. require_once __DIR__ . "/../includes/layout.php";
  5. require_once __DIR__ . "/../includes/backups.php";
  6. manageRequireLogin();
  7. $messages = [];
  8. $errors = [];
  9. if (($_SERVER["REQUEST_METHOD"] ?? "") === "POST") {
  10. try {
  11. manageRequireCsrf();
  12. $action = (string) ($_POST["action"] ?? "");
  13. $instance = trim((string) ($_POST["instance"] ?? ""));
  14. $filename = trim((string) ($_POST["filename"] ?? ""));
  15. if ($action === "download") {
  16. // Sends headers and exits on success.
  17. manageBackupSendDownload($instance, $filename);
  18. } elseif ($action === "delete") {
  19. manageBackupDelete($instance, $filename);
  20. $messages[] = "Backup " . $filename . " wurde gelöscht.";
  21. } elseif ($action === "s3_sync") {
  22. $result = manageBackupSyncAllS3();
  23. if ($result["error"] !== null) {
  24. $errors[] = "S3-Sync abgebrochen: " . $result["error"];
  25. }
  26. $messages[] = "S3-Sync: " . $result["uploaded"] . " hochgeladen, " . $result["pending"] . " offen.";
  27. }
  28. } catch (Throwable $exception) {
  29. $errors[] = $exception->getMessage();
  30. }
  31. }
  32. try {
  33. $grouped = manageBackupGroupByInstance();
  34. $settings = manageBackupSettings();
  35. $registered = [];
  36. foreach (manageInstanceList() as $instance) {
  37. $registered[$instance["id"]] = $instance;
  38. }
  39. } catch (Throwable $exception) {
  40. $grouped = [];
  41. $settings = ["retention" => 0, "s3_retention" => 0];
  42. $registered = [];
  43. $errors[] = $exception->getMessage();
  44. }
  45. manageRenderHeader("Backups", $messages, $errors);
  46. ?>
  47. <section class="cards">
  48. <div class="card">
  49. <p class="card-label">Lokale Aufbewahrung</p>
  50. <p class="card-value"><?php echo (int) $settings["retention"]; ?></p>
  51. <p class="card-hint">pro Instanz</p>
  52. </div>
  53. <div class="card">
  54. <p class="card-label">S3-Aufbewahrung</p>
  55. <p class="card-value"><?php echo manageS3Enabled() ? (int) $settings["s3_retention"] : "–"; ?></p>
  56. <p class="card-hint"><?php echo manageS3Enabled() ? "pro Instanz" : "S3 ist deaktiviert"; ?></p>
  57. </div>
  58. <div class="card">
  59. <p class="card-label">Instanzen mit Backups</p>
  60. <p class="card-value"><?php echo count($grouped); ?></p>
  61. </div>
  62. </section>
  63. <?php if (manageS3Enabled()): ?>
  64. <form method="POST" class="inline-form">
  65. <?php echo manageCsrfField(); ?>
  66. <input type="hidden" name="action" value="s3_sync">
  67. <button type="submit" class="btn btn-secondary">S3-Uploads jetzt nachholen</button>
  68. <span class="hint">Lädt alle lokal vorhandenen Backups hoch, die noch nicht im Bucket bestätigt sind.</span>
  69. </form>
  70. <?php endif; ?>
  71. <?php if ($grouped === []): ?>
  72. <p class="empty">Es wurden noch keine Backups empfangen.</p>
  73. <?php else: ?>
  74. <?php foreach ($grouped as $instanceId => $backups): ?>
  75. <section class="panel" id="<?php echo manageEscape($instanceId); ?>">
  76. <div class="panel-head">
  77. <h2><?php echo manageEscape($instanceId); ?></h2>
  78. <?php if (!isset($registered[$instanceId])): ?>
  79. <span class="badge badge-warn">nicht mehr registriert</span>
  80. <?php elseif (!$registered[$instanceId]["enabled"]): ?>
  81. <span class="badge badge-error">deaktiviert</span>
  82. <?php endif; ?>
  83. <span class="muted"><?php echo count($backups); ?> Backup(s)</span>
  84. </div>
  85. <div class="table-scroll">
  86. <table class="data-table">
  87. <thead>
  88. <tr>
  89. <th>Datei</th>
  90. <th>Empfangen</th>
  91. <th>Größe</th>
  92. <th>Auslöser</th>
  93. <th>Version</th>
  94. <th>Speicherort</th>
  95. <th>Aktionen</th>
  96. </tr>
  97. </thead>
  98. <tbody>
  99. <?php foreach ($backups as $backup): ?>
  100. <?php $filename = (string) ($backup["filename"] ?? ""); ?>
  101. <tr>
  102. <td>
  103. <code><?php echo manageEscape($filename); ?></code>
  104. <?php if (!empty($backup["s3_last_error"])): ?>
  105. <br><span class="badge badge-error">S3-Fehler</span>
  106. <span class="muted"><?php echo manageEscape($backup["s3_last_error"]); ?></span>
  107. <?php endif; ?>
  108. </td>
  109. <td><?php echo manageEscape($backup["uploaded_at"] ?? ""); ?></td>
  110. <td><?php echo manageEscape(manageFormatBytes((int) ($backup["size"] ?? 0))); ?></td>
  111. <td><?php echo manageEscape($backup["trigger"] !== "" ? ($backup["trigger"] ?? "") : "–"); ?></td>
  112. <td><?php echo manageEscape(($backup["app_version"] ?? "") !== "" ? $backup["app_version"] : "–"); ?></td>
  113. <td><?php echo manageEscape(manageBackupStorageLabel($backup)); ?></td>
  114. <td>
  115. <div class="button-row">
  116. <form method="POST">
  117. <?php echo manageCsrfField(); ?>
  118. <input type="hidden" name="action" value="download">
  119. <input type="hidden" name="instance" value="<?php echo manageEscape($instanceId); ?>">
  120. <input type="hidden" name="filename" value="<?php echo manageEscape($filename); ?>">
  121. <button type="submit" class="btn btn-secondary">Herunterladen</button>
  122. </form>
  123. <form method="POST" onsubmit="return confirm('Dieses Backup endgültig löschen?');">
  124. <?php echo manageCsrfField(); ?>
  125. <input type="hidden" name="action" value="delete">
  126. <input type="hidden" name="instance" value="<?php echo manageEscape($instanceId); ?>">
  127. <input type="hidden" name="filename" value="<?php echo manageEscape($filename); ?>">
  128. <button type="submit" class="btn btn-danger">Löschen</button>
  129. </form>
  130. </div>
  131. </td>
  132. </tr>
  133. <?php endforeach; ?>
  134. </tbody>
  135. </table>
  136. </div>
  137. </section>
  138. <?php endforeach; ?>
  139. <?php endif; ?>
  140. <?php manageRenderFooter(); ?>