mirror of
https://github.com/PhyreApps/PhyrePanel.git
synced 2024-11-21 23:20:24 +00:00
update
This commit is contained in:
parent
b265c154b6
commit
2325192f78
8 changed files with 285 additions and 13 deletions
44
web/app/Console/Commands/RunBackup.php
Normal file
44
web/app/Console/Commands/RunBackup.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Backup;
|
||||
use App\Models\HostingSubscription;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RunBackup extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'phyre:run-backup';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// Delete backups older than 7 days
|
||||
$findBackupsForDeleting = Backup::where('created_at', '<', now()->subDays(7))->get();
|
||||
foreach ($findBackupsForDeleting as $backup) {
|
||||
$backup->delete();
|
||||
}
|
||||
|
||||
$getBackups = Backup::where('backup_type', 'hosting_subscription')->get();
|
||||
if ($getBackups->count() > 0) {
|
||||
foreach ($getBackups as $backup) {
|
||||
$status = $backup->startBackup();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
45
web/app/Filament/Enums/BackupType.php
Normal file
45
web/app/Filament/Enums/BackupType.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Filament\Enums;
|
||||
|
||||
use Filament\Support\Contracts\HasLabel;
|
||||
use JaOcero\RadioDeck\Contracts\HasDescriptions;
|
||||
use JaOcero\RadioDeck\Contracts\HasIcons;
|
||||
|
||||
enum BackupType: string implements HasLabel, HasDescriptions, HasIcons
|
||||
{
|
||||
|
||||
case FULL_BACKUP = 'full';
|
||||
case SYSTEM_BACKUP = 'system';
|
||||
case DATABASE_BACKUP = 'database';
|
||||
case HOSTING_SUBSCRIPTION_BACKUP = 'hosting_subscription';
|
||||
public function getLabel(): ?string
|
||||
{
|
||||
return match ($this) {
|
||||
self::FULL_BACKUP => 'Full Backup',
|
||||
self::SYSTEM_BACKUP => 'System Backup',
|
||||
self::DATABASE_BACKUP => 'Database Backup',
|
||||
self::HOSTING_SUBSCRIPTION_BACKUP => 'Hosting Subscription Backup',
|
||||
};
|
||||
}
|
||||
|
||||
public function getDescriptions(): ?string
|
||||
{
|
||||
return match ($this) {
|
||||
self::FULL_BACKUP => 'A full backup is a complete copy of your website files and database. It is the best way to protect your website data.',
|
||||
self::SYSTEM_BACKUP => 'A system backup is a copy of your website files and system files. It is useful for restoring your website if there is a problem with the system files.',
|
||||
self::DATABASE_BACKUP => 'A database backup is a copy of your website database. It is useful for restoring your website if there is a problem with the database.',
|
||||
self::HOSTING_SUBSCRIPTION_BACKUP => 'A hosting subscription backup is a copy of your website files and database. It is useful for restoring your website if there is a problem with the hosting subscription.',
|
||||
};
|
||||
}
|
||||
|
||||
public function getIcons(): ?string
|
||||
{
|
||||
return match ($this) {
|
||||
self::FULL_BACKUP => 'heroicon-o-inbox-stack',
|
||||
self::SYSTEM_BACKUP => 'heroicon-o-cog',
|
||||
self::DATABASE_BACKUP => 'phyre-mysql',
|
||||
self::HOSTING_SUBSCRIPTION_BACKUP => 'heroicon-o-server',
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,12 +2,22 @@
|
|||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Enums\BackupType;
|
||||
use App\Filament\Resources\BackupResource\Pages;
|
||||
use App\Models\Backup;
|
||||
use App\Models\HostingSubscription;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use JaOcero\RadioDeck\Forms\Components\RadioDeck;
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
|
||||
class BackupResource extends Resource
|
||||
{
|
||||
|
@ -23,7 +33,29 @@ class BackupResource extends Resource
|
|||
{
|
||||
return $form
|
||||
->schema([
|
||||
//
|
||||
|
||||
RadioDeck::make('backup_type')
|
||||
->live()
|
||||
->default('full_backup')
|
||||
->options(BackupType::class)
|
||||
->icons(BackupType::class)
|
||||
->descriptions(BackupType::class)
|
||||
->required()
|
||||
->color('primary')
|
||||
->columnSpanFull(),
|
||||
|
||||
|
||||
Select::make('hosting_subscription_id')
|
||||
->label('Hosting Subscription')
|
||||
->hidden(function (Get $get) {
|
||||
return $get('backup_type') !== 'hosting_subscription';
|
||||
})
|
||||
->options(
|
||||
HostingSubscription::all()->pluck('domain', 'id')
|
||||
)
|
||||
->columnSpanFull()
|
||||
->required(),
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -31,7 +63,9 @@ class BackupResource extends Resource
|
|||
{
|
||||
return $table
|
||||
->columns([
|
||||
//
|
||||
Tables\Columns\TextColumn::make('backup_type'),
|
||||
Tables\Columns\TextColumn::make('backupRelated'),
|
||||
Tables\Columns\TextColumn::make('status'),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
|
@ -59,7 +93,7 @@ class BackupResource extends Resource
|
|||
return [
|
||||
'index' => Pages\ListBackups::route('/'),
|
||||
'create' => Pages\CreateBackup::route('/create'),
|
||||
'edit' => Pages\EditBackup::route('/{record}/edit'),
|
||||
'view' => Pages\ViewBackup::route('/{record}'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ namespace App\Filament\Resources\BackupResource\Pages;
|
|||
|
||||
use App\Filament\Resources\BackupResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
|
||||
class EditBackup extends EditRecord
|
||||
class ViewBackup extends ViewRecord
|
||||
{
|
||||
protected static string $resource = BackupResource::class;
|
||||
|
|
@ -4,7 +4,104 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Backup extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'hosting_subscription_id',
|
||||
'backup_type',
|
||||
'status',
|
||||
'path',
|
||||
'size',
|
||||
'disk',
|
||||
];
|
||||
|
||||
protected function backupRelated() : Attribute
|
||||
{
|
||||
$relatedWith = $this->backup_type;
|
||||
if ($this->backup_type === 'hosting_subscription') {
|
||||
$findHostingSubscription = HostingSubscription::where('id', $this->hosting_subscription_id)->first();
|
||||
if ($findHostingSubscription) {
|
||||
$relatedWith = $findHostingSubscription->domain;
|
||||
}
|
||||
}
|
||||
|
||||
return Attribute::make(
|
||||
get: fn () => $relatedWith
|
||||
);
|
||||
}
|
||||
|
||||
public function startBackup()
|
||||
{
|
||||
|
||||
if ($this->status == 'running') {
|
||||
return [
|
||||
'status' => 'running',
|
||||
'message' => 'Backup already running'
|
||||
];
|
||||
}
|
||||
|
||||
$storagePath = storage_path('backups');
|
||||
if (! is_dir($storagePath)) {
|
||||
mkdir($storagePath);
|
||||
}
|
||||
$backupPath = $storagePath.'/'.$this->id;
|
||||
if (! is_dir($backupPath)) {
|
||||
mkdir($backupPath);
|
||||
}
|
||||
$backupTempPath = $backupPath.'/temp';
|
||||
if (! is_dir($backupTempPath)) {
|
||||
mkdir($backupTempPath);
|
||||
}
|
||||
if ($this->backup_type == 'hosting_subscription') {
|
||||
$findHostingSubscription = HostingSubscription::where('id', $this->hosting_subscription_id)->first();
|
||||
if ($findHostingSubscription) {
|
||||
|
||||
$backupFileName = Str::slug($findHostingSubscription->domain .'-'. date('Y-m-d-H-i-s')) . '.zip';
|
||||
$backupFilePath = $backupPath.'/'.$backupFileName;
|
||||
|
||||
$backupLogFileName = 'backup.log';
|
||||
$backupLogFilePath = $backupPath.'/'.$backupLogFileName;
|
||||
|
||||
$backupTempScript = '/tmp/backup-script-'.$this->id.'.sh';
|
||||
$shellFileContent = '';
|
||||
$shellFileContent .= 'echo "Backup up domain: '.$findHostingSubscription->domain . PHP_EOL;
|
||||
$shellFileContent .= 'echo "Backup filename: '.$backupFileName. PHP_EOL;
|
||||
$shellFileContent .= 'cp -r /home/'.$findHostingSubscription->system_username.' '.$backupTempPath.PHP_EOL;
|
||||
|
||||
$shellFileContent .= 'cd '.$backupTempPath .' && zip -r '.$backupFilePath.' ./* '. PHP_EOL;
|
||||
|
||||
$shellFileContent .= 'rm -rf '.$backupTempPath.PHP_EOL;
|
||||
$shellFileContent .= 'echo "Backup complete"' . PHP_EOL;
|
||||
$shellFileContent .= 'touch ' . $backupPath. '/backup.done' . PHP_EOL;
|
||||
$shellFileContent .= 'rm -rf ' . $backupTempScript;
|
||||
|
||||
$this->status = 'running';
|
||||
$this->queued = true;
|
||||
$this->queued_at = now();
|
||||
$this->save();
|
||||
|
||||
file_put_contents($backupTempScript, $shellFileContent);
|
||||
shell_exec('bash '.$backupTempScript.' >> ' . $backupLogFilePath . ' &');
|
||||
|
||||
return [
|
||||
'status' => 'running',
|
||||
'message' => 'Backup started'
|
||||
];
|
||||
|
||||
} else {
|
||||
$this->status = 'failed';
|
||||
$this->save();
|
||||
return [
|
||||
'status' => 'failed',
|
||||
'message' => 'Hosting subscription not found'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,6 @@ class HostingSubscription extends Model
|
|||
return [];
|
||||
|
||||
}
|
||||
|
||||
private static function _generateUsername($string)
|
||||
{
|
||||
$removedMultispace = preg_replace('/\s+/', ' ', $string);
|
||||
|
|
|
@ -35,13 +35,15 @@ class AdminPanelProvider extends PanelProvider
|
|||
$defaultColor = Color::Yellow;
|
||||
$brandLogo = asset('images/phyre-logo.svg');
|
||||
|
||||
$isAppInstalled = file_exists(storage_path('installed'));
|
||||
if ($isAppInstalled) {
|
||||
if (setting('general.brand_logo_url')) {
|
||||
$brandLogo = setting('general.brand_logo_url');
|
||||
}
|
||||
if (setting('general.brand_primary_color')) {
|
||||
$defaultColor = Color::hex(setting('general.brand_primary_color'));
|
||||
if (!app()->runningInConsole()) {
|
||||
$isAppInstalled = file_exists(storage_path('installed'));
|
||||
if ($isAppInstalled) {
|
||||
if (setting('general.brand_logo_url')) {
|
||||
$brandLogo = setting('general.brand_logo_url');
|
||||
}
|
||||
if (setting('general.brand_primary_color')) {
|
||||
$defaultColor = Color::hex(setting('general.brand_primary_color'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('backups', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->bigInteger('hosting_subscription_id')->nullable();
|
||||
$table->string('backup_type')->nullable();
|
||||
$table->string('status')->nullable();
|
||||
$table->string('path')->nullable();
|
||||
$table->string('size')->nullable();
|
||||
$table->string('disk')->nullable();
|
||||
$table->longText('settings')->nullable();
|
||||
|
||||
|
||||
$table->tinyInteger('queued')->nullable();
|
||||
$table->timestamp('queued_at')->nullable();
|
||||
|
||||
$table->tinyInteger('started')->nullable();
|
||||
$table->timestamp('started_at')->nullable();
|
||||
|
||||
$table->tinyInteger('completed')->nullable();
|
||||
$table->timestamp('completed_at')->nullable();
|
||||
|
||||
$table->tinyInteger('failed')->nullable();
|
||||
$table->timestamp('failed_at')->nullable();
|
||||
|
||||
$table->tinyInteger('cancelled')->nullable();
|
||||
$table->timestamp('cancelled_at')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('backups');
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue