2
2
3
3
namespace App \Filament \App \Resources \BackupResource \Pages ;
4
4
5
+ use App \Enums \ServerState ;
6
+ use App \Facades \Activity ;
5
7
use App \Filament \App \Resources \BackupResource ;
6
8
use App \Http \Controllers \Api \Client \Servers \BackupController ;
7
9
use App \Models \Backup ;
10
+ use App \Models \Permission ;
11
+ use App \Repositories \Daemon \DaemonBackupRepository ;
8
12
use App \Services \Backups \DownloadLinkService ;
13
+ use App \Services \Backups \InitiateBackupService ;
9
14
use Filament \Actions ;
10
15
use Filament \Facades \Filament ;
16
+ use Filament \Forms \Components \Checkbox ;
17
+ use Filament \Forms \Components \Placeholder ;
18
+ use Filament \Forms \Components \Textarea ;
19
+ use Filament \Forms \Components \TextInput ;
20
+ use Filament \Forms \Components \Toggle ;
11
21
use Filament \Forms \Form ;
22
+ use Filament \Notifications \Notification ;
12
23
use Filament \Resources \Pages \ListRecords ;
13
24
use Filament \Tables \Actions \Action ;
14
25
use Filament \Tables \Columns \IconColumn ;
15
26
use Filament \Tables \Columns \TextColumn ;
16
27
use Filament \Tables \Table ;
17
28
use Illuminate \Http \Request ;
29
+ use Symfony \Component \HttpKernel \Exception \BadRequestHttpException ;
18
30
19
31
class ListBackups extends ListRecords
20
32
{
21
33
protected static string $ resource = BackupResource::class;
34
+ protected static bool $ canCreateAnother = false ;
22
35
23
36
public function form (Form $ form ): Form
24
37
{
25
38
return $ form
26
39
->schema ([
27
- //TODO
40
+ TextInput::make ('name ' )
41
+ ->label ('Name ' )
42
+ ->columnSpanFull ()
43
+ ->required (),
44
+ TextArea::make ('ignored ' )
45
+ ->columnSpanFull ()
46
+ ->label ('Ignored Files & Directories ' ),
47
+ Toggle::make ('is_locked ' )
48
+ ->label ('Lock? ' )
49
+ ->helperText ('Prevents this backup from being deleted until explicitly unlocked. ' ),
28
50
]);
29
51
}
30
52
31
53
public function table (Table $ table ): Table
32
54
{
55
+ /** @var \App\Models\Server $server */
33
56
$ server = Filament::getTenant ();
34
57
35
58
return $ table
@@ -51,22 +74,106 @@ public function table(Table $table): Table
51
74
])
52
75
->actions ([
53
76
Action::make ('lock ' )
77
+ ->hidden (!auth ()->user ()->can (Permission::ACTION_BACKUP_DELETE , Filament::getTenant ()))
54
78
->label (fn (Backup $ backup ) => !$ backup ->is_locked ? 'Lock ' : 'Unlock ' )
55
79
->action (fn (BackupController $ backupController , Backup $ backup , Request $ request ) => $ backupController ->toggleLock ($ request , $ server , $ backup )),
56
80
Action::make ('download ' )
81
+ ->hidden (!auth ()->user ()->can (Permission::ACTION_BACKUP_DOWNLOAD , Filament::getTenant ()))
57
82
->url (function (DownloadLinkService $ downloadLinkService , Backup $ backup , Request $ request ) {
58
83
return $ downloadLinkService ->handle ($ backup , $ request ->user ());
59
84
}, true ),
60
- Action::make ('restore ' ),
85
+ Action::make ('restore ' )
86
+ ->hidden (!auth ()->user ()->can (Permission::ACTION_BACKUP_RESTORE , Filament::getTenant ()))
87
+ ->form ([
88
+ Placeholder::make ('' )
89
+ ->helperText ('Your server will be stopped. You will not be able to control the power state, access the file manager, or create additional backups until this process is completed. ' ),
90
+ Checkbox::make ('truncate ' )
91
+ ->label ('Delete all files before restoring backup? ' ),
92
+ ])
93
+ ->action (function (Backup $ backup , $ data , DaemonBackupRepository $ daemonRepository , DownloadLinkService $ downloadLinkService ) {
94
+
95
+ /** @var \App\Models\Server $server */
96
+ $ server = Filament::getTenant ();
97
+
98
+ if (!is_null ($ server ->status )) {
99
+ throw new BadRequestHttpException ('This server is not currently in a state that allows for a backup to be restored. ' );
100
+ }
101
+
102
+ if (!$ backup ->is_successful && is_null ($ backup ->completed_at )) {
103
+ throw new BadRequestHttpException ('This backup cannot be restored at this time: not completed or failed. ' );
104
+ }
105
+
106
+ $ log = Activity::event ('server:backup.restore ' )
107
+ ->subject ($ backup )
108
+ ->property (['name ' => $ backup ->name , 'truncate ' => $ data ['truncate ' ]]);
109
+
110
+ $ log ->transaction (function () use ($ downloadLinkService , $ daemonRepository , $ backup , $ server , $ data ) {
111
+ // If the backup is for an S3 file we need to generate a unique Download link for
112
+ // it that will allow daemon to actually access the file.
113
+ if ($ backup ->disk === Backup::ADAPTER_AWS_S3 ) {
114
+ $ url = $ downloadLinkService ->handle ($ backup , auth ()->user ());
115
+ }
116
+
117
+ // Update the status right away for the server so that we know not to allow certain
118
+ // actions against it via the Panel API.
119
+ $ server ->update (['status ' => ServerState::RestoringBackup]);
120
+
121
+ $ daemonRepository ->setServer ($ server )->restore ($ backup , $ url ?? null , $ data ['truncate ' ]);
122
+ });
123
+
124
+ return Notification::make ()->title ('Restoring Backup ' )->send ();
125
+ }),
61
126
Action::make ('delete ' )
127
+ ->fillForm (fn (Backup $ backup ): array => [
128
+ 'name ' => $ backup ->name ,
129
+ ])
130
+ ->form ([
131
+ TextInput::make ('name ' )
132
+ ->label ('Name ' )
133
+ ->disabled (),
134
+ ])
135
+ ->disabled (fn (Backup $ backup ): bool => $ backup ->is_locked )
136
+ ->hidden (!auth ()->user ()->can (Permission::ACTION_BACKUP_DELETE , Filament::getTenant ()))
137
+ ->requiresConfirmation ()
62
138
->action (fn (BackupController $ backupController , Backup $ backup , Request $ request ) => $ backupController ->delete ($ request , $ server , $ backup )),
63
139
]);
64
140
}
65
141
66
142
protected function getHeaderActions (): array
67
143
{
144
+ /** @var \App\Models\Server $server */
145
+ $ server = Filament::getTenant ();
146
+
68
147
return [
69
- Actions \CreateAction::make (),
148
+ Actions \CreateAction::make ()
149
+ ->label (fn () => $ server ->backups ()->count () >= $ server ->backup_limit ? 'Backup Limit Reached ' : 'Create Backup ' )
150
+ ->disabled (fn () => $ server ->backups ()->count () >= $ server ->backup_limit )
151
+ ->createAnother (false )
152
+ ->action (function (InitiateBackupService $ initiateBackupService , $ data ) {
153
+
154
+ /** @var \App\Models\Server $server */
155
+ $ server = Filament::getTenant ();
156
+
157
+ $ action = $ initiateBackupService
158
+ ->setIgnoredFiles (explode (PHP_EOL , $ data ['ignored ' ] ?? '' ));
159
+
160
+ if (auth ()->user ()->can (Permission::ACTION_BACKUP_DELETE , $ server )) {
161
+ $ action ->setIsLocked ((bool ) $ data ['is_locked ' ]);
162
+ }
163
+
164
+ $ backup = $ action ->handle ($ server , $ data ['name ' ]);
165
+
166
+ Activity::event ('server:backup.start ' )
167
+ ->subject ($ backup )
168
+ ->property (['name ' => $ backup ->name , 'locked ' => (bool ) $ data ['is_locked ' ]])
169
+ ->log ();
170
+
171
+ return Notification::make ()
172
+ ->title ('Backup Created ' )
173
+ ->body ($ backup ->name . ' created. ' )
174
+ ->success ()
175
+ ->send ();
176
+ }),
70
177
];
71
178
}
72
179
0 commit comments