mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-20 08:44:46 +02:00
Add "Delete files" task (#470)
* started "delete files" task * add logic to DeleteFilesService * add frontend * make nicer * move description to right place
This commit is contained in:
parent
447e889a4f
commit
bb7c0e0e66
@ -19,7 +19,7 @@ class StoreTaskRequest extends ViewScheduleRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'action' => 'required|in:command,power,backup',
|
||||
'action' => 'required|in:command,power,backup,delete_files',
|
||||
'payload' => 'required_unless:action,backup|string|nullable',
|
||||
'time_offset' => 'required|numeric|min:0|max:900',
|
||||
'sequence_id' => 'sometimes|required|numeric|min:1',
|
||||
|
@ -12,6 +12,7 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use App\Services\Backups\InitiateBackupService;
|
||||
use App\Repositories\Daemon\DaemonPowerRepository;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use App\Services\Files\DeleteFilesService;
|
||||
|
||||
class RunTaskJob extends Job implements ShouldQueue
|
||||
{
|
||||
@ -34,7 +35,8 @@ class RunTaskJob extends Job implements ShouldQueue
|
||||
*/
|
||||
public function handle(
|
||||
InitiateBackupService $backupService,
|
||||
DaemonPowerRepository $powerRepository
|
||||
DaemonPowerRepository $powerRepository,
|
||||
DeleteFilesService $deleteFilesService
|
||||
): void {
|
||||
// Do not process a task that is not set to active, unless it's been manually triggered.
|
||||
if (!$this->task->schedule->is_active && !$this->manualRun) {
|
||||
@ -67,6 +69,9 @@ class RunTaskJob extends Job implements ShouldQueue
|
||||
case Task::ACTION_BACKUP:
|
||||
$backupService->setIgnoredFiles(explode(PHP_EOL, $this->task->payload))->handle($server, null, true);
|
||||
break;
|
||||
case Task::ACTION_DELETE_FILES:
|
||||
$deleteFilesService->handle($server, explode(PHP_EOL, $this->task->payload));
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException('Invalid task action provided: ' . $this->task->action);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ class Task extends Model
|
||||
public const ACTION_POWER = 'power';
|
||||
public const ACTION_COMMAND = 'command';
|
||||
public const ACTION_BACKUP = 'backup';
|
||||
public const ACTION_DELETE_FILES = 'delete_files';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
|
41
app/Services/Files/DeleteFilesService.php
Normal file
41
app/Services/Files/DeleteFilesService.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Files;
|
||||
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use App\Models\Server;
|
||||
use App\Repositories\Daemon\DaemonFileRepository;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DeleteFilesService
|
||||
{
|
||||
/**
|
||||
* DeleteFilesService constructor.
|
||||
*/
|
||||
public function __construct(
|
||||
private DaemonFileRepository $daemonFileRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given files.
|
||||
* @throws DaemonConnectionException
|
||||
*/
|
||||
public function handle(Server $server, array $files): void
|
||||
{
|
||||
$filesToDelete = collect();
|
||||
foreach ($files as $line) {
|
||||
$path = dirname($line);
|
||||
$pattern = basename($line);
|
||||
collect($this->daemonFileRepository->setServer($server)->getDirectory($path))->each(function ($item) use ($path, $pattern, $filesToDelete) {
|
||||
if (Str::is($pattern, $item['name'])) {
|
||||
$filesToDelete->push($path . '/' . $item['name']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($filesToDelete->isNotEmpty()) {
|
||||
$this->daemonFileRepository->setServer($server)->deleteFiles('/', $filesToDelete->toArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import {
|
||||
faPencilAlt,
|
||||
faToggleOn,
|
||||
faTrashAlt,
|
||||
faTrash,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import deleteScheduleTask from '@/api/server/schedules/deleteScheduleTask';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
@ -35,6 +36,8 @@ const getActionDetails = (action: string): [string, any] => {
|
||||
return ['Send Power Action', faToggleOn];
|
||||
case 'backup':
|
||||
return ['Create Backup', faFileArchive];
|
||||
case 'delete_files':
|
||||
return ['Delete Files', faTrash];
|
||||
default:
|
||||
return ['Unknown Action', faCode];
|
||||
}
|
||||
@ -94,6 +97,9 @@ export default ({ schedule, task }: Props) => {
|
||||
{task.action === 'backup' && (
|
||||
<p css={tw`text-xs uppercase text-neutral-400 mb-1`}>Ignoring files & folders:</p>
|
||||
)}
|
||||
{task.action === 'delete_files' && (
|
||||
<p css={tw`text-xs uppercase text-neutral-400 mb-1`}>Files to delete:</p>
|
||||
)}
|
||||
<div
|
||||
css={tw`font-mono bg-neutral-800 rounded py-1 px-2 text-sm w-auto inline-block whitespace-pre-wrap break-all`}
|
||||
>
|
||||
|
@ -34,7 +34,7 @@ interface Values {
|
||||
}
|
||||
|
||||
const schema = object().shape({
|
||||
action: string().required().oneOf(['command', 'power', 'backup']),
|
||||
action: string().required().oneOf(['command', 'power', 'backup', 'delete_files']),
|
||||
payload: string().when('action', {
|
||||
is: (v) => v !== 'backup',
|
||||
then: string().required('A task payload must be provided.'),
|
||||
@ -131,6 +131,7 @@ const TaskDetailsModal = ({ schedule, task }: Props) => {
|
||||
<option value={'command'}>Send command</option>
|
||||
<option value={'power'}>Send power action</option>
|
||||
<option value={'backup'}>Create backup</option>
|
||||
<option value={'delete_files'}>Delete files</option>
|
||||
</FormikField>
|
||||
</FormikFieldWrapper>
|
||||
</div>
|
||||
@ -166,7 +167,7 @@ const TaskDetailsModal = ({ schedule, task }: Props) => {
|
||||
</FormikField>
|
||||
</FormikFieldWrapper>
|
||||
</div>
|
||||
) : (
|
||||
) : values.action === 'backup' ? (
|
||||
<div>
|
||||
<Label>Ignored Files</Label>
|
||||
<FormikFieldWrapper
|
||||
@ -178,6 +179,16 @@ const TaskDetailsModal = ({ schedule, task }: Props) => {
|
||||
<FormikField as={Textarea} name={'payload'} rows={6} />
|
||||
</FormikFieldWrapper>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Label>Files to Delete</Label>
|
||||
<FormikFieldWrapper
|
||||
name={'payload'}
|
||||
description={'Specify the files that will be deleted. (Whitelist)'}
|
||||
>
|
||||
<FormikField as={Textarea} name={'payload'} rows={6} />
|
||||
</FormikFieldWrapper>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div css={tw`mt-6 bg-neutral-700 border border-neutral-800 shadow-inner p-4 rounded`}>
|
||||
|
Loading…
x
Reference in New Issue
Block a user