Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLA-136] Add idempotencyKey to ClaimBeam Mutation #66

Merged
merged 1 commit into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class () extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('beam_claims', function (Blueprint $table) {
$table->string('idempotency_key', 255)->nullable()->unique();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('beam_claims', function (Blueprint $table) {
$table->dropColumn('idempotency_key');
});
}
};
1 change: 1 addition & 0 deletions src/BeamServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public function configurePackage(Package $package): void
->hasMigration('create_beam_scans_table')
->hasMigration('update_beams_table')
->hasMigration('add_collection_chain_id_to_beam_batches_table')
->hasMigration('add_idempotency_key_to_beam_claims_table')
->hasRoute('enjin-platform-beam')
->hasTranslations();
}
Expand Down
13 changes: 12 additions & 1 deletion src/GraphQL/Mutations/ClaimBeamMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Closure;
use Enjin\Platform\Beam\GraphQL\Traits\HasBeamClaimConditions;
use Enjin\Platform\Beam\GraphQL\Traits\HasBeamCommonFields;
use Enjin\Platform\Beam\Models\BeamClaim;
use Enjin\Platform\Beam\Rules\CanClaim;
use Enjin\Platform\Beam\Rules\NotExpired;
use Enjin\Platform\Beam\Rules\NotOwner;
Expand All @@ -13,17 +14,20 @@
use Enjin\Platform\Beam\Rules\VerifySignedMessage;
use Enjin\Platform\Beam\Services\BeamService;
use Enjin\Platform\Enums\Substrate\CryptoSignatureType;
use Enjin\Platform\GraphQL\Types\Input\Substrate\Traits\HasIdempotencyField;
use Enjin\Platform\Interfaces\PlatformPublicGraphQlOperation;
use Enjin\Platform\Rules\ValidSubstrateAccount;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Rebing\GraphQL\Support\Facades\GraphQL;

class ClaimBeamMutation extends Mutation implements PlatformPublicGraphQlOperation
{
use HasBeamCommonFields;
use HasBeamClaimConditions;
use HasIdempotencyField;

/**
* Get the mutation's attributes.
Expand Down Expand Up @@ -67,6 +71,7 @@ public function args(): array
'description' => __('enjin-platform-beam::mutation.claim_beam.args.cryptoSignatureType'),
'defaultValue' => CryptoSignatureType::SR25519->name,
],
...$this->getIdempotencyField(),
];
}

Expand All @@ -81,9 +86,15 @@ public function resolve(
Closure $getSelectFields,
BeamService $beam
) {
$idempotencyKey = Arr::get($args, 'idempotencyKey');
if ($idempotencyKey && BeamClaim::where('idempotency_key', $idempotencyKey)->exists()) {
return true;
}

return DB::transaction(fn () => $beam->claim(
$args['code'],
$args['account']
$args['account'],
$idempotencyKey,
));
}

Expand Down
5 changes: 5 additions & 0 deletions src/GraphQL/Types/BeamClaimType.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ public function fields(): array
'description' => __('enjin-platform::type.transaction.description'),
'is_relation' => true,
],
'idempotencyKey' => [
'type' => GraphQL::type('String'),
'description' => __('enjin-platform::type.transaction.field.idempotencyKey'),
'alias' => 'idempotency_key',
],
];
}
}
8 changes: 7 additions & 1 deletion src/Jobs/ClaimBeam.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,13 @@ protected function buildBeamClaimAttributes(BatchService $batchService, Model $c
protected function buildRequiredClaimAttributes(BatchService $batchService, Model $claim): array
{
return [
...Arr::only($this->data, ['wallet_public_key', 'claimed_at', 'state', 'ip_address']),
...Arr::only($this->data, [
'wallet_public_key',
'claimed_at',
'state',
'ip_address',
'idempotency_key',
]),
'beam_batch_id' => $batchService->getNextBatchId(
BeamType::getEnumCase($claim->type),
$claim->beam->collection_chain_id
Expand Down
1 change: 1 addition & 0 deletions src/Models/Laravel/BeamClaim.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class BeamClaim extends BaseModel
'ip_address',
'code',
'nonce',
'idempotency_key',
];

/**
Expand Down
24 changes: 16 additions & 8 deletions src/Services/BeamService.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public function scanByCode(string $code, ?string $wallet = null): Model|null
/**
* Claim a beam.
*/
public function claim(string $code, string $wallet): bool
public function claim(string $code, string $wallet, ?string $idempotencyKey = null): bool
{
$singleUseCode = null;
$singleUse = static::isSingleUse($code);
Expand Down Expand Up @@ -211,7 +211,7 @@ public function claim(string $code, string $wallet): bool
throw new BeamException(__('enjin-platform-beam::error.no_more_claims'));
}

ClaimBeam::dispatch($claim = $this->buildClaimBeamData($wallet, $beam, $singleUseCode));
ClaimBeam::dispatch($claim = $this->buildClaimBeamData($wallet, $beam, $singleUseCode, $idempotencyKey));
event(new BeamClaimPending($claim));
Cache::decrement($key);
Log::info("Claim beam: {$code}, Remaining: " . Cache::get($key), $claim);
Expand Down Expand Up @@ -428,19 +428,27 @@ protected function createClaims(array $tokens, Model $beam): int
/**
* Build claim payload.
*/
protected function buildClaimBeamData(string $wallet, Model $beam, ?string $singleUseCode = null): array
{
protected function buildClaimBeamData(
string $wallet,
Model $beam,
?string $singleUseCode = null,
?string $idempotencyKey = null
): array {
return array_merge(
$this->buildRequiredClaimBeamData($wallet, $beam, $singleUseCode),
$this->buildRequiredClaimBeamData($wallet, $beam, $singleUseCode, $idempotencyKey),
['extras' => $this->buildExtrasClaimBeamData($wallet, $beam)]
);
}

/**
* Build claim default data.
*/
protected function buildRequiredClaimBeamData(string $wallet, Model $beam, ?string $singleUseCode = null): array
{
protected function buildRequiredClaimBeamData(
string $wallet,
Model $beam,
?string $singleUseCode = null,
?string $idempotencyKey = null
): array {
return [
'wallet_public_key' => SS58Address::getPublicKey($wallet),
'claimed_at' => now(),
Expand All @@ -449,7 +457,7 @@ protected function buildRequiredClaimBeamData(string $wallet, Model $beam, ?stri
'beam_id' => $beam->id,
'ip_address' => request()->getClientIp(),
'code' => $singleUseCode,
'idempotency_key' => Str::uuid()->toString(),
'idempotency_key' => $idempotencyKey ?: Str::uuid()->toString(),
];
}

Expand Down
23 changes: 23 additions & 0 deletions tests/Feature/GraphQL/Mutations/ClaimBeamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
use Enjin\Platform\Beam\Jobs\ClaimBeam;
use Enjin\Platform\Beam\Models\BeamClaim;
use Enjin\Platform\Beam\Rules\PassesClaimConditions;
use Enjin\Platform\Beam\Services\BatchService;
use Enjin\Platform\Beam\Tests\Feature\GraphQL\TestCaseGraphQL;
use Enjin\Platform\Beam\Tests\Feature\Traits\CreateBeamData;
use Enjin\Platform\Beam\Tests\Feature\Traits\SeedBeamData;
use Enjin\Platform\Enums\Substrate\CryptoSignatureType;
use Enjin\Platform\Providers\Faker\SubstrateProvider;
use Enjin\Platform\Services\Database\WalletService;
use Enjin\Platform\Support\Account;
use Enjin\Platform\Support\SS58Address;
use Illuminate\Support\Arr;
Expand Down Expand Up @@ -104,6 +106,27 @@ public function test_it_can_claim_beam_with_ed25519(): void
$this->genericClaimTest(CryptoSignatureType::ED25519);
}

public function test_it_can_claim_beam_job_with_idempotency_key(): void
{
$data = [
'wallet_public_key' => $this->wallet->public_key,
'claimed_at' => Carbon::now()->toDateTimeString(),
'state' => 'PENDING',
'ip_address' => fake()->ipv4(),
'idempotency_key' => $uuid = fake()->uuid(),
'beam' => $this->beam->toArray(),
'beam_id' => $this->beam->id,
'code' => '',
];

(new ClaimBeam($data))->handle(
resolve(BatchService::class),
resolve(WalletService::class)
);

$this->assertTrue(BeamClaim::where('idempotency_key', $uuid)->exists());
}

/**
* Test it can remove a condition from the rule.
*/
Expand Down
1 change: 1 addition & 0 deletions tests/Feature/GraphQL/Resources/GetClaims.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ query GetClaims(
claimStatus
quantity
identifierCode
idempotencyKey
attributes {
key
value
Expand Down
1 change: 1 addition & 0 deletions tests/Feature/GraphQL/Resources/GetPendingClaims.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ query GetPendingClaims(
claimStatus
quantity
identifierCode
idempotencyKey
attributes {
key
value
Expand Down
Loading