diff --git a/README.md b/README.md index d213b4f..d3a20cf 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

- + @@ -18,12 +18,22 @@ > ⚠️ **AVISO CRÍTICO:** Aplicação em estágio inicial de desenvolvimento. Não use em produção — há risco de perda de dados. -Versão atual: **0.0.8** +Versão atual: **0.0.9** --- ## � Changelog +### [0.0.9] — 2026-05-09 + +#### Corrigido +- **Exclusão em cascata de Storage Location não removia arquivos do disco:** ao excluir um Storage Location (que por consequência exclui os profiles vinculados), os arquivos `.tar.gz` e a pasta de cada profile agora são deletados corretamente do disco, da mesma forma que acontece ao excluir um profile individualmente. + +#### Adicionado +- **Crédito do desenvolvedor na aba Sobre:** exibe o texto "Desenvolvido por Alexander Sabino em 2026" ao final da aba Sobre. + +--- + ### [0.0.8] — 2026-05-09 #### Corrigido diff --git a/package.json b/package.json index 6b58b92..d438caf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dockerbackup-app", - "version": "0.0.8", + "version": "0.0.9", "description": "Aplicacao web para backup e restauracao de volumes Docker", "main": "src/server.js", "scripts": { diff --git a/public/index.html b/public/index.html index a441658..ec805c9 100644 --- a/public/index.html +++ b/public/index.html @@ -302,6 +302,7 @@

Carregando changelog...

+

Desenvolvido por Alexander Sabino em 2026

diff --git a/public/styles.css b/public/styles.css index e7c25bc..cf28202 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1203,6 +1203,12 @@ button, input, select { color: var(--text-muted); font-style: italic; } +.about-author { + margin-top: 1.5rem; + font-size: 0.82rem; + color: var(--text-muted); + text-align: center; +} /* --- Modal ----------------------------------------------- */ .modal { diff --git a/src/server.js b/src/server.js index dbbf85e..2c706f8 100644 --- a/src/server.js +++ b/src/server.js @@ -506,7 +506,36 @@ async function main() { app.delete('/api/storage-locations/:id', authMiddleware, async (request, response) => { try { - await store.deleteStorageLocation(request.params.id); + const locationId = request.params.id; + const impact = await store.storageLocationImpact(locationId); + + const slugifyLocal = (value) => value.replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/^-+|-+$/g, '').toLowerCase() || 'item'; + + // Deleta arquivos em disco de cada profile afetado antes de remover do store + for (const profile of impact.profiles) { + const backups = await store.listBackups(profile.id); + const deletedDirs = new Set(); + for (const backup of backups) { + const backupRoot = backup.backupDir; + if (!backupRoot) continue; + for (const container of backup.containers || []) { + if (container.archiveRelativePath) { + await fs.rm(path.join(backupRoot, container.archiveRelativePath), { force: true }); + } + } + if (profile.name) { + deletedDirs.add(path.join(backupRoot, slugifyLocal(profile.name))); + } + } + if (profile.backupDir) { + deletedDirs.add(path.join(profile.backupDir, slugifyLocal(profile.name))); + } + for (const dir of deletedDirs) { + await fs.rm(dir, { recursive: true, force: true }); + } + } + + await store.deleteStorageLocation(locationId); response.status(204).end(); } catch (error) { response.status(500).json({ error: error.message });