From 97889d04cc4696e78b9b59d0d8c2f728c185c081 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 03:50:04 +0000 Subject: [PATCH] chore: fix pint code style and add test config Add phpunit.xml and tests/Pest.php for standalone test execution. Apply Laravel Pint formatting fixes across all source files. Co-Authored-By: Claude Opus 4.6 --- Console/Commands/EncryptTwoFactorSecrets.php | 2 +- Console/Commands/HashInvitationTokens.php | 4 +- Controllers/EntitlementApiController.php | 9 +- Controllers/WorkspaceController.php | 4 +- .../Factories/WorkspaceInvitationFactory.php | 1 - Events/EntitlementCacheInvalidated.php | 20 +-- Services/EntitlementService.php | 163 ++++++++---------- Services/EntitlementWebhookService.php | 1 + phpunit.xml | 39 +++++ tests/Feature/WorkspaceInvitationTest.php | 1 - tests/Pest.php | 7 + 11 files changed, 139 insertions(+), 112 deletions(-) create mode 100644 phpunit.xml create mode 100644 tests/Pest.php diff --git a/Console/Commands/EncryptTwoFactorSecrets.php b/Console/Commands/EncryptTwoFactorSecrets.php index 2d575d4..d76d008 100644 --- a/Console/Commands/EncryptTwoFactorSecrets.php +++ b/Console/Commands/EncryptTwoFactorSecrets.php @@ -54,7 +54,7 @@ class EncryptTwoFactorSecrets extends Command $this->info("Found {$records->count()} 2FA records total."); $this->info("Already encrypted: {$alreadyEncrypted}"); - $this->info("Need migration: ".count($toMigrate)); + $this->info('Need migration: '.count($toMigrate)); if (empty($toMigrate)) { $this->info('All secrets are already encrypted. Nothing to do.'); diff --git a/Console/Commands/HashInvitationTokens.php b/Console/Commands/HashInvitationTokens.php index e8c0ded..5995641 100644 --- a/Console/Commands/HashInvitationTokens.php +++ b/Console/Commands/HashInvitationTokens.php @@ -73,7 +73,7 @@ class HashInvitationTokens extends Command $this->info("Found {$records->count()} invitation records in scope."); $this->info("Already hashed: {$alreadyHashed}"); - $this->info("Need migration: ".count($toMigrate)); + $this->info('Need migration: '.count($toMigrate)); if (empty($toMigrate)) { $this->info('All tokens are already hashed. Nothing to do.'); @@ -86,7 +86,7 @@ class HashInvitationTokens extends Command $nonPendingCount = count($toMigrate) - $pendingCount; $this->newLine(); - $this->warn("IMPORTANT: Hashing tokens is a one-way operation!"); + $this->warn('IMPORTANT: Hashing tokens is a one-way operation!'); $this->warn("- Pending invitations ({$pendingCount}): Links will STOP working"); $this->warn("- Expired/Accepted ({$nonPendingCount}): Safe to hash"); diff --git a/Controllers/EntitlementApiController.php b/Controllers/EntitlementApiController.php index ec19045..8773eab 100644 --- a/Controllers/EntitlementApiController.php +++ b/Controllers/EntitlementApiController.php @@ -6,17 +6,16 @@ namespace Core\Tenant\Controllers; use Core\Api\RateLimit\RateLimit; use Core\Front\Controller; -use Illuminate\Auth\Events\Registered; -use Illuminate\Http\JsonResponse; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Log; -use Illuminate\Support\Str; use Core\Tenant\Models\EntitlementLog; use Core\Tenant\Models\Package; use Core\Tenant\Models\User; use Core\Tenant\Models\Workspace; use Core\Tenant\Models\WorkspacePackage; use Core\Tenant\Services\EntitlementService; +use Illuminate\Auth\Events\Registered; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Str; /** * API controller for entitlement management. diff --git a/Controllers/WorkspaceController.php b/Controllers/WorkspaceController.php index ab74220..f2da608 100644 --- a/Controllers/WorkspaceController.php +++ b/Controllers/WorkspaceController.php @@ -5,14 +5,14 @@ declare(strict_types=1); namespace Core\Tenant\Controllers; use Core\Front\Controller; +use Core\Tenant\Models\User; +use Core\Tenant\Models\Workspace; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Mod\Api\Controllers\Concerns\HasApiResponses; use Mod\Api\Controllers\Concerns\ResolvesWorkspace; use Mod\Api\Resources\PaginatedCollection; use Mod\Api\Resources\WorkspaceResource; -use Core\Tenant\Models\User; -use Core\Tenant\Models\Workspace; /** * Workspace API controller. diff --git a/Database/Factories/WorkspaceInvitationFactory.php b/Database/Factories/WorkspaceInvitationFactory.php index afb76ab..d351281 100644 --- a/Database/Factories/WorkspaceInvitationFactory.php +++ b/Database/Factories/WorkspaceInvitationFactory.php @@ -6,7 +6,6 @@ namespace Core\Tenant\Database\Factories; use Core\Tenant\Models\WorkspaceInvitation; use Illuminate\Database\Eloquent\Factories\Factory; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; /** diff --git a/Events/EntitlementCacheInvalidated.php b/Events/EntitlementCacheInvalidated.php index 0bb5679..aa56a00 100644 --- a/Events/EntitlementCacheInvalidated.php +++ b/Events/EntitlementCacheInvalidated.php @@ -59,10 +59,10 @@ class EntitlementCacheInvalidated /** * Create a new event instance. * - * @param Workspace|null $workspace The affected workspace (null for namespace-only invalidation) - * @param Namespace_|null $namespace The affected namespace (null for workspace-only invalidation) - * @param array $featureCodes Specific feature codes invalidated (empty = all features) - * @param string $reason The reason for invalidation + * @param Workspace|null $workspace The affected workspace (null for namespace-only invalidation) + * @param Namespace_|null $namespace The affected namespace (null for workspace-only invalidation) + * @param array $featureCodes Specific feature codes invalidated (empty = all features) + * @param string $reason The reason for invalidation */ public function __construct( public readonly ?Workspace $workspace, @@ -74,9 +74,9 @@ class EntitlementCacheInvalidated /** * Create an event for workspace cache invalidation. * - * @param Workspace $workspace The workspace whose cache was invalidated - * @param array $featureCodes Specific feature codes (empty = all) - * @param string $reason The reason for invalidation + * @param Workspace $workspace The workspace whose cache was invalidated + * @param array $featureCodes Specific feature codes (empty = all) + * @param string $reason The reason for invalidation */ public static function forWorkspace( Workspace $workspace, @@ -89,9 +89,9 @@ class EntitlementCacheInvalidated /** * Create an event for namespace cache invalidation. * - * @param Namespace_ $namespace The namespace whose cache was invalidated - * @param array $featureCodes Specific feature codes (empty = all) - * @param string $reason The reason for invalidation + * @param Namespace_ $namespace The namespace whose cache was invalidated + * @param array $featureCodes Specific feature codes (empty = all) + * @param string $reason The reason for invalidation */ public static function forNamespace( Namespace_ $namespace, diff --git a/Services/EntitlementService.php b/Services/EntitlementService.php index 1a415da..894f232 100644 --- a/Services/EntitlementService.php +++ b/Services/EntitlementService.php @@ -137,8 +137,8 @@ class EntitlementService /** * Get cache tags for workspace entitlements. * - * @param Workspace $workspace The workspace - * @param string $type The cache type ('limit' or 'usage') + * @param Workspace $workspace The workspace + * @param string $type The cache type ('limit' or 'usage') * @return array Cache tags */ protected function getWorkspaceCacheTags(Workspace $workspace, string $type = 'limit'): array @@ -159,8 +159,8 @@ class EntitlementService /** * Get cache tags for namespace entitlements. * - * @param Namespace_ $namespace The namespace - * @param string $type The cache type ('limit' or 'usage') + * @param Namespace_ $namespace The namespace + * @param string $type The cache type ('limit' or 'usage') * @return array Cache tags */ protected function getNamespaceCacheTags(Namespace_ $namespace, string $type = 'limit'): array @@ -213,11 +213,10 @@ class EntitlementService * echo "Remaining: {$result->getRemaining()}"; * ``` * - * @param Workspace $workspace The workspace to check entitlements for - * @param string $featureCode The feature code to check (e.g., 'pages', 'api_calls', 'custom_domains') - * @param int $quantity The quantity being requested (default: 1). For limit-based features, - * checks if current usage plus this quantity exceeds the limit. - * + * @param Workspace $workspace The workspace to check entitlements for + * @param string $featureCode The feature code to check (e.g., 'pages', 'api_calls', 'custom_domains') + * @param int $quantity The quantity being requested (default: 1). For limit-based features, + * checks if current usage plus this quantity exceeds the limit. * @return EntitlementResult Contains: * - `isAllowed()`: Whether the feature can be used * - `isDenied()`: Inverse of isAllowed @@ -316,10 +315,9 @@ class EntitlementService * // Uses workspace's 'pages' limit if namespace has no direct package * ``` * - * @param Namespace_ $namespace The namespace to check entitlements for - * @param string $featureCode The feature code to check - * @param int $quantity The quantity being requested (default: 1) - * + * @param Namespace_ $namespace The namespace to check entitlements for + * @param string $featureCode The feature code to check + * @param int $quantity The quantity being requested (default: 1) * @return EntitlementResult Contains allowed status, limits, and usage information * * @see self::can() For workspace-level checks @@ -432,12 +430,11 @@ class EntitlementService * ); * ``` * - * @param Namespace_ $namespace The namespace to record usage for - * @param string $featureCode The feature code being consumed - * @param int $quantity The amount to record (default: 1) - * @param User|null $user Optional user who triggered the usage (for attribution) - * @param array|null $metadata Optional metadata for audit/debugging - * + * @param Namespace_ $namespace The namespace to record usage for + * @param string $featureCode The feature code being consumed + * @param int $quantity The amount to record (default: 1) + * @param User|null $user Optional user who triggered the usage (for attribution) + * @param array|null $metadata Optional metadata for audit/debugging * @return UsageRecord The created usage record */ public function recordNamespaceUsage( @@ -500,12 +497,11 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to record usage for - * @param string $featureCode The feature code being consumed - * @param int $quantity The amount to record (default: 1) - * @param User|null $user Optional user who triggered the usage - * @param array|null $metadata Optional metadata for audit/debugging - * + * @param Workspace $workspace The workspace to record usage for + * @param string $featureCode The feature code being consumed + * @param int $quantity The amount to record (default: 1) + * @param User|null $user Optional user who triggered the usage + * @param array|null $metadata Optional metadata for audit/debugging * @return UsageRecord The created usage record */ public function recordUsage( @@ -576,8 +572,8 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to provision the package for - * @param string $packageCode The unique code of the package to provision + * @param Workspace $workspace The workspace to provision the package for + * @param string $packageCode The unique code of the package to provision * @param array{ * source?: string, * starts_at?: \DateTimeInterface, @@ -592,7 +588,6 @@ class EntitlementService * - `billing_cycle_anchor`: Date for monthly usage resets * - `blesta_service_id`: External billing system reference * - `metadata`: Additional data to store with the package - * * @return WorkspacePackage The created workspace package record * * @throws ModelNotFoundException If the package code does not exist @@ -701,8 +696,8 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to provision the boost for - * @param string $featureCode The feature code to boost + * @param Workspace $workspace The workspace to provision the boost for + * @param string $featureCode The feature code to boost * @param array{ * boost_type?: string, * duration_type?: string, @@ -721,7 +716,6 @@ class EntitlementService * - `expires_at`: When the boost expires * - `blesta_addon_id`: External billing reference * - `metadata`: Additional data to store - * * @return Boost The created boost record */ public function provisionBoost( @@ -800,8 +794,7 @@ class EntitlementService * } * ``` * - * @param Workspace $workspace The workspace to get the summary for - * + * @param Workspace $workspace The workspace to get the summary for * @return Collection Active workspace packages with * Package and Feature relations loaded */ @@ -907,8 +899,7 @@ class EntitlementService * } * ``` * - * @param Workspace $workspace The workspace to get boosts for - * + * @param Workspace $workspace The workspace to get boosts for * @return Collection Active, usable boosts ordered by expiry (soonest first) */ public function getActiveBoosts(Workspace $workspace): Collection @@ -949,9 +940,9 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to suspend - * @param string|null $source The source of the suspension for audit logging - * (e.g., 'stripe', 'admin', 'system') + * @param Workspace $workspace The workspace to suspend + * @param string|null $source The source of the suspension for audit logging + * (e.g., 'stripe', 'admin', 'system') * * @see self::reactivateWorkspace() To lift the suspension */ @@ -999,8 +990,8 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to reactivate - * @param string|null $source The source of the reactivation for audit logging + * @param Workspace $workspace The workspace to reactivate + * @param string|null $source The source of the reactivation for audit logging * * @see self::suspendWorkspace() To suspend packages */ @@ -1060,9 +1051,9 @@ class EntitlementService * ); * ``` * - * @param Workspace $workspace The workspace to revoke the package from - * @param string $packageCode The unique code of the package to revoke - * @param string|null $source The source of the revocation for audit logging + * @param Workspace $workspace The workspace to revoke the package from + * @param string $packageCode The unique code of the package to revoke + * @param string|null $source The source of the revocation for audit logging */ public function revokePackage(Workspace $workspace, string $packageCode, ?string $source = null): void { @@ -1101,9 +1092,8 @@ class EntitlementService * the workspace's total capacity for a feature. This is an internal method * used by `can()` and is cached for performance. * - * @param Workspace $workspace The workspace to calculate limits for - * @param string $featureCode The feature code to get the limit for - * + * @param Workspace $workspace The workspace to calculate limits for + * @param string $featureCode The feature code to get the limit for * @return int|null Returns: * - `null` if the feature is not included in any package * - `-1` if the feature is unlimited @@ -1190,10 +1180,9 @@ class EntitlementService * * Results are cached for 60 seconds to reduce database load. * - * @param Workspace $workspace The workspace to get usage for - * @param string $featureCode The feature code to get usage for - * @param Feature $feature The feature model (for reset configuration) - * + * @param Workspace $workspace The workspace to get usage for + * @param string $featureCode The feature code to get usage for + * @param Feature $feature The feature model (for reset configuration) * @return int The current usage count */ protected function getCurrentUsage(Workspace $workspace, string $featureCode, Feature $feature): int @@ -1241,8 +1230,7 @@ class EntitlementService * Retrieves the Feature model from the database, with results cached * for the standard cache TTL (5 minutes). * - * @param string $code The unique feature code (e.g., 'pages', 'api_calls') - * + * @param string $code The unique feature code (e.g., 'pages', 'api_calls') * @return Feature|null The feature model, or null if not found */ protected function getFeature(string $code): ?Feature @@ -1283,9 +1271,9 @@ class EntitlementService * $entitlementService->invalidateCache($workspace); * ``` * - * @param Workspace $workspace The workspace to invalidate caches for - * @param array $featureCodes Specific features to invalidate (empty = all) - * @param string $reason The reason for invalidation (for event dispatch) + * @param Workspace $workspace The workspace to invalidate caches for + * @param array $featureCodes Specific features to invalidate (empty = all) + * @param string $reason The reason for invalidation (for event dispatch) */ public function invalidateCache( Workspace $workspace, @@ -1311,8 +1299,8 @@ class EntitlementService /** * Invalidate cache using cache tags (O(1) operation). * - * @param Workspace $workspace The workspace to invalidate - * @param array $featureCodes Specific features (empty = all) + * @param Workspace $workspace The workspace to invalidate + * @param array $featureCodes Specific features (empty = all) */ protected function invalidateCacheWithTags(Workspace $workspace, array $featureCodes = []): void { @@ -1341,8 +1329,8 @@ class EntitlementService * This is O(n) where n = number of features when no specific features * are provided. * - * @param Workspace $workspace The workspace to invalidate - * @param array $featureCodes Specific features (empty = all) + * @param Workspace $workspace The workspace to invalidate + * @param array $featureCodes Specific features (empty = all) */ protected function invalidateCacheWithoutTags(Workspace $workspace, array $featureCodes = []): void { @@ -1363,8 +1351,8 @@ class EntitlementService * Use this for performance when only usage has changed (e.g., after recording * usage) and limits are known to be unchanged. * - * @param Workspace $workspace The workspace to invalidate usage cache for - * @param string $featureCode The specific feature code to invalidate + * @param Workspace $workspace The workspace to invalidate usage cache for + * @param string $featureCode The specific feature code to invalidate */ public function invalidateUsageCache(Workspace $workspace, string $featureCode): void { @@ -1391,8 +1379,8 @@ class EntitlementService * Use this for performance when only limits have changed (e.g., after * provisioning a package or boost) and usage data is unchanged. * - * @param Workspace $workspace The workspace to invalidate limit cache for - * @param array $featureCodes Specific features (empty = all limit caches) + * @param Workspace $workspace The workspace to invalidate limit cache for + * @param array $featureCodes Specific features (empty = all limit caches) */ public function invalidateLimitCache(Workspace $workspace, array $featureCodes = []): void { @@ -1444,7 +1432,7 @@ class EntitlementService * } * ``` * - * @param Workspace $workspace The workspace to expire boosts for + * @param Workspace $workspace The workspace to expire boosts for */ public function expireCycleBoundBoosts(Workspace $workspace): void { @@ -1489,9 +1477,8 @@ class EntitlementService * Does not include workspace-level entitlements (that cascade is handled * by `canForNamespace()`). * - * @param Namespace_ $namespace The namespace to calculate limits for - * @param string $featureCode The feature code to get the limit for - * + * @param Namespace_ $namespace The namespace to calculate limits for + * @param string $featureCode The feature code to get the limit for * @return int|null Returns: * - `null` if the feature is not included in any namespace package * - `-1` if the feature is unlimited @@ -1579,10 +1566,9 @@ class EntitlementService * The time window for calculation follows the same rules based on feature * reset configuration. * - * @param Namespace_ $namespace The namespace to get usage for - * @param string $featureCode The feature code to get usage for - * @param Feature $feature The feature model (for reset configuration) - * + * @param Namespace_ $namespace The namespace to get usage for + * @param string $featureCode The feature code to get usage for + * @param Feature $feature The feature model (for reset configuration) * @return int The current usage count for the namespace */ protected function getNamespaceCurrentUsage(Namespace_ $namespace, string $featureCode, Feature $feature): int @@ -1652,8 +1638,7 @@ class EntitlementService * } * ``` * - * @param Namespace_ $namespace The namespace to get the summary for - * + * @param Namespace_ $namespace The namespace to get the summary for * @return CollectioninvalidateNamespaceCache($namespace); * ``` * - * @param Namespace_ $namespace The namespace to invalidate caches for - * @param array $featureCodes Specific features to invalidate (empty = all) - * @param string $reason The reason for invalidation (for event dispatch) + * @param Namespace_ $namespace The namespace to invalidate caches for + * @param array $featureCodes Specific features to invalidate (empty = all) + * @param string $reason The reason for invalidation (for event dispatch) * * @see self::invalidateCache() For workspace-level cache invalidation */ @@ -1941,8 +1924,8 @@ class EntitlementService /** * Invalidate namespace cache using cache tags (O(1) operation). * - * @param Namespace_ $namespace The namespace to invalidate - * @param array $featureCodes Specific features (empty = all) + * @param Namespace_ $namespace The namespace to invalidate + * @param array $featureCodes Specific features (empty = all) */ protected function invalidateNamespaceCacheWithTags(Namespace_ $namespace, array $featureCodes = []): void { @@ -1971,8 +1954,8 @@ class EntitlementService * This is O(n) where n = number of features when no specific features * are provided. * - * @param Namespace_ $namespace The namespace to invalidate - * @param array $featureCodes Specific features (empty = all) + * @param Namespace_ $namespace The namespace to invalidate + * @param array $featureCodes Specific features (empty = all) */ protected function invalidateNamespaceCacheWithoutTags(Namespace_ $namespace, array $featureCodes = []): void { @@ -1993,8 +1976,8 @@ class EntitlementService * Use this for performance when only usage has changed (e.g., after recording * usage) and limits are known to be unchanged. * - * @param Namespace_ $namespace The namespace to invalidate usage cache for - * @param string $featureCode The specific feature code to invalidate + * @param Namespace_ $namespace The namespace to invalidate usage cache for + * @param string $featureCode The specific feature code to invalidate */ public function invalidateNamespaceUsageCache(Namespace_ $namespace, string $featureCode): void { diff --git a/Services/EntitlementWebhookService.php b/Services/EntitlementWebhookService.php index f1cf204..b765f2f 100644 --- a/Services/EntitlementWebhookService.php +++ b/Services/EntitlementWebhookService.php @@ -32,6 +32,7 @@ use Illuminate\Support\Str; class EntitlementWebhookService { use PreventsSSRF; + /** * Dispatch an event to all matching webhooks for a workspace. * diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..cb23fe0 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,39 @@ + + + + + tests/Feature + + + tests/Unit + + + + + src + + + + + + + + + + + + + + + + diff --git a/tests/Feature/WorkspaceInvitationTest.php b/tests/Feature/WorkspaceInvitationTest.php index 4417a96..8025647 100644 --- a/tests/Feature/WorkspaceInvitationTest.php +++ b/tests/Feature/WorkspaceInvitationTest.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Core\Tenant\Tests\Feature; -use Core\Tenant\Database\Factories\WorkspaceInvitationFactory; use Core\Tenant\Models\User; use Core\Tenant\Models\Workspace; use Core\Tenant\Models\WorkspaceInvitation; diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..7f6d8cf --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,7 @@ +in('Feature', 'Unit');