diff --git a/Boot.php b/Boot.php index 40eb94d..354c780 100644 --- a/Boot.php +++ b/Boot.php @@ -2,17 +2,24 @@ declare(strict_types=1); -namespace Core\Tenant; +namespace Core\Mod\Tenant; use Core\Events\AdminPanelBooting; +use Core\Events\ApiRoutesRegistering; +use Core\Events\ConsoleBooting; +use Core\Events\WebRoutesRegistering; +use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; /** - * Tenant Module Boot (Host UK extension). + * Tenant Module Boot. * - * Extends core Tenant module with Host UK specific admin features: - * - Team Manager - * - Member Manager + * Core multi-tenancy module handling: + * - Users and authentication + * - Workspaces (the tenant boundary) + * - Account management (deletion, settings) + * - Entitlements (feature access, packages, usage) + * - Referrals */ class Boot extends ServiceProvider { @@ -25,16 +32,96 @@ class Boot extends ServiceProvider */ public static array $listens = [ AdminPanelBooting::class => 'onAdminPanel', + ApiRoutesRegistering::class => 'onApiRoutes', + WebRoutesRegistering::class => 'onWebRoutes', + ConsoleBooting::class => 'onConsole', ]; public function register(): void { - // + $this->app->singleton( + \Core\Mod\Tenant\Contracts\TwoFactorAuthenticationProvider::class, + \Core\Mod\Tenant\Services\TotpService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\EntitlementService::class, + \Core\Mod\Tenant\Services\EntitlementService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\WorkspaceManager::class, + \Core\Mod\Tenant\Services\WorkspaceManager::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\UserStatsService::class, + \Core\Mod\Tenant\Services\UserStatsService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\WorkspaceService::class, + \Core\Mod\Tenant\Services\WorkspaceService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\WorkspaceCacheManager::class, + \Core\Mod\Tenant\Services\WorkspaceCacheManager::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\UsageAlertService::class, + \Core\Mod\Tenant\Services\UsageAlertService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\EntitlementWebhookService::class, + \Core\Mod\Tenant\Services\EntitlementWebhookService::class + ); + + $this->app->singleton( + \Core\Mod\Tenant\Services\WorkspaceTeamService::class, + \Core\Mod\Tenant\Services\WorkspaceTeamService::class + ); + + $this->registerBackwardCompatAliases(); + } + + protected function registerBackwardCompatAliases(): void + { + if (! class_exists(\App\Services\WorkspaceManager::class)) { + class_alias( + \Core\Mod\Tenant\Services\WorkspaceManager::class, + \App\Services\WorkspaceManager::class + ); + } + + if (! class_exists(\App\Services\UserStatsService::class)) { + class_alias( + \Core\Mod\Tenant\Services\UserStatsService::class, + \App\Services\UserStatsService::class + ); + } + + if (! class_exists(\App\Services\WorkspaceService::class)) { + class_alias( + \Core\Mod\Tenant\Services\WorkspaceService::class, + \App\Services\WorkspaceService::class + ); + } + + if (! class_exists(\App\Services\WorkspaceCacheManager::class)) { + class_alias( + \Core\Mod\Tenant\Services\WorkspaceCacheManager::class, + \App\Services\WorkspaceCacheManager::class + ); + } } public function boot(): void { - // + $this->loadMigrationsFrom(__DIR__.'/Migrations'); + $this->loadTranslationsFrom(__DIR__.'/Lang/en_GB', 'tenant'); } // ------------------------------------------------------------------------- @@ -45,12 +132,42 @@ class Boot extends ServiceProvider { $event->views($this->moduleName, __DIR__.'/View/Blade'); - if (file_exists(__DIR__.'/Routes/admin.php')) { - $event->routes(fn () => require __DIR__.'/Routes/admin.php'); + // Admin Livewire components + $event->livewire('tenant.admin.entitlement-webhook-manager', View\Modal\Admin\EntitlementWebhookManager::class); + } + + public function onApiRoutes(ApiRoutesRegistering $event): void + { + if (file_exists(__DIR__.'/Routes/api.php')) { + $event->routes(fn () => Route::middleware('api')->group(__DIR__.'/Routes/api.php')); + } + } + + public function onWebRoutes(WebRoutesRegistering $event): void + { + $event->views($this->moduleName, __DIR__.'/View/Blade'); + + if (file_exists(__DIR__.'/Routes/web.php')) { + $event->routes(fn () => Route::middleware('web')->group(__DIR__.'/Routes/web.php')); } - // Admin components - $event->livewire('tenant.admin.team-manager', View\Modal\Admin\TeamManager::class); - $event->livewire('tenant.admin.member-manager', View\Modal\Admin\MemberManager::class); + // Account management + $event->livewire('tenant.account.cancel-deletion', View\Modal\Web\CancelDeletion::class); + $event->livewire('tenant.account.confirm-deletion', View\Modal\Web\ConfirmDeletion::class); + + // Workspace + $event->livewire('tenant.workspace.home', View\Modal\Web\WorkspaceHome::class); + } + + public function onConsole(ConsoleBooting $event): void + { + $event->middleware('admin.domain', Middleware\RequireAdminDomain::class); + $event->middleware('workspace.permission', Middleware\CheckWorkspacePermission::class); + + // Artisan commands + $event->command(Console\Commands\RefreshUserStats::class); + $event->command(Console\Commands\ProcessAccountDeletions::class); + $event->command(Console\Commands\CheckUsageAlerts::class); + $event->command(Console\Commands\ResetBillingCycles::class); } } diff --git a/src/Concerns/BelongsToNamespace.php b/Concerns/BelongsToNamespace.php similarity index 98% rename from src/Concerns/BelongsToNamespace.php rename to Concerns/BelongsToNamespace.php index 9979e10..ab25e5b 100644 --- a/src/Concerns/BelongsToNamespace.php +++ b/Concerns/BelongsToNamespace.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Concerns; +namespace Core\Mod\Tenant\Concerns; -use Core\Core\Tenant\Models\Namespace_; -use Core\Core\Tenant\Models\User; +use Core\Mod\Tenant\Models\Namespace_; +use Core\Mod\Tenant\Models\User; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Collection; diff --git a/src/Concerns/BelongsToWorkspace.php b/Concerns/BelongsToWorkspace.php similarity index 97% rename from src/Concerns/BelongsToWorkspace.php rename to Concerns/BelongsToWorkspace.php index ad53826..61d45ee 100644 --- a/src/Concerns/BelongsToWorkspace.php +++ b/Concerns/BelongsToWorkspace.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Concerns; +namespace Core\Mod\Tenant\Concerns; -use Core\Core\Tenant\Exceptions\MissingWorkspaceContextException; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Scopes\WorkspaceScope; -use Core\Core\Tenant\Services\WorkspaceCacheManager; +use Core\Mod\Tenant\Exceptions\MissingWorkspaceContextException; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Scopes\WorkspaceScope; +use Core\Mod\Tenant\Services\WorkspaceCacheManager; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Collection; diff --git a/src/Concerns/HasWorkspaceCache.php b/Concerns/HasWorkspaceCache.php similarity index 98% rename from src/Concerns/HasWorkspaceCache.php rename to Concerns/HasWorkspaceCache.php index ccce31b..5ba50ba 100644 --- a/src/Concerns/HasWorkspaceCache.php +++ b/Concerns/HasWorkspaceCache.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Concerns; +namespace Core\Mod\Tenant\Concerns; use Closure; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Services\WorkspaceCacheManager; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Services\WorkspaceCacheManager; use Illuminate\Support\Collection; /** diff --git a/src/Concerns/TwoFactorAuthenticatable.php b/Concerns/TwoFactorAuthenticatable.php similarity index 96% rename from src/Concerns/TwoFactorAuthenticatable.php rename to Concerns/TwoFactorAuthenticatable.php index acbd1b9..f838870 100644 --- a/src/Concerns/TwoFactorAuthenticatable.php +++ b/Concerns/TwoFactorAuthenticatable.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Concerns; +namespace Core\Mod\Tenant\Concerns; -use Core\Core\Tenant\Contracts\TwoFactorAuthenticationProvider; -use Core\Core\Tenant\Models\UserTwoFactorAuth; -use Core\Core\Tenant\Services\TotpService; +use Core\Mod\Tenant\Contracts\TwoFactorAuthenticationProvider; +use Core\Mod\Tenant\Models\UserTwoFactorAuth; +use Core\Mod\Tenant\Services\TotpService; use Illuminate\Database\Eloquent\Relations\HasOne; /** diff --git a/src/Console/Commands/CheckUsageAlerts.php b/Console/Commands/CheckUsageAlerts.php similarity index 98% rename from src/Console/Commands/CheckUsageAlerts.php rename to Console/Commands/CheckUsageAlerts.php index 977137e..35cf2ca 100644 --- a/src/Console/Commands/CheckUsageAlerts.php +++ b/Console/Commands/CheckUsageAlerts.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Console\Commands; +namespace Core\Mod\Tenant\Console\Commands; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Services\UsageAlertService; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Services\UsageAlertService; use Illuminate\Console\Command; /** diff --git a/src/Console/Commands/ProcessAccountDeletions.php b/Console/Commands/ProcessAccountDeletions.php similarity index 96% rename from src/Console/Commands/ProcessAccountDeletions.php rename to Console/Commands/ProcessAccountDeletions.php index e86ad3f..09c57a5 100644 --- a/src/Console/Commands/ProcessAccountDeletions.php +++ b/Console/Commands/ProcessAccountDeletions.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Console\Commands; +namespace Core\Mod\Tenant\Console\Commands; -use Core\Core\Tenant\Models\AccountDeletionRequest; +use Core\Mod\Tenant\Models\AccountDeletionRequest; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; diff --git a/src/Console/Commands/RefreshUserStats.php b/Console/Commands/RefreshUserStats.php similarity index 91% rename from src/Console/Commands/RefreshUserStats.php rename to Console/Commands/RefreshUserStats.php index 5631281..2e69729 100644 --- a/src/Console/Commands/RefreshUserStats.php +++ b/Console/Commands/RefreshUserStats.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Console\Commands; +namespace Core\Mod\Tenant\Console\Commands; -use Core\Core\Tenant\Jobs\ComputeUserStats; -use Core\Core\Tenant\Models\User; +use Core\Mod\Tenant\Jobs\ComputeUserStats; +use Core\Mod\Tenant\Models\User; use Illuminate\Console\Command; class RefreshUserStats extends Command diff --git a/src/Console/Commands/ResetBillingCycles.php b/Console/Commands/ResetBillingCycles.php similarity index 97% rename from src/Console/Commands/ResetBillingCycles.php rename to Console/Commands/ResetBillingCycles.php index 42ff284..4c64106 100644 --- a/src/Console/Commands/ResetBillingCycles.php +++ b/Console/Commands/ResetBillingCycles.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Console\Commands; +namespace Core\Mod\Tenant\Console\Commands; -use Core\Core\Tenant\Models\Boost; -use Core\Core\Tenant\Models\EntitlementLog; -use Core\Core\Tenant\Models\UsageRecord; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Notifications\BoostExpiredNotification; -use Core\Core\Tenant\Services\EntitlementService; +use Core\Mod\Tenant\Models\Boost; +use Core\Mod\Tenant\Models\EntitlementLog; +use Core\Mod\Tenant\Models\UsageRecord; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Notifications\BoostExpiredNotification; +use Core\Mod\Tenant\Services\EntitlementService; use Illuminate\Console\Command; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; diff --git a/src/Contracts/EntitlementWebhookEvent.php b/Contracts/EntitlementWebhookEvent.php similarity index 95% rename from src/Contracts/EntitlementWebhookEvent.php rename to Contracts/EntitlementWebhookEvent.php index eacfed5..569a070 100644 --- a/src/Contracts/EntitlementWebhookEvent.php +++ b/Contracts/EntitlementWebhookEvent.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Contracts; +namespace Core\Mod\Tenant\Contracts; /** * Contract for entitlement webhook events. diff --git a/src/Contracts/TwoFactorAuthenticationProvider.php b/Contracts/TwoFactorAuthenticationProvider.php similarity index 96% rename from src/Contracts/TwoFactorAuthenticationProvider.php rename to Contracts/TwoFactorAuthenticationProvider.php index bf5c768..eb5230b 100644 --- a/src/Contracts/TwoFactorAuthenticationProvider.php +++ b/Contracts/TwoFactorAuthenticationProvider.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Contracts; +namespace Core\Mod\Tenant\Contracts; /** * Contract for two-factor authentication providers. diff --git a/src/Controllers/Api/EntitlementWebhookController.php b/Controllers/Api/EntitlementWebhookController.php similarity index 96% rename from src/Controllers/Api/EntitlementWebhookController.php rename to Controllers/Api/EntitlementWebhookController.php index f756e0a..fe3863a 100644 --- a/src/Controllers/Api/EntitlementWebhookController.php +++ b/Controllers/Api/EntitlementWebhookController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Controllers\Api; +namespace Core\Mod\Tenant\Controllers\Api; -use Core\Core\Tenant\Models\EntitlementWebhook; -use Core\Core\Tenant\Models\EntitlementWebhookDelivery; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Services\EntitlementWebhookService; +use Core\Mod\Tenant\Models\EntitlementWebhook; +use Core\Mod\Tenant\Models\EntitlementWebhookDelivery; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Services\EntitlementWebhookService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Routing\Controller; diff --git a/src/Controllers/EntitlementApiController.php b/Controllers/EntitlementApiController.php similarity index 99% rename from src/Controllers/EntitlementApiController.php rename to Controllers/EntitlementApiController.php index dcb74ee..41f2e48 100644 --- a/src/Controllers/EntitlementApiController.php +++ b/Controllers/EntitlementApiController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Controllers; +namespace Core\Mod\Tenant\Controllers; use Core\Front\Controller; use Illuminate\Auth\Events\Registered; diff --git a/src/Controllers/ReferralController.php b/Controllers/ReferralController.php similarity index 99% rename from src/Controllers/ReferralController.php rename to Controllers/ReferralController.php index 395a10d..2382ac1 100644 --- a/src/Controllers/ReferralController.php +++ b/Controllers/ReferralController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Controllers; +namespace Core\Mod\Tenant\Controllers; use Core\Helpers\PrivacyHelper; use Core\Mod\Trees\Models\TreePlanting; diff --git a/src/Controllers/WorkspaceController.php b/Controllers/WorkspaceController.php similarity index 99% rename from src/Controllers/WorkspaceController.php rename to Controllers/WorkspaceController.php index b67cbf7..86c57ad 100644 --- a/src/Controllers/WorkspaceController.php +++ b/Controllers/WorkspaceController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Controllers; +namespace Core\Mod\Tenant\Controllers; use Core\Front\Controller; use Illuminate\Http\JsonResponse; diff --git a/src/Controllers/WorkspaceInvitationController.php b/Controllers/WorkspaceInvitationController.php similarity index 94% rename from src/Controllers/WorkspaceInvitationController.php rename to Controllers/WorkspaceInvitationController.php index 95f03ce..999d1ff 100644 --- a/src/Controllers/WorkspaceInvitationController.php +++ b/Controllers/WorkspaceInvitationController.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Controllers; +namespace Core\Mod\Tenant\Controllers; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Models\WorkspaceInvitation; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Models\WorkspaceInvitation; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Controller; diff --git a/src/Database/Factories/UserFactory.php b/Database/Factories/UserFactory.php similarity index 92% rename from src/Database/Factories/UserFactory.php rename to Database/Factories/UserFactory.php index 8d1ca5f..3a56e26 100644 --- a/src/Database/Factories/UserFactory.php +++ b/Database/Factories/UserFactory.php @@ -1,13 +1,13 @@ + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Mod\Tenant\Models\User> */ class UserFactory extends Factory { @@ -17,7 +17,7 @@ class UserFactory extends Factory * Uses the backward-compatible alias class to ensure type compatibility * with existing code that expects Mod\Tenant\Models\User. */ - protected $model = \Core\Core\Tenant\Models\User::class; + protected $model = \Core\Mod\Tenant\Models\User::class; /** * The current password being used by the factory. diff --git a/src/Database/Factories/UserTokenFactory.php b/Database/Factories/UserTokenFactory.php similarity index 94% rename from src/Database/Factories/UserTokenFactory.php rename to Database/Factories/UserTokenFactory.php index ae47149..dab5b03 100644 --- a/src/Database/Factories/UserTokenFactory.php +++ b/Database/Factories/UserTokenFactory.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Database\Factories; +namespace Core\Mod\Tenant\Database\Factories; -use Core\Core\Tenant\Models\User; -use Core\Core\Tenant\Models\UserToken; +use Core\Mod\Tenant\Models\User; +use Core\Mod\Tenant\Models\UserToken; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; diff --git a/src/Database/Factories/WaitlistEntryFactory.php b/Database/Factories/WaitlistEntryFactory.php similarity index 92% rename from src/Database/Factories/WaitlistEntryFactory.php rename to Database/Factories/WaitlistEntryFactory.php index 5696625..01ca0dd 100644 --- a/src/Database/Factories/WaitlistEntryFactory.php +++ b/Database/Factories/WaitlistEntryFactory.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Database\Factories; +namespace Core\Mod\Tenant\Database\Factories; -use Core\Core\Tenant\Models\WaitlistEntry; +use Core\Mod\Tenant\Models\WaitlistEntry; use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Core\Tenant\Models\WaitlistEntry> + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Mod\Tenant\Models\WaitlistEntry> */ class WaitlistEntryFactory extends Factory { diff --git a/src/Database/Factories/WorkspaceFactory.php b/Database/Factories/WorkspaceFactory.php similarity index 94% rename from src/Database/Factories/WorkspaceFactory.php rename to Database/Factories/WorkspaceFactory.php index 073f7e7..55f4cc2 100644 --- a/src/Database/Factories/WorkspaceFactory.php +++ b/Database/Factories/WorkspaceFactory.php @@ -1,12 +1,12 @@ + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Mod\Tenant\Models\Workspace> */ class WorkspaceFactory extends Factory { diff --git a/src/Database/Factories/WorkspaceInvitationFactory.php b/Database/Factories/WorkspaceInvitationFactory.php similarity index 92% rename from src/Database/Factories/WorkspaceInvitationFactory.php rename to Database/Factories/WorkspaceInvitationFactory.php index 9cc4b9c..c1771b2 100644 --- a/src/Database/Factories/WorkspaceInvitationFactory.php +++ b/Database/Factories/WorkspaceInvitationFactory.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Database\Factories; +namespace Core\Mod\Tenant\Database\Factories; -use Core\Core\Tenant\Models\WorkspaceInvitation; +use Core\Mod\Tenant\Models\WorkspaceInvitation; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Core\Tenant\Models\WorkspaceInvitation> + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\Core\Mod\Tenant\Models\WorkspaceInvitation> */ class WorkspaceInvitationFactory extends Factory { diff --git a/src/Database/Seeders/DemoTestUserSeeder.php b/Database/Seeders/DemoTestUserSeeder.php similarity index 97% rename from src/Database/Seeders/DemoTestUserSeeder.php rename to Database/Seeders/DemoTestUserSeeder.php index 84fdeb6..d1da763 100644 --- a/src/Database/Seeders/DemoTestUserSeeder.php +++ b/Database/Seeders/DemoTestUserSeeder.php @@ -1,10 +1,10 @@ \Core\Core\Tenant\Middleware\RequireWorkspaceContext::class, + * 'workspace.required' => \Core\Mod\Tenant\Middleware\RequireWorkspaceContext::class, */ class RequireWorkspaceContext { diff --git a/src/Middleware/ResolveNamespace.php b/Middleware/ResolveNamespace.php similarity index 95% rename from src/Middleware/ResolveNamespace.php rename to Middleware/ResolveNamespace.php index a926837..9a8eed9 100644 --- a/src/Middleware/ResolveNamespace.php +++ b/Middleware/ResolveNamespace.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Middleware; +namespace Core\Mod\Tenant\Middleware; use Closure; -use Core\Core\Tenant\Services\NamespaceService; +use Core\Mod\Tenant\Services\NamespaceService; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Middleware/ResolveWorkspaceFromSubdomain.php b/Middleware/ResolveWorkspaceFromSubdomain.php similarity index 97% rename from src/Middleware/ResolveWorkspaceFromSubdomain.php rename to Middleware/ResolveWorkspaceFromSubdomain.php index 3e4a312..9f195ff 100644 --- a/src/Middleware/ResolveWorkspaceFromSubdomain.php +++ b/Middleware/ResolveWorkspaceFromSubdomain.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Middleware; +namespace Core\Mod\Tenant\Middleware; use Closure; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Services\WorkspaceService; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Services\WorkspaceService; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Migrations/0001_01_01_000000_create_tenant_tables.php b/Migrations/0001_01_01_000000_create_tenant_tables.php similarity index 100% rename from src/Migrations/0001_01_01_000000_create_tenant_tables.php rename to Migrations/0001_01_01_000000_create_tenant_tables.php diff --git a/src/Migrations/2026_01_26_000000_create_workspace_invitations_table.php b/Migrations/2026_01_26_000000_create_workspace_invitations_table.php similarity index 100% rename from src/Migrations/2026_01_26_000000_create_workspace_invitations_table.php rename to Migrations/2026_01_26_000000_create_workspace_invitations_table.php diff --git a/src/Migrations/2026_01_26_120000_create_usage_alert_history_table.php b/Migrations/2026_01_26_120000_create_usage_alert_history_table.php similarity index 100% rename from src/Migrations/2026_01_26_120000_create_usage_alert_history_table.php rename to Migrations/2026_01_26_120000_create_usage_alert_history_table.php diff --git a/src/Migrations/2026_01_26_140000_create_entitlement_webhooks_tables.php b/Migrations/2026_01_26_140000_create_entitlement_webhooks_tables.php similarity index 100% rename from src/Migrations/2026_01_26_140000_create_entitlement_webhooks_tables.php rename to Migrations/2026_01_26_140000_create_entitlement_webhooks_tables.php diff --git a/src/Migrations/2026_01_26_140000_create_workspace_teams_table.php b/Migrations/2026_01_26_140000_create_workspace_teams_table.php similarity index 100% rename from src/Migrations/2026_01_26_140000_create_workspace_teams_table.php rename to Migrations/2026_01_26_140000_create_workspace_teams_table.php diff --git a/src/Models/AccountDeletionRequest.php b/Models/AccountDeletionRequest.php similarity index 99% rename from src/Models/AccountDeletionRequest.php rename to Models/AccountDeletionRequest.php index 49041b3..5716742 100644 --- a/src/Models/AccountDeletionRequest.php +++ b/Models/AccountDeletionRequest.php @@ -1,6 +1,6 @@ check() && auth()->user() instanceof \Core\Core\Tenant\Models\User) { + if (auth()->check() && auth()->user() instanceof \Core\Mod\Tenant\Models\User) { return auth()->user()->defaultHostWorkspace(); } @@ -680,7 +680,7 @@ class Workspace extends Model ]); // Send notification - $invitation->notify(new \Core\Core\Tenant\Notifications\WorkspaceInvitationNotification($invitation)); + $invitation->notify(new \Core\Mod\Tenant\Notifications\WorkspaceInvitationNotification($invitation)); return $invitation; } diff --git a/src/Models/WorkspaceInvitation.php b/Models/WorkspaceInvitation.php similarity index 94% rename from src/Models/WorkspaceInvitation.php rename to Models/WorkspaceInvitation.php index be08094..a863a82 100644 --- a/src/Models/WorkspaceInvitation.php +++ b/Models/WorkspaceInvitation.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Models; +namespace Core\Mod\Tenant\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -15,9 +15,9 @@ class WorkspaceInvitation extends Model use HasFactory; use Notifiable; - protected static function newFactory(): \Core\Core\Tenant\Database\Factories\WorkspaceInvitationFactory + protected static function newFactory(): \Core\Mod\Tenant\Database\Factories\WorkspaceInvitationFactory { - return \Core\Core\Tenant\Database\Factories\WorkspaceInvitationFactory::new(); + return \Core\Mod\Tenant\Database\Factories\WorkspaceInvitationFactory::new(); } protected $fillable = [ diff --git a/src/Models/WorkspaceMember.php b/Models/WorkspaceMember.php similarity index 99% rename from src/Models/WorkspaceMember.php rename to Models/WorkspaceMember.php index e345fff..6d49df7 100644 --- a/src/Models/WorkspaceMember.php +++ b/Models/WorkspaceMember.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Models; +namespace Core\Mod\Tenant\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; diff --git a/src/Models/WorkspacePackage.php b/Models/WorkspacePackage.php similarity index 99% rename from src/Models/WorkspacePackage.php rename to Models/WorkspacePackage.php index 7f31a21..629073b 100644 --- a/src/Models/WorkspacePackage.php +++ b/Models/WorkspacePackage.php @@ -1,6 +1,6 @@ prefix('admin/tenant')->name('hub.admin.tenant.')->group(function () { - // Team Manager - Route::get('/teams', \Core\Tenant\View\Modal\Admin\TeamManager::class) - ->name('teams'); - - // Member Manager - Route::get('/members', \Core\Tenant\View\Modal\Admin\MemberManager::class) - ->name('members'); -}); diff --git a/src/Routes/api.php b/Routes/api.php similarity index 98% rename from src/Routes/api.php rename to Routes/api.php index f5c0f3e..fd148cb 100644 --- a/src/Routes/api.php +++ b/Routes/api.php @@ -10,7 +10,7 @@ declare(strict_types=1); */ use Core\Mod\Api\Controllers\WorkspaceController; -use Core\Core\Tenant\Controllers\Api\EntitlementWebhookController; +use Core\Mod\Tenant\Controllers\Api\EntitlementWebhookController; use Illuminate\Support\Facades\Route; /* diff --git a/src/Routes/web.php b/Routes/web.php similarity index 85% rename from src/Routes/web.php rename to Routes/web.php index f1deab5..e3bf445 100644 --- a/src/Routes/web.php +++ b/Routes/web.php @@ -8,9 +8,9 @@ declare(strict_types=1); * Account management and workspace routes. */ -use Core\Core\Tenant\View\Modal\Web\CancelDeletion; -use Core\Core\Tenant\View\Modal\Web\ConfirmDeletion; -use Core\Core\Tenant\View\Modal\Web\WorkspaceHome; +use Core\Mod\Tenant\View\Modal\Web\CancelDeletion; +use Core\Mod\Tenant\View\Modal\Web\ConfirmDeletion; +use Core\Mod\Tenant\View\Modal\Web\WorkspaceHome; use Illuminate\Support\Facades\Route; /* @@ -41,7 +41,7 @@ Route::prefix('account')->name('account.')->group(function () { | */ -Route::get('/workspace/invitation/{token}', \Core\Core\Tenant\Controllers\WorkspaceInvitationController::class) +Route::get('/workspace/invitation/{token}', \Core\Mod\Tenant\Controllers\WorkspaceInvitationController::class) ->name('workspace.invitation.accept'); /* diff --git a/src/Rules/CheckUserPasswordRule.php b/Rules/CheckUserPasswordRule.php similarity index 94% rename from src/Rules/CheckUserPasswordRule.php rename to Rules/CheckUserPasswordRule.php index 56458ec..94d5814 100644 --- a/src/Rules/CheckUserPasswordRule.php +++ b/Rules/CheckUserPasswordRule.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Rules; +namespace Core\Mod\Tenant\Rules; use Closure; -use Core\Core\Tenant\Models\User; +use Core\Mod\Tenant\Models\User; use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Support\Facades\Hash; diff --git a/src/Rules/ResourceStatusRule.php b/Rules/ResourceStatusRule.php similarity index 96% rename from src/Rules/ResourceStatusRule.php rename to Rules/ResourceStatusRule.php index 119965a..8d338c0 100644 --- a/src/Rules/ResourceStatusRule.php +++ b/Rules/ResourceStatusRule.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Rules; +namespace Core\Mod\Tenant\Rules; use Closure; use Core\Mod\Social\Enums\ResourceStatus; diff --git a/src/Scopes/WorkspaceScope.php b/Scopes/WorkspaceScope.php similarity index 97% rename from src/Scopes/WorkspaceScope.php rename to Scopes/WorkspaceScope.php index e066d05..3af629f 100644 --- a/src/Scopes/WorkspaceScope.php +++ b/Scopes/WorkspaceScope.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Scopes; +namespace Core\Mod\Tenant\Scopes; -use Core\Core\Tenant\Exceptions\MissingWorkspaceContextException; -use Core\Core\Tenant\Models\Workspace; +use Core\Mod\Tenant\Exceptions\MissingWorkspaceContextException; +use Core\Mod\Tenant\Models\Workspace; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; diff --git a/src/Services/EntitlementResult.php b/Services/EntitlementResult.php similarity index 99% rename from src/Services/EntitlementResult.php rename to Services/EntitlementResult.php index e2ec3ab..078ba09 100644 --- a/src/Services/EntitlementResult.php +++ b/Services/EntitlementResult.php @@ -1,6 +1,6 @@ cached_stats) { // Queue background refresh - dispatch(new \Core\Core\Tenant\Jobs\ComputeUserStats($user->id))->onQueue('stats'); + dispatch(new \Core\Mod\Tenant\Jobs\ComputeUserStats($user->id))->onQueue('stats'); return $user->cached_stats; } diff --git a/src/Services/WorkspaceCacheManager.php b/Services/WorkspaceCacheManager.php similarity index 99% rename from src/Services/WorkspaceCacheManager.php rename to Services/WorkspaceCacheManager.php index 55f63fc..ef046f8 100644 --- a/src/Services/WorkspaceCacheManager.php +++ b/Services/WorkspaceCacheManager.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Services; +namespace Core\Mod\Tenant\Services; use Closure; -use Core\Core\Tenant\Models\Workspace; +use Core\Mod\Tenant\Models\Workspace; use Illuminate\Cache\TaggableStore; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; diff --git a/src/Services/WorkspaceManager.php b/Services/WorkspaceManager.php similarity index 98% rename from src/Services/WorkspaceManager.php rename to Services/WorkspaceManager.php index 0542a52..f3b9a48 100644 --- a/src/Services/WorkspaceManager.php +++ b/Services/WorkspaceManager.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Services; +namespace Core\Mod\Tenant\Services; -use Core\Core\Tenant\Models\User; -use Core\Core\Tenant\Models\Workspace; +use Core\Mod\Tenant\Models\User; +use Core\Mod\Tenant\Models\Workspace; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Validation\Rule; diff --git a/src/Services/WorkspaceService.php b/Services/WorkspaceService.php similarity index 97% rename from src/Services/WorkspaceService.php rename to Services/WorkspaceService.php index 68d2b7b..30d08fc 100644 --- a/src/Services/WorkspaceService.php +++ b/Services/WorkspaceService.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Services; +namespace Core\Mod\Tenant\Services; -use Core\Core\Tenant\Models\Workspace; +use Core\Mod\Tenant\Models\Workspace; use Illuminate\Support\Facades\Session; /** diff --git a/src/Services/WorkspaceTeamService.php b/Services/WorkspaceTeamService.php similarity index 98% rename from src/Services/WorkspaceTeamService.php rename to Services/WorkspaceTeamService.php index c9687a3..34dcf0e 100644 --- a/src/Services/WorkspaceTeamService.php +++ b/Services/WorkspaceTeamService.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Core\Tenant\Services; +namespace Core\Mod\Tenant\Services; -use Core\Core\Tenant\Models\User; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Models\WorkspaceMember; -use Core\Core\Tenant\Models\WorkspaceTeam; +use Core\Mod\Tenant\Models\User; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Models\WorkspaceMember; +use Core\Mod\Tenant\Models\WorkspaceTeam; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; diff --git a/src/View/Blade/admin/entitlement-webhook-manager.blade.php b/View/Blade/admin/entitlement-webhook-manager.blade.php similarity index 100% rename from src/View/Blade/admin/entitlement-webhook-manager.blade.php rename to View/Blade/admin/entitlement-webhook-manager.blade.php diff --git a/View/Blade/admin/member-manager.blade.php b/View/Blade/admin/member-manager.blade.php deleted file mode 100644 index ab53310..0000000 --- a/View/Blade/admin/member-manager.blade.php +++ /dev/null @@ -1,370 +0,0 @@ - - - - {{-- Stats cards --}} -
-
-
-
- -
-
-
{{ number_format($this->stats['total_members']) }}
-
{{ __('tenant::tenant.admin.member_manager.stats.total_members') }}
-
-
-
-
-
-
- -
-
-
{{ number_format($this->stats['with_team']) }}
-
{{ __('tenant::tenant.admin.member_manager.stats.with_team') }}
-
-
-
-
-
-
- -
-
-
{{ number_format($this->stats['with_custom_permissions']) }}
-
{{ __('tenant::tenant.admin.member_manager.stats.with_custom') }}
-
-
-
-
- - - - - - - - {{-- Bulk action bar --}} - @if(count($selected) > 0) -
-
- - - {{ __('tenant::tenant.admin.member_manager.bulk.selected', ['count' => count($selected)]) }} - -
-
- @if($workspaceFilter) - - {{ __('tenant::tenant.admin.member_manager.bulk.assign_team') }} - - @endif - - {{ __('tenant::tenant.admin.member_manager.bulk.remove_team') }} - - - {{ __('tenant::tenant.admin.member_manager.bulk.clear_permissions') }} - - - {{ __('tenant::tenant.admin.member_manager.bulk.clear') }} - -
-
- @endif - - {{-- Members table --}} - @if($this->members->isEmpty()) -
-
-
- -
- {{ __('tenant::tenant.admin.member_manager.empty_state.title') }} - {{ __('tenant::tenant.admin.member_manager.empty_state.description') }} -
-
- @else -
-
- - - - - - - - - - - - - - @foreach($this->members as $member) - - {{-- Checkbox --}} - - - {{-- Member info --}} - - - {{-- Workspace --}} - - - {{-- Team --}} - - - {{-- Legacy role --}} - - - {{-- Custom permissions indicator --}} - - - {{-- Actions --}} - - - @endforeach - -
- - {{ __('tenant::tenant.admin.member_manager.columns.member') }}{{ __('tenant::tenant.admin.member_manager.columns.workspace') }}{{ __('tenant::tenant.admin.member_manager.columns.team') }}{{ __('tenant::tenant.admin.member_manager.columns.role') }}{{ __('tenant::tenant.admin.member_manager.columns.permissions') }}{{ __('tenant::tenant.admin.member_manager.columns.actions') }}
- - -
- @if($member->user?->avatar_url) - - @else -
- -
- @endif -
-
{{ $member->user?->name ?? __('tenant::tenant.common.unknown') }}
-
{{ $member->user?->email }}
-
-
-
-
{{ $member->workspace?->name ?? __('tenant::tenant.common.na') }}
-
- @if($member->team) - - {{ $member->team->name }} - - @else - {{ __('tenant::tenant.admin.member_manager.labels.no_team') }} - @endif - - {{ $member->role }} - - @php - $customPerms = $member->custom_permissions ?? []; - $grantCount = count(array_filter($customPerms, fn($p) => !str_starts_with($p, '-'))); - $revokeCount = count(array_filter($customPerms, fn($p) => str_starts_with($p, '-'))); - @endphp - @if(!empty($customPerms)) -
- @if($grantCount > 0) - +{{ $grantCount }} - @endif - @if($revokeCount > 0) - -{{ $revokeCount }} - @endif -
- @else - {{ __('tenant::tenant.admin.member_manager.labels.inherited') }} - @endif -
- - - - - {{ __('tenant::tenant.admin.member_manager.actions.assign_team') }} - - - {{ __('tenant::tenant.admin.member_manager.actions.custom_permissions') }} - - @if($member->team_id) - - {{ __('tenant::tenant.admin.member_manager.actions.remove_from_team') }} - - @endif - @if(!empty($member->custom_permissions)) - - - {{ __('tenant::tenant.admin.member_manager.actions.clear_permissions') }} - - @endif - - -
-
- - @if($this->members->hasPages()) -
- {{ $this->members->links() }} -
- @endif -
- @endif - - {{-- Assign to Team Modal --}} - - - {{ __('tenant::tenant.admin.member_manager.assign_modal.title') }} - - -
- - - @foreach($this->teamsForAssignment as $team) - - @endforeach - - -
- - {{ __('tenant::tenant.admin.member_manager.modal.actions.cancel') }} - - - {{ __('tenant::tenant.admin.member_manager.modal.actions.save') }} - -
-
-
- - {{-- Custom Permissions Modal --}} - - - {{ __('tenant::tenant.admin.member_manager.permissions_modal.title') }} - - - @if($this->memberForPermissions) -
- {{-- Member info --}} -
- @if($this->memberForPermissions->user?->avatar_url) - - @else -
- -
- @endif -
-
{{ $this->memberForPermissions->user?->name }}
-
- {{ __('tenant::tenant.admin.member_manager.permissions_modal.team_permissions', ['team' => $this->memberForPermissions->team?->name ?? __('tenant::tenant.common.none')]) }} -
-
-
- -
- - {{ __('tenant::tenant.admin.member_manager.permissions_modal.description') }} -
- -
- {{-- Granted permissions (additions) --}} -
- - -
- @foreach($this->permissionGroups as $groupKey => $group) -
-
{{ $group['label'] }}
-
- @foreach($group['permissions'] as $permKey => $permLabel) - - @endforeach -
-
- @endforeach -
-
- - {{-- Revoked permissions (removals) --}} -
- - -
- @foreach($this->permissionGroups as $groupKey => $group) -
-
{{ $group['label'] }}
-
- @foreach($group['permissions'] as $permKey => $permLabel) - - @endforeach -
-
- @endforeach -
-
- -
- - {{ __('tenant::tenant.admin.member_manager.modal.actions.cancel') }} - - - {{ __('tenant::tenant.admin.member_manager.modal.actions.save') }} - -
-
-
- @endif -
- - {{-- Bulk Assign Modal --}} - - - {{ __('tenant::tenant.admin.member_manager.bulk_assign_modal.title') }} - - -
-
- {{ __('tenant::tenant.admin.member_manager.bulk_assign_modal.description', ['count' => count($selected)]) }} -
- - - - @foreach($this->teamsForBulkAssignment as $team) - - @endforeach - - -
- - {{ __('tenant::tenant.admin.member_manager.modal.actions.cancel') }} - - - {{ __('tenant::tenant.admin.member_manager.modal.actions.assign') }} - -
-
-
-
diff --git a/View/Blade/admin/team-manager.blade.php b/View/Blade/admin/team-manager.blade.php deleted file mode 100644 index ca70046..0000000 --- a/View/Blade/admin/team-manager.blade.php +++ /dev/null @@ -1,276 +0,0 @@ - - - - -
- @if($workspaceFilter) - - - - - {{ __('tenant::tenant.admin.team_manager.actions.seed_defaults') }} - - - {{ __('tenant::tenant.admin.team_manager.actions.migrate_members') }} - - - - @endif - - {{ __('tenant::tenant.admin.team_manager.actions.create_team') }} - -
-
- - {{-- Stats cards --}} -
-
-
-
- -
-
-
{{ number_format($this->stats['total_teams']) }}
-
{{ __('tenant::tenant.admin.team_manager.stats.total_teams') }}
-
-
-
-
-
-
- -
-
-
{{ number_format($this->stats['total_members']) }}
-
{{ __('tenant::tenant.admin.team_manager.stats.total_members') }}
-
-
-
-
-
-
- -
-
-
{{ number_format($this->stats['members_with_team']) }}
-
{{ __('tenant::tenant.admin.team_manager.stats.members_assigned') }}
-
-
-
-
- - - - - - - {{-- Teams table --}} - @if($this->teams->isEmpty()) -
-
-
- -
- {{ __('tenant::tenant.admin.team_manager.empty_state.title') }} - {{ __('tenant::tenant.admin.team_manager.empty_state.description') }} -
- - {{ __('tenant::tenant.admin.team_manager.actions.create_team') }} - - @if($workspaceFilter) - - {{ __('tenant::tenant.admin.team_manager.actions.seed_defaults') }} - - @endif -
-
-
- @else -
-
- - - - - - - - - - - - @foreach($this->teams as $team) - - {{-- Team info --}} - - - {{-- Workspace --}} - - - {{-- Member count --}} - - - {{-- Permissions count --}} - - - {{-- Actions --}} - - - @endforeach - -
{{ __('tenant::tenant.admin.team_manager.columns.team') }}{{ __('tenant::tenant.admin.team_manager.columns.workspace') }}{{ __('tenant::tenant.admin.team_manager.columns.members') }}{{ __('tenant::tenant.admin.team_manager.columns.permissions') }}{{ __('tenant::tenant.admin.team_manager.columns.actions') }}
-
-
- -
-
-
- {{ $team->name }} - @if($team->is_system) - {{ __('tenant::tenant.admin.team_manager.badges.system') }} - @endif - @if($team->is_default) - {{ __('tenant::tenant.admin.team_manager.badges.default') }} - @endif -
- @if($team->description) -
{{ $team->description }}
- @endif -
-
-
-
{{ $team->workspace?->name ?? __('tenant::tenant.common.na') }}
-
- {{ number_format($team->members_count) }} - -
- {{ count($team->permissions ?? []) }} {{ __('tenant::tenant.admin.team_manager.labels.permissions') }} -
-
- - - - - {{ __('tenant::tenant.admin.team_manager.actions.edit') }} - - - {{ __('tenant::tenant.admin.team_manager.actions.view_members') }} - - @unless($team->is_system) - - - {{ __('tenant::tenant.admin.team_manager.actions.delete') }} - - @endunless - - -
-
- - @if($this->teams->hasPages()) -
- {{ $this->teams->links() }} -
- @endif -
- @endif - - {{-- Create/Edit Team Modal --}} - - - {{ $editingTeamId ? __('tenant::tenant.admin.team_manager.modal.title_edit') : __('tenant::tenant.admin.team_manager.modal.title_create') }} - - -
- - - @foreach($this->workspaces as $workspace) - - @endforeach - - -
- - - @unless($editingTeamId) - - @endunless -
- - - -
- - @foreach($this->colourOptions as $value => $label) - - @endforeach - - -
- -
-
- - {{-- Permissions matrix --}} -
- - -
- @foreach($this->permissionGroups as $groupKey => $group) -
-
{{ $group['label'] }}
-
- @foreach($group['permissions'] as $permKey => $permLabel) - - @endforeach -
-
- @endforeach -
-
- -
- - {{ __('tenant::tenant.admin.team_manager.modal.actions.cancel') }} - - - {{ $editingTeamId ? __('tenant::tenant.admin.team_manager.modal.actions.update') : __('tenant::tenant.admin.team_manager.modal.actions.create') }} - -
- -
-
diff --git a/src/View/Blade/admin/workspace-details.blade.php b/View/Blade/admin/workspace-details.blade.php similarity index 100% rename from src/View/Blade/admin/workspace-details.blade.php rename to View/Blade/admin/workspace-details.blade.php diff --git a/src/View/Blade/admin/workspace-manager.blade.php b/View/Blade/admin/workspace-manager.blade.php similarity index 100% rename from src/View/Blade/admin/workspace-manager.blade.php rename to View/Blade/admin/workspace-manager.blade.php diff --git a/src/View/Blade/emails/account-deletion-requested.blade.php b/View/Blade/emails/account-deletion-requested.blade.php similarity index 100% rename from src/View/Blade/emails/account-deletion-requested.blade.php rename to View/Blade/emails/account-deletion-requested.blade.php diff --git a/src/View/Blade/emails/usage-alert.blade.php b/View/Blade/emails/usage-alert.blade.php similarity index 92% rename from src/View/Blade/emails/usage-alert.blade.php rename to View/Blade/emails/usage-alert.blade.php index 7cb3fff..ef8290e 100644 --- a/src/View/Blade/emails/usage-alert.blade.php +++ b/View/Blade/emails/usage-alert.blade.php @@ -1,7 +1,7 @@ @php $appName = config('core.app.name', __('core::core.brand.name')); - $isLimit = $threshold === \Core\Core\Tenant\Models\UsageAlertHistory::THRESHOLD_LIMIT; - $isCritical = $threshold === \Core\Core\Tenant\Models\UsageAlertHistory::THRESHOLD_CRITICAL; + $isLimit = $threshold === \Core\Mod\Tenant\Models\UsageAlertHistory::THRESHOLD_LIMIT; + $isCritical = $threshold === \Core\Mod\Tenant\Models\UsageAlertHistory::THRESHOLD_CRITICAL; @endphp diff --git a/src/View/Blade/web/account/cancel-deletion.blade.php b/View/Blade/web/account/cancel-deletion.blade.php similarity index 100% rename from src/View/Blade/web/account/cancel-deletion.blade.php rename to View/Blade/web/account/cancel-deletion.blade.php diff --git a/src/View/Blade/web/account/confirm-deletion.blade.php b/View/Blade/web/account/confirm-deletion.blade.php similarity index 100% rename from src/View/Blade/web/account/confirm-deletion.blade.php rename to View/Blade/web/account/confirm-deletion.blade.php diff --git a/src/View/Blade/web/workspace/home.blade.php b/View/Blade/web/workspace/home.blade.php similarity index 100% rename from src/View/Blade/web/workspace/home.blade.php rename to View/Blade/web/workspace/home.blade.php diff --git a/src/View/Modal/Admin/EntitlementWebhookManager.php b/View/Modal/Admin/EntitlementWebhookManager.php similarity index 97% rename from src/View/Modal/Admin/EntitlementWebhookManager.php rename to View/Modal/Admin/EntitlementWebhookManager.php index 94b8888..7e3ea60 100644 --- a/src/View/Modal/Admin/EntitlementWebhookManager.php +++ b/View/Modal/Admin/EntitlementWebhookManager.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Core\Tenant\View\Modal\Admin; +namespace Core\Mod\Tenant\View\Modal\Admin; -use Core\Core\Tenant\Models\EntitlementWebhook; -use Core\Core\Tenant\Models\EntitlementWebhookDelivery; -use Core\Core\Tenant\Models\Workspace; -use Core\Core\Tenant\Services\EntitlementWebhookService; +use Core\Mod\Tenant\Models\EntitlementWebhook; +use Core\Mod\Tenant\Models\EntitlementWebhookDelivery; +use Core\Mod\Tenant\Models\Workspace; +use Core\Mod\Tenant\Services\EntitlementWebhookService; use Illuminate\Contracts\View\View; use Livewire\Attributes\Computed; use Livewire\Attributes\Title; diff --git a/View/Modal/Admin/MemberManager.php b/View/Modal/Admin/MemberManager.php deleted file mode 100644 index 9d30db3..0000000 --- a/View/Modal/Admin/MemberManager.php +++ /dev/null @@ -1,404 +0,0 @@ -checkHadesAccess(); - $this->workspaceFilter = $workspaceFilter; - $this->teamFilter = $teamFilter; - } - - public function updatingSearch(): void - { - $this->resetPage(); - $this->clearSelection(); - } - - public function updatingWorkspaceFilter(): void - { - $this->resetPage(); - $this->clearSelection(); - $this->teamFilter = null; - } - - public function updatingTeamFilter(): void - { - $this->resetPage(); - $this->clearSelection(); - } - - public function updatedSelectAll(bool $value): void - { - $this->selected = $value - ? $this->members->pluck('id')->map(fn ($id) => (string) $id)->toArray() - : []; - } - - public function clearSelection(): void - { - $this->selected = []; - $this->selectAll = false; - } - - // ───────────────────────────────────────────────────────────────────────── - // Team Assignment - // ───────────────────────────────────────────────────────────────────────── - - public function openAssignModal(int $memberId): void - { - $member = WorkspaceMember::findOrFail($memberId); - - $this->assignMemberId = $memberId; - $this->assignTeamId = $member->team_id; - $this->showAssignModal = true; - } - - public function saveAssignment(): void - { - $member = WorkspaceMember::findOrFail($this->assignMemberId); - - // Validate team belongs to same workspace - if ($this->assignTeamId) { - $team = WorkspaceTeam::where('id', $this->assignTeamId) - ->where('workspace_id', $member->workspace_id) - ->first(); - - if (! $team) { - session()->flash('error', __('tenant::tenant.admin.member_manager.messages.invalid_team')); - - return; - } - } - - $member->update(['team_id' => $this->assignTeamId]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.team_assigned')); - $this->closeAssignModal(); - } - - public function removeFromTeam(int $memberId): void - { - $member = WorkspaceMember::findOrFail($memberId); - $member->update(['team_id' => null]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.removed_from_team')); - } - - public function closeAssignModal(): void - { - $this->showAssignModal = false; - $this->assignMemberId = null; - $this->assignTeamId = null; - } - - // ───────────────────────────────────────────────────────────────────────── - // Custom Permissions - // ───────────────────────────────────────────────────────────────────────── - - public function openPermissionsModal(int $memberId): void - { - $member = WorkspaceMember::findOrFail($memberId); - - $this->permissionsMemberId = $memberId; - $this->grantedPermissions = []; - $this->revokedPermissions = []; - - // Parse existing custom permissions - foreach ($member->custom_permissions ?? [] as $permission) { - if (str_starts_with($permission, '-')) { - $this->revokedPermissions[] = substr($permission, 1); - } elseif (str_starts_with($permission, '+')) { - $this->grantedPermissions[] = substr($permission, 1); - } else { - $this->grantedPermissions[] = $permission; - } - } - - $this->showPermissionsModal = true; - } - - public function savePermissions(): void - { - $member = WorkspaceMember::findOrFail($this->permissionsMemberId); - - // Build custom permissions array - $customPermissions = []; - - foreach ($this->grantedPermissions as $permission) { - $customPermissions[] = '+'.$permission; - } - - foreach ($this->revokedPermissions as $permission) { - $customPermissions[] = '-'.$permission; - } - - $member->update([ - 'custom_permissions' => ! empty($customPermissions) ? $customPermissions : null, - ]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.permissions_updated')); - $this->closePermissionsModal(); - } - - public function clearPermissions(int $memberId): void - { - $member = WorkspaceMember::findOrFail($memberId); - $member->update(['custom_permissions' => null]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.permissions_cleared')); - } - - public function closePermissionsModal(): void - { - $this->showPermissionsModal = false; - $this->permissionsMemberId = null; - $this->grantedPermissions = []; - $this->revokedPermissions = []; - } - - // ───────────────────────────────────────────────────────────────────────── - // Bulk Operations - // ───────────────────────────────────────────────────────────────────────── - - public function openBulkAssignModal(): void - { - $this->bulkTeamId = null; - $this->showBulkAssignModal = true; - } - - public function closeBulkAssignModal(): void - { - $this->showBulkAssignModal = false; - $this->bulkTeamId = null; - } - - public function bulkAssignTeam(): void - { - if (empty($this->selected)) { - session()->flash('error', __('tenant::tenant.admin.member_manager.messages.no_members_selected')); - - return; - } - - // Validate team exists - if ($this->bulkTeamId) { - $team = WorkspaceTeam::find($this->bulkTeamId); - if (! $team) { - session()->flash('error', __('tenant::tenant.admin.member_manager.messages.invalid_team')); - - return; - } - - // Update only members from same workspace as the team - $updated = WorkspaceMember::whereIn('id', $this->selected) - ->where('workspace_id', $team->workspace_id) - ->update(['team_id' => $this->bulkTeamId]); - } else { - // Remove from teams - $updated = WorkspaceMember::whereIn('id', $this->selected) - ->update(['team_id' => null]); - } - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.bulk_team_assigned', ['count' => $updated])); - $this->closeBulkAssignModal(); - $this->clearSelection(); - } - - public function bulkRemoveFromTeam(): void - { - if (empty($this->selected)) { - session()->flash('error', __('tenant::tenant.admin.member_manager.messages.no_members_selected')); - - return; - } - - $updated = WorkspaceMember::whereIn('id', $this->selected) - ->update(['team_id' => null]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.bulk_removed_from_team', ['count' => $updated])); - $this->clearSelection(); - } - - public function bulkClearPermissions(): void - { - if (empty($this->selected)) { - session()->flash('error', __('tenant::tenant.admin.member_manager.messages.no_members_selected')); - - return; - } - - $updated = WorkspaceMember::whereIn('id', $this->selected) - ->update(['custom_permissions' => null]); - - session()->flash('message', __('tenant::tenant.admin.member_manager.messages.bulk_permissions_cleared', ['count' => $updated])); - $this->clearSelection(); - } - - // ───────────────────────────────────────────────────────────────────────── - // Computed Properties - // ───────────────────────────────────────────────────────────────────────── - - #[Computed] - public function members(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return WorkspaceMember::query() - ->with(['user', 'workspace', 'team', 'inviter']) - ->when($this->search, function ($query) { - $query->whereHas('user', function ($q) { - $q->where('name', 'like', "%{$this->search}%") - ->orWhere('email', 'like', "%{$this->search}%"); - }); - }) - ->when($this->workspaceFilter, function ($query) { - $query->where('workspace_id', $this->workspaceFilter); - }) - ->when($this->teamFilter, function ($query) { - $query->where('team_id', $this->teamFilter); - }) - ->orderBy('created_at', 'desc') - ->paginate(20); - } - - #[Computed] - public function workspaces(): \Illuminate\Database\Eloquent\Collection - { - return Workspace::orderBy('name')->get(); - } - - #[Computed] - public function teamsForFilter(): \Illuminate\Database\Eloquent\Collection - { - $query = WorkspaceTeam::query(); - - if ($this->workspaceFilter) { - $query->where('workspace_id', $this->workspaceFilter); - } - - return $query->ordered()->get(); - } - - #[Computed] - public function teamsForAssignment(): \Illuminate\Database\Eloquent\Collection - { - if ($this->assignMemberId) { - $member = WorkspaceMember::find($this->assignMemberId); - if ($member) { - return WorkspaceTeam::where('workspace_id', $member->workspace_id) - ->ordered() - ->get(); - } - } - - return new \Illuminate\Database\Eloquent\Collection; - } - - #[Computed] - public function teamsForBulkAssignment(): \Illuminate\Database\Eloquent\Collection - { - // Only show teams from the current workspace filter - if ($this->workspaceFilter) { - return WorkspaceTeam::where('workspace_id', $this->workspaceFilter) - ->ordered() - ->get(); - } - - return new \Illuminate\Database\Eloquent\Collection; - } - - #[Computed] - public function permissionGroups(): array - { - return WorkspaceTeam::getAvailablePermissions(); - } - - #[Computed] - public function memberForPermissions(): ?WorkspaceMember - { - if ($this->permissionsMemberId) { - return WorkspaceMember::with(['team'])->find($this->permissionsMemberId); - } - - return null; - } - - #[Computed] - public function stats(): array - { - $query = WorkspaceMember::query(); - - if ($this->workspaceFilter) { - $query->where('workspace_id', $this->workspaceFilter); - } - - if ($this->teamFilter) { - $query->where('team_id', $this->teamFilter); - } - - return [ - 'total_members' => (clone $query)->count(), - 'with_team' => (clone $query)->whereNotNull('team_id')->count(), - 'with_custom_permissions' => (clone $query)->whereNotNull('custom_permissions')->count(), - ]; - } - - private function checkHadesAccess(): void - { - if (! auth()->user()?->isHades()) { - abort(403, __('tenant::tenant.errors.hades_required')); - } - } - - public function render(): View - { - return view('tenant::admin.member-manager') - ->layout('hub::admin.layouts.app', ['title' => __('tenant::tenant.admin.member_manager.title')]); - } -} diff --git a/View/Modal/Admin/TeamManager.php b/View/Modal/Admin/TeamManager.php deleted file mode 100644 index ad0f2d6..0000000 --- a/View/Modal/Admin/TeamManager.php +++ /dev/null @@ -1,289 +0,0 @@ -checkHadesAccess(); - } - - public function updatingSearch(): void - { - $this->resetPage(); - $this->clearSelection(); - } - - public function updatingWorkspaceFilter(): void - { - $this->resetPage(); - $this->clearSelection(); - } - - public function updatedSelectAll(bool $value): void - { - $this->selected = $value - ? $this->teams->pluck('id')->map(fn ($id) => (string) $id)->toArray() - : []; - } - - public function clearSelection(): void - { - $this->selected = []; - $this->selectAll = false; - } - - // ───────────────────────────────────────────────────────────────────────── - // Team CRUD - // ───────────────────────────────────────────────────────────────────────── - - public function openCreateTeam(): void - { - $this->resetTeamForm(); - $this->showTeamModal = true; - } - - public function openEditTeam(int $id): void - { - $team = WorkspaceTeam::findOrFail($id); - - $this->editingTeamId = $id; - $this->teamName = $team->name; - $this->teamSlug = $team->slug ?? ''; - $this->teamDescription = $team->description ?? ''; - $this->teamPermissions = $team->permissions ?? []; - $this->teamIsDefault = $team->is_default; - $this->teamColour = $team->colour ?? 'zinc'; - $this->teamWorkspaceId = $team->workspace_id; - - $this->showTeamModal = true; - } - - public function saveTeam(): void - { - $this->validate([ - 'teamName' => ['required', 'string', 'max:255'], - 'teamSlug' => ['nullable', 'string', 'max:255', 'alpha_dash'], - 'teamDescription' => ['nullable', 'string', 'max:1000'], - 'teamPermissions' => ['array'], - 'teamIsDefault' => ['boolean'], - 'teamColour' => ['required', 'string', 'max:32'], - 'teamWorkspaceId' => ['required', 'exists:workspaces,id'], - ]); - - $data = [ - 'name' => $this->teamName, - 'description' => $this->teamDescription ?: null, - 'permissions' => $this->teamPermissions, - 'is_default' => $this->teamIsDefault, - 'colour' => $this->teamColour, - 'workspace_id' => $this->teamWorkspaceId, - ]; - - // Only set slug for new teams or if explicitly provided - if (! $this->editingTeamId && $this->teamSlug) { - $data['slug'] = $this->teamSlug; - } - - // If setting as default, unset other defaults for this workspace - if ($this->teamIsDefault) { - WorkspaceTeam::where('workspace_id', $this->teamWorkspaceId) - ->where('is_default', true) - ->when($this->editingTeamId, fn ($q) => $q->where('id', '!=', $this->editingTeamId)) - ->update(['is_default' => false]); - } - - if ($this->editingTeamId) { - $team = WorkspaceTeam::findOrFail($this->editingTeamId); - - // Don't allow editing system team slug - if ($team->is_system) { - unset($data['slug']); - } - - $team->update($data); - session()->flash('message', __('tenant::tenant.admin.team_manager.messages.team_updated')); - } else { - WorkspaceTeam::create($data); - session()->flash('message', __('tenant::tenant.admin.team_manager.messages.team_created')); - } - - $this->closeTeamModal(); - } - - public function deleteTeam(int $id): void - { - $team = WorkspaceTeam::findOrFail($id); - - if ($team->is_system) { - session()->flash('error', __('tenant::tenant.admin.team_manager.messages.cannot_delete_system')); - - return; - } - - $memberCount = WorkspaceMember::where('team_id', $team->id)->count(); - if ($memberCount > 0) { - session()->flash('error', __('tenant::tenant.admin.team_manager.messages.cannot_delete_has_members', ['count' => $memberCount])); - - return; - } - - $team->delete(); - session()->flash('message', __('tenant::tenant.admin.team_manager.messages.team_deleted')); - } - - public function closeTeamModal(): void - { - $this->showTeamModal = false; - $this->resetTeamForm(); - } - - protected function resetTeamForm(): void - { - $this->editingTeamId = null; - $this->teamName = ''; - $this->teamSlug = ''; - $this->teamDescription = ''; - $this->teamPermissions = []; - $this->teamIsDefault = false; - $this->teamColour = 'zinc'; - $this->teamWorkspaceId = null; - } - - public function seedDefaultTeams(int $workspaceId): void - { - $workspace = Workspace::findOrFail($workspaceId); - - $teamService = app(WorkspaceTeamService::class)->forWorkspace($workspace); - $teamService->seedDefaultTeams(); - - session()->flash('message', __('tenant::tenant.admin.team_manager.messages.defaults_seeded')); - } - - public function migrateMembers(int $workspaceId): void - { - $workspace = Workspace::findOrFail($workspaceId); - - $teamService = app(WorkspaceTeamService::class)->forWorkspace($workspace); - $migrated = $teamService->migrateExistingMembers(); - - session()->flash('message', __('tenant::tenant.admin.team_manager.messages.members_migrated', ['count' => $migrated])); - } - - // ───────────────────────────────────────────────────────────────────────── - // Computed Properties - // ───────────────────────────────────────────────────────────────────────── - - #[Computed] - public function teams(): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - return WorkspaceTeam::query() - ->with(['workspace']) - ->when($this->search, function ($query) { - $query->where(function ($q) { - $q->where('name', 'like', "%{$this->search}%") - ->orWhere('description', 'like', "%{$this->search}%"); - }); - }) - ->when($this->workspaceFilter, function ($query) { - $query->where('workspace_id', $this->workspaceFilter); - }) - ->withCount('members') - ->orderBy('workspace_id') - ->ordered() - ->paginate(20); - } - - #[Computed] - public function workspaces(): \Illuminate\Database\Eloquent\Collection - { - return Workspace::orderBy('name')->get(); - } - - #[Computed] - public function permissionGroups(): array - { - return WorkspaceTeam::getAvailablePermissions(); - } - - #[Computed] - public function colourOptions(): array - { - return WorkspaceTeam::getColourOptions(); - } - - #[Computed] - public function stats(): array - { - $teamQuery = WorkspaceTeam::query(); - $memberQuery = WorkspaceMember::query(); - - if ($this->workspaceFilter) { - $teamQuery->where('workspace_id', $this->workspaceFilter); - $memberQuery->where('workspace_id', $this->workspaceFilter); - } - - return [ - 'total_teams' => $teamQuery->count(), - 'total_members' => $memberQuery->count(), - 'members_with_team' => (clone $memberQuery)->whereNotNull('team_id')->count(), - ]; - } - - private function checkHadesAccess(): void - { - if (! auth()->user()?->isHades()) { - abort(403, __('tenant::tenant.errors.hades_required')); - } - } - - public function render(): View - { - return view('tenant::admin.team-manager') - ->layout('hub::admin.layouts.app', ['title' => __('tenant::tenant.admin.team_manager.title')]); - } -} diff --git a/src/View/Modal/Admin/WorkspaceDetails.php b/View/Modal/Admin/WorkspaceDetails.php similarity index 91% rename from src/View/Modal/Admin/WorkspaceDetails.php rename to View/Modal/Admin/WorkspaceDetails.php index bebbe16..8f0c0c0 100644 --- a/src/View/Modal/Admin/WorkspaceDetails.php +++ b/View/Modal/Admin/WorkspaceDetails.php @@ -1,9 +1,9 @@ workspace->entitlementLogs() ->with('user', 'feature') @@ -147,7 +147,7 @@ class WorkspaceDetails extends Component } // Usage records - if (class_exists(\Core\Core\Tenant\Models\UsageRecord::class)) { + if (class_exists(\Core\Mod\Tenant\Models\UsageRecord::class)) { try { $usage = $this->workspace->usageRecords() ->with('user', 'feature') @@ -325,7 +325,7 @@ class WorkspaceDetails extends Component #[Computed] public function allPackages() { - return \Core\Core\Tenant\Models\Package::active() + return \Core\Mod\Tenant\Models\Package::active() ->ordered() ->get(); } @@ -333,7 +333,7 @@ class WorkspaceDetails extends Component #[Computed] public function allFeatures() { - return \Core\Core\Tenant\Models\Feature::active() + return \Core\Mod\Tenant\Models\Feature::active() ->orderBy('category') ->orderBy('sort_order') ->get(); @@ -403,7 +403,7 @@ class WorkspaceDetails extends Component public function resolvedEntitlements() { try { - return app(\Core\Core\Tenant\Services\EntitlementService::class) + return app(\Core\Mod\Tenant\Services\EntitlementService::class) ->getUsageSummary($this->workspace); } catch (\Exception $e) { return collect(); @@ -431,7 +431,7 @@ class WorkspaceDetails extends Component return; } - $package = \Core\Core\Tenant\Models\Package::findOrFail($this->selectedPackageId); + $package = \Core\Mod\Tenant\Models\Package::findOrFail($this->selectedPackageId); // Check if already assigned $existing = $this->workspace->workspacePackages() @@ -446,7 +446,7 @@ class WorkspaceDetails extends Component return; } - \Core\Core\Tenant\Models\WorkspacePackage::create([ + \Core\Mod\Tenant\Models\WorkspacePackage::create([ 'workspace_id' => $this->workspace->id, 'package_id' => $package->id, 'status' => 'active', @@ -461,7 +461,7 @@ class WorkspaceDetails extends Component public function removePackage(int $workspacePackageId): void { - $wp = \Core\Core\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) + $wp = \Core\Mod\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) ->findOrFail($workspacePackageId); $packageName = $wp->package?->name ?? 'Package'; @@ -474,7 +474,7 @@ class WorkspaceDetails extends Component public function suspendPackage(int $workspacePackageId): void { - $wp = \Core\Core\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) + $wp = \Core\Mod\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) ->findOrFail($workspacePackageId); $wp->suspend(); @@ -486,7 +486,7 @@ class WorkspaceDetails extends Component public function reactivatePackage(int $workspacePackageId): void { - $wp = \Core\Core\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) + $wp = \Core\Mod\Tenant\Models\WorkspacePackage::where('workspace_id', $this->workspace->id) ->findOrFail($workspacePackageId); $wp->reactivate(); @@ -523,7 +523,7 @@ class WorkspaceDetails extends Component return; } - $feature = \Core\Core\Tenant\Models\Feature::where('code', $this->selectedFeatureCode)->first(); + $feature = \Core\Mod\Tenant\Models\Feature::where('code', $this->selectedFeatureCode)->first(); if (! $feature) { $this->actionMessage = 'Feature not found.'; @@ -534,24 +534,24 @@ class WorkspaceDetails extends Component // Map type to boost type constant $boostType = match ($this->entitlementType) { - 'enable' => \Core\Core\Tenant\Models\Boost::BOOST_TYPE_ENABLE, - 'add_limit' => \Core\Core\Tenant\Models\Boost::BOOST_TYPE_ADD_LIMIT, - 'unlimited' => \Core\Core\Tenant\Models\Boost::BOOST_TYPE_UNLIMITED, - default => \Core\Core\Tenant\Models\Boost::BOOST_TYPE_ENABLE, + 'enable' => \Core\Mod\Tenant\Models\Boost::BOOST_TYPE_ENABLE, + 'add_limit' => \Core\Mod\Tenant\Models\Boost::BOOST_TYPE_ADD_LIMIT, + 'unlimited' => \Core\Mod\Tenant\Models\Boost::BOOST_TYPE_UNLIMITED, + default => \Core\Mod\Tenant\Models\Boost::BOOST_TYPE_ENABLE, }; $durationType = $this->entitlementDuration === 'permanent' - ? \Core\Core\Tenant\Models\Boost::DURATION_PERMANENT - : \Core\Core\Tenant\Models\Boost::DURATION_DURATION; + ? \Core\Mod\Tenant\Models\Boost::DURATION_PERMANENT + : \Core\Mod\Tenant\Models\Boost::DURATION_DURATION; - \Core\Core\Tenant\Models\Boost::create([ + \Core\Mod\Tenant\Models\Boost::create([ 'workspace_id' => $this->workspace->id, 'feature_code' => $this->selectedFeatureCode, 'boost_type' => $boostType, 'duration_type' => $durationType, 'limit_value' => $this->entitlementType === 'add_limit' ? $this->entitlementLimit : null, 'consumed_quantity' => 0, - 'status' => \Core\Core\Tenant\Models\Boost::STATUS_ACTIVE, + 'status' => \Core\Mod\Tenant\Models\Boost::STATUS_ACTIVE, 'starts_at' => now(), 'expires_at' => $this->entitlementExpiresAt ? \Carbon\Carbon::parse($this->entitlementExpiresAt) : null, 'metadata' => ['granted_by' => auth()->id(), 'granted_at' => now()->toDateTimeString()], @@ -565,7 +565,7 @@ class WorkspaceDetails extends Component public function removeBoost(int $boostId): void { - $boost = \Core\Core\Tenant\Models\Boost::where('workspace_id', $this->workspace->id) + $boost = \Core\Mod\Tenant\Models\Boost::where('workspace_id', $this->workspace->id) ->findOrFail($boostId); $featureCode = $boost->feature_code; diff --git a/src/View/Modal/Admin/WorkspaceManager.php b/View/Modal/Admin/WorkspaceManager.php similarity index 99% rename from src/View/Modal/Admin/WorkspaceManager.php rename to View/Modal/Admin/WorkspaceManager.php index ffa7abe..f01fa04 100644 --- a/src/View/Modal/Admin/WorkspaceManager.php +++ b/View/Modal/Admin/WorkspaceManager.php @@ -1,9 +1,9 @@ - */ - public static array $listens = [ - AdminPanelBooting::class => 'onAdminPanel', - ApiRoutesRegistering::class => 'onApiRoutes', - WebRoutesRegistering::class => 'onWebRoutes', - ConsoleBooting::class => 'onConsole', - ]; - - public function register(): void - { - $this->app->singleton( - \Core\Core\Tenant\Contracts\TwoFactorAuthenticationProvider::class, - \Core\Core\Tenant\Services\TotpService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\EntitlementService::class, - \Core\Core\Tenant\Services\EntitlementService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\WorkspaceManager::class, - \Core\Core\Tenant\Services\WorkspaceManager::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\UserStatsService::class, - \Core\Core\Tenant\Services\UserStatsService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\WorkspaceService::class, - \Core\Core\Tenant\Services\WorkspaceService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\WorkspaceCacheManager::class, - \Core\Core\Tenant\Services\WorkspaceCacheManager::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\UsageAlertService::class, - \Core\Core\Tenant\Services\UsageAlertService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\EntitlementWebhookService::class, - \Core\Core\Tenant\Services\EntitlementWebhookService::class - ); - - $this->app->singleton( - \Core\Core\Tenant\Services\WorkspaceTeamService::class, - \Core\Core\Tenant\Services\WorkspaceTeamService::class - ); - - $this->registerBackwardCompatAliases(); - } - - protected function registerBackwardCompatAliases(): void - { - if (! class_exists(\App\Services\WorkspaceManager::class)) { - class_alias( - \Core\Core\Tenant\Services\WorkspaceManager::class, - \App\Services\WorkspaceManager::class - ); - } - - if (! class_exists(\App\Services\UserStatsService::class)) { - class_alias( - \Core\Core\Tenant\Services\UserStatsService::class, - \App\Services\UserStatsService::class - ); - } - - if (! class_exists(\App\Services\WorkspaceService::class)) { - class_alias( - \Core\Core\Tenant\Services\WorkspaceService::class, - \App\Services\WorkspaceService::class - ); - } - - if (! class_exists(\App\Services\WorkspaceCacheManager::class)) { - class_alias( - \Core\Core\Tenant\Services\WorkspaceCacheManager::class, - \App\Services\WorkspaceCacheManager::class - ); - } - } - - public function boot(): void - { - $this->loadMigrationsFrom(__DIR__.'/Migrations'); - $this->loadTranslationsFrom(__DIR__.'/Lang/en_GB', 'tenant'); - } - - // ------------------------------------------------------------------------- - // Event-driven handlers - // ------------------------------------------------------------------------- - - public function onAdminPanel(AdminPanelBooting $event): void - { - $event->views($this->moduleName, __DIR__.'/View/Blade'); - - // Admin Livewire components - $event->livewire('tenant.admin.entitlement-webhook-manager', View\Modal\Admin\EntitlementWebhookManager::class); - } - - public function onApiRoutes(ApiRoutesRegistering $event): void - { - if (file_exists(__DIR__.'/Routes/api.php')) { - $event->routes(fn () => Route::middleware('api')->group(__DIR__.'/Routes/api.php')); - } - } - - public function onWebRoutes(WebRoutesRegistering $event): void - { - $event->views($this->moduleName, __DIR__.'/View/Blade'); - - if (file_exists(__DIR__.'/Routes/web.php')) { - $event->routes(fn () => Route::middleware('web')->group(__DIR__.'/Routes/web.php')); - } - - // Account management - $event->livewire('tenant.account.cancel-deletion', View\Modal\Web\CancelDeletion::class); - $event->livewire('tenant.account.confirm-deletion', View\Modal\Web\ConfirmDeletion::class); - - // Workspace - $event->livewire('tenant.workspace.home', View\Modal\Web\WorkspaceHome::class); - } - - public function onConsole(ConsoleBooting $event): void - { - $event->middleware('admin.domain', Middleware\RequireAdminDomain::class); - $event->middleware('workspace.permission', Middleware\CheckWorkspacePermission::class); - - // Artisan commands - $event->command(Console\Commands\RefreshUserStats::class); - $event->command(Console\Commands\ProcessAccountDeletions::class); - $event->command(Console\Commands\CheckUsageAlerts::class); - $event->command(Console\Commands\ResetBillingCycles::class); - } -} diff --git a/tests/Feature/AccountDeletionTest.php b/tests/Feature/AccountDeletionTest.php index 6d6fcdb..7d9455b 100644 --- a/tests/Feature/AccountDeletionTest.php +++ b/tests/Feature/AccountDeletionTest.php @@ -2,10 +2,10 @@ declare(strict_types=1); -use Core\Core\Tenant\Jobs\ProcessAccountDeletion; -use Core\Core\Tenant\Models\AccountDeletionRequest; -use Core\Core\Tenant\Models\User; -use Core\Core\Tenant\Models\Workspace; +use Core\Mod\Tenant\Jobs\ProcessAccountDeletion; +use Core\Mod\Tenant\Models\AccountDeletionRequest; +use Core\Mod\Tenant\Models\User; +use Core\Mod\Tenant\Models\Workspace; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Queue; diff --git a/tests/Feature/AuthenticationTest.php b/tests/Feature/AuthenticationTest.php index 3c0a98c..f165040 100644 --- a/tests/Feature/AuthenticationTest.php +++ b/tests/Feature/AuthenticationTest.php @@ -1,8 +1,8 @@ create(); diff --git a/tests/Feature/ProfileTest.php b/tests/Feature/ProfileTest.php index 3e96182..0c75a4b 100644 --- a/tests/Feature/ProfileTest.php +++ b/tests/Feature/ProfileTest.php @@ -1,9 +1,9 @@