Skip to content

Commit c5cac16

Browse files
committed
feat: make package development independent
1 parent c3aad43 commit c5cac16

40 files changed

Lines changed: 2637 additions & 33 deletions

.lando.dist.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
#file: noinspection ComposeUnknownKeys,YAMLSchemaValidation
22
name: eclipsephp-cms
3+
recipe: laravel
4+
config:
5+
webroot: workbench/public
6+
php: '8.3'
7+
via: nginx
8+
database: mariadb:10.11
39
services:
410
appserver:
511
type: php:custom
612
xdebug: "debug,develop,coverage"
7-
via: cli
13+
environment:
14+
TZ: "Europe/Ljubljana"
15+
APP_BASE_PATH: "/app/workbench"
16+
TESTBENCH_WORKING_PATH: "/app"
817
overrides:
9-
image: slimdeluxe/php:8.2-v1.2
18+
image: slimdeluxe/php:8.3-v1.3
19+
platform: linux/amd64
20+
run:
21+
- composer install --no-interaction --prefer-dist
22+
- composer run setup --no-interaction
23+
- composer run build --no-interaction
24+
appserver_nginx:
25+
scanner:
26+
path: /admin/login
27+
retry: 5
1028
tooling:
1129
php:
1230
service: appserver

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@
7575
"@php vendor/bin/testbench serve --ansi"
7676
],
7777
"setup": [
78-
"@php vendor/bin/testbench vendor:publish --provider='Spatie\\Permission\\PermissionServiceProvider'",
78+
"@php -r \"if (!file_exists('workbench/.env')) { copy('workbench/.env.example', 'workbench/.env'); echo '.env file created from .env.example\\n'; }\"",
79+
"@php vendor/bin/testbench key:generate --ansi",
80+
"npm install",
7981
"@php vendor/bin/testbench vendor:publish --tag='filament-shield-config'",
82+
"@php vendor/bin/testbench filament:assets",
8083
"@php vendor/bin/testbench package:sync-skeleton"
8184
]
8285
},

database/factories/SectionFactory.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use Eclipse\Cms\Enums\SectionType;
66
use Eclipse\Cms\Models\Section;
77
use Illuminate\Database\Eloquent\Factories\Factory;
8-
use Illuminate\Support\Arr;
98
use Illuminate\Support\Carbon;
109
use Illuminate\Support\Str;
1110

@@ -17,7 +16,7 @@ public function definition(): array
1716
{
1817
$attrs = [
1918
'name' => Str::of($this->faker->words(asText: true))->ucwords(),
20-
'type' => $this->faker->randomElement(Arr::pluck(SectionType::cases(), 'name')),
19+
'type' => $this->faker->randomElement(SectionType::cases())->value,
2120
'created_at' => Carbon::now(),
2221
'updated_at' => Carbon::now(),
2322
];

src/Admin/Filament/Resources/SectionResource.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
use Eclipse\Cms\Admin\Filament\Resources\SectionResource\Pages\CreateSection;
66
use Eclipse\Cms\Admin\Filament\Resources\SectionResource\Pages\EditSection;
77
use Eclipse\Cms\Admin\Filament\Resources\SectionResource\Pages\ListSections;
8+
use Eclipse\Cms\Enums\SectionType;
89
use Eclipse\Cms\Models\Section;
910
use Filament\Actions;
11+
use Filament\Forms\Components\Select;
1012
use Filament\Forms\Components\TextInput;
1113
use Filament\Resources\Resource;
1214
use Filament\Schemas\Schema;
@@ -35,7 +37,8 @@ public static function form(Schema $schema): Schema
3537
TextInput::make('name')
3638
->required(),
3739

38-
TextInput::make('type')
40+
Select::make('type')
41+
->options(SectionType::class)
3942
->required(),
4043
]);
4144
}

src/Enums/SectionType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
use Filament\Support\Contracts\HasLabel;
66

7-
enum SectionType implements HasLabel
7+
enum SectionType: string implements HasLabel
88
{
9-
case Pages;
9+
case Pages = 'pages';
1010

1111
public function getLabel(): ?string
1212
{

workbench/.env.example

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
APP_NAME=Laravel
1+
APP_NAME="Eclipse CMS Plugin"
22
APP_ENV=local
3-
APP_KEY=AckfSECXIvnK5r28GVIWUAxmbBSjTsmF
3+
APP_KEY=
44
APP_DEBUG=true
5-
APP_URL=http://localhost
5+
APP_URL=https://eclipsephp-cms.lndo.site
66

77
APP_LOCALE=en
88
APP_FALLBACK_LOCALE=en
99
APP_FAKER_LOCALE=en_US
1010

1111
APP_MAINTENANCE_DRIVER=file
12-
# APP_MAINTENANCE_STORE=database
13-
14-
# PHP_CLI_SERVER_WORKERS=4
1512

1613
BCRYPT_ROUNDS=12
1714

@@ -21,24 +18,22 @@ LOG_DEPRECATIONS_CHANNEL=null
2118
LOG_LEVEL=debug
2219

2320
DB_CONNECTION=sqlite
24-
# DB_HOST=127.0.0.1
25-
# DB_PORT=3306
26-
# DB_DATABASE=laravel
27-
# DB_USERNAME=root
28-
# DB_PASSWORD=
21+
DB_DATABASE=/app/workbench/database/database.sqlite
2922

30-
SESSION_DRIVER=cookie
23+
SESSION_DRIVER=database
3124
SESSION_LIFETIME=120
3225
SESSION_ENCRYPT=false
3326
SESSION_PATH=/
34-
SESSION_DOMAIN=null
27+
SESSION_DOMAIN=.eclipsephp-cms.lndo.site
28+
SESSION_SECURE_COOKIE=true
29+
SESSION_HTTP_ONLY=true
30+
SESSION_SAME_SITE=lax
3531

3632
BROADCAST_CONNECTION=log
3733
FILESYSTEM_DISK=local
38-
QUEUE_CONNECTION=database
34+
QUEUE_CONNECTION=sync
3935

40-
CACHE_STORE=database
41-
# CACHE_PREFIX=
36+
CACHE_STORE=array
4237

4338
MEMCACHED_HOST=127.0.0.1
4439

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<?php
2+
3+
namespace Workbench\App\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\Artisan;
8+
use Illuminate\Support\Facades\Auth;
9+
use Illuminate\Support\Facades\Cache;
10+
use Illuminate\Support\Facades\DB;
11+
use Illuminate\Support\Facades\Hash;
12+
use Illuminate\Support\Facades\Log;
13+
use Spatie\Permission\Models\Permission;
14+
use Spatie\Permission\Models\Role;
15+
use Spatie\Permission\PermissionRegistrar;
16+
use Throwable;
17+
use Workbench\App\Models\User;
18+
19+
class WorkbenchBootstrap
20+
{
21+
public function handle(Request $request, Closure $next)
22+
{
23+
if (config('app.env') === 'local' && ! Auth::guard('web')->check()) {
24+
$user = User::query()->first();
25+
26+
if (! $user) {
27+
try {
28+
$user = User::query()->firstOrCreate(
29+
['email' => 'test@example.com'],
30+
[
31+
'name' => 'Admin User',
32+
'password' => Hash::make('password'),
33+
'email_verified_at' => now(),
34+
],
35+
);
36+
} catch (Throwable $e) {
37+
Log::error('[Workbench] User creation failed', ['message' => $e->getMessage()]);
38+
// In case of a race/unique constraint, fetch the existing one
39+
$user = User::query()->where('email', 'test@example.com')->first();
40+
}
41+
}
42+
43+
if ($user) {
44+
$this->bootstrapPermissionsAndAssign($user);
45+
Auth::guard('web')->login($user);
46+
$request->session()->regenerate();
47+
48+
if ($request->is('admin/login')) {
49+
return redirect()->to('/admin');
50+
}
51+
}
52+
}
53+
54+
return $next($request);
55+
}
56+
57+
private function bootstrapPermissionsAndAssign(User $user): void
58+
{
59+
// Use cache to prevent running this multiple times
60+
$cacheKey = 'workbench:permissions:bootstrapped';
61+
62+
if (Cache::has($cacheKey)) {
63+
// Just ensure user has roles if already bootstrapped
64+
$this->ensureUserHasRoles($user);
65+
66+
return;
67+
}
68+
69+
try {
70+
// Use lock to prevent concurrent execution
71+
Cache::lock('workbench:bootstrap-permissions', 30)->block(10, function () use ($user, $cacheKey) {
72+
// Double-check inside the lock
73+
if (Cache::has($cacheKey)) {
74+
return;
75+
}
76+
77+
// Normalize guards first
78+
DB::table('permissions')->whereNull('guard_name')->orWhere('guard_name', '')->update(['guard_name' => 'web']);
79+
DB::table('roles')->whereNull('guard_name')->orWhere('guard_name', '')->update(['guard_name' => 'web']);
80+
81+
// Generate Filament Shield permissions if none exist yet
82+
if (Permission::query()->count() === 0) {
83+
Artisan::call('shield:generate', [
84+
'--all' => true,
85+
'--panel' => 'admin',
86+
]);
87+
}
88+
89+
// Reset caches/registrar to ensure guards are picked up
90+
Artisan::call('permission:cache-reset');
91+
app(PermissionRegistrar::class)->forgetCachedPermissions();
92+
93+
// Ensure roles with correct guard
94+
$this->ensureRolesHaveCorrectGuard();
95+
96+
// Create roles
97+
$superAdmin = Role::firstOrCreate(['name' => 'super_admin', 'guard_name' => 'web']);
98+
$panelUser = Role::firstOrCreate(['name' => 'panel_user', 'guard_name' => 'web']);
99+
100+
// Only assign permissions if the role doesn't already have them
101+
$this->assignPermissionsToRole($superAdmin);
102+
103+
// Assign roles to user
104+
$this->ensureUserHasRoles($user);
105+
106+
// Mark as bootstrapped (cache for 1 hour)
107+
Cache::put($cacheKey, true, 3600);
108+
});
109+
} catch (Throwable $e) {
110+
Log::error('[Workbench] Bootstrap permissions failed', ['message' => $e->getMessage()]);
111+
}
112+
}
113+
114+
private function ensureRolesHaveCorrectGuard(): void
115+
{
116+
$existingSuper = Role::where('name', 'super_admin')->first();
117+
if ($existingSuper && $existingSuper->guard_name !== 'web') {
118+
$existingSuper->guard_name = 'web';
119+
$existingSuper->save();
120+
}
121+
122+
$existingPanel = Role::where('name', 'panel_user')->first();
123+
if ($existingPanel && $existingPanel->guard_name !== 'web') {
124+
$existingPanel->guard_name = 'web';
125+
$existingPanel->save();
126+
}
127+
}
128+
129+
private function assignPermissionsToRole(Role $role): void
130+
{
131+
// Check if role already has permissions to avoid duplicate inserts
132+
if ($role->permissions()->count() > 0) {
133+
return;
134+
}
135+
136+
$permissions = Permission::query()->where('guard_name', 'web')->get();
137+
if ($permissions->isNotEmpty()) {
138+
// Use DB transaction to ensure atomicity
139+
DB::transaction(function () use ($role, $permissions) {
140+
// Clear existing permissions first to avoid duplicates
141+
$role->permissions()->detach();
142+
143+
// Batch insert to avoid individual constraint violations
144+
$pivotData = $permissions->map(function ($permission) use ($role) {
145+
return [
146+
'role_id' => $role->id,
147+
'permission_id' => $permission->id,
148+
];
149+
})->toArray();
150+
151+
// Use insert ignore equivalent for SQLite
152+
foreach ($pivotData as $data) {
153+
DB::table('role_has_permissions')
154+
->insertOrIgnore($data);
155+
}
156+
});
157+
}
158+
}
159+
160+
private function ensureUserHasRoles(User $user): void
161+
{
162+
$superAdmin = Role::where('name', 'super_admin')->where('guard_name', 'web')->first();
163+
$panelUser = Role::where('name', 'panel_user')->where('guard_name', 'web')->first();
164+
165+
$rolesToAssign = collect([$superAdmin, $panelUser])
166+
->filter()
167+
->pluck('name')
168+
->toArray();
169+
170+
if (! empty($rolesToAssign)) {
171+
// Only sync if user doesn't already have these roles
172+
$existingRoles = $user->roles()->pluck('name')->toArray();
173+
$missingRoles = array_diff($rolesToAssign, $existingRoles);
174+
175+
if (! empty($missingRoles)) {
176+
$user->assignRole($missingRoles);
177+
}
178+
}
179+
}
180+
}

workbench/app/Providers/AdminPanelProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Illuminate\Support\Facades\Blade;
2121
use Illuminate\View\Middleware\ShareErrorsFromSession;
2222
use LaraZeus\SpatieTranslatable\SpatieTranslatablePlugin;
23+
use Workbench\App\Http\Middleware\WorkbenchBootstrap;
2324

2425
class AdminPanelProvider extends PanelProvider
2526
{
@@ -40,6 +41,7 @@ public function panel(Panel $panel): Panel
4041
SubstituteBindings::class,
4142
DisableBladeIconComponents::class,
4243
DispatchServingFilamentEvent::class,
44+
WorkbenchBootstrap::class,
4345
])
4446
->authMiddleware([
4547
Authenticate::class,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Workbench\App\Providers;
4+
5+
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
6+
7+
class AuthServiceProvider extends ServiceProvider
8+
{
9+
protected $policies = [];
10+
11+
public function boot(): void
12+
{
13+
$this->registerPolicies();
14+
}
15+
}

workbench/app/Providers/WorkbenchServiceProvider.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,25 @@
22

33
namespace Workbench\App\Providers;
44

5+
use BezhanSalleh\FilamentShield\FilamentShieldServiceProvider;
56
use Eclipse\Common\CommonServiceProvider;
7+
use Filament\FilamentServiceProvider;
68
use Illuminate\Support\ServiceProvider;
9+
use Livewire\LivewireServiceProvider;
10+
use Spatie\Permission\PermissionServiceProvider;
711

812
class WorkbenchServiceProvider extends ServiceProvider
913
{
10-
/**
11-
* Register services.
12-
*/
1314
public function register(): void
1415
{
16+
$this->app->register(PermissionServiceProvider::class);
17+
$this->app->register(FilamentShieldServiceProvider::class);
18+
$this->app->register(LivewireServiceProvider::class);
19+
$this->app->register(FilamentServiceProvider::class);
1520
$this->app->register(CommonServiceProvider::class);
1621
$this->app->register(AdminPanelProvider::class);
22+
$this->app->register(AuthServiceProvider::class);
1723
}
1824

19-
/**
20-
* Bootstrap services.
21-
*/
2225
public function boot(): void {}
2326
}

0 commit comments

Comments
 (0)