feat(doctor): claim captcha+mobile, owner profile delete, admin map zoom fix
- DoctorClaimController: ALTCHA CaptchaGuard on /claim (dev no-op via ALTCHA_ENABLED=false); optional `mobile` field must match the logged-in user's number (422 ERR_CONFLICT_001 on mismatch) - DoctorController::delete: now IS_AUTHENTICATED_FULLY — admin (any) or the owner of a claimed profile (IDOR-guarded); FK appointment guard kept - DoctorDetailPage address map: MapController calls map.invalidateSize() before flyTo (fixes needing to pick a city twice on a freshly-mounted map); geocode retries once (nominatim empty/429 on first hit) - tests: mobile mismatch, owner-delete allowed + others 403, unclaimed not deletable by random user - docs: doctor-claim.md (mobile+captcha), doctor.md (delete permission) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,47 @@ class DoctorClaimTest extends ApiTestCase
|
||||
$this->assertSame(422, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testMobileMismatchIsRejected(): void
|
||||
{
|
||||
$uuid = $this->importUnclaimedDoctor();
|
||||
$this->mockApiIr();
|
||||
$claimer = $this->createUser(['ROLE_USER']);
|
||||
|
||||
$body = $this->claimBody();
|
||||
$body['mobile'] = '09990000000'; // متفاوت با موبایل کاربر
|
||||
$this->authJson('POST', "/api/v1/doctor/{$uuid}/claim", $claimer, $body);
|
||||
$this->assertSame(422, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testOwnerCanDeleteOwnProfileButOthersCannot(): void
|
||||
{
|
||||
$uuid = $this->importUnclaimedDoctor();
|
||||
$this->mockApiIr();
|
||||
$claimer = $this->createUser(['ROLE_USER']);
|
||||
$this->authJson('POST', "/api/v1/doctor/{$uuid}/claim", $claimer, $this->claimBody());
|
||||
$this->assertSame(200, $this->responseCode());
|
||||
|
||||
// کاربر دیگر → 403
|
||||
$other = $this->createUser(['ROLE_USER']);
|
||||
$this->authJson('DELETE', "/api/v1/doctor/{$uuid}", $other);
|
||||
$this->assertSame(403, $this->responseCode());
|
||||
|
||||
// مالک → 200
|
||||
$this->authJson('DELETE', "/api/v1/doctor/{$uuid}", $claimer);
|
||||
$this->assertSame(200, $this->responseCode());
|
||||
|
||||
$this->em->clear();
|
||||
$this->assertNull($this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $uuid]));
|
||||
}
|
||||
|
||||
public function testUnclaimedProfileNotDeletableByRandomUser(): void
|
||||
{
|
||||
$uuid = $this->importUnclaimedDoctor();
|
||||
$user = $this->createUser(['ROLE_USER']);
|
||||
$this->authJson('DELETE', "/api/v1/doctor/{$uuid}", $user);
|
||||
$this->assertSame(403, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testClaimInfoIsPublic(): void
|
||||
{
|
||||
$uuid = $this->importUnclaimedDoctor();
|
||||
|
||||
Reference in New Issue
Block a user