new modules
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Administration',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Administration\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Administration\Support\ModuleInfo;
|
||||
|
||||
final class AdministrationServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Administration\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Administration', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Administration\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Administration'; }
|
||||
public static function nameLower(): string { return 'administration'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Administration module', function (): void {
|
||||
expect(config('administration.name'))->toBe('Administration');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/administration-module",
|
||||
"description": "Administration foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Administration\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Administration",
|
||||
"alias": "administration",
|
||||
"version": "1.0.0",
|
||||
"description": "Administration foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"administration"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Administration\\Providers\\AdministrationServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Audit',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;
|
||||
return new class extends Migration { public function up(): void { Schema::create('audit_logs', function(Blueprint $table): void { $table->id(); $table->nullableMorphs('actor'); $table->string('event')->index(); $table->nullableMorphs('auditable'); $table->json('old_values')->nullable(); $table->json('new_values')->nullable(); $table->string('ip_address',45)->nullable(); $table->text('user_agent')->nullable(); $table->timestamp('created_at')->useCurrent(); }); } public function down(): void { Schema::dropIfExists('audit_logs'); } };
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
namespace Modules\Audit\Models; use Illuminate\Database\Eloquent\Model;
|
||||
final class AuditLog extends Model { public $timestamps=false; protected $guarded=[]; protected function casts(): array { return ['old_values'=>'array','new_values'=>'array','created_at'=>'datetime']; } }
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Audit\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Audit\Support\ModuleInfo;
|
||||
|
||||
final class AuditServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Audit\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Audit', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Audit\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Audit'; }
|
||||
public static function nameLower(): string { return 'audit'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Audit module', function (): void {
|
||||
expect(config('audit.name'))->toBe('Audit');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/audit-module",
|
||||
"description": "Audit foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Audit\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Audit",
|
||||
"alias": "audit",
|
||||
"version": "1.0.0",
|
||||
"description": "Audit foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"audit"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Audit\\Providers\\AuditServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Core',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Contracts;
|
||||
|
||||
interface ModuleRegistry
|
||||
{
|
||||
/** @return array<int, array{name:string, alias:string, version:string, enabled:bool}> */
|
||||
public function all(): array;
|
||||
public function enabled(string $name): bool;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Core\Support\ModuleInfo;
|
||||
use Modules\Core\Contracts\ModuleRegistry;
|
||||
use Modules\Core\Services\LaravelModuleRegistry;
|
||||
|
||||
final class CoreServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->app->singleton(ModuleRegistry::class, LaravelModuleRegistry::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Core', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Services;
|
||||
|
||||
use Modules\Core\Contracts\ModuleRegistry;
|
||||
|
||||
final class LaravelModuleRegistry implements ModuleRegistry
|
||||
{
|
||||
public function all(): array
|
||||
{
|
||||
$statuses = json_decode((string) @file_get_contents(base_path('modules_statuses.json')), true) ?: [];
|
||||
$modules = [];
|
||||
foreach (glob(base_path('Modules/*/module.json')) ?: [] as $manifest) {
|
||||
$data = json_decode((string) file_get_contents($manifest), true) ?: [];
|
||||
$name = (string) ($data['name'] ?? basename(dirname($manifest)));
|
||||
$modules[] = [
|
||||
'name' => $name,
|
||||
'alias' => (string) ($data['alias'] ?? strtolower($name)),
|
||||
'version' => (string) ($data['version'] ?? '0.0.0'),
|
||||
'enabled' => (bool) ($statuses[$name] ?? false),
|
||||
];
|
||||
}
|
||||
usort($modules, fn (array $a, array $b): int => $a['name'] <=> $b['name']);
|
||||
return $modules;
|
||||
}
|
||||
|
||||
public function enabled(string $name): bool
|
||||
{
|
||||
foreach ($this->all() as $module) {
|
||||
if (strcasecmp($module['name'], $name) === 0) return $module['enabled'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Core'; }
|
||||
public static function nameLower(): string { return 'core'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Core module', function (): void {
|
||||
expect(config('core.name'))->toBe('Core');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/core-module",
|
||||
"description": "Core foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Core\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Core",
|
||||
"alias": "core",
|
||||
"version": "1.0.0",
|
||||
"description": "Core foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"core"
|
||||
],
|
||||
"priority": 100,
|
||||
"providers": [
|
||||
"Modules\\Core\\Providers\\CoreServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": []
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Media',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;
|
||||
return new class extends Migration { public function up(): void { Schema::create('media', function(Blueprint $table): void { $table->id(); $table->uuid('uuid')->unique(); $table->nullableMorphs('attachable'); $table->string('collection')->default('default')->index(); $table->string('disk')->default('public'); $table->string('path'); $table->string('original_name'); $table->string('mime_type')->nullable(); $table->unsignedBigInteger('size')->default(0); $table->string('title')->nullable(); $table->string('alt_text')->nullable(); $table->text('caption')->nullable(); $table->json('metadata')->nullable(); $table->unsignedInteger('sort_order')->default(0); $table->foreignId('uploaded_by')->nullable()->constrained('users')->nullOnDelete(); $table->timestamps(); $table->softDeletes(); $table->index(['attachable_type','attachable_id','collection','sort_order'],'media_attachable_collection_index'); }); } public function down(): void { Schema::dropIfExists('media'); } };
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
namespace Modules\Media\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Str;
|
||||
final class Media extends Model { use SoftDeletes; protected $table='media'; protected $guarded=[]; protected static function booted(): void { static::creating(fn(self $m) => $m->uuid ??= (string) Str::uuid()); } protected function casts(): array { return ['metadata'=>'array','size'=>'integer','sort_order'=>'integer']; } }
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Media\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Media\Support\ModuleInfo;
|
||||
|
||||
final class MediaServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Media\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Media', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Media\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Media'; }
|
||||
public static function nameLower(): string { return 'media'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Media module', function (): void {
|
||||
expect(config('media.name'))->toBe('Media');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/media-module",
|
||||
"description": "Media foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Media\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Media",
|
||||
"alias": "media",
|
||||
"version": "1.0.0",
|
||||
"description": "Media foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"media"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Media\\Providers\\MediaServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Roles',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
$modelMorphKey = $columnNames['model_morph_key'] ?? 'model_id';
|
||||
|
||||
throw_if(
|
||||
empty($tableNames),
|
||||
RuntimeException::class,
|
||||
'The Spatie permission configuration could not be loaded.'
|
||||
);
|
||||
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use (
|
||||
$tableNames,
|
||||
$pivotPermission,
|
||||
$modelMorphKey
|
||||
): void {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($modelMorphKey);
|
||||
|
||||
$table->index([$modelMorphKey, 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id')
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->primary(
|
||||
[$pivotPermission, $modelMorphKey, 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary'
|
||||
);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use (
|
||||
$tableNames,
|
||||
$pivotRole,
|
||||
$modelMorphKey
|
||||
): void {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($modelMorphKey);
|
||||
|
||||
$table->index([$modelMorphKey, 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
$table->foreign($pivotRole)
|
||||
->references('id')
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->primary(
|
||||
[$pivotRole, $modelMorphKey, 'model_type'],
|
||||
'model_has_roles_role_model_type_primary'
|
||||
);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use (
|
||||
$tableNames,
|
||||
$pivotRole,
|
||||
$pivotPermission
|
||||
): void {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id')
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
$table->foreign($pivotRole)
|
||||
->references('id')
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')->store(config('permission.cache.store') === 'default'
|
||||
? null
|
||||
: config('permission.cache.store'))
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
Schema::dropIfExists($tableNames['role_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['model_has_roles']);
|
||||
Schema::dropIfExists($tableNames['model_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['roles']);
|
||||
Schema::dropIfExists($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Roles\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\PermissionRegistrar;
|
||||
|
||||
final class RolePermissionSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$registrar = app(PermissionRegistrar::class);
|
||||
$registrar->forgetCachedPermissions();
|
||||
|
||||
$permissions = [
|
||||
'administration.access',
|
||||
'users.view',
|
||||
'users.create',
|
||||
'users.update',
|
||||
'users.delete',
|
||||
'roles.manage',
|
||||
'settings.manage',
|
||||
'audit.view',
|
||||
'media.view',
|
||||
'media.upload',
|
||||
'media.update',
|
||||
'media.delete',
|
||||
'seo.manage',
|
||||
'search.manage',
|
||||
'themes.manage',
|
||||
];
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
Permission::findOrCreate($permission, 'web');
|
||||
}
|
||||
|
||||
$administrator = Role::findOrCreate('admin', 'web');
|
||||
$administrator->syncPermissions($permissions);
|
||||
|
||||
$registrar->forgetCachedPermissions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Roles\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Roles\Support\ModuleInfo;
|
||||
|
||||
final class RolesServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Roles\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Roles', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Roles\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Roles'; }
|
||||
public static function nameLower(): string { return 'roles'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Roles module', function (): void {
|
||||
expect(config('roles.name'))->toBe('Roles');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/roles-module",
|
||||
"description": "Roles foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Roles\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Roles",
|
||||
"alias": "roles",
|
||||
"version": "1.0.0",
|
||||
"description": "Roles foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"roles"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Roles\\Providers\\RolesServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Search',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;
|
||||
return new class extends Migration { public function up(): void { Schema::create('search_index', function(Blueprint $table): void { $table->id(); $table->morphs('searchable'); $table->string('title')->index(); $table->text('summary')->nullable(); $table->longText('content')->nullable(); $table->string('url')->nullable(); $table->json('metadata')->nullable(); $table->boolean('is_public')->default(true)->index(); $table->timestamp('published_at')->nullable()->index(); $table->timestamps(); $table->unique(['searchable_type','searchable_id']); }); } public function down(): void { Schema::dropIfExists('search_index'); } };
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Search\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Search', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Search\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Search\Support\ModuleInfo;
|
||||
|
||||
final class SearchServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Search\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Search'; }
|
||||
public static function nameLower(): string { return 'search'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Search module', function (): void {
|
||||
expect(config('search.name'))->toBe('Search');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/search-module",
|
||||
"description": "Search foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Search\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Search",
|
||||
"alias": "search",
|
||||
"version": "1.0.0",
|
||||
"description": "Search foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"search"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Search\\Providers\\SearchServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Seo',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;
|
||||
return new class extends Migration { public function up(): void { Schema::create('seo_metadata', function(Blueprint $table): void { $table->id(); $table->morphs('seoable'); $table->string('title')->nullable(); $table->text('description')->nullable(); $table->string('canonical_url')->nullable(); $table->string('robots')->default('index,follow'); $table->string('og_title')->nullable(); $table->text('og_description')->nullable(); $table->string('og_image')->nullable(); $table->string('twitter_card')->default('summary_large_image'); $table->string('schema_type')->nullable(); $table->json('schema_data')->nullable(); $table->boolean('include_in_sitemap')->default(true); $table->decimal('sitemap_priority',2,1)->default(0.5); $table->string('sitemap_change_frequency')->default('monthly'); $table->timestamps(); $table->unique(['seoable_type','seoable_id']); }); } public function down(): void { Schema::dropIfExists('seo_metadata'); } };
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
namespace Modules\Seo\Models; use Illuminate\Database\Eloquent\Model;
|
||||
final class SeoMetadata extends Model { protected $table='seo_metadata'; protected $guarded=[]; protected function casts(): array { return ['schema_data'=>'array','include_in_sitemap'=>'boolean','sitemap_priority'=>'decimal:1']; } }
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Seo\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Seo', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Seo\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Seo\Support\ModuleInfo;
|
||||
|
||||
final class SeoServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Seo\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Seo'; }
|
||||
public static function nameLower(): string { return 'seo'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Seo module', function (): void {
|
||||
expect(config('seo.name'))->toBe('Seo');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/seo-module",
|
||||
"description": "Seo foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Seo\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Seo",
|
||||
"alias": "seo",
|
||||
"version": "1.0.0",
|
||||
"description": "Seo foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"seo"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Seo\\Providers\\SeoServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Settings',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void {
|
||||
Schema::create('settings', function (Blueprint $table): void {
|
||||
$table->id(); $table->string('group')->default('general')->index(); $table->string('key');
|
||||
$table->longText('value')->nullable(); $table->string('type')->default('string'); $table->boolean('is_public')->default(false);
|
||||
$table->timestamps(); $table->unique(['group','key']);
|
||||
});
|
||||
}
|
||||
public function down(): void { Schema::dropIfExists('settings'); }
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Settings\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class Setting extends Model
|
||||
{
|
||||
protected $fillable = ['group','key','value','type','is_public'];
|
||||
protected function casts(): array { return ['is_public'=>'boolean']; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Settings\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Settings', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Settings\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Settings\Support\ModuleInfo;
|
||||
|
||||
final class SettingsServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Settings\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Modules\Settings\Models\Setting;
|
||||
|
||||
final class SettingsRepository
|
||||
{
|
||||
public function get(string $key, mixed $default = null, string $group = 'general'): mixed
|
||||
{ return Cache::rememberForever("settings.$group.$key", fn () => Setting::query()->where(compact('group','key'))->value('value') ?? $default); }
|
||||
public function put(string $key, mixed $value, string $group = 'general', string $type = 'string', bool $public = false): Setting
|
||||
{
|
||||
$setting = Setting::query()->updateOrCreate(compact('group','key'), ['value'=>is_scalar($value)||$value===null?(string)$value:json_encode($value, JSON_THROW_ON_ERROR),'type'=>$type,'is_public'=>$public]);
|
||||
Cache::forget("settings.$group.$key"); return $setting;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Settings\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Settings'; }
|
||||
public static function nameLower(): string { return 'settings'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Settings module', function (): void {
|
||||
expect(config('settings.name'))->toBe('Settings');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/settings-module",
|
||||
"description": "Settings foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Settings\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Settings",
|
||||
"alias": "settings",
|
||||
"version": "1.0.0",
|
||||
"description": "Settings foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"settings"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Settings\\Providers\\SettingsServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'Users',
|
||||
'enabled' => true,
|
||||
];
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Users\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
final class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
$this->routes(function (): void {
|
||||
Route::middleware('web')->group(module_path('Users', 'Routes/web.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Users\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Users\Support\ModuleInfo;
|
||||
|
||||
final class UsersServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->register(RouteServiceProvider::class);
|
||||
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
||||
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Module routes are intentionally registered by each feature as it is enabled.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Users\Support;
|
||||
|
||||
final class ModuleInfo
|
||||
{
|
||||
public static function name(): string { return 'Users'; }
|
||||
public static function nameLower(): string { return 'users'; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
it('boots the Users module', function (): void {
|
||||
expect(config('users.name'))->toBe('Users');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "absdev/users-module",
|
||||
"description": "Users foundation module for the ABSDEV Laravel application platform.",
|
||||
"type": "laravel-module",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Users\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Users",
|
||||
"alias": "users",
|
||||
"version": "1.0.0",
|
||||
"description": "Users foundation module for the ABSDEV Laravel application platform.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"modules",
|
||||
"users"
|
||||
],
|
||||
"priority": 10,
|
||||
"providers": [
|
||||
"Modules\\Users\\Providers\\UsersServiceProvider"
|
||||
],
|
||||
"aliases": {},
|
||||
"files": [],
|
||||
"requires": [
|
||||
"Core"
|
||||
]
|
||||
}
|
||||
+10
-1
@@ -1,3 +1,12 @@
|
||||
{
|
||||
"Stylist": true
|
||||
"Stylist": true,
|
||||
"Core": true,
|
||||
"Administration": true,
|
||||
"Users": true,
|
||||
"Roles": true,
|
||||
"Settings": true,
|
||||
"Audit": true,
|
||||
"Media": true,
|
||||
"Seo": true,
|
||||
"Search": true
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user