Skip to content

Commit fad5464

Browse files
committed
fix: review feedback
Signed-off-by: romanetar <roman_ag@hotmail.com>
1 parent a3459ad commit fad5464

3 files changed

Lines changed: 44 additions & 16 deletions

File tree

app/Models/Foundation/Main/Member.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,20 +2014,6 @@ public function addSummitRegistrationOrder(SummitOrder $summit_order)
20142014
$summit_order->setOwner($this);
20152015
}
20162016

2017-
/**
2018-
* @param Summit $summit
2019-
* @param int $sponsor_id
2020-
* @return Sponsor|null
2021-
*/
2022-
public function getSponsorBySummitAndId(Summit $summit, int $sponsor_id): ?Sponsor
2023-
{
2024-
$sponsor = $this->sponsor_memberships->filter(function ($entity) use ($summit, $sponsor_id) {
2025-
return $entity->getSummitId() == $summit->getId() && $entity->getId() == $sponsor_id;
2026-
})->first();
2027-
2028-
return $sponsor === false ? null : $sponsor;
2029-
}
2030-
20312017
/**
20322018
* @return string|null
20332019
*/

app/Services/Model/Imp/SponsorUserSyncService.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
use App\Services\Model\AbstractService;
1616
use App\Services\Model\ISponsorUserSyncService;
1717
use Illuminate\Support\Facades\Log;
18+
use LaravelDoctrine\ORM\Facades\Registry;
1819
use libs\utils\ITransactionService;
1920
use models\exceptions\EntityNotFoundException;
2021
use models\main\IGroupRepository;
2122
use models\main\IMemberRepository;
2223
use models\summit\ISummitRepository;
2324
use models\summit\Summit;
25+
use models\utils\SilverstripeBaseModel;
2426
use services\model\ISummitSponsorService;
2527

2628
/**
@@ -168,8 +170,18 @@ public function addSponsorUserToGroup(int $user_id, string $group_slug, int $spo
168170

169171
$this->summit_sponsor_service->addSponsorUser($summit, $sponsor_id, $member->getId());
170172

173+
// Flush the UoW so the INSERT is visible to the raw SQL retry
174+
// on the same connection within the active transaction.
175+
Registry::getManager(SilverstripeBaseModel::EntityManager)->flush();
176+
171177
// Retry now that the row exists.
172-
$member->addSponsorPermission($sponsor_id, $group_slug);
178+
$retryResult = $member->addSponsorPermission($sponsor_id, $group_slug);
179+
if ($retryResult === 0) {
180+
throw new \RuntimeException(
181+
"Failed to write permission after eager Sponsor_Users creation " .
182+
"for member {$member->getId()} / sponsor {$sponsor_id}"
183+
);
184+
}
173185
}
174186

175187
// Add to global group only if not already a member.
@@ -217,4 +229,4 @@ public function removeSponsorUserFromGroup(int $user_id, string $group_slug, int
217229
}
218230
});
219231
}
220-
}
232+
}

tests/Unit/Services/SponsorUserPermissionTrackingTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ private function getPermissions(int $sponsor_id, int $member_id): array
9393
// addSponsorUserToGroup
9494
// -------------------------------------------------------------------------
9595

96+
/**
97+
* MQ race: the group event arrives before the membership event, so there is
98+
* no Sponsor_Users row yet when addSponsorUserToGroup is called.
99+
* The service must create the row eagerly, flush the UoW so the INSERT is
100+
* visible to the raw SQL retry, and then successfully write the permission.
101+
*/
102+
public function testAddSponsorUserToGroupEagerlyCreatesRowAndWritesPermissionOnRetry(): void
103+
{
104+
// sponsors[1] has no Sponsor_Users row — the member is not yet a user
105+
// of this sponsor, simulating the race condition.
106+
$sponsor_id = self::$sponsors[1]->getId();
107+
$member_id = self::$member->getId();
108+
$external_id = self::$member->getUserExternalId();
109+
$summit_id = self::$summit->getId();
110+
111+
$conn = self::$em->getConnection();
112+
113+
// Confirm no row exists before the call.
114+
$exists = $conn->executeQuery(
115+
'SELECT COUNT(*) FROM Sponsor_Users WHERE SponsorID = ? AND MemberID = ?',
116+
[$sponsor_id, $member_id]
117+
)->fetchOne();
118+
$this->assertEquals(0, (int)$exists, 'Pre-condition: no Sponsor_Users row should exist');
119+
120+
$this->getService()->addSponsorUserToGroup($external_id, IGroup::Sponsors, $sponsor_id, $summit_id);
121+
122+
// The row must have been created and the permission written.
123+
$this->assertContains(IGroup::Sponsors, $this->getPermissions($sponsor_id, $member_id));
124+
}
125+
96126
/**
97127
* The group slug must be written into the Sponsor_Users.Permissions JSON
98128
* column for the correct (SponsorID, MemberID) row.

0 commit comments

Comments
 (0)