Skip to content

Commit

Permalink
Merge pull request #15296 from uberbrady/expose_restore_sanitize
Browse files Browse the repository at this point in the history
Expose the 'sanitize' system for backup restores to the web GUI
  • Loading branch information
snipe authored Aug 22, 2024
2 parents 94300d8 + 738ef44 commit ec0b9b1
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 89 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ DB_PREFIX=null
DB_DUMP_PATH='/usr/bin'
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_SANITIZE_BY_DEFAULT=false


# --------------------------------------------
# OPTIONAL: SSL DATABASE SETTINGS
Expand Down
28 changes: 22 additions & 6 deletions app/Http/Controllers/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,7 @@ public function postUploadBackup(Request $request) : RedirectResponse
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0]
*/
public function postRestore($filename = null) : RedirectResponse
public function postRestore(Request $request, $filename = null): RedirectResponse
{

if (! config('app.lock_passwords')) {
Expand All @@ -1224,13 +1224,29 @@ public function postRestore($filename = null) : RedirectResponse

Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);

// run the restore command
Artisan::call('snipeit:restore',
[
$restore_params = [
'--force' => true,
'--no-progress' => true,
'filename' => storage_path($path).'/'.$filename
]);
'filename' => storage_path($path) . '/' . $filename
];

if ($request->input('clean')) {
Log::debug("Attempting 'clean' - first, guessing prefix...");
Artisan::call('snipeit:restore', [
'--sanitize-guess-prefix' => true,
'filename' => storage_path($path) . '/' . $filename
]);
$guess_prefix_output = Artisan::output();
Log::debug("Sanitize output is: $guess_prefix_output");
list($prefix, $_output) = explode("\n", $guess_prefix_output);
Log::debug("prefix is: '$prefix'");
$restore_params['--sanitize-with-prefix'] = $prefix;
}

// run the restore command
Artisan::call('snipeit:restore',
$restore_params
);

// If it's greater than 300, it probably worked
$output = Artisan::output();
Expand Down
2 changes: 2 additions & 0 deletions config/backup.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,6 @@
],
],

