feat: add app and database modules
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user