Skip to content

Commit

Permalink
Tokens support (#277)
Browse files Browse the repository at this point in the history
Co-authored-by: Ryan Mitchell <[email protected]>
Co-authored-by: Jason Varga <[email protected]>
  • Loading branch information
3 people authored May 2, 2024
1 parent b3b2d76 commit 0a08a75
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 1 deletion.
5 changes: 5 additions & 0 deletions config/eloquent-driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,9 @@
'driver' => 'file',
'model' => \Statamic\Eloquent\Taxonomies\TermModel::class,
],

'tokens' => [
'driver' => 'file',
'model' => \Statamic\Eloquent\Tokens\TokenModel::class,
],
];
25 changes: 25 additions & 0 deletions database/migrations/2024_03_07_100000_create_tokens_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Statamic\Eloquent\Database\BaseMigration as Migration;

return new class extends Migration
{
public function up()
{
Schema::create($this->prefix('tokens'), function (Blueprint $table) {
$table->id();
$table->string('token')->unique();
$table->string('handler');
$table->jsonb('data');
$table->timestamp('expire_at');
$table->timestamps();
});
}

public function down()
{
Schema::dropIfExists($this->prefix('tokens'));
}
};
23 changes: 22 additions & 1 deletion src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Statamic\Contracts\Structures\NavTreeRepository as NavTreeRepositoryContract;
use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract;
use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract;
use Statamic\Contracts\Tokens\TokenRepository as TokenRepositoryContract;
use Statamic\Eloquent\Assets\AssetContainerContents as EloquentAssetContainerContents;
use Statamic\Eloquent\Assets\AssetContainerRepository;
use Statamic\Eloquent\Assets\AssetQueryBuilder;
Expand All @@ -38,6 +39,7 @@
use Statamic\Eloquent\Taxonomies\TaxonomyRepository;
use Statamic\Eloquent\Taxonomies\TermQueryBuilder;
use Statamic\Eloquent\Taxonomies\TermRepository;
use Statamic\Eloquent\Tokens\TokenRepository;
use Statamic\Events\CollectionTreeSaved;
use Statamic\Providers\AddonServiceProvider;
use Statamic\Statamic;
Expand Down Expand Up @@ -158,6 +160,10 @@ private function publishMigrations(): void
__DIR__.'/../database/migrations/2024_03_07_100000_create_revisions_table.php' => database_path('migrations/2024_03_07_100000_create_revisions_table.php'),
], 'statamic-eloquent-revision-migrations');

$this->publishes($tokenMigrations = [
__DIR__.'/../database/migrations/2024_03_07_100000_create_tokens_table.php' => database_path('migrations/2024_03_07_100000_create_tokens_table.php'),
], 'statamic-eloquent-token-migrations');

$this->publishes(
array_merge(
$taxonomyMigrations,
Expand All @@ -172,7 +178,8 @@ private function publishMigrations(): void
$formSubmissionMigrations,
$assetContainerMigrations,
$assetMigrations,
$revisionMigrations
$revisionMigrations,
$tokenMigrations
),
'migrations'
);
Expand Down Expand Up @@ -203,6 +210,7 @@ public function register()
$this->registerStructureTrees();
$this->registerTaxonomies();
$this->registerTerms();
$this->registerTokens();
}

private function registerAssetContainers()
Expand Down Expand Up @@ -478,6 +486,19 @@ public function registerTerms()
Statamic::repository(TermRepositoryContract::class, TermRepository::class);
}

public function registerTokens()
{
if (config('statamic.eloquent-driver.tokens.driver', 'file') != 'eloquent') {
return;
}

$this->app->bind('statamic.eloquent.tokens.model', function () {
return config('statamic.eloquent-driver.tokens.model');
});

Statamic::repository(TokenRepositoryContract::class, TokenRepository::class);
}

protected function addAboutCommandInfo()
{
if (! class_exists(AboutCommand::class)) {
Expand Down
46 changes: 46 additions & 0 deletions src/Tokens/Token.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Statamic\Eloquent\Tokens;

use Illuminate\Database\Eloquent\Model;
use Statamic\Contracts\Tokens\Token as Contract;
use Statamic\Tokens\Token as AbstractToken;

class Token extends AbstractToken
{
protected $model;

public static function fromModel(Model $model)
{
return (new static($model->token, $model->handler, $model->data))
->expireAt($model->expire_at)
->model($model);
}

public function toModel()
{
return self::makeModelFromContract($this);
}

public static function makeModelFromContract(Contract $source)
{
$class = app('statamic.eloquent.tokens.model');

return $class::firstOrNew(['token' => $source->token()])->fill([
'handler' => $source->handler(),
'data' => $source->data(),
'expire_at' => $source->expiry(),
]);
}

public function model($model = null)
{
if (func_num_args() === 0) {
return $this->model;
}

$this->model = $model;

return $this;
}
}
17 changes: 17 additions & 0 deletions src/Tokens/TokenModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Statamic\Eloquent\Tokens;

use Statamic\Eloquent\Database\BaseModel;

class TokenModel extends BaseModel
{
protected $guarded = [];

protected $table = 'tokens';

protected $casts = [
'data' => 'json',
'expire_at' => 'datetime',
];
}
42 changes: 42 additions & 0 deletions src/Tokens/TokenRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Statamic\Eloquent\Tokens;

use Statamic\Contracts\Tokens\Token as TokenContract;
use Statamic\Tokens\TokenRepository as Repository;

class TokenRepository extends Repository
{
public function find(string $token): ?Token
{
$model = app('statamic.eloquent.tokens.model')::whereToken($token)->first();

if (! $model) {
return null;
}

return Token::fromModel($model);
}

public function save(TokenContract $token): bool
{
return $token->toModel()->save();
}

public function delete(TokenContract $token): bool
{
return $token->toModel()->delete();
}

public function collectGarbage(): void
{
app('statamic.eloquent.tokens.model')::where('expire_at', '<', now())->delete();
}

public static function bindings(): array
{
return [
TokenContract::class => Token::class,
];
}
}
50 changes: 50 additions & 0 deletions tests/Repositories/TokenRepositoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Tests\Repositories;

use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Statamic\Contracts\Tokens\Token;
use Statamic\Eloquent\Tokens\TokenRepository;
use Tests\TestCase;

class TokenRepositoryTest extends TestCase
{
use RefreshDatabase;

public function setUp(): void
{
parent::setUp();

$this->repo = new TokenRepository();

$this->repo->make('abc', 'ExampleHandler', ['foo' => 'bar'])->save();
}

/** @test */
public function it_gets_a_token()
{
tap($this->repo->find('abc'), function ($token) {
$this->assertInstanceOf(Token::class, $token);
$this->assertEquals('abc', $token->token());
$this->assertEquals('ExampleHandler', $token->handler());
$this->assertEquals(['foo' => 'bar'], $token->data()->all());
$this->assertInstanceOf(Carbon::class, $token->expiry());
});

$this->assertNull($this->repo->find('unknown'));
}

/** @test */
public function it_saves_a_token_to_the_database()
{
$token = $this->repo->make('new', 'ExampleHandler', ['foo' => 'bar']);

$this->assertNull($this->repo->find('new'));

$this->repo->save($token);

$this->assertNotNull($item = $this->repo->find('new'));
$this->assertEquals(['foo' => 'bar'], $item->data()->all());
}
}

0 comments on commit 0a08a75

Please sign in to comment.