From d5884f7a63a2c77a6e665ef92595b6faa6a80f1b Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 26 Apr 2024 13:21:05 -0400 Subject: [PATCH 1/5] Add contract and typehints --- src/Contracts/Tokens/TokenRepository.php | 16 ++++++++++++++++ src/Tokens/TokenRepository.php | 14 ++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 src/Contracts/Tokens/TokenRepository.php diff --git a/src/Contracts/Tokens/TokenRepository.php b/src/Contracts/Tokens/TokenRepository.php new file mode 100644 index 0000000000..84b23977ff --- /dev/null +++ b/src/Contracts/Tokens/TokenRepository.php @@ -0,0 +1,16 @@ +makeFromPath($path); } - public function save(Token $token) + public function save(TokenContract $token): bool { File::put(storage_path('statamic/tokens/'.$token->token().'.yaml'), $token->fileContents()); return true; } - public function delete(Token $token) + public function delete(TokenContract $token): bool { File::delete(storage_path('statamic/tokens/'.$token->token().'.yaml')); return true; } - public function collectGarbage() + public function collectGarbage(): void { File::getFilesByType(storage_path('statamic/tokens'), 'yaml') ->map(fn ($path) => $this->makeFromPath($path)) From 10a6907c4f52a645170068e8454f3bb793c6a6fd Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 26 Apr 2024 13:21:16 -0400 Subject: [PATCH 2/5] Fill out facade docblock --- src/Facades/Token.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Facades/Token.php b/src/Facades/Token.php index 270c81ffbc..e253c5b410 100644 --- a/src/Facades/Token.php +++ b/src/Facades/Token.php @@ -5,6 +5,13 @@ use Illuminate\Support\Facades\Facade; use Statamic\Tokens\TokenRepository; +/** + * @method static \Statamic\Contracts\Tokens\Token make(?string $token, string $handler, array $data = []) + * @method static \Statamic\Contracts\Tokens\Token find(string $token) + * @method static bool save(\Statamic\Contracts\Tokens\Token $token) + * @method static bool delete(\Statamic\Contracts\Tokens\Token $token) + * @method static void collectGarbage() + */ class Token extends Facade { protected static function getFacadeAccessor() From 704525754425416920006e87821db6351e44d788 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 26 Apr 2024 13:24:10 -0400 Subject: [PATCH 3/5] Point facade to contract --- src/Facades/Token.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Facades/Token.php b/src/Facades/Token.php index e253c5b410..d2a8b7bc18 100644 --- a/src/Facades/Token.php +++ b/src/Facades/Token.php @@ -3,7 +3,7 @@ namespace Statamic\Facades; use Illuminate\Support\Facades\Facade; -use Statamic\Tokens\TokenRepository; +use Statamic\Contracts\Tokens\TokenRepository; /** * @method static \Statamic\Contracts\Tokens\Token make(?string $token, string $handler, array $data = []) @@ -11,6 +11,8 @@ * @method static bool save(\Statamic\Contracts\Tokens\Token $token) * @method static bool delete(\Statamic\Contracts\Tokens\Token $token) * @method static void collectGarbage() + * + * @see \Statamic\Tokens\TokenRepository */ class Token extends Facade { From 2db9f606feeab52f842c4c4d5d7a843ff4b44570 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 26 Apr 2024 13:24:23 -0400 Subject: [PATCH 4/5] Set up repository bindings --- src/Providers/AppServiceProvider.php | 1 + src/Tokens/TokenRepository.php | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php index 2bac85a9d3..6998ec3b16 100644 --- a/src/Providers/AppServiceProvider.php +++ b/src/Providers/AppServiceProvider.php @@ -121,6 +121,7 @@ public function register() \Statamic\Contracts\Assets\AssetRepository::class => \Statamic\Assets\AssetRepository::class, \Statamic\Contracts\Forms\FormRepository::class => \Statamic\Forms\FormRepository::class, \Statamic\Contracts\Forms\SubmissionRepository::class => \Statamic\Stache\Repositories\SubmissionRepository::class, + \Statamic\Contracts\Tokens\TokenRepository::class => \Statamic\Tokens\TokenRepository::class, ])->each(function ($concrete, $abstract) { if (! $this->app->bound($abstract)) { Statamic::repository($abstract, $concrete); diff --git a/src/Tokens/TokenRepository.php b/src/Tokens/TokenRepository.php index 7bde443ac6..da65bb9935 100644 --- a/src/Tokens/TokenRepository.php +++ b/src/Tokens/TokenRepository.php @@ -12,7 +12,7 @@ class TokenRepository implements Contract { public function make(?string $token, string $handler, array $data = []): TokenContract { - return new Token($token, $handler, $data); + return app()->makeWith(TokenContract::class, compact('token', 'handler', 'data')); } public function find(string $token): ?TokenContract @@ -58,4 +58,11 @@ private function makeFromPath(string $path): Token ->make($token, $yaml['handler'], $yaml['data'] ?? []) ->expireAt(Carbon::createFromTimestamp($yaml['expires_at'])); } + + public static function bindings(): array + { + return [ + TokenContract::class => Token::class, + ]; + } } From 986e047cfe0ab99c431385f107d0e6bf3958613c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 26 Apr 2024 13:43:57 -0400 Subject: [PATCH 5/5] Move file logic into file specific classes --- src/Providers/AppServiceProvider.php | 2 +- src/Tokens/AbstractToken.php | 78 ---------------------------- src/Tokens/FileToken.php | 24 +++++++++ src/Tokens/FileTokenRepository.php | 67 ++++++++++++++++++++++++ src/Tokens/Token.php | 76 +++++++++++++++++++++++---- src/Tokens/TokenRepository.php | 56 +------------------- tests/Tokens/TokenRepositoryTest.php | 4 +- tests/Tokens/TokenTest.php | 2 +- 8 files changed, 162 insertions(+), 147 deletions(-) delete mode 100644 src/Tokens/AbstractToken.php create mode 100644 src/Tokens/FileToken.php create mode 100644 src/Tokens/FileTokenRepository.php diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php index 6998ec3b16..83e71c5dd3 100644 --- a/src/Providers/AppServiceProvider.php +++ b/src/Providers/AppServiceProvider.php @@ -121,7 +121,7 @@ public function register() \Statamic\Contracts\Assets\AssetRepository::class => \Statamic\Assets\AssetRepository::class, \Statamic\Contracts\Forms\FormRepository::class => \Statamic\Forms\FormRepository::class, \Statamic\Contracts\Forms\SubmissionRepository::class => \Statamic\Stache\Repositories\SubmissionRepository::class, - \Statamic\Contracts\Tokens\TokenRepository::class => \Statamic\Tokens\TokenRepository::class, + \Statamic\Contracts\Tokens\TokenRepository::class => \Statamic\Tokens\FileTokenRepository::class, ])->each(function ($concrete, $abstract) { if (! $this->app->bound($abstract)) { Statamic::repository($abstract, $concrete); diff --git a/src/Tokens/AbstractToken.php b/src/Tokens/AbstractToken.php deleted file mode 100644 index 7038cce0a9..0000000000 --- a/src/Tokens/AbstractToken.php +++ /dev/null @@ -1,78 +0,0 @@ -token = $token ?? Generator::generate(); - $this->handler = $handler; - $this->data = collect($data); - $this->expiry = Carbon::now()->addHour(); - } - - public function token(): string - { - return $this->token; - } - - public function handler(): string - { - return $this->handler; - } - - public function data(): Collection - { - return $this->data; - } - - public function get(string $key) - { - return $this->data->get($key); - } - - public function save() - { - return Token::save($this); - } - - public function delete() - { - return Token::delete($this); - } - - public function handle($request, Closure $next) - { - return app($this->handler)->handle($this, $request, $next); - } - - public function expiry(): Carbon - { - return $this->expiry; - } - - public function expireAt(Carbon $expiry): self - { - $this->expiry = $expiry; - - return $this; - } - - public function hasExpired(): bool - { - return $this->expiry->isPast(); - } -} diff --git a/src/Tokens/FileToken.php b/src/Tokens/FileToken.php new file mode 100644 index 0000000000..28cb75d05b --- /dev/null +++ b/src/Tokens/FileToken.php @@ -0,0 +1,24 @@ +token().'.yaml'); + } + + public function fileData() + { + return [ + 'handler' => $this->handler, + 'expires_at' => $this->expiry->timestamp, + 'data' => $this->data->all(), + ]; + } +} diff --git a/src/Tokens/FileTokenRepository.php b/src/Tokens/FileTokenRepository.php new file mode 100644 index 0000000000..95d0d36357 --- /dev/null +++ b/src/Tokens/FileTokenRepository.php @@ -0,0 +1,67 @@ +makeWith(TokenContract::class, compact('token', 'handler', 'data')); + } + + public function find(string $token): ?TokenContract + { + $path = storage_path('statamic/tokens/'.$token.'.yaml'); + + if (! File::exists($path)) { + return null; + } + + return $this->makeFromPath($path); + } + + public function save(TokenContract $token): bool + { + File::put(storage_path('statamic/tokens/'.$token->token().'.yaml'), $token->fileContents()); + + return true; + } + + public function delete(TokenContract $token): bool + { + File::delete(storage_path('statamic/tokens/'.$token->token().'.yaml')); + + return true; + } + + public function collectGarbage(): void + { + File::getFilesByType(storage_path('statamic/tokens'), 'yaml') + ->map(fn ($path) => $this->makeFromPath($path)) + ->filter->hasExpired() + ->each->delete(); + } + + private function makeFromPath(string $path): FileToken + { + $yaml = YAML::file($path)->parse(); + + $token = basename($path, '.yaml'); + + return $this + ->make($token, $yaml['handler'], $yaml['data'] ?? []) + ->expireAt(Carbon::createFromTimestamp($yaml['expires_at'])); + } + + public static function bindings(): array + { + return [ + TokenContract::class => FileToken::class, + ]; + } +} diff --git a/src/Tokens/Token.php b/src/Tokens/Token.php index 5a403307f5..803a6faf00 100644 --- a/src/Tokens/Token.php +++ b/src/Tokens/Token.php @@ -2,23 +2,77 @@ namespace Statamic\Tokens; -use Statamic\Data\ExistsAsFile; +use Closure; +use Facades\Statamic\Tokens\Generator; +use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; +use Statamic\Contracts\Tokens\Token as Contract; +use Statamic\Facades\Token as Tokens; -class Token extends AbstractToken +abstract class Token implements Contract { - use ExistsAsFile; + protected $token; + protected $handler; + protected $data; + protected $expiry; - public function path() + public function __construct(?string $token, string $handler, array $data = []) { - return storage_path('statamic/tokens/'.$this->token().'.yaml'); + $this->token = $token ?? Generator::generate(); + $this->handler = $handler; + $this->data = collect($data); + $this->expiry = Carbon::now()->addHour(); } - public function fileData() + public function token(): string { - return [ - 'handler' => $this->handler, - 'expires_at' => $this->expiry->timestamp, - 'data' => $this->data->all(), - ]; + return $this->token; + } + + public function handler(): string + { + return $this->handler; + } + + public function data(): Collection + { + return $this->data; + } + + public function get(string $key) + { + return $this->data->get($key); + } + + public function save() + { + return Tokens::save($this); + } + + public function delete() + { + return Tokens::delete($this); + } + + public function handle($request, Closure $next) + { + return app($this->handler)->handle($this, $request, $next); + } + + public function expiry(): Carbon + { + return $this->expiry; + } + + public function expireAt(Carbon $expiry): self + { + $this->expiry = $expiry; + + return $this; + } + + public function hasExpired(): bool + { + return $this->expiry->isPast(); } } diff --git a/src/Tokens/TokenRepository.php b/src/Tokens/TokenRepository.php index da65bb9935..982174d02e 100644 --- a/src/Tokens/TokenRepository.php +++ b/src/Tokens/TokenRepository.php @@ -2,67 +2,15 @@ namespace Statamic\Tokens; -use Illuminate\Support\Carbon; use Statamic\Contracts\Tokens\Token as TokenContract; use Statamic\Contracts\Tokens\TokenRepository as Contract; -use Statamic\Facades\File; -use Statamic\Facades\YAML; -class TokenRepository implements Contract +abstract class TokenRepository implements Contract { public function make(?string $token, string $handler, array $data = []): TokenContract { return app()->makeWith(TokenContract::class, compact('token', 'handler', 'data')); } - public function find(string $token): ?TokenContract - { - $path = storage_path('statamic/tokens/'.$token.'.yaml'); - - if (! File::exists($path)) { - return null; - } - - return $this->makeFromPath($path); - } - - public function save(TokenContract $token): bool - { - File::put(storage_path('statamic/tokens/'.$token->token().'.yaml'), $token->fileContents()); - - return true; - } - - public function delete(TokenContract $token): bool - { - File::delete(storage_path('statamic/tokens/'.$token->token().'.yaml')); - - return true; - } - - public function collectGarbage(): void - { - File::getFilesByType(storage_path('statamic/tokens'), 'yaml') - ->map(fn ($path) => $this->makeFromPath($path)) - ->filter->hasExpired() - ->each->delete(); - } - - private function makeFromPath(string $path): Token - { - $yaml = YAML::file($path)->parse(); - - $token = basename($path, '.yaml'); - - return $this - ->make($token, $yaml['handler'], $yaml['data'] ?? []) - ->expireAt(Carbon::createFromTimestamp($yaml['expires_at'])); - } - - public static function bindings(): array - { - return [ - TokenContract::class => Token::class, - ]; - } + abstract public static function bindings(): array; } diff --git a/tests/Tokens/TokenRepositoryTest.php b/tests/Tokens/TokenRepositoryTest.php index 8d11a98158..35adf65fb5 100644 --- a/tests/Tokens/TokenRepositoryTest.php +++ b/tests/Tokens/TokenRepositoryTest.php @@ -7,7 +7,7 @@ use Illuminate\Support\Collection; use Statamic\Contracts\Tokens\Token; use Statamic\Facades\File; -use Statamic\Tokens\TokenRepository; +use Statamic\Tokens\FileTokenRepository; use Tests\TestCase; class TokenRepositoryTest extends TestCase @@ -18,7 +18,7 @@ public function setUp(): void { parent::setUp(); - $this->tokens = new TokenRepository; + $this->tokens = new FileTokenRepository; } /** @test */ diff --git a/tests/Tokens/TokenTest.php b/tests/Tokens/TokenTest.php index f56eac71c0..cecda739c8 100644 --- a/tests/Tokens/TokenTest.php +++ b/tests/Tokens/TokenTest.php @@ -5,7 +5,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Statamic\Facades; -use Statamic\Tokens\Token; +use Statamic\Tokens\FileToken as Token; use Tests\TestCase; class TokenTest extends TestCase