'sanitize_by_default' => env('DB_SANITIZE_BY_DEFAULT', false),

];
103 changes: 32 additions & 71 deletions resources/assets/js/snipeit.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,84 +82,45 @@ pieOptions = {

var baseUrl = $('meta[name="baseUrl"]').attr('content');

(function($, settings) {
var Components = {};
Components.modals = {};
$(function () {

// confirm restore modal
Components.modals.confirmRestore = function() {
var $el = $('table');

var events = {
'click': function(evnt) {
var $context = $(this);
var $restoreConfirmModal = $('#restoreConfirmModal');
var href = $context.attr('href');
var message = $context.attr('data-content');
var title = $context.attr('data-title');

$('#restoreConfirmModalLabel').text(title);
$restoreConfirmModal.find('.modal-body').text(message);
$('#restoreForm').attr('action', href);
$restoreConfirmModal.modal({
show: true
});
return false;
}
};
var $el = $('table');

var render = function() {
$el.on('click', '.restore-asset', events['click']);
};
// confirm restore modal

return {
render: render
};
};
$el.on('click', '.restore-asset', function (evnt) {
var $context = $(this);
var $restoreConfirmModal = $('#restoreConfirmModal');
var href = $context.attr('href');
var message = $context.attr('data-content');
var title = $context.attr('data-title');

$('#confirmModalLabel').text(title);
$restoreConfirmModal.find('.modal-body').text(message);
$('#restoreForm').attr('action', href);
$restoreConfirmModal.modal({
show: true
});
return false;
});

// confirm delete modal
Components.modals.confirmDelete = function() {
var $el = $('table');

var events = {
'click': function(evnt) {
var $context = $(this);
var $dataConfirmModal = $('#dataConfirmModal');
var href = $context.attr('href');
var message = $context.attr('data-content');
var title = $context.attr('data-title');

$('#myModalLabel').text(title);
$dataConfirmModal.find('.modal-body').text(message);
$('#deleteForm').attr('action', href);
$dataConfirmModal.modal({
show: true
});
return false;
}
};

var render = function() {
$el.on('click', '.delete-asset', events['click']);
};

return {
render: render
};
};


/**
* Application start point
* Component definition stays out of load event, execution only happens.
*/
$(function() {
new Components.modals.confirmRestore().render();
new Components.modals.confirmDelete().render();
$el.on('click', '.delete-asset', function (evnt) {
var $context = $(this);
var $dataConfirmModal = $('#dataConfirmModal');
var href = $context.attr('href');
var message = $context.attr('data-content');
var title = $context.attr('data-title');

$('#myModalLabel').text(title);
$dataConfirmModal.find('.modal-body').text(message);
$('#deleteForm').attr('action', href);
$dataConfirmModal.modal({
show: true
});
return false;
});
}(jQuery, window.snipeit.settings));

$(document).ready(function () {

/*
* Slideout help menu
Expand Down
2 changes: 2 additions & 0 deletions resources/lang/en-US/admin/settings/general.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
'backups' => 'Backups',
'backups_help' => 'Create, download, and restore backups ',
'backups_restoring' => 'Restoring from Backup',
'backups_clean' => 'Clean the backed-up database before restore',
'backups_clean_helptext' => "This can be useful if you're changing between database versions",
'backups_upload' => 'Upload Backup',
'backups_path' => 'Backups on the server are stored in <code>:path</code>',
'backups_restore_warning' => 'Use the restore button <small><span class="btn btn-xs btn-warning"><i class="text-white fas fa-retweet" aria-hidden="true"></i></span></small> to restore from a previous backup. (This does not currently work with S3 file storage or Docker.)<br><br>Your <strong>entire :app_name database and any uploaded files will be completely replaced</strong> by what\'s in the backup file. ',
Expand Down
61 changes: 49 additions & 12 deletions resources/views/settings/backups.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@stop

@section('header_right')
<a href="{{ route('settings.index') }}" class="btn btn-default pull-right" style="margin-left: 5px;">
<a href="{{ route('settings.index') }}" class="btn btn-default pull-right" style="margin-left: 5px;">
{{ trans('general.back') }}
</a>

Expand All @@ -21,8 +21,36 @@
{{-- Page content --}}
@section('content')

<div class="modal modal-warning fade" tabindex="-1" role="dialog" id="backupRestoreModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form method="post" role="form">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>{{ trans('admin/settings/message.backup.restore_warning') }}</p>
<p><label><input type="checkbox"
name="clean" {{ config('backup.sanitize_by_default') ? "checked='checked'" : "" }}>{{ trans('admin/settings/general.backups_clean') }}
</label></p>
<p>{{ trans('admin/settings/general.backups_clean_helptext') }}</p>
</div>
<div class="modal-footer">
{{ csrf_field() }}
{{ method_field('POST') }}
<button type="button" class="btn btn-default pull-left"
data-dismiss="modal">{{ trans('general.cancel') }}</button>
<button type="submit" class="btn btn-outline">{{ trans('general.yes') }}</button>
</div>
</form>
</div>
</div>
</div>

<div class="row">
<div class="row">

<div class="col-md-8">

Expand Down Expand Up @@ -85,13 +113,12 @@ class="btn delete-asset btn-danger btn-sm disabled">
</a>
@endif

<a data-html="true"
href="{{ route('settings.backups.restore', $file['filename']) }}"
class="btn btn-warning btn-sm restore-asset {{ (config('app.lock_passwords')) ? ' disabled': '' }}"
data-toggle="modal"
data-content="{{ trans('admin/settings/message.backup.restore_warning') }}"
data-title="{{ trans('admin/settings/message.backup.restore_confirm', array('filename' => e($file['filename']))) }}"
onClick="return false;">
<a data-html="true"
href="{{ route('settings.backups.restore', $file['filename']) }}"
class="btn btn-warning btn-sm restore-backup {{ (config('app.lock_passwords')) ? ' disabled': '' }}"
data-target="#backupRestoreModal"
data-title="{{ trans('admin/settings/message.backup.restore_confirm', array('filename' => e($file['filename']))) }}"
onClick="return false;">
<i class="fas fa-retweet" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.restore') }}</span>
</a>
Expand Down Expand Up @@ -230,11 +257,21 @@ class="btn btn-warning btn-sm restore-asset {{ (config('app.lock_passwords')) ?
});
}
});
});
// due to dynamic loading, we have to use the below 'weird' way of adding event handlers instead of just saying
// $('.restore-backup').on( .....
$('table').on('click', '.restore-backup', function (event) {
event.preventDefault();
var modal = $('#backupRestoreModal');
modal.find('.modal-title').text($(this).data('title'));
modal.find('form').attr('action', $(this).attr('href'));
modal.modal({
show: true
});
return false;
})
</script>
@stop

0 comments on commit ec0b9b1

Please sign in to comment.