From 6b02e98751a8d281534ebe2ee47c759f409420f1 Mon Sep 17 00:00:00 2001 From: Thiritin Date: Sun, 12 Feb 2023 13:41:13 +0100 Subject: [PATCH] Release --- app/Filament/Resources/AppResource.php | 105 +++++++++++------- .../GroupsRelationManager.php | 46 ++++++++ app/Http/Controllers/DashboardController.php | 31 ++++++ app/Models/App.php | 7 +- app/Models/Group.php | 5 + ...12_103409_create_app_group_pivot_table.php | 33 ++++++ ..._02_12_114846_add_fields_to_apps_table.php | 39 +++++++ resources/js/Pages/Dashboard.vue | 33 +++--- routes/web.php | 3 +- 9 files changed, 242 insertions(+), 60 deletions(-) create mode 100644 app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php create mode 100644 app/Http/Controllers/DashboardController.php create mode 100644 database/migrations/2023_02_12_103409_create_app_group_pivot_table.php create mode 100644 database/migrations/2023_02_12_114846_add_fields_to_apps_table.php diff --git a/app/Filament/Resources/AppResource.php b/app/Filament/Resources/AppResource.php index fc1c07d9..22e57d83 100644 --- a/app/Filament/Resources/AppResource.php +++ b/app/Filament/Resources/AppResource.php @@ -3,11 +3,13 @@ namespace App\Filament\Resources; use App\Filament\Resources\AppResource\Pages; +use App\Filament\Resources\AppResource\RelationManagers\GroupsRelationManager; use App\Models\App; use App\Services\Hydra\Client; use Filament\Forms\Components\Card; use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\CheckboxList; +use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\Group; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Section; @@ -43,17 +45,17 @@ public static function form(Form $form): Form Tabs::make('Tabs')->tabs([ Tabs\Tab::make('Information')->icon('heroicon-o-paper-clip')->schema([ TextInput::make('data.client_uri') - ->url() - ->helperText('A URL string of a web page providing information about the client'), + ->url() + ->helperText('A URL string of a web page providing information about the client'), TextInput::make('data.logo_uri') - ->url() - ->helperText('A URL string that references a logo for the client'), + ->url() + ->helperText('A URL string that references a logo for the client'), TextInput::make('data.policy_uri') - ->url() - ->helperText('A URL string that references the privacy policy for the client'), + ->url() + ->helperText('A URL string that references the privacy policy for the client'), TextInput::make('data.tos_uri') - ->url() - ->helperText('A URL string that references the terms of service for the client'), + ->url() + ->helperText('A URL string that references the terms of service for the client'), ]), Tabs\Tab::make('Login')->icon('heroicon-o-login')->schema([ TagsInput::make('data.redirect_uris')->columnSpan(2), @@ -81,8 +83,8 @@ public static function form(Form $form): Form "none" => "none", ]), TextInput::make('data.jwks_uri') - ->helperText('When authenticating with a signed jwks key against the token endpoint, you may enter a path to a keys.json containing the public keys of your app here.') - ->url(), + ->helperText('When authenticating with a signed jwks key against the token endpoint, you may enter a path to a keys.json containing the public keys of your app here.') + ->url(), CheckboxList::make('data.scope')->options(static function () { return collect((new Client())->getScopes())->mapWithKeys(fn($v) => [$v => $v]); @@ -97,24 +99,24 @@ public static function form(Form $form): Form Tabs\Tab::make('Logout')->icon('heroicon-o-logout')->schema([ TagsInput::make('data.post_logout_redirect_uris')->columnSpan(2), Section::make('Frontchannel Logout') - ->description('Configure frontchannel logout.') - ->schema([ - TextInput::make('data.frontchannel_logout_uri') - ->helperText('Client URL that will cause the client to log itself out when rendered in an iframe by Identity') - ->url(), - Checkbox::make('data.frontchannel_logout_session_required') - ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the frontchannel logout is used.'), - ]), + ->description('Configure frontchannel logout.') + ->schema([ + TextInput::make('data.frontchannel_logout_uri') + ->helperText('Client URL that will cause the client to log itself out when rendered in an iframe by Identity') + ->url(), + Checkbox::make('data.frontchannel_logout_session_required') + ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the frontchannel logout is used.'), + ]), Section::make('Backchannel Logout') - ->description('Configure backchannel logout.') - ->schema([ - TextInput::make('data.backchannel_logout_uri') - ->helperText('Client URL that will cause the client to log itself out when sent a Logout Token by Identity.') - ->url(), - Checkbox::make('data.backchannel_logout_session_required') - ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the backchannel logout is used.') - - ]), + ->description('Configure backchannel logout.') + ->schema([ + TextInput::make('data.backchannel_logout_uri') + ->helperText('Client URL that will cause the client to log itself out when sent a Logout Token by Identity.') + ->url(), + Checkbox::make('data.backchannel_logout_session_required') + ->helperText('Specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the backchannel logout is used.'), + + ]), ]), Tabs\Tab::make('Request')->icon('heroicon-o-status-online')->schema([ @@ -138,21 +140,37 @@ public static function form(Form $form): Form Group::make()->columnSpan(1)->schema([ Section::make('Owner') - ->columns(1) - ->schema([ - Select::make('user_id') - ->label('Owner') - ->relationship('owner', 'name')->required(), - ]), + ->columns(1) + ->schema([ + Select::make('user_id') + ->label('Owner') + ->relationship('owner', 'name')->required(), + ]), + Section::make('Dashboard Settings') + ->description('These settings control the visibility of the app on the dashboard. This is NOT access control in any way.') + ->columns(1) + ->schema([ + DateTimePicker::make('starts_at')->hint('UTC')->nullable(), + DateTimePicker::make('ends_at')->hint('UTC')->nullable(), + TextInput::make('priority')->numeric()->minValue('1')->maxValue('10000')->hint('Sets order of dashboard apps'), + Checkbox::make('public')->hint('App is publicly visible (ignoring group selection)'), + TextInput::make('name')->required(), + TextInput::make('description')->required(), + Select::make('icon')->options([ + "TicketDuotone" => "TicketDuotone", + "CogsDuotone" => "CogsDuotone", + ])->hint('Request new Icons @ Thiritin')->required(), + TextInput::make('url')->url(), + ]), Card::make()->schema([ Placeholder::make('created_at') - ->label("Created At") - ->content(fn(?App $record): string => $record?->created_at?->diffForHumans() ?? '-'), + ->label("Created At") + ->content(fn(?App $record): string => $record?->created_at?->diffForHumans() ?? '-'), Placeholder::make('updated_at') - ->label("Updated At") - ->content(fn(?App $record): string => $record?->updated_at?->diffForHumans() ?? '-'), - ]) + ->label("Updated At") + ->content(fn(?App $record): string => $record?->updated_at?->diffForHumans() ?? '-'), + ]), ]), ])->columns(3); @@ -164,7 +182,7 @@ public static function table(Table $table): Table ->columns([ TextColumn::make('client_id'), TextColumn::make('data.client_name')->label('Name'), - TextColumn::make('owner.name') + TextColumn::make('owner.name'), ]); } @@ -177,10 +195,17 @@ public static function getPages(): array ]; } + public static function getRelations(): array + { + return [ + GroupsRelationManager::class, + ]; + } + public static function getGloballySearchableAttributes(): array { return [ - "data.client_name" + "data.client_name", ]; } } diff --git a/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php b/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php new file mode 100644 index 00000000..d97ff793 --- /dev/null +++ b/app/Filament/Resources/AppResource/RelationManagers/GroupsRelationManager.php @@ -0,0 +1,46 @@ +schema([ + Forms\Components\TextInput::make('name') + ->required() + ->maxLength(255), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('name'), + ]) + ->filters([ + // + ]) + ->headerActions([ + Tables\Actions\AttachAction::make(), + ]) + ->actions([ + Tables\Actions\DetachAction::make(), + ]) + ->bulkActions([ + Tables\Actions\DetachBulkAction::make(), + ]); + } +} diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php new file mode 100644 index 00000000..b833811d --- /dev/null +++ b/app/Http/Controllers/DashboardController.php @@ -0,0 +1,31 @@ +where('public', '=', true)->orWhereHas('groups', function (Builder $q) { + $q->whereIn('id', Auth::user()->groups->pluck('id')); + }); + })->where(function (Builder $q) { + $q->where(function (Builder $q) { + $q->whereDate('starts_at', '<=', now())->orWhereNull('starts_at'); + })->where(function (Builder $q) { + $q->whereDate('ends_at', '>=', now())->orWhereNull('ends_at'); + }); + })->get(); + + return Inertia::render('Dashboard', [ + 'apps' => $apps, + ]); + } +} diff --git a/app/Models/App.php b/app/Models/App.php index 613f71bb..7e6f267f 100644 --- a/app/Models/App.php +++ b/app/Models/App.php @@ -9,11 +9,16 @@ class App extends Model { protected $guarded = []; protected $casts = [ - "data" => "array" + "data" => "array", ]; public function owner(): BelongsTo { return $this->belongsTo(User::class, 'user_id', 'id'); } + + public function groups() + { + return $this->belongsToMany(Group::class); + } } diff --git a/app/Models/Group.php b/app/Models/Group.php index a474595b..514eb468 100644 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -55,6 +55,11 @@ public function users() ); } + public function apps() + { + return $this->belongsToMany(App::class); + } + public function getHashidsConnection() { return 'group'; diff --git a/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php b/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php new file mode 100644 index 00000000..fbb10d0a --- /dev/null +++ b/database/migrations/2023_02_12_103409_create_app_group_pivot_table.php @@ -0,0 +1,33 @@ +unsignedBigInteger('app_id')->index(); + $table->foreign('app_id')->references('id')->on('apps')->onDelete('cascade'); + $table->unsignedBigInteger('group_id')->index(); + $table->foreign('group_id')->references('id')->on('groups')->onDelete('cascade'); + $table->primary(['app_id', 'group_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('app_group'); + } +} diff --git a/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php b/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php new file mode 100644 index 00000000..d0beecc1 --- /dev/null +++ b/database/migrations/2023_02_12_114846_add_fields_to_apps_table.php @@ -0,0 +1,39 @@ +timestamp("starts_at")->nullable()->after('client_id'); + $table->timestamp("ends_at")->nullable()->after('starts_at'); + $table->boolean('public')->default(false)->after('ends_at'); + $table->boolean('featured')->default(false)->after('ends_at'); + $table->integer('priority')->unsigned()->default(1000)->after('public'); + $table->string('name')->nullable()->after('client_id'); + $table->string('description')->nullable()->after('name'); + $table->string('icon')->nullable()->after('description'); + $table->string('url')->nullable()->after('icon'); + }); + } + + public function down() + { + Schema::table('apps', function (Blueprint $table) { + $table->dropColumn([ + "starts_at", + "ends_at", + "public", + "featured", + "priority", + "name", + "description", + "icon", + "url", + ]); + }); + } +}; diff --git a/resources/js/Pages/Dashboard.vue b/resources/js/Pages/Dashboard.vue index 4dc4ba7e..4a12b383 100644 --- a/resources/js/Pages/Dashboard.vue +++ b/resources/js/Pages/Dashboard.vue @@ -15,31 +15,28 @@ items-start lg:grid-cols-3 lg:gap-8 '> - - -

Hotel Staff 2022

-

Book your hotel room trough the IDP.

+
+ +

{{ app.name }}

+

{{ app.description }}

- - -

Your Settings

-

Configure your account.

-
diff --git a/routes/web.php b/routes/web.php index 16424854..6a95e0bb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -15,6 +15,7 @@ use App\Http\Controllers\Auth\RegisterController; use App\Http\Controllers\Auth\ResendVerificationEmailController; use App\Http\Controllers\Auth\VerifyEmailController; +use App\Http\Controllers\DashboardController; use App\Http\Controllers\Profile\SecurityController; use App\Http\Controllers\Profile\Settings\UpdatePasswordController; use App\Http\Controllers\Profile\StoreAvatarController; @@ -87,7 +88,7 @@ // General Routes Route::middleware(['auth', 'verified', 'auth.oidc'])->group(function () { - Route::inertia('/dashboard', 'Dashboard')->name('dashboard'); + Route::get('/dashboard', DashboardController::class)->name('dashboard'); Route::inertia('/profile', 'Profile/Show')->name('profile'); Route::inertia('/settings/profile', 'Settings/Profile')->name('settings.profile'); Route::post('/settings/profile/update', UpdateProfileController::class)->name('settings.update-profile.update');