257 lines
8.8 KiB
PHP
257 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\SystemSettings;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Services\System\BackupManagementService;
|
|
use App\Services\SystemConfig\SystemConfigService;
|
|
use Exception;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Validation\Rule;
|
|
use Laravel\Socialite\Facades\Socialite;
|
|
|
|
class BackupRestoreController extends Controller
|
|
{
|
|
protected $backupService;
|
|
|
|
protected $systemConfig;
|
|
|
|
public function __construct(
|
|
BackupManagementService $backupService,
|
|
SystemConfigService $systemConfig
|
|
) {
|
|
$this->backupService = $backupService;
|
|
$this->systemConfig = $systemConfig;
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
if ($request->wantsJson() || $request->ajax()) {
|
|
try {
|
|
session_write_close();
|
|
$driver = $request->get('driver');
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'backups' => $this->backupService->getBackupList(),
|
|
'stats' => $this->backupService->getStorageStats($driver),
|
|
]);
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
return view('pages.system_settings.backup-restore', [
|
|
'settings' => $this->systemConfig->all(),
|
|
]);
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
try {
|
|
// Prevent session locking during the long-running backup process
|
|
session_write_close();
|
|
|
|
set_time_limit(0);
|
|
ini_set('memory_limit', '512M');
|
|
|
|
$this->backupService->createBackup();
|
|
|
|
// ✍️ Log "Action Log" backup creation
|
|
activity('backups')
|
|
->causedBy(auth()->user())
|
|
->withProperties([
|
|
'ip' => request()->ip(),
|
|
'agent' => request()->userAgent(),
|
|
'details' => __('Manually triggered a system and database backup.'),
|
|
])
|
|
->log(__('Generated System Backup'));
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => __('Backup created successfully'),
|
|
'backups' => $this->backupService->getBackupList(forceRefresh: true),
|
|
]);
|
|
} catch (Exception $e) {
|
|
Log::error('Backup failed: '.$e->getMessage());
|
|
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function allowedDisks(): array
|
|
{
|
|
return ['local', 's3', 'gdrive'];
|
|
}
|
|
|
|
public function download(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'disk' => ['required', 'string', Rule::in($this->allowedDisks())],
|
|
'path' => ['required', 'string'],
|
|
]);
|
|
$disk = $validated['disk'];
|
|
$path = $validated['path'];
|
|
|
|
if (! Storage::disk($disk)->exists($path)) {
|
|
abort(404, __('File not found'));
|
|
}
|
|
|
|
// ✍️ Log "Action Log" backup download
|
|
activity('backups')
|
|
->causedBy(auth()->user())
|
|
->withProperties([
|
|
'ip' => $request->ip(),
|
|
'agent' => $request->userAgent(),
|
|
'file' => $path,
|
|
'disk' => $disk,
|
|
'details' => __('Downloaded backup file: :file from :disk storage.', ['file' => $path, 'disk' => $disk]),
|
|
])
|
|
->log(__('Downloaded Backup File'));
|
|
|
|
return Storage::disk($disk)->download($path);
|
|
}
|
|
|
|
public function destroy(Request $request)
|
|
{
|
|
try {
|
|
session_write_close();
|
|
$validated = $request->validate([
|
|
'disk' => ['required', 'string', Rule::in($this->allowedDisks())],
|
|
'path' => ['required', 'string'],
|
|
]);
|
|
$disk = $validated['disk'];
|
|
$path = $validated['path'];
|
|
|
|
if (Storage::disk($disk)->exists($path)) {
|
|
Storage::disk($disk)->delete($path);
|
|
|
|
// ✍️ Log "Action Log" backup deletion
|
|
activity('backups')
|
|
->causedBy(auth()->user())
|
|
->withProperties([
|
|
'ip' => $request->ip(),
|
|
'agent' => $request->userAgent(),
|
|
'file' => $path,
|
|
'details' => __('Permanently deleted backup file: :file', ['file' => $path]),
|
|
])
|
|
->log(__('Deleted Backup File'));
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => __('Backup deleted successfully'),
|
|
'backups' => $this->backupService->getBackupList(forceRefresh: true),
|
|
]);
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function restore(Request $request)
|
|
{
|
|
try {
|
|
session_write_close();
|
|
set_time_limit(0);
|
|
ini_set('memory_limit', '512M');
|
|
|
|
$validated = $request->validate([
|
|
'disk' => ['required', 'string', Rule::in($this->allowedDisks())],
|
|
'path' => ['required', 'string'],
|
|
]);
|
|
$disk = $validated['disk'];
|
|
$path = $validated['path'];
|
|
|
|
$this->backupService->restoreBackup($disk, $path);
|
|
|
|
// ✍️ Log "Action Log" system restore
|
|
activity('backups')
|
|
->causedBy(auth()->user())
|
|
->withProperties([
|
|
'ip' => $request->ip(),
|
|
'agent' => $request->userAgent(),
|
|
'file' => $path,
|
|
'details' => __('Successfully restored system from backup: :file', ['file' => $path]),
|
|
])
|
|
->log(__('Restored System from Backup'));
|
|
|
|
return response()->json([
|
|
'message' => __('System restored successfully. Cache cleared.'),
|
|
]);
|
|
} catch (Exception $e) {
|
|
Log::error('Restore failed: '.$e->getMessage());
|
|
|
|
return response()->json(['message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function testConnection()
|
|
{
|
|
try {
|
|
$result = $this->backupService->testConnection();
|
|
|
|
return response()->json($result);
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirect to Google for authorization.
|
|
*/
|
|
public function googleAuth()
|
|
{
|
|
$settings = $this->systemConfig->all();
|
|
|
|
if (empty($settings['gdrive_client_id']) || empty($settings['gdrive_client_secret'])) {
|
|
return redirect()->back()->with('error', __('Please save Client ID and Secret first.'));
|
|
}
|
|
|
|
// Dynamically set config for Socialite to use settings from database
|
|
config([
|
|
'services.google.client_id' => $settings['gdrive_client_id'],
|
|
'services.google.client_secret' => $settings['gdrive_client_secret'],
|
|
'services.google.redirect' => route('backup-restore.google-callback'),
|
|
]);
|
|
|
|
return Socialite::driver('google')
|
|
->scopes(['https://www.googleapis.com/auth/drive.file'])
|
|
->with(['access_type' => 'offline', 'prompt' => 'consent'])
|
|
->redirect();
|
|
}
|
|
|
|
/**
|
|
* Handle Google authorization callback.
|
|
*/
|
|
public function googleCallback()
|
|
{
|
|
try {
|
|
$settings = $this->systemConfig->all();
|
|
|
|
config([
|
|
'services.google.client_id' => $settings['gdrive_client_id'],
|
|
'services.google.client_secret' => $settings['gdrive_client_secret'],
|
|
'services.google.redirect' => route('backup-restore.google-callback'),
|
|
]);
|
|
|
|
$user = Socialite::driver('google')->user();
|
|
$refreshToken = $user->refreshToken;
|
|
|
|
if (! $refreshToken) {
|
|
return redirect()->route('backup-restore.index')->with('error', __('Failed to get refresh token. Please ensure you have not already authorized this app, or try revoking access and authorizing again.'));
|
|
}
|
|
|
|
// Save the refresh token to system settings
|
|
$this->systemConfig->update(['gdrive_refresh_token' => $refreshToken]);
|
|
|
|
return redirect()->route('backup-restore.index')->with('status', __('Google Drive authorized successfully!'));
|
|
} catch (Exception $e) {
|
|
Log::error('Google Auth Failed: '.$e->getMessage());
|
|
|
|
return redirect()->route('backup-restore.index')->with('error', __('Authorization failed: ').$e->getMessage());
|
|
}
|
|
}
|
|
}
|