Skip to content

Commit b817753

Browse files
committed
update
1 parent 19db870 commit b817753

File tree

4 files changed

+440
-0
lines changed

4 files changed

+440
-0
lines changed

web/Modules/Microweber/App/Models/MicroweberInstallation.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function getTemplateAttribute()
2020
if (empty($this->template)) {
2121
return 'Default';
2222
}
23+
return $this->template;
2324
}
2425

2526
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
namespace Modules\Microweber\Filament\Clusters\Microweber\Pages;
4+
5+
use Filament\Actions\Action;
6+
use Filament\Forms\Components\TextInput;
7+
use Filament\Notifications\Notification;
8+
use Filament\Pages\Page;
9+
use Modules\Microweber\App\Models\MicroweberInstallation;
10+
use Modules\Microweber\Filament\Clusters\MicroweberCluster;
11+
use Modules\Microweber\Jobs\RunInstallationCommands;
12+
13+
class Utilities extends Page
14+
{
15+
protected static ?string $navigationGroup = 'Microweber';
16+
17+
protected static ?string $cluster = MicroweberCluster::class;
18+
19+
protected static ?string $navigationIcon = 'heroicon-o-wrench-screwdriver';
20+
21+
protected static string $view = 'microweber::filament.admin.pages.utilities';
22+
23+
protected static ?int $navigationSort = 4;
24+
25+
protected static ?string $navigationLabel = 'Utilities';
26+
27+
public static function getNavigationLabel(): string
28+
{
29+
return self::$navigationLabel;
30+
}
31+
32+
public function getTitle(): string
33+
{
34+
return self::$navigationLabel;
35+
}
36+
37+
protected function getViewData(): array
38+
{
39+
$installations = MicroweberInstallation::with('domain')->get();
40+
41+
return [
42+
'installations' => $installations,
43+
'totalInstallations' => $installations->count(),
44+
];
45+
}
46+
47+
protected function getHeaderActions(): array
48+
{
49+
return [
50+
Action::make('clearCacheAll')
51+
->label('Clear Cache (All Installations)')
52+
->icon('heroicon-o-trash')
53+
->color('warning')
54+
->requiresConfirmation()
55+
->modalHeading('Clear Cache for All Installations')
56+
->modalDescription('This will run "php artisan cache:clear" on all Microweber installations. This may take some time.')
57+
->action(function () {
58+
RunInstallationCommands::dispatch('cache:clear');
59+
60+
Notification::make()
61+
->title('Cache Clear Job Dispatched')
62+
->body('The cache clear command has been queued for all installations.')
63+
->success()
64+
->send();
65+
}),
66+
67+
Action::make('composerPublicshAssets')
68+
->label('Composer Publish Assets (All Installations)')
69+
->icon('heroicon-o-code-bracket')
70+
->color('info')
71+
->requiresConfirmation()
72+
->modalHeading('Composer Publish Assets for All Installations')
73+
->modalDescription('This will run "composer:publish-assets" on all Microweber installations. This may take some time.')
74+
->action(function () {
75+
RunInstallationCommands::dispatch('composer:publish-assets');
76+
77+
Notification::make()
78+
->title('Composer composer:publish-assets Job Dispatched')
79+
->body('The composer:publish-assets command has been queued for all installations.')
80+
->success()
81+
->send();
82+
}),
83+
84+
85+
Action::make('composerDumpAll')
86+
->label('Composer Dump (All Installations)')
87+
->icon('heroicon-o-code-bracket')
88+
->color('info')
89+
->requiresConfirmation()
90+
->modalHeading('Composer Dump for All Installations')
91+
->modalDescription('This will run "composer dump-autoload" on all Microweber installations. This may take some time.')
92+
->action(function () {
93+
RunInstallationCommands::dispatch('composer:dump');
94+
95+
Notification::make()
96+
->title('Composer Dump Job Dispatched')
97+
->body('The composer dump command has been queued for all installations.')
98+
->success()
99+
->send();
100+
}),
101+
102+
Action::make('customCommand')
103+
->label('Run Custom Command')
104+
105+
->color('gray')
106+
->form([
107+
TextInput::make('command')
108+
->label('Command')
109+
->helperText('Enter the command to run (e.g., "cache:clear", "config:cache", etc.)')
110+
->required(),
111+
])
112+
->action(function (array $data) {
113+
RunInstallationCommands::dispatch($data['command']);
114+
115+
Notification::make()
116+
->title('Custom Command Job Dispatched')
117+
->body("The command '{$data['command']}' has been queued for all installations.")
118+
->success()
119+
->send();
120+
}),
121+
];
122+
}
123+
124+
public function clearCacheForInstallation($installationId)
125+
{
126+
RunInstallationCommands::dispatch('cache:clear', $installationId);
127+
128+
Notification::make()
129+
->title('Cache Clear Job Dispatched')
130+
->body('The cache clear command has been queued for this installation.')
131+
->success()
132+
->send();
133+
}
134+
135+
public function composerDumpForInstallation($installationId)
136+
{
137+
RunInstallationCommands::dispatch('composer:dump', $installationId);
138+
139+
Notification::make()
140+
->title('Composer Dump Job Dispatched')
141+
->body('The composer dump command has been queued for this installation.')
142+
->success()
143+
->send();
144+
}
145+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
namespace Modules\Microweber\Jobs;
4+
5+
use App\Models\HostingSubscription;
6+
use App\ShellApi;
7+
use Illuminate\Bus\Queueable;
8+
use Illuminate\Contracts\Queue\ShouldQueue;
9+
use Illuminate\Foundation\Bus\Dispatchable;
10+
use Illuminate\Queue\InteractsWithQueue;
11+
use Illuminate\Queue\SerializesModels;
12+
use Modules\Microweber\App\Models\MicroweberInstallation;
13+
14+
class RunInstallationCommands implements ShouldQueue
15+
{
16+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
17+
18+
public static $displayName = 'Run Installation Commands';
19+
public static $displayDescription = 'Execute commands on Microweber installations';
20+
21+
protected $command;
22+
protected $installationId;
23+
24+
public function __construct(string $command, ?int $installationId = null)
25+
{
26+
$this->command = $command;
27+
$this->installationId = $installationId;
28+
}
29+
30+
public function handle(): void
31+
{
32+
set_time_limit(0);
33+
34+
if ($this->installationId) {
35+
$installations = MicroweberInstallation::where('id', $this->installationId)->get();
36+
} else {
37+
$installations = MicroweberInstallation::all();
38+
}
39+
40+
if ($installations->isEmpty()) {
41+
\Log::info('No installations found to run command: ' . $this->command);
42+
return;
43+
}
44+
45+
foreach ($installations as $installation) {
46+
47+
$this->runCommandForInstallation($installation, $this->command);
48+
49+
50+
// try {
51+
// } catch (\Exception $e) {
52+
// \Log::error('Error running command "' . $this->command . '" on installation: ' . $installation->installation_path . ' - ' . $e->getMessage());
53+
// }
54+
}
55+
}
56+
57+
private function runCommandForInstallation(MicroweberInstallation $installation, string $command): void
58+
{
59+
$domain = $installation->domain;
60+
if (!$domain) {
61+
\Log::warning('Domain not found for installation: ' . $installation->id);
62+
return;
63+
}
64+
65+
$hostingSubscription = HostingSubscription::where('id', $domain->hosting_subscription_id)->first();
66+
if (!$hostingSubscription) {
67+
\Log::warning('Hosting subscription not found for domain: ' . $domain->id);
68+
return;
69+
}
70+
71+
$installationPath = $installation->installation_path;
72+
if (!is_dir($installationPath)) {
73+
\Log::warning('Installation path does not exist: ' . $installationPath);
74+
return;
75+
}
76+
77+
$username = $hostingSubscription->system_username;
78+
79+
switch ($command) {
80+
case 'cache:clear':
81+
$this->runArtisanCommand($installationPath, 'cache:clear', $username);
82+
break;
83+
84+
case 'composer:dump':
85+
$this->runComposerCommand($installationPath, 'dump-autoload', $username);
86+
break;
87+
88+
case 'composer:publish-assets':
89+
$this->runComposerCommand($installationPath, 'publish-assets', $username);
90+
break;
91+
92+
default:
93+
// For custom artisan commands
94+
$this->runArtisanCommand($installationPath, $command, $username);
95+
break;
96+
}
97+
98+
\Log::info("Command '{$command}' executed successfully for installation: {$installationPath}");
99+
}
100+
101+
private function runArtisanCommand(string $installationPath, string $command, string $username): void
102+
{
103+
$artisanPath = $installationPath . '/artisan';
104+
105+
if (!file_exists($artisanPath)) {
106+
throw new \Exception('Artisan file not found at: ' . $artisanPath);
107+
}
108+
109+
$fullCommand = "cd {$installationPath} && sudo -u {$username} php {$artisanPath} {$command}";
110+
\Log::info("Executing artisan command: {$fullCommand}");
111+
112+
$result = ShellApi::exec($fullCommand);
113+
114+
if ($result['exit_code'] !== 0) {
115+
throw new \Exception('Artisan command failed: ' . $result['output']);
116+
}
117+
}
118+
119+
private function runComposerCommand(string $installationPath, string $command, string $username): void
120+
{
121+
$composerPath = $installationPath . '/composer.json';
122+
123+
if (!file_exists($composerPath)) {
124+
throw new \Exception('Composer.json file not found at: ' . $composerPath);
125+
}
126+
127+
$fullCommand = "cd {$installationPath} && sudo -u {$username} composer {$command}";
128+
129+
130+
\Log::info("Executing composer command: {$fullCommand}");
131+
132+
$result = ShellApi::exec($fullCommand);
133+
134+
// if(!isset( $result['exit_code'])){
135+
// dd($result);
136+
// }
137+
//
138+
// if ($result['exit_code'] !== 0) {
139+
// throw new \Exception('Composer command failed: ' . $result['output']);
140+
// }
141+
}
142+
}

0 commit comments

Comments
 (0)