turned on backups

ported over the backup functionality from the old build to the new while
making  few tweaks

instead of packaging up all files in the site to create massive zip
files, now a list of files is created for the user and blog directories
that the system will use to download and put them in the appropriate
directories, resulting in a such slimmer backup file.

archiving images my be added at a later date, but will be kept seperate
from the current back up process
This commit is contained in:
ro 2024-04-05 12:29:38 -06:00
parent 1f62e6f816
commit f8005aa60d
No known key found for this signature in database
GPG key ID: 29B551CDBD4D3B50
8 changed files with 138 additions and 9 deletions

View file

@ -6,16 +6,26 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\SettingsService; use App\Services\SettingsService;
use App\Services\RenderService; use App\Services\RenderService;
use App\Services\MaintenanceService;
use App\Services\AuthService;
class SettingsAPIController extends Controller class SettingsAPIController extends Controller
{ {
protected $settings; protected $settings;
protected $render; protected $render;
protected $mainteance;
protected $auth;
public function __construct(SettingsService $settingsService, RenderService $renderService) public function __construct(
{ SettingsService $settingsService,
$this->settings = $settingsService; RenderService $renderService,
$this->render = $renderService; MaintenanceService $maintenanceService,
AuthService $authService
) {
$this->settings = $settingsService;
$this->render = $renderService;
$this->maintenance = $maintenanceService;
$this->auth = $authService;
} }
public function publish(Request $request) public function publish(Request $request)
@ -37,4 +47,18 @@ class SettingsAPIController extends Controller
$result = $this->settings->navSync($body); $result = $this->settings->navSync($body);
return response()->json($result)->header('Content-Type', 'application/json'); return response()->json($result)->header('Content-Type', 'application/json');
} }
public function createBackup(Request $request)
{
return response()->json($this->maintenance->createBackup())->header('Content-Type', 'application/json');
}
public function downloadBackup(Request $request)
{
if ($this->auth::status()) {
$latest = $this->settings->getGlobal()['last_backup'];
$file = 'backup-' . $latest . '.zip';
return response()->download('../content/backups/' . $file, $file, ['Content-Type: application/zip']);
}
}
} }

View file

