ADD EV3-431 Profitcenter - betűkód phase1 addd feature flag override relation manager
This commit is contained in:
parent
d6c6f0af1c
commit
259df71c7b
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides;
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Pages\CreateFeatureFlagOverride;
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Pages\EditFeatureFlagOverride;
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Pages\ListFeatureFlagOverrides;
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Schemas\FeatureFlagOverrideForm;
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Tables\FeatureFlagOverridesTable;
|
||||||
|
use App\Models\FeatureFlagOverride;
|
||||||
|
use BackedEnum;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class FeatureFlagOverrideResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = FeatureFlagOverride::class;
|
||||||
|
|
||||||
|
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-user-circle';
|
||||||
|
|
||||||
|
protected static string|\UnitEnum|null $navigationGroup = 'Rendszer';
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Egyéni felülbírálások';
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return FeatureFlagOverrideForm::configure($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return FeatureFlagOverridesTable::configure($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => ListFeatureFlagOverrides::route('/'),
|
||||||
|
'create' => CreateFeatureFlagOverride::route('/create'),
|
||||||
|
'edit' => EditFeatureFlagOverride::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\FeatureFlagOverrideResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateFeatureFlagOverride extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = FeatureFlagOverrideResource::class;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\FeatureFlagOverrideResource;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditFeatureFlagOverride extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = FeatureFlagOverrideResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\FeatureFlagOverrideResource;
|
||||||
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListFeatureFlagOverrides extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = FeatureFlagOverrideResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides\Schemas;
|
||||||
|
|
||||||
|
use App\Models\FeatureFlag;
|
||||||
|
use App\Models\User;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
|
||||||
|
class FeatureFlagOverrideForm
|
||||||
|
{
|
||||||
|
public static function configure(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
Select::make('feature_flag_id')
|
||||||
|
->label('Feature flag')
|
||||||
|
->searchable()
|
||||||
|
->options(fn () => FeatureFlag::pluck('label', 'id'))
|
||||||
|
->disabledOn('edit')
|
||||||
|
->required(),
|
||||||
|
Select::make('user_id')
|
||||||
|
->label('Felhasználó')
|
||||||
|
->searchable()
|
||||||
|
->options(fn () => User::pluck('name', 'id'))
|
||||||
|
->disabledOn('edit')
|
||||||
|
->required(),
|
||||||
|
Toggle::make('active')
|
||||||
|
->label('Bekapcsolva')
|
||||||
|
->required(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlagOverrides\Tables;
|
||||||
|
|
||||||
|
use App\Models\FeatureFlag;
|
||||||
|
use App\Models\User;
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteBulkAction;
|
||||||
|
use Filament\Actions\EditAction;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class FeatureFlagOverridesTable
|
||||||
|
{
|
||||||
|
public static function configure(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('featureFlag.label')
|
||||||
|
->label('Feature flag')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
TextColumn::make('user.name')
|
||||||
|
->label('Felhasználó')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
IconColumn::make('active')
|
||||||
|
->label('Állapot')
|
||||||
|
->boolean(),
|
||||||
|
TextColumn::make('updated_at')
|
||||||
|
->label('Módosítva')
|
||||||
|
->dateTime()
|
||||||
|
->sortable(),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
SelectFilter::make('feature_flag_id')
|
||||||
|
->label('Feature flag')
|
||||||
|
->options(fn () => FeatureFlag::pluck('label', 'id')),
|
||||||
|
SelectFilter::make('user_id')
|
||||||
|
->label('Felhasználó')
|
||||||
|
->options(fn () => User::pluck('name', 'id'))
|
||||||
|
->searchable(),
|
||||||
|
])
|
||||||
|
->recordActions([
|
||||||
|
EditAction::make(),
|
||||||
|
])
|
||||||
|
->toolbarActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Filament\Resources\FeatureFlags\Pages\CreateFeatureFlag;
|
use App\Filament\Resources\FeatureFlags\Pages\CreateFeatureFlag;
|
||||||
use App\Filament\Resources\FeatureFlags\Pages\EditFeatureFlag;
|
use App\Filament\Resources\FeatureFlags\Pages\EditFeatureFlag;
|
||||||
use App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags;
|
use App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags;
|
||||||
|
use App\Filament\Resources\FeatureFlags\RelationManagers\OverridesRelationManager;
|
||||||
use App\Filament\Resources\FeatureFlags\Schemas\FeatureFlagForm;
|
use App\Filament\Resources\FeatureFlags\Schemas\FeatureFlagForm;
|
||||||
use App\Filament\Resources\FeatureFlags\Tables\FeatureFlagsTable;
|
use App\Filament\Resources\FeatureFlags\Tables\FeatureFlagsTable;
|
||||||
use App\Models\FeatureFlag;
|
use App\Models\FeatureFlag;
|
||||||
@ -36,7 +37,7 @@ public static function table(Table $table): Table
|
|||||||
public static function getRelations(): array
|
public static function getRelations(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
//
|
OverridesRelationManager::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\FeatureFlags\RelationManagers;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Actions\EditAction;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Resources\RelationManagers\RelationManager;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class OverridesRelationManager extends RelationManager
|
||||||
|
{
|
||||||
|
protected static string $relationship = 'overrides';
|
||||||
|
|
||||||
|
protected static ?string $title = 'Egyéni felülbírálások';
|
||||||
|
|
||||||
|
public function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
Select::make('user_id')
|
||||||
|
->label('Felhasználó')
|
||||||
|
->searchable()
|
||||||
|
->options(fn () => User::pluck('name', 'id'))
|
||||||
|
->disabledOn('edit')
|
||||||
|
->required(),
|
||||||
|
Toggle::make('active')
|
||||||
|
->label('Bekapcsolva')
|
||||||
|
->required(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->recordTitleAttribute('user.name')
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('user.name')
|
||||||
|
->label('Felhasználó')
|
||||||
|
->searchable(),
|
||||||
|
IconColumn::make('active')
|
||||||
|
->label('Állapot')
|
||||||
|
->boolean(),
|
||||||
|
TextColumn::make('updated_at')
|
||||||
|
->label('Módosítva')
|
||||||
|
->dateTime()
|
||||||
|
->sortable(),
|
||||||
|
])
|
||||||
|
->headerActions([
|
||||||
|
CreateAction::make(),
|
||||||
|
])
|
||||||
|
->recordActions([
|
||||||
|
EditAction::make(),
|
||||||
|
DeleteAction::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,6 @@
|
|||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
use Filament\Tables\Columns\ToggleColumn;
|
use Filament\Tables\Columns\ToggleColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Laravel\Pennant\Feature;
|
|
||||||
|
|
||||||
class FeatureFlagsTable
|
class FeatureFlagsTable
|
||||||
{
|
{
|
||||||
@ -69,19 +68,19 @@ public static function configure(Table $table): Table
|
|||||||
$user = User::findOrFail($data['user_id']);
|
$user = User::findOrFail($data['user_id']);
|
||||||
|
|
||||||
if ($data['override'] === 'inherit') {
|
if ($data['override'] === 'inherit') {
|
||||||
|
// model-instance delete() kell, hogy a FeatureFlagOverrideObserver
|
||||||
|
// (Pennant purge) ténylegesen kiváltódjon - a query builder delete()
|
||||||
|
// nem hívja meg a modell eseményeit
|
||||||
FeatureFlagOverride::where('feature_flag_id', $record->id)
|
FeatureFlagOverride::where('feature_flag_id', $record->id)
|
||||||
->where('user_id', $user->id)
|
->where('user_id', $user->id)
|
||||||
->delete();
|
->first()
|
||||||
|
?->delete();
|
||||||
} else {
|
} else {
|
||||||
FeatureFlagOverride::updateOrCreate(
|
FeatureFlagOverride::updateOrCreate(
|
||||||
['feature_flag_id' => $record->id, 'user_id' => $user->id],
|
['feature_flag_id' => $record->id, 'user_id' => $user->id],
|
||||||
['active' => $data['override'] === 'on'],
|
['active' => $data['override'] === 'on'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// csak ennek az egy usernek a gyorsítótárazott Pennant-feloldását
|
|
||||||
// érvénytelenítjük, a többi felhasználót nem érinti
|
|
||||||
Feature::for($user)->forget($record->name);
|
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
->toolbarActions([
|
->toolbarActions([
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
class FeatureFlag extends BaseAuditable
|
class FeatureFlag extends BaseAuditable
|
||||||
{
|
{
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@ -9,4 +11,9 @@ class FeatureFlag extends BaseAuditable
|
|||||||
'stages' => 'array',
|
'stages' => 'array',
|
||||||
'roles' => 'array',
|
'roles' => 'array',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function overrides(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(FeatureFlagOverride::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
app/Observers/FeatureFlagOverrideObserver.php
Normal file
33
app/Observers/FeatureFlagOverrideObserver.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Observers;
|
||||||
|
|
||||||
|
use App\Models\FeatureFlagOverride;
|
||||||
|
use Laravel\Pennant\Feature;
|
||||||
|
|
||||||
|
class FeatureFlagOverrideObserver
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Létrehozás/módosítás/törlés után csak az érintett usernek a gyorsítótárazott
|
||||||
|
* Pennant-feloldását érvénytelenítjük, a többi felhasználót nem érinti.
|
||||||
|
*/
|
||||||
|
public function saved(FeatureFlagOverride $override): void
|
||||||
|
{
|
||||||
|
$this->forget($override);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleted(FeatureFlagOverride $override): void
|
||||||
|
{
|
||||||
|
$this->forget($override);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function forget(FeatureFlagOverride $override): void
|
||||||
|
{
|
||||||
|
$user = $override->user;
|
||||||
|
$flag = $override->featureFlag;
|
||||||
|
|
||||||
|
if ($user && $flag) {
|
||||||
|
Feature::for($user)->forget($flag->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
app/Policies/FeatureFlagOverridePolicy.php
Normal file
50
app/Policies/FeatureFlagOverridePolicy.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\FeatureFlagOverride;
|
||||||
|
use App\Models\User;
|
||||||
|
use Laravel\Pennant\Feature;
|
||||||
|
|
||||||
|
class FeatureFlagOverridePolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Ugyanaz a "FeatureFlagAdmin" flag szabályozza a hozzáférést, mint a
|
||||||
|
* FeatureFlagPolicy-nál - a felülbírálások ugyanannak a jogosultsági
|
||||||
|
* körnek a részei, mint maguk a flagek.
|
||||||
|
*/
|
||||||
|
protected function hasAccess(User $user): bool
|
||||||
|
{
|
||||||
|
return Feature::for($user)->active('FeatureFlagAdmin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(User $user, FeatureFlagOverride $featureFlagOverride): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, FeatureFlagOverride $featureFlagOverride): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(User $user, FeatureFlagOverride $featureFlagOverride): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
app/Policies/FeatureFlagPolicy.php
Normal file
50
app/Policies/FeatureFlagPolicy.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\FeatureFlag;
|
||||||
|
use App\Models\User;
|
||||||
|
use Laravel\Pennant\Feature;
|
||||||
|
|
||||||
|
class FeatureFlagPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A feature flag admin felület elérését magára a "FeatureFlagAdmin" flagre bízzuk,
|
||||||
|
* hogy a hozzáférés szabályozása (stage/szerepkör/felhasználó szinten) deploy
|
||||||
|
* nélkül, az admin felületről állítható legyen.
|
||||||
|
*/
|
||||||
|
protected function hasAccess(User $user): bool
|
||||||
|
{
|
||||||
|
return Feature::for($user)->active('FeatureFlagAdmin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(User $user, FeatureFlag $featureFlag): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, FeatureFlag $featureFlag): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(User $user, FeatureFlag $featureFlag): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $this->hasAccess($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,9 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Models\FeatureFlag;
|
use App\Models\FeatureFlag;
|
||||||
|
use App\Models\FeatureFlagOverride;
|
||||||
use App\Observers\FeatureFlagObserver;
|
use App\Observers\FeatureFlagObserver;
|
||||||
|
use App\Observers\FeatureFlagOverrideObserver;
|
||||||
use App\Repositories\AddressRepository;
|
use App\Repositories\AddressRepository;
|
||||||
use App\Repositories\AddressRepositoryInterface;
|
use App\Repositories\AddressRepositoryInterface;
|
||||||
use App\Repositories\ContactRepository;
|
use App\Repositories\ContactRepository;
|
||||||
@ -58,6 +60,7 @@ public function boot(): void
|
|||||||
URL::forceScheme('https');
|
URL::forceScheme('https');
|
||||||
|
|
||||||
FeatureFlag::observe(FeatureFlagObserver::class);
|
FeatureFlag::observe(FeatureFlagObserver::class);
|
||||||
|
FeatureFlagOverride::observe(FeatureFlagOverrideObserver::class);
|
||||||
|
|
||||||
// Schema::hasTable védi a friss telepítést / migrate-et megelőző state-et,
|
// Schema::hasTable védi a friss telepítést / migrate-et megelőző state-et,
|
||||||
// amikor a feature_flags tábla még nem létezik.
|
// amikor a feature_flags tábla még nem létezik.
|
||||||
@ -103,6 +106,11 @@ public function boot(): void
|
|||||||
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.list-feature-flags', \App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags::class);
|
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.list-feature-flags', \App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags::class);
|
||||||
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.create-feature-flag', \App\Filament\Resources\FeatureFlags\Pages\CreateFeatureFlag::class);
|
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.create-feature-flag', \App\Filament\Resources\FeatureFlags\Pages\CreateFeatureFlag::class);
|
||||||
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.edit-feature-flag', \App\Filament\Resources\FeatureFlags\Pages\EditFeatureFlag::class);
|
\Livewire\Livewire::component('app.filament.resources.feature-flags.pages.edit-feature-flag', \App\Filament\Resources\FeatureFlags\Pages\EditFeatureFlag::class);
|
||||||
|
\Livewire\Livewire::component('app.filament.resources.feature-flags.relation-managers.overrides-relation-manager', \App\Filament\Resources\FeatureFlags\RelationManagers\OverridesRelationManager::class);
|
||||||
|
|
||||||
|
\Livewire\Livewire::component('app.filament.resources.feature-flag-overrides.pages.list-feature-flag-overrides', \App\Filament\Resources\FeatureFlagOverrides\Pages\ListFeatureFlagOverrides::class);
|
||||||
|
\Livewire\Livewire::component('app.filament.resources.feature-flag-overrides.pages.create-feature-flag-override', \App\Filament\Resources\FeatureFlagOverrides\Pages\CreateFeatureFlagOverride::class);
|
||||||
|
\Livewire\Livewire::component('app.filament.resources.feature-flag-overrides.pages.edit-feature-flag-override', \App\Filament\Resources\FeatureFlagOverrides\Pages\EditFeatureFlagOverride::class);
|
||||||
|
|
||||||
\Livewire\Livewire::component('filament.livewire.notifications', \Filament\Livewire\Notifications::class);
|
\Livewire\Livewire::component('filament.livewire.notifications', \Filament\Livewire\Notifications::class);
|
||||||
\Livewire\Livewire::component('filament.livewire.database-notifications', \Filament\Livewire\DatabaseNotifications::class);
|
\Livewire\Livewire::component('filament.livewire.database-notifications', \Filament\Livewire\DatabaseNotifications::class);
|
||||||
|
|||||||
@ -13,7 +13,8 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
* @var array<class-string, class-string>
|
* @var array<class-string, class-string>
|
||||||
*/
|
*/
|
||||||
protected $policies = [
|
protected $policies = [
|
||||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
\App\Models\FeatureFlag::class => \App\Policies\FeatureFlagPolicy::class,
|
||||||
|
\App\Models\FeatureFlagOverride::class => \App\Policies\FeatureFlagOverridePolicy::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -20,8 +20,18 @@
|
|||||||
['displayName' => 'Munkanaptárak', 'link' => \App\Filament\Resources\WorkCalendars\WorkCalendarResource::getUrl()],
|
['displayName' => 'Munkanaptárak', 'link' => \App\Filament\Resources\WorkCalendars\WorkCalendarResource::getUrl()],
|
||||||
]],
|
]],
|
||||||
['name' => 'calendarTest', 'displayName' => 'Naptár Teszt', 'icon' => 'idopontok', 'link' => \App\Filament\Pages\CalendarTest::getUrl(), 'roles' => ['root','developer','admin']],
|
['name' => 'calendarTest', 'displayName' => 'Naptár Teszt', 'icon' => 'idopontok', 'link' => \App\Filament\Pages\CalendarTest::getUrl(), 'roles' => ['root','developer','admin']],
|
||||||
['name' => 'featureFlags', 'displayName' => 'Feature flagek', 'icon' => 'setup', 'link' => \App\Filament\Resources\FeatureFlags\FeatureFlagResource::getUrl(), 'roles' => ['root','developer']],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// A feature flag admin felület megjelenítését nem statikus role-listával,
|
||||||
|
// hanem a FeatureFlagResource jogosultság-ellenőrzésével (FeatureFlagPolicy,
|
||||||
|
// ami a "FeatureFlagAdmin" flaget nézi) döntjük el - így a hozzáférés
|
||||||
|
// deploy nélkül, az admin felületről szabályozható.
|
||||||
|
if (\App\Filament\Resources\FeatureFlags\FeatureFlagResource::canViewAny()) {
|
||||||
|
$modules[] = ['name' => 'featureFlags', 'displayName' => 'Feature flagek', 'icon' => 'setup', 'roles' => ['root','developer','admin','profit-center'], 'children' => [
|
||||||
|
['displayName' => 'Flagek', 'link' => \App\Filament\Resources\FeatureFlags\FeatureFlagResource::getUrl()],
|
||||||
|
['displayName' => 'Egyéni felülbírálások', 'link' => \App\Filament\Resources\FeatureFlagOverrides\FeatureFlagOverrideResource::getUrl()],
|
||||||
|
]];
|
||||||
|
}
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<nav class="fi-speed-button-nav flex items-center h-full ml-4 w-full">
|
<nav class="fi-speed-button-nav flex items-center h-full ml-4 w-full">
|
||||||
|
|||||||
@ -1,30 +1,70 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlags\FeatureFlagResource;
|
||||||
use App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags;
|
use App\Filament\Resources\FeatureFlags\Pages\ListFeatureFlags;
|
||||||
use App\Models\FeatureFlag;
|
use App\Models\FeatureFlag;
|
||||||
use App\Models\Role;
|
use App\Models\Role;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Services\FeatureFlagRegistrar;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
uses(TestCase::class, RefreshDatabase::class);
|
uses(TestCase::class, RefreshDatabase::class);
|
||||||
|
|
||||||
test('a lista oldal hiba nélkül renderel, ha egy flagnek van szerepköre és stage-e', function () {
|
test('a lista oldal hiba nélkül renderel, ha egy flagnek van szerepköre és stage-e', function () {
|
||||||
$adminRole = Role::create(['name' => 'admin', 'display_name' => 'Admin']);
|
$devRole = Role::create(['name' => 'developer', 'display_name' => 'Developer']);
|
||||||
$admin = User::factory()->create();
|
$developer = User::factory()->create();
|
||||||
$admin->addRole($adminRole);
|
$developer->addRole($devRole);
|
||||||
|
|
||||||
|
FeatureFlag::create([
|
||||||
|
'name' => 'FeatureFlagAdmin',
|
||||||
|
'label' => 'Feature flag admin felület',
|
||||||
|
'enabled' => true,
|
||||||
|
'stages' => null,
|
||||||
|
'roles' => ['developer'],
|
||||||
|
]);
|
||||||
FeatureFlag::create([
|
FeatureFlag::create([
|
||||||
'name' => 'ui-test-flag',
|
'name' => 'ui-test-flag',
|
||||||
'label' => 'UI teszt flag',
|
'label' => 'UI teszt flag',
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'stages' => ['TEST'],
|
'stages' => ['TEST'],
|
||||||
'roles' => ['admin'],
|
'roles' => ['developer'],
|
||||||
]);
|
]);
|
||||||
|
app(FeatureFlagRegistrar::class)->registerAll();
|
||||||
|
|
||||||
$this->actingAs($admin);
|
$this->actingAs($developer);
|
||||||
|
|
||||||
Livewire::test(ListFeatureFlags::class)
|
Livewire::test(ListFeatureFlags::class)
|
||||||
->assertSuccessful();
|
->assertSuccessful();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('csak a FeatureFlagAdmin flaggel rendelkező szerepkör éri el a feature flag admin felületet', function () {
|
||||||
|
$adminRole = Role::create(['name' => 'admin', 'display_name' => 'Admin']);
|
||||||
|
$devRole = Role::create(['name' => 'developer', 'display_name' => 'Developer']);
|
||||||
|
|
||||||
|
$admin = User::factory()->create();
|
||||||
|
$admin->addRole($adminRole);
|
||||||
|
|
||||||
|
$developer = User::factory()->create();
|
||||||
|
$developer->addRole($devRole);
|
||||||
|
|
||||||
|
FeatureFlag::create([
|
||||||
|
'name' => 'FeatureFlagAdmin',
|
||||||
|
'label' => 'Feature flag admin felület',
|
||||||
|
'enabled' => true,
|
||||||
|
'stages' => null,
|
||||||
|
'roles' => ['developer'],
|
||||||
|
]);
|
||||||
|
app(FeatureFlagRegistrar::class)->registerAll();
|
||||||
|
|
||||||
|
expect(Gate::forUser($admin)->allows('viewAny', FeatureFlag::class))->toBeFalse();
|
||||||
|
expect(Gate::forUser($developer)->allows('viewAny', FeatureFlag::class))->toBeTrue();
|
||||||
|
|
||||||
|
$this->actingAs($admin);
|
||||||
|
$this->get(FeatureFlagResource::getUrl())->assertForbidden();
|
||||||
|
|
||||||
|
$this->actingAs($developer);
|
||||||
|
$this->get(FeatureFlagResource::getUrl())->assertSuccessful();
|
||||||
|
});
|
||||||
|
|||||||
103
tests/Feature/FeatureFlagOverrideUiTest.php
Normal file
103
tests/Feature/FeatureFlagOverrideUiTest.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\FeatureFlagOverrideResource;
|
||||||
|
use App\Filament\Resources\FeatureFlagOverrides\Pages\ListFeatureFlagOverrides;
|
||||||
|
use App\Filament\Resources\FeatureFlags\Pages\EditFeatureFlag;
|
||||||
|
use App\Models\FeatureFlag;
|
||||||
|
use App\Models\FeatureFlagOverride;
|
||||||
|
use App\Models\Role;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\FeatureFlagRegistrar;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Laravel\Pennant\Feature;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
uses(TestCase::class, RefreshDatabase::class);
|
||||||
|
|
||||||
|
function actAsDeveloper(): User
|
||||||
|
{
|
||||||
|
$devRole = Role::firstOrCreate(['name' => 'developer'], ['display_name' => 'Developer']);
|
||||||
|
$developer = User::factory()->create();
|
||||||
|
$developer->addRole($devRole);
|
||||||
|
|
||||||
|
FeatureFlag::firstOrCreate(
|
||||||
|
['name' => 'FeatureFlagAdmin'],
|
||||||
|
['label' => 'Feature flag admin felület', 'enabled' => true, 'stages' => null, 'roles' => ['developer']],
|
||||||
|
);
|
||||||
|
app(FeatureFlagRegistrar::class)->registerAll();
|
||||||
|
|
||||||
|
return $developer;
|
||||||
|
}
|
||||||
|
|
||||||
|
test('a flag szerkesztő oldalán megjelenik az egyéni felülbírálások relation manager', function () {
|
||||||
|
$developer = actAsDeveloper();
|
||||||
|
|
||||||
|
$flag = FeatureFlag::create([
|
||||||
|
'name' => 'rm-test-flag',
|
||||||
|
'label' => 'RM teszt flag',
|
||||||
|
'enabled' => true,
|
||||||
|
]);
|
||||||
|
app(FeatureFlagRegistrar::class)->registerAll();
|
||||||
|
|
||||||
|
$targetUser = User::factory()->create();
|
||||||
|
FeatureFlagOverride::create([
|
||||||
|
'feature_flag_id' => $flag->id,
|
||||||
|
'user_id' => $targetUser->id,
|
||||||
|
'active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->actingAs($developer);
|
||||||
|
|
||||||
|
Livewire::test(EditFeatureFlag::class, ['record' => $flag->getRouteKey()])
|
||||||
|
->assertSuccessful();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a globális felülbírálás lista renderel, és csak fejlesztők érik el', function () {
|
||||||
|
$developer = actAsDeveloper();
|
||||||
|
|
||||||
|
$adminRole = Role::firstOrCreate(['name' => 'admin'], ['display_name' => 'Admin']);
|
||||||
|
$admin = User::factory()->create();
|
||||||
|
$admin->addRole($adminRole);
|
||||||
|
|
||||||
|
expect(Gate::forUser($admin)->allows('viewAny', FeatureFlagOverride::class))->toBeFalse();
|
||||||
|
expect(Gate::forUser($developer)->allows('viewAny', FeatureFlagOverride::class))->toBeTrue();
|
||||||
|
|
||||||
|
$this->actingAs($admin);
|
||||||
|
$this->get(FeatureFlagOverrideResource::getUrl())->assertForbidden();
|
||||||
|
|
||||||
|
$this->actingAs($developer);
|
||||||
|
Livewire::test(ListFeatureFlagOverrides::class)->assertSuccessful();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('az "örökölt"-re állítás (mass delete) is érvényteleníti a gyorsítótárazott Pennant-feloldást', function () {
|
||||||
|
actAsDeveloper();
|
||||||
|
|
||||||
|
$flag = FeatureFlag::create([
|
||||||
|
'name' => 'purge-test-flag',
|
||||||
|
'label' => 'Purge teszt flag',
|
||||||
|
'enabled' => false,
|
||||||
|
]);
|
||||||
|
app(FeatureFlagRegistrar::class)->registerAll();
|
||||||
|
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
FeatureFlagOverride::create([
|
||||||
|
'feature_flag_id' => $flag->id,
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'active' => true,
|
||||||
|
]);
|
||||||
|
Feature::for($user)->forget('purge-test-flag');
|
||||||
|
expect(Feature::for($user)->active('purge-test-flag'))->toBeTrue();
|
||||||
|
|
||||||
|
// ugyanaz a mintázat, mint amit a FeatureFlagsTable "Egyéni felülbírálás"
|
||||||
|
// akciója az "örökölt" választásnál használ - model-instance delete()-en
|
||||||
|
// keresztül, hogy a FeatureFlagOverrideObserver kiváltódjon
|
||||||
|
FeatureFlagOverride::where('feature_flag_id', $flag->id)
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->first()
|
||||||
|
?->delete();
|
||||||
|
|
||||||
|
expect(Feature::for($user)->active('purge-test-flag'))->toBeFalse();
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user