mirror of
https://github.com/pelican-dev/panel.git
synced 2025-10-29 14:36:52 +01:00
Add own endpoint for exporting eggs (#1760)
This commit is contained in:
parent
432fb8a514
commit
a58ae874f3
@ -4,7 +4,6 @@ namespace App\Filament\Components\Actions;
|
|||||||
|
|
||||||
use App\Enums\EggFormat;
|
use App\Enums\EggFormat;
|
||||||
use App\Models\Egg;
|
use App\Models\Egg;
|
||||||
use App\Services\Eggs\Sharing\EggExporterService;
|
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
use Filament\Infolists\Components\TextEntry;
|
use Filament\Infolists\Components\TextEntry;
|
||||||
use Filament\Support\Enums\Alignment;
|
use Filament\Support\Enums\Alignment;
|
||||||
@ -38,17 +37,15 @@ class ExportEggAction extends Action
|
|||||||
|
|
||||||
$this->modalFooterActionsAlignment(Alignment::Center);
|
$this->modalFooterActionsAlignment(Alignment::Center);
|
||||||
|
|
||||||
$this->modalFooterActions([ //TODO: Close modal after clicking ->close() does not allow action to preform before closing modal
|
$this->modalFooterActions([
|
||||||
Action::make('json')
|
Action::make('json')
|
||||||
->label(trans('admin/egg.export.as', ['format' => 'json']))
|
->label(trans('admin/egg.export.as', ['format' => 'json']))
|
||||||
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
|
->url(fn (Egg $egg) => route('api.application.eggs.eggs.export', ['egg' => $egg, 'format' => EggFormat::JSON->value]), true)
|
||||||
echo $service->handle($egg->id, EggFormat::JSON);
|
->close(),
|
||||||
}, 'egg-' . $egg->getKebabName() . '.json')),
|
|
||||||
Action::make('yaml')
|
Action::make('yaml')
|
||||||
->label(trans('admin/egg.export.as', ['format' => 'yaml']))
|
->label(trans('admin/egg.export.as', ['format' => 'yaml']))
|
||||||
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
|
->url(fn (Egg $egg) => route('api.application.eggs.eggs.export', ['egg' => $egg, 'format' => EggFormat::YAML->value]), true)
|
||||||
echo $service->handle($egg->id, EggFormat::YAML);
|
->close(),
|
||||||
}, 'egg-' . $egg->getKebabName() . '.yaml')),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,8 @@ class ExportScheduleAction extends Action
|
|||||||
|
|
||||||
$this->action(fn (ScheduleExporterService $service, Schedule $schedule) => response()->streamDownload(function () use ($service, $schedule) {
|
$this->action(fn (ScheduleExporterService $service, Schedule $schedule) => response()->streamDownload(function () use ($service, $schedule) {
|
||||||
echo $service->handle($schedule);
|
echo $service->handle($schedule);
|
||||||
}, 'schedule-' . str($schedule->name)->kebab()->lower()->trim() . '.json'));
|
}, 'schedule-' . str($schedule->name)->kebab()->lower()->trim() . '.json', [
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,24 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api\Application\Eggs;
|
namespace App\Http\Controllers\Api\Application\Eggs;
|
||||||
|
|
||||||
|
use App\Enums\EggFormat;
|
||||||
use App\Http\Controllers\Api\Application\ApplicationApiController;
|
use App\Http\Controllers\Api\Application\ApplicationApiController;
|
||||||
|
use App\Http\Requests\Api\Application\Eggs\ExportEggRequest;
|
||||||
use App\Http\Requests\Api\Application\Eggs\GetEggRequest;
|
use App\Http\Requests\Api\Application\Eggs\GetEggRequest;
|
||||||
use App\Http\Requests\Api\Application\Eggs\GetEggsRequest;
|
use App\Http\Requests\Api\Application\Eggs\GetEggsRequest;
|
||||||
use App\Models\Egg;
|
use App\Models\Egg;
|
||||||
|
use App\Services\Eggs\Sharing\EggExporterService;
|
||||||
use App\Transformers\Api\Application\EggTransformer;
|
use App\Transformers\Api\Application\EggTransformer;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
class EggController extends ApplicationApiController
|
class EggController extends ApplicationApiController
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private EggExporterService $exporterService,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List eggs
|
* List eggs
|
||||||
*
|
*
|
||||||
@ -37,4 +47,20 @@ class EggController extends ApplicationApiController
|
|||||||
->transformWith($this->getTransformer(EggTransformer::class))
|
->transformWith($this->getTransformer(EggTransformer::class))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export egg
|
||||||
|
*
|
||||||
|
* Return a single egg as yaml or json file (defaults to YAML)
|
||||||
|
*/
|
||||||
|
public function export(ExportEggRequest $request, Egg $egg): StreamedResponse
|
||||||
|
{
|
||||||
|
$format = EggFormat::tryFrom($request->input('format')) ?? EggFormat::YAML;
|
||||||
|
|
||||||
|
return response()->streamDownload(function () use ($egg, $format) {
|
||||||
|
echo $this->exporterService->handle($egg->id, $format);
|
||||||
|
}, 'egg-' . $egg->getKebabName() . '.' . $format->value, [
|
||||||
|
'Content-Type' => 'application/' . $format->value,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class AuthenticateApplicationUser
|
|||||||
{
|
{
|
||||||
/** @var User|null $user */
|
/** @var User|null $user */
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
if (!$user || !$user->isRootAdmin()) {
|
if (!$user || !$user->isAdmin()) {
|
||||||
throw new AccessDeniedHttpException('This account does not have permission to access the API.');
|
throw new AccessDeniedHttpException('This account does not have permission to access the API.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,10 +41,14 @@ abstract class ApplicationApiRequest extends FormRequest
|
|||||||
$token = $this->user()->currentAccessToken();
|
$token = $this->user()->currentAccessToken();
|
||||||
|
|
||||||
if ($token instanceof TransientToken) {
|
if ($token instanceof TransientToken) {
|
||||||
return true;
|
return match ($this->permission) {
|
||||||
|
default => false,
|
||||||
|
AdminAcl::READ => $this->user()->can('viewList ' . $this->resource) && $this->user()->can('view ' . $this->resource),
|
||||||
|
AdminAcl::WRITE => $this->user()->can('update ' . $this->resource),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($token->key_type === ApiKey::TYPE_ACCOUNT) {
|
if ($this->user()->isRootAdmin() && $token->key_type === ApiKey::TYPE_ACCOUNT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
app/Http/Requests/Api/Application/Eggs/ExportEggRequest.php
Normal file
13
app/Http/Requests/Api/Application/Eggs/ExportEggRequest.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Api\Application\Eggs;
|
||||||
|
|
||||||
|
class ExportEggRequest extends GetEggRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'format' => 'nullable|string|in:yaml,json',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -101,6 +101,7 @@ Route::prefix('/servers')->group(function () {
|
|||||||
Route::prefix('/eggs')->group(function () {
|
Route::prefix('/eggs')->group(function () {
|
||||||
Route::get('/', [Application\Eggs\EggController::class, 'index'])->name('api.application.eggs.eggs');
|
Route::get('/', [Application\Eggs\EggController::class, 'index'])->name('api.application.eggs.eggs');
|
||||||
Route::get('/{egg:id}', [Application\Eggs\EggController::class, 'view'])->name('api.application.eggs.eggs.view');
|
Route::get('/{egg:id}', [Application\Eggs\EggController::class, 'view'])->name('api.application.eggs.eggs.view');
|
||||||
|
Route::get('/{egg:id}/export', [Application\Eggs\EggController::class, 'export'])->name('api.application.eggs.eggs.export');
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -35,10 +35,11 @@ trait RequestMockHelpers
|
|||||||
/**
|
/**
|
||||||
* Generates a new request user model and also returns the generated model.
|
* Generates a new request user model and also returns the generated model.
|
||||||
*/
|
*/
|
||||||
public function generateRequestUserModel(bool $isRootAdmin, array $args = []): void
|
public function generateRequestUserModel(bool $isAdmin, bool $isRootAdmin, array $args = []): void
|
||||||
{
|
{
|
||||||
$user = User::factory()->make($args);
|
$user = User::factory()->make($args);
|
||||||
$user = m::mock($user)->makePartial();
|
$user = m::mock($user)->makePartial();
|
||||||
|
$user->shouldReceive('isAdmin')->andReturn($isAdmin);
|
||||||
$user->shouldReceive('isRootAdmin')->andReturn($isRootAdmin);
|
$user->shouldReceive('isRootAdmin')->andReturn($isRootAdmin);
|
||||||
|
|
||||||
/** @var User|Mock $user */
|
/** @var User|Mock $user */
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class AuthenticateUserTest extends MiddlewareTestCase
|
|||||||
{
|
{
|
||||||
$this->expectException(AccessDeniedHttpException::class);
|
$this->expectException(AccessDeniedHttpException::class);
|
||||||
|
|
||||||
$this->generateRequestUserModel(false);
|
$this->generateRequestUserModel(false, false);
|
||||||
|
|
||||||
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
||||||
}
|
}
|
||||||
@ -37,7 +37,17 @@ class AuthenticateUserTest extends MiddlewareTestCase
|
|||||||
*/
|
*/
|
||||||
public function test_admin_user(): void
|
public function test_admin_user(): void
|
||||||
{
|
{
|
||||||
$this->generateRequestUserModel(true);
|
$this->generateRequestUserModel(true, false);
|
||||||
|
|
||||||
|
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a root admin user continues though the middleware.
|
||||||
|
*/
|
||||||
|
public function test_root_admin_user(): void
|
||||||
|
{
|
||||||
|
$this->generateRequestUserModel(true, true);
|
||||||
|
|
||||||
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
$this->getMiddleware()->handle($this->request, $this->getClosureAssertions());
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user