mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-24 03:57:22 +08:00
admin add claim
This commit is contained in:
@@ -78,8 +78,8 @@ class Test extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$r = range(0, 23);
|
||||
dd($r);
|
||||
$r = User::query()->find(10003, ['id', 'added', 'donoruntil']);
|
||||
dd($r->donoruntil->toDateTimeString() < '1978');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,4 +7,12 @@ trait OptionsTrait
|
||||
private static array $matchTypes = ['dec' => 'dec', 'hex' => 'hex'];
|
||||
|
||||
private static array $yesOrNo = ['yes' => 'yes', 'no' => 'no'];
|
||||
|
||||
private static function getEnableDisableOptions($enableValue = 0, $disableValue = 1): array
|
||||
{
|
||||
return [
|
||||
$enableValue => __('label.enabled'),
|
||||
$disableValue => __('label.disabled'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ class AgentAllowResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.agent_allows');
|
||||
|
||||
@@ -21,6 +21,8 @@ class AgentDenyResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 4;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.agent_denies');
|
||||
|
||||
@@ -14,6 +14,7 @@ use Filament\Resources\Table;
|
||||
use Filament\Tables;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ExamResource extends Resource
|
||||
{
|
||||
@@ -25,9 +26,9 @@ class ExamResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
const IS_DISCOVERED_OPTIONS = ['0' => 'No', '1' => 'Yes'];
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
const STATUS_OPTIONS = ['0' => 'Enabled', '1' => 'Disabled'];
|
||||
const IS_DISCOVERED_OPTIONS = ['0' => 'No', '1' => 'Yes'];
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
@@ -44,46 +45,67 @@ class ExamResource extends Resource
|
||||
$userRep = new UserRepository();
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('Base info')->schema([
|
||||
Forms\Components\Section::make(__('label.exam.section_base_info'))->schema([
|
||||
Forms\Components\TextInput::make('name')->required()->columnSpan(['sm' => 2])->label(__('label.name')),
|
||||
Forms\Components\TextInput::make('priority')
|
||||
->columnSpan(['sm' => 2])
|
||||
->label(__("label.priority"))
|
||||
->helperText('The higher the value, the higher the priority, and when multiple exam match the same user, the one with the highest priority is assigned.'),
|
||||
Forms\Components\Repeater::make('indexes')->schema([
|
||||
Forms\Components\Select::make('index')
|
||||
->options(Exam::listIndex(true))
|
||||
->label(__('label.exam.index_required_label'))
|
||||
->rules([Rule::in(array_keys(Exam::$indexes))])
|
||||
->required(),
|
||||
Forms\Components\TextInput::make('require_value')
|
||||
->label(__('label.exam.index_required_value'))
|
||||
->placeholder(__('label.exam.index_placeholder'))
|
||||
->integer()
|
||||
->required(),
|
||||
Forms\Components\Hidden::make('checked')->default(true),
|
||||
])
|
||||
->label(__('label.exam.index_formatted'))
|
||||
->required(),
|
||||
|
||||
Forms\Components\Radio::make('status')
|
||||
->options(self::STATUS_OPTIONS)
|
||||
->options(self::getEnableDisableOptions())
|
||||
->inline()
|
||||
->required()
|
||||
->label(__('label.status'))
|
||||
->columnSpan(['sm' => 2]),
|
||||
Forms\Components\Radio::make('is_discovered')
|
||||
->options(self::IS_DISCOVERED_OPTIONS)
|
||||
->label(__('label.exam.is_discovered'))
|
||||
->inline()
|
||||
->required()
|
||||
->columnSpan(['sm' => 2]),
|
||||
Forms\Components\TextInput::make('priority')
|
||||
->columnSpan(['sm' => 2])
|
||||
->integer()
|
||||
->label(__("label.priority"))
|
||||
->helperText(__('label.exam.priority_help')),
|
||||
])->columns(2),
|
||||
|
||||
Forms\Components\Section::make('Time')->schema([
|
||||
Forms\Components\Section::make(__('label.exam.section_time'))->schema([
|
||||
Forms\Components\DateTimePicker::make('begin')->label(__('label.begin')),
|
||||
Forms\Components\DateTimePicker::make('end')->label(__('label.begin')),
|
||||
Forms\Components\TextInput::make('duration')
|
||||
->integer()
|
||||
->columnSpan(['sm' => 2])
|
||||
->label(__('label.duration'))
|
||||
->helperText('Unit: days. When assign to user, begin and end are used if they are specified. Otherwise begin time is the time at assignment, and the end time is the time at assignment plus the duration.'),
|
||||
->helperText(__('label.exam.duration_help')),
|
||||
])->columns(2),
|
||||
|
||||
Forms\Components\Section::make('Select user')->schema([
|
||||
Forms\Components\Section::make(__('label.exam.section_target_user'))->schema([
|
||||
Forms\Components\CheckboxList::make('filters.classes')
|
||||
->options($userRep->listClass())->columnSpan(['sm' => 2])
|
||||
->columns(4)
|
||||
->label(__('label.user.class')),
|
||||
Forms\Components\DateTimePicker::make('filters.register_time_range.0')->label(__("label.exam.register_time_range.begin")),
|
||||
Forms\Components\DateTimePicker::make('filters.register_time_range.1')->label(__("label.exam.register_time_range.end")),
|
||||
Forms\Components\Toggle::make('filters.donate_status')->label(__('label.exam.donated')),
|
||||
Forms\Components\CheckboxList::make('filters.donate_status')
|
||||
->options(self::$yesOrNo)
|
||||
->label(__('label.exam.donated')),
|
||||
])->columns(2),
|
||||
|
||||
|
||||
Forms\Components\Textarea::make('description')->columnSpan(['sm' => 2]),
|
||||
Forms\Components\Textarea::make('description')->columnSpan(['sm' => 2])->label(__('label.description')),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -104,10 +126,10 @@ class ExamResource extends Resource
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\SelectFilter::make('is_discovered')->options(self::IS_DISCOVERED_OPTIONS)->label(__("label.exam.is_discovered")),
|
||||
Tables\Filters\SelectFilter::make('status')->options(self::STATUS_OPTIONS)->label(__("label.status")),
|
||||
Tables\Filters\SelectFilter::make('status')->options(self::getEnableDisableOptions())->label(__("label.status")),
|
||||
])
|
||||
->actions([
|
||||
// Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
@@ -125,8 +147,8 @@ class ExamResource extends Resource
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListExams::route('/'),
|
||||
// 'create' => Pages\CreateExam::route('/create'),
|
||||
// 'edit' => Pages\EditExam::route('/{record}/edit'),
|
||||
'create' => Pages\CreateExam::route('/create'),
|
||||
'edit' => Pages\EditExam::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,34 @@
|
||||
namespace App\Filament\Resources\System\ExamResource\Pages;
|
||||
|
||||
use App\Filament\Resources\System\ExamResource;
|
||||
use App\Repositories\ExamRepository;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateExam extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ExamResource::class;
|
||||
|
||||
public function create(bool $another = false): void
|
||||
{
|
||||
$data = $this->form->getState();
|
||||
// dd($data);
|
||||
$examRep = new ExamRepository();
|
||||
try {
|
||||
$examRep->store($data);
|
||||
$this->notify('success', $this->getCreatedNotificationMessage());
|
||||
if ($another) {
|
||||
// Ensure that the form record is anonymized so that relationships aren't loaded.
|
||||
$this->form->model($this->record::class);
|
||||
$this->record = null;
|
||||
|
||||
$this->fillForm();
|
||||
|
||||
return;
|
||||
}
|
||||
$this->redirect($this->getRedirectUrl());
|
||||
} catch (\Exception $exception) {
|
||||
$this->notify('danger', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Resources\System\ExamResource\Pages;
|
||||
|
||||
use App\Filament\Resources\System\ExamResource;
|
||||
use App\Repositories\ExamRepository;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
@@ -16,4 +17,17 @@ class EditExam extends EditRecord
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
public function save(bool $shouldRedirect = true): void
|
||||
{
|
||||
$data = $this->form->getState();
|
||||
$examRep = new ExamRepository();
|
||||
try {
|
||||
$examRep->update($data, $this->record->id);
|
||||
$this->notify('success', $this->getSavedNotificationMessage());
|
||||
$this->redirect($this->getResource()::getUrl('index'));
|
||||
} catch (\Exception $exception) {
|
||||
$this->notify('danger', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class ListExams extends PageList
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
// Actions\CreateAction::make(),
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ class MedalResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.medals_list');
|
||||
|
||||
@@ -24,7 +24,7 @@ class SettingResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'System';
|
||||
|
||||
protected static bool $shouldRegisterNavigation = true;
|
||||
protected static ?int $navigationSort = 100;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@ class TagResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'Torrent';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.tags_list');
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User;
|
||||
|
||||
use App\Filament\Resources\User\ClaimResource\Pages;
|
||||
use App\Filament\Resources\User\ClaimResource\RelationManagers;
|
||||
use App\Models\Claim;
|
||||
use Filament\Forms;
|
||||
use Filament\Resources\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Resources\Table;
|
||||
use Filament\Tables;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class ClaimResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Claim::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-collection';
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 4;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.claims');
|
||||
}
|
||||
|
||||
public static function getBreadcrumb(): string
|
||||
{
|
||||
return self::getNavigationLabel();
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
//
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id')->sortable(),
|
||||
Tables\Columns\TextColumn::make('user.username')->label(__('label.user.label'))->searchable(),
|
||||
Tables\Columns\TextColumn::make('torrent.name')->limit(50)->label(__('label.torrent.label'))->searchable(),
|
||||
Tables\Columns\TextColumn::make('torrent.size')->label(__('label.torrent.size'))->formatStateUsing(fn ($record) => mksize($record->size)),
|
||||
Tables\Columns\TextColumn::make('torrent.added')->label(__('label.torrent.ttl'))->formatStateUsing(fn ($record) => mkprettytime($record->added)),
|
||||
Tables\Columns\TextColumn::make('created_at')->label(__('label.created_at'))->dateTime(),
|
||||
Tables\Columns\TextColumn::make('last_settle_at')->label(__('label.claim.last_settle_at'))->dateTime(),
|
||||
Tables\Columns\TextColumn::make('seedTimeThisMonth')->label(__('label.claim.seed_time_this_month')),
|
||||
Tables\Columns\TextColumn::make('uploadedThisMonth')->label(__('label.claim.uploaded_this_month')),
|
||||
Tables\Columns\BooleanColumn::make('isReachedThisMonth')->label(__('label.claim.is_reached_this_month')),
|
||||
])
|
||||
->defaultSort('id', 'desc')
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->actions([
|
||||
// Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->bulkActions([
|
||||
// Tables\Actions\DeleteBulkAction::make(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListClaims::route('/'),
|
||||
'create' => Pages\CreateClaim::route('/create'),
|
||||
'edit' => Pages\EditClaim::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\ClaimResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\ClaimResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateClaim extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ClaimResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\ClaimResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\ClaimResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditClaim extends EditRecord
|
||||
{
|
||||
protected static string $resource = ClaimResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\ClaimResource\Pages;
|
||||
|
||||
use App\Filament\PageList;
|
||||
use App\Filament\Resources\User\ClaimResource;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListClaims extends PageList
|
||||
{
|
||||
protected static string $resource = ClaimResource::class;
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
// Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ class ExamUserResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.exam_users');
|
||||
@@ -61,7 +63,7 @@ class ExamUserResource extends Resource
|
||||
Tables\Filters\SelectFilter::make('is_done')->options(['0' => 'No', '1' => 'yes'])->label(__('label.exam.is_done')),
|
||||
])
|
||||
->actions([
|
||||
// Tables\Actions\ViewAction::make(),
|
||||
Tables\Actions\ViewAction::make(),
|
||||
])
|
||||
->prependBulkActions([
|
||||
Tables\Actions\BulkAction::make('Avoid')->action(function (Collection $records) {
|
||||
@@ -86,8 +88,9 @@ class ExamUserResource extends Resource
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListExamUsers::route('/'),
|
||||
'create' => Pages\CreateExamUser::route('/create'),
|
||||
'edit' => Pages\EditExamUser::route('/{record}/edit'),
|
||||
// 'create' => Pages\CreateExamUser::route('/create'),
|
||||
// 'edit' => Pages\EditExamUser::route('/{record}/edit'),
|
||||
'view' => Pages\ViewExamUser::route('/{record}'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\User\ExamUserResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\ExamUserResource;
|
||||
use App\Repositories\ExamRepository;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class ViewExamUser extends ViewRecord
|
||||
{
|
||||
protected static string $resource = ExamUserResource::class;
|
||||
|
||||
protected static string $view = 'filament.resources.user.exam-user-resource.pages.detail';
|
||||
|
||||
private function getDetailCardData(): array
|
||||
{
|
||||
// dd($this->record->progressFormatted);
|
||||
$data = [];
|
||||
$record = $this->record;
|
||||
$data[] = [
|
||||
'label' => 'ID',
|
||||
'value' => $record->id,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.status'),
|
||||
'value' => $record->statusText,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.username'),
|
||||
'value' => $record->user->username,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.exam.label'),
|
||||
'value' => $record->exam->name,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.begin'),
|
||||
'value' => $record->begin,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.end'),
|
||||
'value' => $record->end,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.exam_user.is_done'),
|
||||
'value' => $record->isDoneText,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.created_at'),
|
||||
'value' => $record->created_at,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.updated_at'),
|
||||
'value' => $record->updated_at,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getViewData(): array
|
||||
{
|
||||
return [
|
||||
'cardData' => $this->getDetailCardData(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\Action::make('Avoid')
|
||||
->requiresConfirmation()
|
||||
->action(function () {
|
||||
$examRep = new ExamRepository();
|
||||
try {
|
||||
$examRep->avoidExamUser($this->record->id);
|
||||
$this->notify('success', 'Success !');
|
||||
$this->record = $this->resolveRecord($this->record->id);
|
||||
} catch (\Exception $exception) {
|
||||
$this->notify('danger', $exception->getMessage());
|
||||
}
|
||||
})
|
||||
->label(__('admin.resources.exam_user.action_avoid')),
|
||||
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getProgress()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ class HitAndRunResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.hit_and_runs');
|
||||
@@ -34,18 +36,18 @@ class HitAndRunResource extends Resource
|
||||
return self::getNavigationLabel();
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema(Forms\Components\Card::make()->schema([
|
||||
// Forms\Components\Select::make('user')->relationship('user', 'username')->required(),
|
||||
// Forms\Components\Select::make('torrent_id')->relationship('torrent', 'name')->required(),
|
||||
Forms\Components\Radio::make('status')->options(HitAndRun::listStatus(true))->inline()->required(),
|
||||
// Forms\Components\Select::make('snatch_id')->relationship('snatch', 'uploaded'),
|
||||
Forms\Components\Textarea::make('comment'),
|
||||
Forms\Components\DateTimePicker::make('created_at')->displayFormat('Y-m-d H:i:s'),
|
||||
]));
|
||||
}
|
||||
// public static function form(Form $form): Form
|
||||
// {
|
||||
// return $form
|
||||
// ->schema(Forms\Components\Card::make()->schema([
|
||||
//// Forms\Components\Select::make('user')->relationship('user', 'username')->required(),
|
||||
//// Forms\Components\Select::make('torrent_id')->relationship('torrent', 'name')->required(),
|
||||
// Forms\Components\Radio::make('status')->options(HitAndRun::listStatus(true))->inline()->required(),
|
||||
//// Forms\Components\Select::make('snatch_id')->relationship('snatch', 'uploaded'),
|
||||
// Forms\Components\Textarea::make('comment'),
|
||||
// Forms\Components\DateTimePicker::make('created_at')->displayFormat('Y-m-d H:i:s'),
|
||||
// ]));
|
||||
// }
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
@@ -74,6 +76,8 @@ class HitAndRunResource extends Resource
|
||||
$rep->bulkPardon(['id' => $idArr], Auth::user());
|
||||
})
|
||||
->deselectRecordsAfterCompletion()
|
||||
->label(__('admin.resources.hit_and_run.bulk_action_pardon'))
|
||||
->icon('heroicon-o-x')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,22 +4,98 @@ namespace App\Filament\Resources\User\HitAndRunResource\Pages;
|
||||
|
||||
use App\Filament\Resources\User\HitAndRunResource;
|
||||
use App\Models\HitAndRun;
|
||||
use App\Repositories\HitAndRunRepository;
|
||||
use Filament\Pages\Actions;
|
||||
use Filament\Resources\Pages\ViewRecord;
|
||||
use Filament\Forms;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ViewHitAndRun extends ViewRecord
|
||||
{
|
||||
protected static string $resource = HitAndRunResource::class;
|
||||
|
||||
protected function getFormSchema(): array
|
||||
protected static string $view = 'filament.detail-card';
|
||||
|
||||
private function getDetailCardData(): array
|
||||
{
|
||||
$data = [];
|
||||
$record = $this->record;
|
||||
$data[] = [
|
||||
'label' => 'ID',
|
||||
'value' => $record->id,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.status'),
|
||||
'value' => $record->statusText,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.username'),
|
||||
'value' => $record->user->username,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.torrent.label'),
|
||||
'value' => $record->torrent->name,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.uploaded'),
|
||||
'value' => $record->snatch->uploadedText,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.downloaded'),
|
||||
'value' => $record->snatch->downloadedText,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.ratio'),
|
||||
'value' => $record->snatch->shareRatio,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.seed_time_required'),
|
||||
'value' => $record->seedTimeRequired,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.inspect_time_left'),
|
||||
'value' => $record->inspectTimeLeft,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.comment'),
|
||||
'value' => nl2br($record->comment),
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.created_at'),
|
||||
'value' => $record->created_at,
|
||||
];
|
||||
$data[] = [
|
||||
'label' => __('label.updated_at'),
|
||||
'value' => $record->updated_at,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getViewData(): array
|
||||
{
|
||||
return [
|
||||
Forms\Components\TextInput::make('id'),
|
||||
Forms\Components\TextInput::make('uid'),
|
||||
Forms\Components\Radio::make('status')->options(HitAndRun::listStatus(true))->inline(),
|
||||
Forms\Components\Textarea::make('comment'),
|
||||
Forms\Components\DateTimePicker::make('created_at'),
|
||||
'cardData' => $this->getDetailCardData(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\Action::make('Pardon')
|
||||
->requiresConfirmation()
|
||||
->action(function () {
|
||||
$hitAndRunRep = new HitAndRunRepository();
|
||||
try {
|
||||
$hitAndRunRep->pardon($this->record->id, Auth::user());
|
||||
$this->notify('success', 'Success !');
|
||||
$this->record = $this->resolveRecord($this->record->id);
|
||||
} catch (\Exception $exception) {
|
||||
$this->notify('danger', $exception->getMessage());
|
||||
}
|
||||
})
|
||||
->label(__('admin.resources.hit_and_run.action_pardon')),
|
||||
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@ class UserMedalResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 5;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.users_medal');
|
||||
return __('admin.sidebar.users_medals');
|
||||
}
|
||||
|
||||
public static function getBreadcrumb(): string
|
||||
|
||||
@@ -26,6 +26,8 @@ class UserResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static function getNavigationLabel(): string
|
||||
{
|
||||
return __('admin.sidebar.users_list');
|
||||
|
||||
@@ -22,6 +22,30 @@ class Claim extends NexusModel
|
||||
'last_settle_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function getSeedTimeThisMonthAttribute()
|
||||
{
|
||||
return mkprettytime($this->snatch->seedtime - $this->seed_time_begin);
|
||||
}
|
||||
|
||||
public function getUploadedThisMonthAttribute()
|
||||
{
|
||||
return mksize($this->snatch->uploaded - $this->uploaded_begin);
|
||||
}
|
||||
|
||||
public function getIsReachedThisMonthAttribute(): bool
|
||||
{
|
||||
$seedTimeRequiredHours = self::getConfigStandardSeedTimeHours();
|
||||
$uploadedRequiredTimes = self::getConfigStandardUploadedTimes();
|
||||
if (
|
||||
bcsub($this->snatch->seedtime, $this->seed_time_begin) >= $seedTimeRequiredHours * 3600
|
||||
|| bcsub($this->snatch->uploaded, $this->uploaded_begin) >= $uploadedRequiredTimes * $this->torrent->size
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'uid');
|
||||
|
||||
+24
-9
@@ -39,8 +39,8 @@ class Exam extends NexusModel
|
||||
|
||||
public static $indexes = [
|
||||
self::INDEX_UPLOADED => ['name' => 'Uploaded', 'unit' => 'GB', 'source_user_field' => 'uploaded'],
|
||||
self::INDEX_SEED_TIME_AVERAGE => ['name' => 'Seed time average', 'unit' => 'Hour', 'source_user_field' => 'seedtime'],
|
||||
self::INDEX_DOWNLOADED => ['name' => 'Downloaded', 'unit' => 'GB', 'source_user_field' => 'downloaded'],
|
||||
self::INDEX_SEED_TIME_AVERAGE => ['name' => 'Seed time average', 'unit' => 'Hour', 'source_user_field' => 'seedtime'],
|
||||
self::INDEX_SEED_BONUS => ['name' => 'Bonus', 'unit' => '', 'source_user_field' => 'seedbonus'],
|
||||
];
|
||||
|
||||
@@ -61,9 +61,24 @@ class Exam extends NexusModel
|
||||
});
|
||||
}
|
||||
|
||||
public static function listIndex($onlyKeyValue = false): array
|
||||
{
|
||||
$result = self::$indexes;
|
||||
$keyValues = [];
|
||||
foreach ($result as $key => &$value) {
|
||||
$text = nexus_trans("exam.index_text_$key");
|
||||
$value['text'] = $text;
|
||||
$keyValues[$key] = $text;
|
||||
}
|
||||
if ($onlyKeyValue) {
|
||||
return $keyValues;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getStatusTextAttribute(): string
|
||||
{
|
||||
return self::$status[$this->status]['text'] ?? '';
|
||||
return $this->status == self::STATUS_ENABLED ? nexus_trans('label.enabled') : nexus_trans('label.disabled');
|
||||
}
|
||||
|
||||
public function getIsDiscoveredTextAttribute(): string
|
||||
@@ -87,7 +102,7 @@ class Exam extends NexusModel
|
||||
if (isset($index['checked']) && $index['checked']) {
|
||||
$arr[] = sprintf(
|
||||
'%s: %s %s',
|
||||
self::$indexes[$index['index']]['name'] ?? '',
|
||||
nexus_trans("exam.index_text_{$index['index']}"),
|
||||
$index['require_value'],
|
||||
self::$indexes[$index['index']]['unit'] ?? ''
|
||||
);
|
||||
@@ -103,24 +118,24 @@ class Exam extends NexusModel
|
||||
$filter = self::FILTER_USER_CLASS;
|
||||
if (!empty($currentFilters->{$filter})) {
|
||||
$classes = collect(User::$classes)->only($currentFilters->{$filter});
|
||||
$arr[] = sprintf('%s: %s', self::$filters[$filter]['name'], $classes->pluck('text')->implode(', '));
|
||||
$arr[] = sprintf('%s: %s', nexus_trans("exam.filters.$filter"), $classes->pluck('text')->implode(', '));
|
||||
}
|
||||
|
||||
$filter = self::FILTER_USER_REGISTER_TIME_RANGE;
|
||||
if (!empty($currentFilters->{$filter})) {
|
||||
$range = $currentFilters->{$filter};
|
||||
$arr[] = sprintf(
|
||||
"%s: \n%s ~ %s",
|
||||
self::$filters[$filter]['name'],
|
||||
$range[0] ? Carbon::parse($range[0])->toDateTimeString() : '-',
|
||||
$range[1] ? Carbon::parse($range[1])->toDateTimeString() : '-'
|
||||
"%s: <br/>%s ~ %s",
|
||||
nexus_trans("exam.filters.$filter"),
|
||||
$range[0] ? Carbon::parse($range[0])->toDateTimeString() : '--',
|
||||
$range[1] ? Carbon::parse($range[1])->toDateTimeString() : '--'
|
||||
);
|
||||
}
|
||||
|
||||
$filter = self::FILTER_USER_DONATE;
|
||||
if (!empty($currentFilters->{$filter})) {
|
||||
$donateStatus = $classes = collect(User::$donateStatus)->only($currentFilters->{$filter});
|
||||
$arr[] = sprintf('%s: %s', self::$filters[$filter]['name'], $donateStatus->pluck('text')->implode(', '));
|
||||
$arr[] = sprintf('%s: %s', nexus_trans("exam.filters.$filter"), $donateStatus->pluck('text')->implode(', '));
|
||||
}
|
||||
|
||||
return implode("<br/>", $arr);
|
||||
|
||||
@@ -41,6 +41,41 @@ class ExamUser extends NexusModel
|
||||
return self::$isDoneInfo[$this->is_done]['text'] ?? '';
|
||||
}
|
||||
|
||||
public function getProgressFormattedAttribute(): array
|
||||
{
|
||||
$result = [];
|
||||
$progress = $this->progress;
|
||||
foreach ($this->exam->indexes as $key => $index) {
|
||||
if (!isset($index['checked']) || !$index['checked']) {
|
||||
continue;
|
||||
}
|
||||
$currentValue = $progress[$index['index']] ?? 0;
|
||||
$requireValue = $index['require_value'];
|
||||
switch ($index['index']) {
|
||||
case Exam::INDEX_UPLOADED:
|
||||
case Exam::INDEX_DOWNLOADED:
|
||||
$currentValueFormatted = mksize($currentValue);
|
||||
$requireValueAtomic = $requireValue * 1024 * 1024 * 1024;
|
||||
break;
|
||||
case Exam::INDEX_SEED_TIME_AVERAGE:
|
||||
$currentValueFormatted = number_format($currentValue / 3600, 2) . " {$index['unit']}";
|
||||
$requireValueAtomic = $requireValue * 3600;
|
||||
break;
|
||||
default:
|
||||
$currentValueFormatted = $currentValue;
|
||||
$requireValueAtomic = $requireValue;
|
||||
}
|
||||
$index['name'] = Exam::$indexes[$index['index']]['name'] ?? '';
|
||||
$index['index_formatted'] = nexus_trans('exam.index_text_' . $index['index']);
|
||||
$index['require_value_formatted'] = "$requireValue " . ($index['unit'] ?? '');
|
||||
$index['current_value'] = $currentValue;
|
||||
$index['current_value_formatted'] = $currentValueFormatted;
|
||||
$index['passed'] = $currentValue >= $requireValueAtomic;
|
||||
$result[] = $index;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function listStatus($onlyKeyValue = false): array
|
||||
{
|
||||
$result = self::$status;
|
||||
|
||||
@@ -35,6 +35,10 @@ class Snatch extends NexusModel
|
||||
|
||||
const FINISHED_NO = 'no';
|
||||
|
||||
/**
|
||||
* @deprecated Use uploadedText instead
|
||||
* @return Attribute
|
||||
*/
|
||||
protected function uploadText(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
@@ -42,6 +46,10 @@ class Snatch extends NexusModel
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use downloadedText instead
|
||||
* @return Attribute
|
||||
*/
|
||||
protected function downloadText(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
@@ -49,6 +57,20 @@ class Snatch extends NexusModel
|
||||
);
|
||||
}
|
||||
|
||||
protected function uploadedText(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn($value, $attributes) => sprintf('%s@%s', mksize($attributes['uploaded']), $this->getUploadSpeed())
|
||||
);
|
||||
}
|
||||
|
||||
protected function downloadedText(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn($value, $attributes) => sprintf('%s@%s', mksize($attributes['downloaded']), $this->getDownloadSpeed())
|
||||
);
|
||||
}
|
||||
|
||||
protected function shareRatio(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ class User extends Authenticatable implements FilamentUser, HasName
|
||||
|
||||
public function canAccessFilament(): bool
|
||||
{
|
||||
return $this->class >= self::CLASS_ADMINISTRATOR;
|
||||
return $this->canAccessAdmin();
|
||||
}
|
||||
|
||||
public function getFilamentName(): string
|
||||
|
||||
@@ -185,7 +185,7 @@ class ClaimRepository extends BaseRepository
|
||||
if ($startOfThisMonth->diffInMonths($targetStartOfMonth) > 1) {
|
||||
do_log("[UNREACHED_REMOVE], uid: $uid, torrent: " . $row->torrent_id);
|
||||
$unReachedIdArr[] = $row->id;
|
||||
$unReachedTorrentIdArr = $row->torrent_id;
|
||||
$unReachedTorrentIdArr[] = $row->torrent_id;
|
||||
} else {
|
||||
do_log("[UNREACHED_FIRST_MONTH], uid: $uid, torrent: " . $row->torrent_id);
|
||||
$seedTimeCaseWhen[] = sprintf('when %s then %s', $row->id, $row->snatch->seedtime);
|
||||
@@ -290,9 +290,9 @@ class ClaimRepository extends BaseRepository
|
||||
if ($deductTotal) {
|
||||
$msg[] = nexus_trans(
|
||||
"claim.claim_unreached_summary", [
|
||||
'deduct_per_torrent '=> number_format($deductPerTorrent, 2),
|
||||
'deduct_total' => number_format($deductTotal, 2)
|
||||
], $locale
|
||||
'deduct_per_torrent' => number_format($deductPerTorrent, 2),
|
||||
'deduct_total' => number_format($deductTotal, 2)
|
||||
], $locale
|
||||
);
|
||||
}
|
||||
return [
|
||||
|
||||
@@ -37,7 +37,7 @@ class DashboardRepository extends BaseRepository
|
||||
$result[$name] = [
|
||||
'name' => $name,
|
||||
'text' => nexus_trans("dashboard.system_info.$name"),
|
||||
'value' => '2.13.11',
|
||||
'value' => "2.13.14",
|
||||
];
|
||||
$name = 'php_version';
|
||||
$result[$name] = [
|
||||
@@ -287,6 +287,4 @@ class DashboardRepository extends BaseRepository
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -70,9 +70,7 @@ class ExamRepository extends BaseRepository
|
||||
if (isset($params['end']) && $params['end'] == '') {
|
||||
$params['end'] = null;
|
||||
}
|
||||
if (isset($params['priority'])) {
|
||||
$params['priority'] = intval($params['priority']);
|
||||
}
|
||||
$params['priority'] = intval($params['priority'] ?? 0);
|
||||
return $params;
|
||||
}
|
||||
|
||||
@@ -86,12 +84,15 @@ class ExamRepository extends BaseRepository
|
||||
if (isset($index['checked']) && !$index['checked']) {
|
||||
continue;
|
||||
}
|
||||
if (isset($validIndex[$index['index']])) {
|
||||
throw new \InvalidArgumentException(nexus_trans('admin.resources.exam.index_duplicate', ['index' => nexus_trans("exam.index_text_{$index['index']}")]));
|
||||
}
|
||||
if (isset($index['require_value']) && !ctype_digit((string)$index['require_value'])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid require value for index: %s.', $index['index']
|
||||
));
|
||||
}
|
||||
$validIndex[] = $index;
|
||||
$validIndex[$index['index']] = $index;
|
||||
}
|
||||
if (empty($validIndex)) {
|
||||
throw new \InvalidArgumentException("Require valid index.");
|
||||
@@ -861,12 +862,12 @@ class ExamRepository extends BaseRepository
|
||||
$filter = Exam::FILTER_USER_REGISTER_TIME_RANGE;
|
||||
$range = $filters->$filter;
|
||||
if (!empty($range)) {
|
||||
/**
|
||||
* begin and end will be exists at the same time
|
||||
* @see checkBeginEnd()
|
||||
*/
|
||||
$baseQuery->where("$userTable.added", ">=", Carbon::parse($range[0])->toDateTimeString())
|
||||
->where("$userTable.added", '<=', Carbon::parse($range[1])->toDateTimeString());
|
||||
if (!empty($range[0])) {
|
||||
$baseQuery->where("$userTable.added", ">=", Carbon::parse($range[0])->toDateTimeString());
|
||||
}
|
||||
if (!empty($range[1])) {
|
||||
$baseQuery->where("$userTable.added", '<=', Carbon::parse($range[1])->toDateTimeString());
|
||||
}
|
||||
}
|
||||
//Does not has this exam
|
||||
$baseQuery->whereDoesntHave('exams', function (Builder $query) use ($exam) {
|
||||
|
||||
@@ -380,7 +380,7 @@ class HitAndRunRepository extends BaseRepository
|
||||
throw new \LogicException("Can't be pardoned due to status is: " . $model->status_text . " !");
|
||||
}
|
||||
$model->status = HitAndRun::STATUS_PARDONED;
|
||||
$model->comment = $this->getCommentUpdateRaw(addslashes('Pardon by ' . $user->username));
|
||||
$model->comment = $this->getCommentUpdateRaw(addslashes(date('Y-m-d') . ' - Pardon by ' . $user->username));
|
||||
$model->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user