From 43962c4a5ae07b333f3ca4e2bc37c4ff84b31698 Mon Sep 17 00:00:00 2001 From: Girish Ramakrishnan Date: Mon, 6 Oct 2025 14:10:29 +0200 Subject: [PATCH] add route to list backups by site --- src/backups.js | 13 +++++++++++++ src/routes/backupsites.js | 16 ++++++++++++++++ src/routes/test/backups-test.js | 9 +++++++++ src/routes/test/backupsites-test.js | 9 +++++++++ src/server.js | 1 + 5 files changed, 48 insertions(+) diff --git a/src/backups.js b/src/backups.js index 082c454a5..13063ec03 100644 --- a/src/backups.js +++ b/src/backups.js @@ -9,6 +9,7 @@ exports = module.exports = { update, setState, list, + listBySiteId, del, removePrivateFields, @@ -195,6 +196,18 @@ async function list(page, perPage) { return results; } +async function listBySiteId(siteId, page, perPage) { + assert.strictEqual(typeof siteId, 'string'); + assert(typeof page === 'number' && page > 0); + assert(typeof perPage === 'number' && perPage > 0); + + const results = await database.query(`SELECT ${BACKUPS_FIELDS} FROM backups WHERE siteId=? ORDER BY creationTime DESC LIMIT ?,?`, [ siteId, (page-1)*perPage, perPage ]); + + results.forEach(function (result) { postProcess(result); }); + + return results; +} + async function del(id) { assert.strictEqual(typeof id, 'string'); diff --git a/src/routes/backupsites.js b/src/routes/backupsites.js index 245956dfe..d7b9902dd 100644 --- a/src/routes/backupsites.js +++ b/src/routes/backupsites.js @@ -18,6 +18,7 @@ exports = module.exports = { setContents, setEncryption, + listBackups, createBackup, cleanup, remount, @@ -26,6 +27,7 @@ exports = module.exports = { const assert = require('node:assert'), AuditSource = require('../auditsource.js'), + backups = require('../backups.js'), backupSites = require('../backupsites.js'), BoxError = require('../boxerror.js'), HttpError = require('@cloudron/connect-lastmile').HttpError, @@ -254,3 +256,17 @@ async function getStatus(req, res, next) { if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, mountStatus)); } + +async function listBackups(req, res, next) { + assert.strictEqual(typeof req.resources.backupSite, 'object'); + + const page = typeof req.query.page === 'string' ? parseInt(req.query.page) : 1; + if (!page || page < 0) return next(new HttpError(400, 'page query param has to be a postive number')); + + const perPage = typeof req.query.per_page === 'string'? parseInt(req.query.per_page) : 25; + if (!perPage || perPage < 0) return next(new HttpError(400, 'per_page query param has to be a postive number')); + + const [error, results] = await safe(backups.listBySiteId(req.resources.backupSite.id, page, perPage)); + if (error) return next(BoxError.toHttpError(error)); + next(new HttpSuccess(200, { backups: results })); +} diff --git a/src/routes/test/backups-test.js b/src/routes/test/backups-test.js index afc5f88ec..b4800afb5 100644 --- a/src/routes/test/backups-test.js +++ b/src/routes/test/backups-test.js @@ -32,6 +32,15 @@ describe('Backups API', function () { someBackup = response.body.backups[0]; }); + it('can list by site id', async function () { + const site = await getDefaultBackupSite(); + const response = await superagent.get(`${serverUrl}/api/v1/backup_sites/${site.id}/backups`) + .query({ access_token: admin.token }); + expect(response.status).to.equal(200); + expect(response.body.backups.length).to.be(1); + }); + + it('cannot get random id', async function () { const response = await superagent.get(`${serverUrl}/api/v1/backups/bad_id`) .query({ access_token: owner.token }) diff --git a/src/routes/test/backupsites-test.js b/src/routes/test/backupsites-test.js index 08e76d104..d12720333 100644 --- a/src/routes/test/backupsites-test.js +++ b/src/routes/test/backupsites-test.js @@ -364,4 +364,13 @@ describe('Backups API', function () { await waitForTask(response.body.taskId); }); }); + + describe('listBySiteId', async function () { + it('succeeds', async function () { + const response = await superagent.get(`${serverUrl}/api/v1/backup_sites/${newSite.id}/backups`) + .query({ access_token: admin.token }); + expect(response.status).to.equal(200); + expect(response.body.backups).to.be.an(Array); + }); + }); }); diff --git a/src/server.js b/src/server.js index 6d348d468..6a891288d 100644 --- a/src/server.js +++ b/src/server.js @@ -163,6 +163,7 @@ async function initializeExpressSync() { router.post('/api/v1/backup_sites', json, token, authorizeOwner, routes.backupSites.add); router.del ('/api/v1/backup_sites/:id', token, authorizeOwner, routes.backupSites.load, routes.backupSites.del); router.get ('/api/v1/backup_sites/:id/status', token, authorizeAdmin, routes.backupSites.load, routes.backupSites.getStatus); + router.get ('/api/v1/backup_sites/:id/backups', token, authorizeAdmin, routes.backupSites.load, routes.backupSites.listBackups); router.post('/api/v1/backup_sites/:id/create_backup', token, authorizeAdmin, routes.backupSites.load, routes.backupSites.createBackup); router.post('/api/v1/backup_sites/:id/cleanup', json, token, authorizeAdmin, routes.backupSites.load, routes.backupSites.cleanup); router.post('/api/v1/backup_sites/:id/remount', json, token, authorizeAdmin, routes.backupSites.load, routes.backupSites.remount);