forked from projects/fipamo
FEATURE: File Backup
Turned on file backups that grabs uploaded images in the public directory and saves them in a zip so they can be downloaded and archived.
This commit is contained in:
parent
bc7b1fe7ec
commit
4e880092c1
8 changed files with 144 additions and 46 deletions
|
@ -58,15 +58,36 @@ class SettingsAPIController extends Controller
|
|||
|
||||
public function createBackup(Request $request)
|
||||
{
|
||||
return response()->json($this->maintenance->createBackup())->header('Content-Type', 'application/json');
|
||||
$body = json_decode($request->getContent());
|
||||
if ($body->task == 'content_backup') {
|
||||
return response()->json(
|
||||
$this->maintenance->createContentBackUp()
|
||||
)->header('Content-Type', 'application/json');
|
||||
} else {
|
||||
return response()->json(
|
||||
$this->maintenance->createFileBackUp()
|
||||
)->header('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
||||
public function downloadBackup(Request $request)
|
||||
{
|
||||
if ($this->member::status()) {
|
||||
$latest = $this->settings->getGlobal()['last_backup'];
|
||||
$file = 'backup-' . $latest . '.zip';
|
||||
return response()->download('../content/backups/' . $file, $file, ['Content-Type: application/zip']);
|
||||
$latest = '';
|
||||
$file = '';
|
||||
if (explode('/', $request->getRequestUri())[4] == 'content-download') {
|
||||
$latest = $this->settings->getGlobal()['last_content_backup'];
|
||||
$file = 'backup-content-' . $latest . '.zip';
|
||||
} else {
|
||||
$latest = $this->settings->getGlobal()['last_files_backup'];
|
||||
$file = 'backup-files-' . $latest . '.zip';
|
||||
}
|
||||
|
||||
return response()->download(
|
||||
'../content/backups/' . $file,
|
||||
$file,
|
||||
['Content-Type: application/zip']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,8 @@ class SortingService
|
|||
public function settings()
|
||||
{
|
||||
$global = $this->settings->getGlobal();
|
||||
$updated = new Carbon($global['last_backup']);
|
||||
$updatedContent = new Carbon($global['last_content_backup']);
|
||||
$updatedFiles = new Carbon($global['last_files_backup']);
|
||||
$status = session('member') != '' ? true : false;
|
||||
$pageOptions = [
|
||||
'title' => 'Settings',
|
||||
|
@ -279,7 +280,8 @@ class SortingService
|
|||
'siteTitle' => $global['title'],
|
||||
'baseUrl' => $global['base_url'],
|
||||
'desc' => $global['descriptions'],
|
||||
'lastBackup' => $updated->format('Y F d H i s'),
|
||||
'lastContentBackup' => $updatedContent->format('Y F d H i s'),
|
||||
'lastFilesBackup' => $updatedFiles->format('Y F d H i s'),
|
||||
'currentTheme' => $global['theme'],
|
||||
'themes' => $this->themes->getThemes(),
|
||||
'apiStatus' => isset($global['externalAPI']) ? $global['externalAPI'] : 'false',
|
||||
|
|
|
@ -14,7 +14,7 @@ class MaintenanceService
|
|||
$this->settings = $settingsService;
|
||||
}
|
||||
|
||||
public function createBackUp()
|
||||
public function createContentBackUp()
|
||||
{
|
||||
//make sure back directory is there
|
||||
$stamp = Carbon::now()->format("YmdGis");
|
||||
|
@ -25,7 +25,7 @@ class MaintenanceService
|
|||
$zip = new \ZipArchive();
|
||||
|
||||
$zip->open(
|
||||
env('FIPAMO_BACKUPS') . '/backup-' . $stamp . '.zip',
|
||||
env('FIPAMO_BACKUPS') . '/backup-content-' . $stamp . '.zip',
|
||||
\ZipArchive::CREATE | \ZipArchive::OVERWRITE
|
||||
);
|
||||
//gather data and path info for md pages
|
||||
|
@ -63,29 +63,36 @@ class MaintenanceService
|
|||
|
||||
//gather paths for user images
|
||||
$userImages = [];
|
||||
if (is_dir('../public/assets/images/user')) {
|
||||
$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()];
|
||||
};
|
||||
}
|
||||
|
||||
//gather paths for blog documents
|
||||
$blogDocs = [];
|
||||
if (is_dir('../public/assets/docs/blog')) {
|
||||
$dir = new \RecursiveDirectoryIterator('../public/assets/docs/blog');
|
||||
$flat = new \RecursiveIteratorIterator($dir);
|
||||
$files = new \RegexIterator($flat, '/\.txt|pdf|rtf$/i');
|
||||
foreach ($files as $file) {
|
||||
$blogDocs[] = ['path' => $file->getPath(), 'file' => $file->getFilename()];
|
||||
};
|
||||
}
|
||||
|
||||
//gather paths for blog videos
|
||||
$blogVids = [];
|
||||
if (is_dir('../public/assets/video/blog')) {
|
||||
$dir = new \RecursiveDirectoryIterator('../public/assets/video/blog');
|
||||
$flat = new \RecursiveIteratorIterator($dir);
|
||||
$files = new \RegexIterator($flat, '/\.mp4$/i');
|
||||
foreach ($files as $file) {
|
||||
$blogVids[] = ['path' => $file->getPath(), 'file' => $file->getFilename()];
|
||||
};
|
||||
}
|
||||
|
||||
//add directory for settings and save them
|
||||
$zip->addEmptyDir('config');
|
||||
|
@ -112,8 +119,55 @@ class MaintenanceService
|
|||
unlink(env('FIPAMO_BACKUPS') . '/blog_vids_temp.json');
|
||||
|
||||
//update settings file with latest back up date
|
||||
$this->settings->updateGlobalData('last_backup', $stamp);
|
||||
$this->settings->updateGlobalData('last_content_backup', $stamp);
|
||||
|
||||
return ['message' => "Backup created. THIS IS A SAFE SPACE!"];
|
||||
return ['message' => "Content backup created. THIS IS A SAFE SPACE!"];
|
||||
}
|
||||
|
||||
public function createFileBackUp()
|
||||
{
|
||||
$stamp = Carbon::now()->format("YmdGis");
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open(
|
||||
env('FIPAMO_BACKUPS') . '/backup-files-' . $stamp . '.zip',
|
||||
\ZipArchive::CREATE | \ZipArchive::OVERWRITE
|
||||
);
|
||||
//gather data and path info for blog images
|
||||
$blogImagesPath = '../public/assets/images/blog';
|
||||
$yearPaths = glob($blogImagesPath . '/*', GLOB_ONLYDIR);
|
||||
foreach ($yearPaths as $years) {
|
||||
$year = explode('/', $years);
|
||||
$monthsPath = glob($blogImagesPath . '/' . $year[5] . '/*', GLOB_ONLYDIR);
|
||||
foreach ($monthsPath as $months) {
|
||||
$month = explode('/', $months);
|
||||
//once info is collected, add images pages to zip
|
||||
$options = [
|
||||
'add_path' => 'public/assets/images/blog/' . $year[5] . '/' . $month[6] . '/',
|
||||
'remove_all_path' => true,
|
||||
];
|
||||
$zip->addGlob($months . '/*.*', GLOB_BRACE, $options);
|
||||
}
|
||||
}
|
||||
|
||||
//gather data and path info for user images
|
||||
$userImagesPath = '../public/assets/images/user';
|
||||
$yearPaths = glob($userImagesPath . '/*', GLOB_ONLYDIR);
|
||||
foreach ($yearPaths as $years) {
|
||||
$year = explode('/', $years);
|
||||
$monthsPath = glob($userImagesPath . '/' . $year[5] . '/*', GLOB_ONLYDIR);
|
||||
foreach ($monthsPath as $months) {
|
||||
$month = explode('/', $months);
|
||||
//once info is collected, add images pages to zip
|
||||
$options = [
|
||||
'add_path' => 'public/assets/images/user/' . $year[5] . '/' . $month[6] . '/',
|
||||
'remove_all_path' => true,
|
||||
];
|
||||
$zip->addGlob($months . '/*.*', GLOB_BRACE, $options);
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
$this->settings->updateGlobalData('last_files_backup', $stamp);
|
||||
return ['message' => "Files are backed up. Breath Easy!"];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"renderOnSave": "false",
|
||||
"theme": "fipamo-default-v2",
|
||||
"display_limit": 5,
|
||||
"last_backup": null,
|
||||
"last_content_backup": null,
|
||||
"last_file_backup": null,
|
||||
"externalAPI": "false",
|
||||
"dynamicRender": "false"
|
||||
},
|
||||
|
|
|
@ -151,7 +151,7 @@ class MaintenanceManager {
|
|||
* Promise method for creating a zip back up of current site. For local use only.
|
||||
*/
|
||||
|
||||
backup() {
|
||||
backup(backup_task) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var url, event, method, type, data;
|
||||
|
||||
|
@ -159,7 +159,7 @@ class MaintenanceManager {
|
|||
event = TASK_BACKUP_CREATE;
|
||||
method = REQUEST_TYPE_PUT;
|
||||
type = CONTENT_TYPE_JSON;
|
||||
data = { task: 'create_backup' };
|
||||
data = backup_task;
|
||||
this._request(url, null, event, method, type, data)
|
||||
.then(result => {
|
||||
resolve(result);
|
||||
|
|
|
@ -156,7 +156,11 @@ export default class SettingsIndex {
|
|||
}
|
||||
//handle backup from settings
|
||||
document
|
||||
.getElementById('create-backup')
|
||||
.getElementById('create-content-backup')
|
||||
.addEventListener('click', e => this.handleBackup(e));
|
||||
|
||||
document
|
||||
.getElementById('create-file-backup')
|
||||
.addEventListener('click', e => this.handleBackup(e));
|
||||
}
|
||||
//--------------------------
|
||||
|
@ -259,9 +263,19 @@ export default class SettingsIndex {
|
|||
handleBackup(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
notify.alert('Creating backup', null);
|
||||
let id = '';
|
||||
let type = '';
|
||||
|
||||
e.target.id == '' ? (id = e.target.parentNode.id) : (id = e.target.id);
|
||||
if (id == 'create-content-backup') {
|
||||
notify.alert('Creating Content Backup', null);
|
||||
type = { task: 'content_backup' };
|
||||
} else {
|
||||
notify.alert('Creating File Backup', null);
|
||||
type = { task: 'file_backup' };
|
||||
}
|
||||
this.mm
|
||||
.backup()
|
||||
.backup(type)
|
||||
.then(r => {
|
||||
notify.alert(r.message, true);
|
||||
})
|
||||
|
|
|
@ -94,19 +94,18 @@
|
|||
<svg id="nav-menu-icon" class="icon">
|
||||
<use id="nav-menu-icon" xlink:href="/assets/images/global/sprite.svg#entypo-copy"/>
|
||||
</svg>
|
||||
<button id="create-backup">
|
||||
<button id="create-content-backup">
|
||||
<span>CONTENT BACKUP</span>
|
||||
</button>
|
||||
<span>
|
||||
@if($lastBackup != '')
|
||||
LAST BACK UP
|
||||
<a href="/api/v1/backup/download">{{ $lastBackup }}</a><br/>
|
||||
@if($lastContentBackup != '')
|
||||
MOST RECENT:
|
||||
<a href="/api/v1/backup/content-download">{{ $lastContentBackup }}</a><br/>
|
||||
@else
|
||||
<span>span No back ups. Frowny face.</span>
|
||||
@endif
|
||||
<span>
|
||||
</div>
|
||||
<!-- TODO: File Back up option
|
||||
<div class="option-container">
|
||||
<svg id="nav-menu-icon" class="icon">
|
||||
<use id="nav-menu-icon" xlink:href="/assets/images/global/sprite.svg#entypo-images"/>
|
||||
|
@ -114,9 +113,15 @@
|
|||
<button id="create-file-backup">
|
||||
<span>FILE BACKUP</span>
|
||||
</button>
|
||||
<span>COMING SOON</span>
|
||||
<span>
|
||||
@if($lastFilesBackup != '')
|
||||
MOST RECENT:
|
||||
<a href="/api/v1/backup/files-download">{{ $lastFilesBackup }}</a><br/>
|
||||
@else
|
||||
<span>span No back ups. Frowny face.</span>
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
-->
|
||||
<div class="option-container">
|
||||
<svg id="nav-menu-icon" class="icon">
|
||||
<use id="nav-menu-icon" xlink:href="/assets/images/global/sprite.svg#entypo-back-in-time"/>
|
||||
|
@ -124,7 +129,7 @@
|
|||
<button id="reset-to-default">
|
||||
<span>RESET TO DEFAULT</span>
|
||||
</button>
|
||||
<span>Restores site to default state. !CANNOT UNDO!</span>
|
||||
<span>Deletes all content and configs <strong>CANNOT UNDO</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -31,7 +31,8 @@ Route::put("/v1/settings/publish", [SettingsAPIController::class, 'publish']);
|
|||
Route::put("/v1/settings/sync", [SettingsAPIController::class, 'sync']);
|
||||
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']);
|
||||
Route::get("/v1/backup/content-download", [SettingsAPIController::class, 'downloadBackup']);
|
||||
Route::get("/v1/backup/files-download", [SettingsAPIController::class, 'downloadBackup']);
|
||||
//init
|
||||
Route::post("/v1/init", [InitAPIController::class, 'setupFresh']);
|
||||
Route::post("/v1/restore", [InitAPIController::class, 'setupRestore']);
|
||||
|
|
Loading…
Reference in a new issue