@ -15,6 +15,7 @@ use App\Services\FileUploadService;
use App\Services\RenderService; use App\Services\RenderService;
use App\Services\SortingService; use App\Services\SortingService;
use App\Services\AssetService; use App\Services\AssetService;
use App\Services\MaintenanceService;
class FipamoServiceProvider extends ServiceProvider class FipamoServiceProvider extends ServiceProvider
{ {
@ -79,6 +80,12 @@ class FipamoServiceProvider extends ServiceProvider
) )
); );
}); });
$this->app->bind(MaintenanceService::class, function ($app) {
return new MaintenanceService(
new SettingsService(new DocService(), new ContentService())
);
});
} }
/** /**

View file

@ -0,0 +1,96 @@
<?php
namespace App\Services;
use Carbon\Carbon;
class MaintenanceService
{
protected $settings;
public function __construct(SettingsService $settingsService)
{
$this->settings = $settingsService;
}
public function createBackUp()
{
//make sure back directory is there
$stamp = Carbon::now()->format("YmdGis");
if (!is_dir('../content/backups')) {
mkdir('../content/backups', 0755, true);
}
//creat backup zip
$zip = new \ZipArchive();
$zip->open(
'../content/backups/backup-' . $stamp . '.zip',
\ZipArchive::CREATE | \ZipArchive::OVERWRITE
);
//gather data and path info for md pages
$pagePath = '../content/pages';
$yearPaths = glob($pagePath . '/*', GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode('/', $years);
//grap the index and save it
if (trim($year[3]) == 'start') {
$options = [
'add_path' => 'content/pages/' . $year[3] . '/',
'remove_all_path' => true,
];
$zip->addGlob($years . '/*.md', GLOB_BRACE, $options);
}
$monthsPath = glob($pagePath . '/' . $year[3] . '/*', GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode('/', $months);
//once info is collected, add md pages to zip
$options = [
'add_path' => 'content/pages/' . $year[3] . '/' . $month[4] . '/',
'remove_all_path' => true,
];
$zip->addGlob($months . '/*.md', GLOB_BRACE, $options);
}
}
//gather paths for blog images
$blogImages = [];
$dir = new \RecursiveDirectoryIterator('../public/assets/images/blog');
$flat = new \RecursiveIteratorIterator($dir);
$files = new \RegexIterator($flat, '/\.png|jpg|gif$/i');
foreach ($files as $file) {
$blogImages[] = ['path' => $file->getPath(), 'file' => $file->getFilename()];
};
//gather paths for user images
$userImages = [];
$dir = new \RecursiveDirectoryIterator('../public/assets/images/user');
$flat = new \RecursiveIteratorIterator($dir);
$files = new \RegexIterator($flat, '/\.png|jpg|gif$/i');
foreach ($files as $file) {
$userImages[] = ['path' => $file->getPath(), 'file' => $file->getFilename()];
};
//add directory for settings and save them
$zip->addEmptyDir('config');
$zip->addEmptyDir('images');
$zip->addFile(env('SETTINGS_PATH'), 'config/settings.json');
$zip->addFile(env('FOLKS_PATH'), 'config/folks.json');
$zip->addFile(env('TAGS_PATH'), 'config/tags.json');
// create temp files for image lists
file_put_contents('../content/backups/blog_temp.json', json_encode($blogImages));
file_put_contents('../content/backups/user_temp.json', json_encode($userImages));
//add to zip
$zip->addFile('../content/backups/blog_temp.json', 'images/blog.json');
$zip->addFile('../content/backups/user_temp.json', 'images/user.json');
//save zip file
$zip->close();
//clean up temp files
unlink('../content/backups/blog_temp.json');
unlink('../content/backups/user_temp.json');
//update settings file with latest back up date
$this->settings->updateGlobalData('last_backup', $stamp);
return ['message' => "Backup created. THIS IS A SAFE SPACE!"];
}
}

View file

@ -70,7 +70,7 @@ class SettingsService
public function updateGlobalData($key, $value) public function updateGlobalData($key, $value)
{ {
$this->settings = $this->loadSettings(); $this->settings = $this->loadSettings();
$this->settings['global'][$key] = $data; $this->settings['global'][$key] = $value;
$this->docs->writeSettings($this->settings); $this->docs->writeSettings($this->settings);
} }

View file

@ -274,7 +274,7 @@ class SortingService
'siteTitle' => $global['title'], 'siteTitle' => $global['title'],
'baseUrl' => $global['base_url'], 'baseUrl' => $global['base_url'],
'desc' => $global['descriptions'], 'desc' => $global['descriptions'],
'lastBackup' => $updated->format('Y M D d'), 'lastBackup' => $updated->format('Y M D G i s'),
'currentTheme' => $global['theme'], 'currentTheme' => $global['theme'],
'themes' => $this->themes->getThemes(), 'themes' => $this->themes->getThemes(),
'apiStatus' => isset($global['externalAPI']) ? $global['externalAPI'] : 'false', 'apiStatus' => isset($global['externalAPI']) ? $global['externalAPI'] : 'false',

View file

@ -12,7 +12,7 @@ export const API_INIT = '/api/v1/init';
export const API_RESTORE = '/api/v1/restore'; export const API_RESTORE = '/api/v1/restore';
export const API_GET_SECRET = '/api/v1/get-secret'; export const API_GET_SECRET = '/api/v1/get-secret';
export const API_RESET_PASS = '/api/v1/reset-password'; export const API_RESET_PASS = '/api/v1/reset-password';
export const API_CREATE_BACKUP = '/api/v1/backup'; export const API_CREATE_BACKUP = '/api/v1/backup/create';
export const API_DOWNLOAD_BACKUP = '/api/v1/backup/download'; export const API_DOWNLOAD_BACKUP = '/api/v1/backup/download';
export const API_RESTORE_BACKUP = '/api/v1/backup/restore'; export const API_RESTORE_BACKUP = '/api/v1/backup/restore';
export const API_UPLOAD_AVATAR = '/api/v1/settings/add-avatar'; export const API_UPLOAD_AVATAR = '/api/v1/settings/add-avatar';
@ -133,7 +133,7 @@ class MaintenanceManager {
url = API_CREATE_BACKUP; url = API_CREATE_BACKUP;
event = TASK_BACKUP_CREATE; event = TASK_BACKUP_CREATE;
method = REQUEST_TYPE_POST; method = REQUEST_TYPE_PUT;
type = CONTENT_TYPE_JSON; type = CONTENT_TYPE_JSON;
data = { task: 'create_backup' }; data = { task: 'create_backup' };
this._request(url, null, event, method, type, data) this._request(url, null, event, method, type, data)

View file

@ -30,7 +30,7 @@
</button><br/> </button><br/>
@if($lastBackup != '') @if($lastBackup != '')
LAST BACK UP<br/> LAST BACK UP<br/>
<a href="/api/v1/files">{{ $lastBackup }}</a><br/> <a href="/api/v1/backup/download">{{ $lastBackup }}</a><br/>
@else @else
<span>span No back ups. Frowny face.</span> <span>span No back ups. Frowny face.</span>
@endif @endif

View file

@ -28,3 +28,5 @@ Route::post("/v1/files", [FileUploadAPIController::class, 'upload']);
Route::put("/v1/settings/publish", [SettingsAPIController::class, 'publish']); Route::put("/v1/settings/publish", [SettingsAPIController::class, 'publish']);
Route::put("/v1/settings/sync", [SettingsAPIController::class, 'sync']); Route::put("/v1/settings/sync", [SettingsAPIController::class, 'sync']);
Route::put("/v1/settings/nav-sync", [SettingsAPIController::class, 'navSync']); Route::put("/v1/settings/nav-sync", [SettingsAPIController::class, 'navSync']);
Route::put("/v1/backup/create", [SettingsAPIController::class, 'createBackup']);
Route::get("/v1/backup/download", [SettingsAPIController::class, 'downloadBackup']);