feat: add app backup functionality for admins

This commit is contained in:
jeremy bayse
2026-03-28 07:59:17 +01:00
parent 03006051a9
commit 7d94be7a8c
3 changed files with 62 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use ZipArchive;
class BackupController extends Controller
{
public function download()
{
$databaseName = env('DB_DATABASE');
$userName = env('DB_USERNAME');
$password = env('DB_PASSWORD');
$host = env('DB_HOST', '127.0.0.1');
$backupFileName = 'backup_quizzcabm_' . date('Y-m-d_H-i-s') . '.zip';
$backupFilePath = storage_path('app/' . $backupFileName);
$sqlDumpFilePath = storage_path('app/dump.sql');
// Execute mysqldump
$command = "mysqldump --user={$userName} --password={$password} --host={$host} {$databaseName} > " . escapeshellarg($sqlDumpFilePath);
if (empty($password)) {
$command = "mysqldump --user={$userName} --host={$host} {$databaseName} > " . escapeshellarg($sqlDumpFilePath);
}
exec($command);
$zip = new ZipArchive;
if ($zip->open($backupFilePath, ZipArchive::CREATE) === TRUE) {
// Add DB dump
if (file_exists($sqlDumpFilePath)) {
$zip->addFile($sqlDumpFilePath, 'database.sql');
}
// Add documents specifically searching the local disk
$allFiles = Storage::disk('local')->allFiles();
foreach ($allFiles as $filePath) {
$fullPath = Storage::disk('local')->path($filePath);
// The zip structure will have a folder 'storage_files' containing the relative path
$zip->addFile($fullPath, 'storage_files/' . $filePath);
}
$zip->close();
}
if (file_exists($sqlDumpFilePath)) {
unlink($sqlDumpFilePath);
}
if (file_exists($backupFilePath)) {
return response()->download($backupFilePath)->deleteFileAfterSend(true);
}
return back()->with('error', 'Erreur lors de la création de la sauvegarde.');
}
}

View File

@@ -115,6 +115,7 @@ const isSidebarOpen = ref(true);
</template>
<template #content>
<DropdownLink :href="route('profile.edit')">Profil</DropdownLink>
<DropdownLink :href="route('admin.backup')" as="a">Sauvegarde App</DropdownLink>
<DropdownLink :href="route('logout')" method="post" as="button">Déconnexion</DropdownLink>
</template>
</Dropdown>

View File

@@ -83,6 +83,7 @@ Route::middleware('auth')->group(function () {
Route::resource('quizzes', \App\Http\Controllers\QuizController::class)->only(['index', 'store', 'show', 'update', 'destroy']);
Route::resource('job-positions', \App\Http\Controllers\JobPositionController::class)->only(['index', 'store', 'update', 'destroy']);
Route::resource('quizzes.questions', \App\Http\Controllers\QuestionController::class)->only(['store', 'update', 'destroy']);
Route::get('/backup', [\App\Http\Controllers\BackupController::class, 'download'])->name('backup');
Route::delete('/attempts/{attempt}', [\App\Http\Controllers\AttemptController::class, 'destroy'])->name('attempts.destroy');
Route::patch('/answers/{answer}/score', [\App\Http\Controllers\AttemptController::class, 'updateAnswerScore'])->name('answers.update-score');
});