Skip to content

Commit

Permalink
Add tests remove tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
enjinabner committed Jul 30, 2024
1 parent 32e6a50 commit d38c19b
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 32 deletions.
1 change: 1 addition & 0 deletions lang/en/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@
'can_use_on_beam_pack' => 'This mutation is not applicable to non-beam packs.',
'can_use_on_beam' => 'This mutation is not applicable to beam packs.',
'beam_pack_exist_in_beam' => 'The :attribute doesn\'t exist in beam.',
'tokens_exist_in_beam_pack' => 'The :attribute doesn\'t exist in beam pack.',
];
23 changes: 19 additions & 4 deletions src/GraphQL/Mutations/RemoveTokensBeamPackMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

use Closure;
use Enjin\Platform\Beam\Rules\BeamExists;
use Enjin\Platform\Beam\Rules\BeamPackExistInBeam;
use Enjin\Platform\Beam\Rules\CanUseOnBeamPack;
use Enjin\Platform\Beam\Rules\TokensExistInBeam;
use Enjin\Platform\Beam\Rules\TokensExistInBeamPack;
use Enjin\Platform\Beam\Services\BeamService;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
Expand Down Expand Up @@ -77,16 +78,30 @@ protected function rules(array $args = []): array
new BeamExists(),
new CanUseOnBeamPack(),
],
'tokenIds' => [
'packs' => [
'bail',
'required',
'array',
'min:1',
'max:1000',
],
'packs.*.id' => [
'filled',
'integer',
'distinct',
new BeamPackExistInBeam(),
],
'packs.*.tokenIds' => [
'array',
'min:1',
'max:1000',
'distinct',
],
'tokenIds.*' => [
'packs.*.tokenIds.*' => [
'bail',
'filled',
'distinct',
new TokensExistInBeam(),
new TokensExistInBeamPack(),
],
];
}
Expand Down
14 changes: 2 additions & 12 deletions src/Rules/BeamPackExistInBeam.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,9 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
return;
}

if (!Beam::whereHas('packs', fn ($query) => $query->where('id', $value))->exists()) {
$fail($this->message())->translate();
if (!Beam::where('code', $this->data['code'])->whereHas('packs', fn ($query) => $query->where('id', $value))->exists()) {
$fail('enjin-platform-beam::validation.beam_pack_exist_in_beam')->translate();
}

}

/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'enjin-platform-beam::validation.beam_pack_exist_in_beam';
}
}
62 changes: 62 additions & 0 deletions src/Rules/TokensExistInBeamPack.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Enjin\Platform\Beam\Rules;

use Closure;
use Enjin\Platform\Beam\Models\BeamClaim;
use Enjin\Platform\Beam\Rules\Traits\IntegerRange;
use Enjin\Platform\Rules\Traits\HasDataAwareRule;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Arr;

class TokensExistInBeamPack implements DataAwareRule, ValidationRule
{
use HasDataAwareRule;
use IntegerRange;

/**
* Determine if the validation rule passes.
*
* @param Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$parts = explode('.', $attribute);
$key = "packs.{$parts[1]}.id";
if ($id = Arr::get($this->data, $key)) {
[$integers, $ranges] = collect($value)->partition(fn ($val) => $this->integerRange($val) === false);
if (count($integers)) {
$count = BeamClaim::whereIn('token_chain_id', $integers)
->whereNull('claimed_at')
->where('beam_pack_id', $id)
->count();
if ($count != count($integers)) {
$fail($this->message())->translate();

return;
}
}
foreach ($ranges as $range) {
[$from, $to] = $this->integerRange($range);
$count = BeamClaim::whereBetween('token_chain_id', [(int) $from, (int) $to])
->whereNull('claimed_at')
->where('beam_pack_id', $id)
->count();
if ($count !== ($to - $from) + 1) {
$fail($this->message())->translate();
}
}
}
}

/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'enjin-platform-beam::validation.tokens_exist_in_beam_pack';
}
}
41 changes: 26 additions & 15 deletions src/Services/BeamService.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,38 +368,49 @@ public function deleteByCode(string $code): bool
public function removeBeamPack(string $code, array $packs): bool
{
$packCollection = collect($packs)->keyBy('id');
$beamPacks = BeamPack::whereHas('beam', fn ($query) => $query->where('code', $code))
->whereIn('id', $packCollection->pluck('id'))
->get(['id']);

$deletedTokens = 0;
$forDeletion = [];
foreach ($beamPacks as $pack) {
foreach ($packCollection as $pack) {
if (empty($pack['tokenIds'])) {
$forDeletion[] = $pack->id;
$forDeletion[] = $pack['id'];

continue;
}

$ranges = $this->integerRange($pack['tokenIds']);
$deletedTokens += BeamClaim::where('beam_pack_id', $pack->id)
->whereNull('claimed_at')
->when($ranges === false, fn ($query) => $query->whereIn('token_chain_id', $pack['tokenIds']))
->when($ranges !== false, fn ($query) => $query->whereBetween('token_chain_id', [(int) $ranges[0], (int) $ranges[1]]))
->delete();
[$tokenIds, $tokenIdRanges] = collect($pack['tokenIds'])->partition(fn ($val) => $this->integerRange($val) === false);
if ($tokenIds) {
$deletedTokens += BeamClaim::where('beam_pack_id', $pack['id'])
->whereNull('claimed_at')
->whereIn('token_chain_id', $tokenIds)
->delete();
}

if ($tokenIdRanges) {
$deletedTokens += BeamClaim::where('beam_pack_id', $pack['id'])
->whereNull('claimed_at')
->where(function ($query) use ($tokenIdRanges) {
$tokenIdRanges->each(function ($tokenString) use ($query) {
$ranges = $this->integerRange($tokenString);
$query->orWhereBetween('token_chain_id', [(int) $ranges[0], (int) $ranges[1]]);
});
})
->delete();
}
}

$beamPacks->loadCount('claims');
$forDeletion = array_merge($forDeletion, $beamPacks->where('claims_count', 0)->all());
$beamPacks = BeamPack::whereHas('beam', fn ($query) => $query->where('code', $code))
->whereIn('id', $packCollection->pluck('id'))
->withCount('claims')
->get(['id']);
$forDeletion = array_merge($forDeletion, $beamPacks->where('claims_count', 0)->pluck('id')->all());
if (count($forDeletion)) {
BeamPack::whereIn('id', $forDeletion)
->whereDoesntHave('claims', fn ($query) => $query->whereNotNull('claimed_at'))
->delete();
}

if ($deletedTokens) {
TokensRemoved::safeBroadcast(event: ['code' => $code, 'tokenIds' => $packCollection->pluck('tokenIds')->all()]);
TokensRemoved::safeBroadcast(event: ['code' => $code, 'tokenIds' => $packCollection->pluck('tokenIds')->flatten()->all()]);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function test_it_cannot_claim_expire_single_use_codes_beam_pack(): void

$response = $this->graphql('ClaimBeam', [
'code' => Arr::get($singleUseCodes, 'edges.0.node.code'),
'account' => app(Generator::class)->public_key()
'account' => app(Generator::class)->public_key(),
], true);

}
Expand Down
Loading

0 comments on commit d38c19b

Please sign in to comment.