Fix member resync
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
de7ee9cda2
commit
211f93ec17
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Initialize\Actions;
|
||||
|
||||
use App\Actions\InsertCoursesAction;
|
||||
use App\Actions\InsertMemberAction;
|
||||
use App\Actions\InsertMembershipsAction;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Zoomyboy\LaravelNami\Data\Course as NamiCourse;
|
||||
use Zoomyboy\LaravelNami\Data\Member as NamiMember;
|
||||
use Zoomyboy\LaravelNami\Data\MembershipEntry as NamiMembershipEntry;
|
||||
|
||||
class ProcessRedisAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'single';
|
||||
|
||||
/**
|
||||
* @param array{member: array<string, mixed>, memberships: array<string, mixed>, courses: array<string, mixed>} $data
|
||||
*/
|
||||
public function handle(array $data): void
|
||||
{
|
||||
$localMember = InsertMemberAction::run(NamiMember::from($data['member']));
|
||||
InsertMembershipsAction::run(
|
||||
$localMember,
|
||||
collect($data['memberships'])->map(fn ($membership) => NamiMembershipEntry::from($membership)),
|
||||
);
|
||||
InsertCoursesAction::run(
|
||||
$localMember,
|
||||
collect($data['courses'])->map(fn ($course) => NamiCourse::from($course)),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
namespace App\Initialize;
|
||||
|
||||
use App\Initialize\Actions\ProcessRedisAction;
|
||||
use App\Nami\Api\CompleteMemberToRedisJob;
|
||||
use App\Member\Actions\InsertFullMemberAction;
|
||||
use App\Member\Data\FullMember;
|
||||
use App\Nami\Api\FullMemberAction;
|
||||
use App\Setting\NamiSettings;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
@ -23,13 +24,16 @@ class InitializeMembers
|
|||
Redis::delete('members');
|
||||
|
||||
$jobs = $api->search([])->map(function (NamiMemberEntry $member) use ($api) {
|
||||
return new CompleteMemberToRedisJob($api, $member->groupId, $member->id);
|
||||
return FullMemberAction::makeJob($api, $member->groupId, $member->id, 'members');
|
||||
})->toArray();
|
||||
|
||||
Bus::batch($jobs)
|
||||
->finally(function () {
|
||||
foreach (Redis::lrange('members', 0, -1) as $data) {
|
||||
ProcessRedisAction::dispatch(json_decode($data, true));
|
||||
/** @var array<int, FullMember> */
|
||||
$members = array_map(fn ($member) => FullMember::from(json_decode($member, true)), Redis::lrange('members', 0, -1));
|
||||
|
||||
foreach ($members as $data) {
|
||||
InsertFullMemberAction::dispatch($data);
|
||||
}
|
||||
})
|
||||
->onQueue('long')
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Member\Actions;
|
||||
|
||||
use App\Actions\InsertCoursesAction;
|
||||
use App\Actions\InsertMemberAction;
|
||||
use App\Actions\InsertMembershipsAction;
|
||||
use App\Member\Data\FullMember;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class InsertFullMemberAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public string $jobQueue = 'single';
|
||||
|
||||
public function handle(FullMember $member): void
|
||||
{
|
||||
$localMember = InsertMemberAction::run($member->member);
|
||||
InsertMembershipsAction::run($localMember, $member->memberships->toCollection());
|
||||
InsertCoursesAction::run($localMember, $member->courses->toCollection());
|
||||
}
|
||||
}
|
|
@ -2,15 +2,13 @@
|
|||
|
||||
namespace App\Member\Actions;
|
||||
|
||||
use App\Actions\PullMemberAction;
|
||||
use App\Actions\PullMembershipsAction;
|
||||
use App\Member\Member;
|
||||
use App\Nami\Api\FullMemberAction;
|
||||
use App\Setting\NamiSettings;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Zoomyboy\LaravelNami\Exceptions\Skippable;
|
||||
|
||||
class MemberResyncAction
|
||||
{
|
||||
|
@ -24,13 +22,9 @@ class MemberResyncAction
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$localMember = app(PullMemberAction::class)->handle($member->group->nami_id, $member->nami_id);
|
||||
} catch (Skippable $e) {
|
||||
return;
|
||||
}
|
||||
$fullMember = FullMemberAction::run($api, $member->group->nami_id, $member->nami_id);
|
||||
|
||||
app(PullMembershipsAction::class)->handle($localMember);
|
||||
InsertFullMemberAction::dispatch($fullMember);
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request, Member $member): RedirectResponse|Response
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Member\Data;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
use Zoomyboy\LaravelNami\Data\Course as NamiCourse;
|
||||
use Zoomyboy\LaravelNami\Data\Member as NamiMember;
|
||||
use Zoomyboy\LaravelNami\Data\MembershipEntry as NamiMembershipEntry;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
|
||||
class FullMember extends Data {
|
||||
/**
|
||||
* @param DataCollection<int, NamiCourse> $courses
|
||||
* @param DataCollection<int, NamiMembershipEntry> $memberships
|
||||
*/
|
||||
public function __construct(
|
||||
public NamiMember $member,
|
||||
#[DataCollectionOf(NamiCourse::class)]
|
||||
public DataCollection $courses,
|
||||
#[DataCollectionOf(NamiMembershipEntry::class)]
|
||||
public DataCollection $memberships,
|
||||
) {}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Nami\Api;
|
||||
|
||||
use Illuminate\Bus\Batchable;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Zoomyboy\LaravelNami\Api;
|
||||
|
||||
class CompleteMemberToRedisJob implements ShouldQueue
|
||||
{
|
||||
use Batchable;
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
private Api $api,
|
||||
private int $groupId,
|
||||
private int $memberId,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
if ($this->batch()->cancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Redis::rpush('members', collect([
|
||||
'member' => MemberAction::run($this->api, $this->groupId, $this->memberId),
|
||||
'memberships' => MembershipsOfAction::run($this->api, $this->memberId),
|
||||
'courses' => CoursesOfAction::run($this->api, $this->memberId),
|
||||
])->toJson());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Nami\Api;
|
||||
|
||||
use App\Member\Data\FullMember;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Zoomyboy\LaravelNami\Api;
|
||||
|
||||
class FullMemberAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(Api $api, int $groupId, int $memberId, ?string $redisKey = null): FullMember
|
||||
{
|
||||
$fullMember = FullMember::from([
|
||||
'member' => MemberAction::run($api, $groupId, $memberId),
|
||||
'memberships' => MembershipsOfAction::run($api, $memberId),
|
||||
'courses' => CoursesOfAction::run($api, $memberId),
|
||||
]);
|
||||
|
||||
if (!$redisKey) {
|
||||
return $fullMember;
|
||||
}
|
||||
|
||||
Redis::rpush($redisKey, $fullMember->toJson());
|
||||
|
||||
return $fullMember;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\LazyCollection\\<int,Zoomyboy\\\\LaravelNami\\\\Data\\\\MemberEntry\\>\\:\\:each\\(\\) expects callable\\(int, int\\)\\: mixed, Closure\\(Zoomyboy\\\\LaravelNami\\\\Data\\\\MemberEntry\\)\\: void given\\.$#"
|
||||
count: 1
|
||||
path: app/Initialize/InitializeMembers.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:never\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Initialize/InitializeActionTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:with\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Initialize/InitializeActionTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:once\\(\\)\\.$#"
|
||||
count: 10
|
||||
path: tests/Feature/Initialize/InitializeMembersTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$mock of static method Phake\\:\\:verify\\(\\) expects Phake\\\\IMock, App\\\\Actions\\\\PullMemberAction given\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/NamiPutMemberActionTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$mock of static method Phake\\:\\:verify\\(\\) expects Phake\\\\IMock, App\\\\Actions\\\\PullMembershipsAction given\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/NamiPutMemberActionTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:never\\(\\)\\.$#"
|
||||
count: 4
|
||||
path: tests/Feature/Member/ResyncTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:once\\(\\)\\.$#"
|
||||
count: 2
|
||||
path: tests/Feature/Member/ResyncTest.php
|
35
phpstan.neon
35
phpstan.neon
|
@ -599,13 +599,38 @@ parameters:
|
|||
count: 1
|
||||
path: tests/Feature/Member/NamiPutMemberActionTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:never\\(\\)\\.$#"
|
||||
count: 4
|
||||
path: tests/Feature/Member/ResyncTest.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Mockery\\\\ExpectationInterface\\|Mockery\\\\HigherOrderMessage\\:\\:once\\(\\)\\.$#"
|
||||
count: 2
|
||||
path: tests/Feature/Member/ResyncTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Region\\:\\:forSelect\\(\\) should return Illuminate\\\\Support\\\\Collection\\<int, array\\{id\\: int, name\\: string\\}\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Collection\\<int, App\\\\Region\\>\\.$#"
|
||||
count: 1
|
||||
path: app/Region.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Sabre\\\\VObject\\\\Component\\\\VCard\\:\\:\\$BDAY\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/DavTest.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Sabre\\\\VObject\\\\Component\\\\VCard\\:\\:\\$FN\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/DavTest.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Sabre\\\\VObject\\\\Component\\\\VCard\\:\\:\\$N\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/DavTest.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Sabre\\\\VObject\\\\Component\\\\VCard\\:\\:\\$TEL\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/DavTest.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Sabre\\\\VObject\\\\Component\\\\VCard\\:\\:\\$UID\\.$#"
|
||||
count: 1
|
||||
path: tests/Feature/Member/DavTest.php
|
||||
|
||||
|
|
|
@ -2,42 +2,35 @@
|
|||
|
||||
namespace Tests\Feature\Member;
|
||||
|
||||
use App\Actions\PullCoursesAction;
|
||||
use App\Actions\PullMemberAction;
|
||||
use App\Actions\PullMembershipsAction;
|
||||
use App\Group;
|
||||
use App\Member\Actions\InsertFullMemberAction;
|
||||
use App\Member\Data\FullMember;
|
||||
use App\Member\Member;
|
||||
use App\Nami\Api\FullMemberAction;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
use Zoomyboy\LaravelNami\Api;
|
||||
use Zoomyboy\LaravelNami\Fakes\MemberFake;
|
||||
|
||||
class ResyncTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
private Api $api;
|
||||
|
||||
public function testItCanResyncAMember(): void
|
||||
{
|
||||
$this->api = $this->createStub(Api::class);
|
||||
$this->login()->loginNami();
|
||||
app(MemberFake::class)->shows(32, 33);
|
||||
$fullMember = FullMember::from(['courses' => [], 'memberships' => [], 'member' => $this->api->member(32, 33)]);
|
||||
FullMemberAction::shouldRun()->once()->andReturn($fullMember);
|
||||
InsertFullMemberAction::shouldRun()->once();
|
||||
$member = Member::factory()->defaults()->for(Group::factory()->inNami(32))->inNami(33)->create();
|
||||
PullMemberAction::shouldRun()->once()->with(32, 33)->andReturn($member);
|
||||
PullMembershipsAction::shouldRun()->once()->with($member);
|
||||
PullCoursesAction::shouldRun()->never();
|
||||
|
||||
$response = $this->from('/member')->get(route('member.resync', ['member' => $member]));
|
||||
|
||||
$response->assertRedirect('/member');
|
||||
}
|
||||
|
||||
public function testItReturnsErrorWhenMemberIsNotInNami(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
$member = Member::factory()->defaults()->create();
|
||||
|
||||
PullMemberAction::shouldRun()->never();
|
||||
PullMembershipsAction::shouldRun()->never();
|
||||
PullCoursesAction::shouldRun()->never();
|
||||
|
||||
$response = $this->from('/member')->get(route('member.resync', ['member' => $member]));
|
||||
|
||||
$response->assertRedirect('/member');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue