feat(prohibition): add default times for expires_at field & filter/scopes (#1057)

This commit is contained in:
Kyrch
2026-01-21 23:27:44 -03:00
committed by GitHub
parent 33650905d9
commit dfd958ef69
8 changed files with 236 additions and 47 deletions
@@ -11,8 +11,11 @@ use App\Filament\Components\Fields\TextInput;
use App\Filament\Resources\Auth\Prohibition as ProhibitionResource; use App\Filament\Resources\Auth\Prohibition as ProhibitionResource;
use App\Models\Auth\Prohibition; use App\Models\Auth\Prohibition;
use App\Models\Auth\User; use App\Models\Auth\User;
use Filament\Actions\Action;
use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\DateTimePicker;
use Filament\Schemas\Schema; use Filament\Schemas\Schema;
use Filament\Support\Colors\Color;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Date;
@@ -49,7 +52,9 @@ class GiveProhibitionAction extends BaseAction
$reason = Arr::get($data, 'reason'); $reason = Arr::get($data, 'reason');
$expiresAt = Date::createFromFormat('Y-m-d H:i:s', Arr::get($data, 'expires_at')); $expiresAt = ($expiresAtField = Arr::get($data, 'expires_at'))
? Date::createFromFormat('Y-m-d H:i:s', $expiresAtField)
: null;
$user->prohibit($prohibition, $expiresAt, $reason, Auth::user()); $user->prohibit($prohibition, $expiresAt, $reason, Auth::user());
@@ -72,15 +77,85 @@ class GiveProhibitionAction extends BaseAction
->required() ->required()
->options($prohibitions), ->options($prohibitions),
DateTimePicker::make('expires_at') static::getExpiresAtField(),
->label(__('filament.actions.user.give_prohibition.expires_at.name'))
->helperText(__('filament.actions.user.give_prohibition.expires_at.help'))
->nullable(),
TextInput::make('reason') static::getReasonField(),
->label(__('filament.actions.user.give_prohibition.reason.name'))
->helperText(__('filament.actions.user.give_prohibition.reason.help'))
->required(),
]); ]);
} }
public static function getExpiresAtField(): DateTimePicker
{
return DateTimePicker::make('expires_at')
->label(__('filament.actions.user.give_prohibition.expires_at.name'))
->helperText(__('filament.actions.user.give_prohibition.expires_at.help'))
->default(now())
->native(false)
->hintActions(static::getHintDateActions())
->suffixAction(
Action::make('clear')
->icon(Heroicon::Trash)
->color(Color::Red)
->action(fn (DateTimePicker $component): DateTimePicker => $component->state(null))
)
->minDate(now())
->nullable();
}
public static function getReasonField(): TextInput
{
return TextInput::make('reason')
->label(__('filament.actions.user.give_prohibition.reason.name'))
->helperText(__('filament.actions.user.give_prohibition.reason.help'))
->required();
}
/**
* Get hint actions for date picker.
*
* @return Action[]
*/
public static function getHintDateActions(): array
{
return [
Action::make('1 hour')
->label('+1 hour')
->action(
fn (DateTimePicker $component): DateTimePicker => $component->state(
Date::parse($component->getState() ?? now())
->addHour()
->format($component->getFormat())
)
),
Action::make('1 day')
->label('+1 day')
->action(
fn (DateTimePicker $component): DateTimePicker => $component->state(
Date::parse($component->getState() ?? now())
->addDay()
->format($component->getFormat())
)
),
Action::make('1 week')
->label('+1 week')
->action(
fn (DateTimePicker $component): DateTimePicker => $component->state(
Date::parse($component->getState() ?? now())
->addWeek()
->format($component->getFormat())
)
),
Action::make('1 month')
->label('+1 month')
->action(
fn (DateTimePicker $component): DateTimePicker => $component->state(
Date::parse($component->getState() ?? now())
->addMonth()
->format($component->getFormat())
)
),
];
}
} }
@@ -7,11 +7,9 @@ namespace App\Filament\Actions\Models\Auth\User;
use App\Events\Auth\Sanction\ModelSanctioned; use App\Events\Auth\Sanction\ModelSanctioned;
use App\Filament\Actions\BaseAction; use App\Filament\Actions\BaseAction;
use App\Filament\Components\Fields\Select; use App\Filament\Components\Fields\Select;
use App\Filament\Components\Fields\TextInput;
use App\Filament\Resources\Auth\Sanction as SanctionResource; use App\Filament\Resources\Auth\Sanction as SanctionResource;
use App\Models\Auth\Sanction; use App\Models\Auth\Sanction;
use App\Models\Auth\User; use App\Models\Auth\User;
use Filament\Forms\Components\DateTimePicker;
use Filament\Schemas\Schema; use Filament\Schemas\Schema;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@@ -48,7 +46,9 @@ class GiveSanctionAction extends BaseAction
$reason = Arr::get($data, 'reason'); $reason = Arr::get($data, 'reason');
$expiresAt = Date::createFromFormat('Y-m-d H:i:s', Arr::get($data, 'expires_at')); $expiresAt = ($expiresAtField = Arr::get($data, 'expires_at'))
? Date::createFromFormat('Y-m-d H:i:s', $expiresAtField)
: null;
$user->applySanction($sanction, $expiresAt, $reason, Auth::user()); $user->applySanction($sanction, $expiresAt, $reason, Auth::user());
@@ -71,15 +71,11 @@ class GiveSanctionAction extends BaseAction
->required() ->required()
->options($sanctions), ->options($sanctions),
DateTimePicker::make('expires_at') GiveProhibitionAction::getExpiresAtField()
->label(__('filament.actions.user.give_sanction.expires_at.name')) ->helperText(__('filament.actions.user.give_sanction.expires_at.help')),
->helperText(__('filament.actions.user.give_sanction.expires_at.help'))
->nullable(),
TextInput::make('reason') GiveProhibitionAction::getReasonField()
->label(__('filament.actions.user.give_sanction.reason.name')) ->helperText(__('filament.actions.user.give_sanction.reason.help')),
->helperText(__('filament.actions.user.give_sanction.reason.help'))
->required(),
]); ]);
} }
} }
@@ -4,13 +4,14 @@ declare(strict_types=1);
namespace App\Filament\Resources\Auth\User\RelationManagers; namespace App\Filament\Resources\Auth\User\RelationManagers;
use App\Filament\Actions\Models\Auth\User\GiveProhibitionAction;
use App\Filament\Components\Columns\TextColumn; use App\Filament\Components\Columns\TextColumn;
use App\Filament\Components\Fields\TextInput;
use App\Filament\RelationManagers\Auth\ProhibitionRelationManager; use App\Filament\RelationManagers\Auth\ProhibitionRelationManager;
use App\Models\Auth\Prohibition; use App\Models\Auth\Prohibition;
use App\Models\Auth\User; use App\Models\Auth\User;
use Filament\Forms\Components\DateTimePicker; use Filament\Tables\Filters\Filter;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Support\Facades\Config;
class ProhibitionUserRelationManager extends ProhibitionRelationManager class ProhibitionUserRelationManager extends ProhibitionRelationManager
{ {
@@ -22,14 +23,9 @@ class ProhibitionUserRelationManager extends ProhibitionRelationManager
public function getPivotComponents(): array public function getPivotComponents(): array
{ {
return [ return [
DateTimePicker::make('expires_at') GiveProhibitionAction::getExpiresAtField(),
->label(__('filament.actions.user.give_prohibition.expires_at.name'))
->helperText(__('filament.actions.user.give_prohibition.expires_at.help'))
->nullable(),
TextInput::make('reason') GiveProhibitionAction::getReasonField()
->label(__('filament.actions.user.give_prohibition.reason.name'))
->helperText(__('filament.actions.user.give_prohibition.reason.help'))
->disabled(), ->disabled(),
]; ];
} }
@@ -51,11 +47,25 @@ class ProhibitionUserRelationManager extends ProhibitionRelationManager
return parent::table( return parent::table(
$table $table
->inverseRelationship(Prohibition::RELATION_USERS) ->inverseRelationship(Prohibition::RELATION_USERS)
); )
->defaultSort(Config::string('prohibition.table_names.model_prohibitions').'.created_at', 'desc');
} }
public static function getBulkActions(?array $actionsIncludedInGroup = []): array public static function getBulkActions(?array $actionsIncludedInGroup = []): array
{ {
return []; return [];
} }
public static function getFilters(): array
{
return [
...parent::getFilters(),
Filter::make('expired')
->modifyQueryUsing(fn ($query) => $query->expired()),
Filter::make('not expired')
->modifyQueryUsing(fn ($query) => $query->notExpired()),
];
}
} }
@@ -4,13 +4,14 @@ declare(strict_types=1);
namespace App\Filament\Resources\Auth\User\RelationManagers; namespace App\Filament\Resources\Auth\User\RelationManagers;
use App\Filament\Actions\Models\Auth\User\GiveProhibitionAction;
use App\Filament\Components\Columns\TextColumn; use App\Filament\Components\Columns\TextColumn;
use App\Filament\Components\Fields\TextInput;
use App\Filament\RelationManagers\Auth\SanctionRelationManager; use App\Filament\RelationManagers\Auth\SanctionRelationManager;
use App\Models\Auth\Sanction; use App\Models\Auth\Sanction;
use App\Models\Auth\User; use App\Models\Auth\User;
use Filament\Forms\Components\DateTimePicker; use Filament\Tables\Filters\Filter;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Support\Facades\Config;
class SanctionUserRelationManager extends SanctionRelationManager class SanctionUserRelationManager extends SanctionRelationManager
{ {
@@ -19,24 +20,13 @@ class SanctionUserRelationManager extends SanctionRelationManager
*/ */
protected static string $relationship = User::RELATION_SANCTIONS; protected static string $relationship = User::RELATION_SANCTIONS;
public function table(Table $table): Table
{
return parent::table(
$table
->inverseRelationship(Sanction::RELATION_USERS)
);
}
public function getPivotComponents(): array public function getPivotComponents(): array
{ {
return [ return [
DateTimePicker::make('expires_at') GiveProhibitionAction::getExpiresAtField()
->label(__('filament.actions.user.give_sanction.expires_at.name')) ->helperText(__('filament.actions.user.give_sanction.expires_at.help')),
->helperText(__('filament.actions.user.give_sanction.expires_at.help'))
->nullable(),
TextInput::make('reason') GiveProhibitionAction::getReasonField()
->label(__('filament.actions.user.give_sanction.reason.name'))
->helperText(__('filament.actions.user.give_sanction.reason.help')) ->helperText(__('filament.actions.user.give_sanction.reason.help'))
->disabled(), ->disabled(),
]; ];
@@ -56,6 +46,15 @@ class SanctionUserRelationManager extends SanctionRelationManager
]; ];
} }
public function table(Table $table): Table
{
return parent::table(
$table
->inverseRelationship(Sanction::RELATION_USERS)
)
->defaultSort(Config::string('prohibition.table_names.model_sanctions').'.created_at', 'desc');
}
/** /**
* @return array<int, \Filament\Actions\Action> * @return array<int, \Filament\Actions\Action>
*/ */
@@ -70,4 +69,17 @@ class SanctionUserRelationManager extends SanctionRelationManager
{ {
return []; return [];
} }
public static function getFilters(): array
{
return [
...parent::getFilters(),
Filter::make('expired')
->modifyQueryUsing(fn ($query) => $query->expired()),
Filter::make('not expired')
->modifyQueryUsing(fn ($query) => $query->notExpired()),
];
}
} }
+20
View File
@@ -5,6 +5,9 @@ declare(strict_types=1);
namespace App\Models\Auth; namespace App\Models\Auth;
use App\Contracts\Models\Nameable; use App\Contracts\Models\Nameable;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Config;
use Kyrch\Prohibition\Models\Prohibition as BaseProhibition; use Kyrch\Prohibition\Models\Prohibition as BaseProhibition;
class Prohibition extends BaseProhibition implements Nameable class Prohibition extends BaseProhibition implements Nameable
@@ -21,4 +24,21 @@ class Prohibition extends BaseProhibition implements Nameable
{ {
return $this->name; return $this->name;
} }
#[Scope]
protected function expired(Builder $query): Builder
{
$tableName = Config::string('prohibition.table_names.model_prohibitions');
return $query->where("$tableName.expires_at", '<', now());
}
#[Scope]
protected function notExpired(Builder $query): Builder
{
$tableName = Config::string('prohibition.table_names.model_prohibitions');
return $query->where("$tableName.expires_at", '>', now())
->orWhereNull("$tableName.expires_at");
}
} }
+20
View File
@@ -5,6 +5,9 @@ declare(strict_types=1);
namespace App\Models\Auth; namespace App\Models\Auth;
use App\Contracts\Models\Nameable; use App\Contracts\Models\Nameable;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Config;
use Kyrch\Prohibition\Models\Sanction as BaseSanction; use Kyrch\Prohibition\Models\Sanction as BaseSanction;
class Sanction extends BaseSanction implements Nameable class Sanction extends BaseSanction implements Nameable
@@ -21,4 +24,21 @@ class Sanction extends BaseSanction implements Nameable
{ {
return $this->name; return $this->name;
} }
#[Scope]
protected function expired(Builder $query): Builder
{
$tableName = Config::string('prohibition.table_names.model_sanctions');
return $query->where("$tableName.expires_at", '<', now());
}
#[Scope]
protected function notExpired(Builder $query): Builder
{
$tableName = Config::string('prohibition.table_names.model_sanctions');
return $query->where("$tableName.expires_at", '>', now())
->orWhereNull("$tableName.expires_at");
}
} }
@@ -57,7 +57,7 @@ class ProhibitionOrSanctionNotification extends Notification
return "This {$type} is permanent."; return "This {$type} is permanent.";
} }
$human = Date::instance($this->expiresAt)->diffForHumans(syntax: Carbon::DIFF_ABSOLUTE, parts: 4); $human = Date::instance($this->expiresAt)->diffForHumans(syntax: Carbon::DIFF_ABSOLUTE, parts: 3);
return "This {$type} will expire in {$human}."; return "This {$type} will expire in {$human}.";
} }
+56
View File
@@ -86,6 +86,62 @@ class UserPolicy extends BasePolicy
: Response::deny(); : Response::deny();
} }
public function attachAnySanction(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function attachSanction(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function detachAnySanction(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function detachSanction(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function attachAnyProhibition(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function attachProhibition(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function detachAnyProhibition(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function detachProhibition(User $user): Response
{
return $user->hasRole(RoleEnum::ADMIN->value)
? Response::allow()
: Response::deny();
}
public function addPlaylist(User $user): Response public function addPlaylist(User $user): Response
{ {
return $user->hasRole(RoleEnum::ADMIN->value) return $user->hasRole(RoleEnum::ADMIN->value)