feat: claim approval/rejection API endpoints

POST /v1/names/claims/{id}/approve — changes status, logs activity.
POST /v1/names/claims/{id}/reject — changes status, logs activity.
Both require auth.api middleware. Validates claim exists and is pending.
Completes the claim lifecycle: submit → review → approve/reject.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude 2026-04-04 12:07:38 +01:00
parent 1ef6ed1c7b
commit 3f82c497fd
No known key found for this signature in database
GPG key ID: AF404715446AEB41
2 changed files with 59 additions and 0 deletions

View file

@ -525,6 +525,63 @@ class NamesController extends Controller
* Matches daemon's validate_alias_name: a-z, 0-9, dash, dot. Max 255 chars.
* We additionally require at least 1 char (daemon allows empty but we don't).
*/
/**
* POST /v1/names/claims/{id}/approve
*/
public function approveClaim(string $id): JsonResponse
{
$claim = NameClaim::where('claim_id', $id)->first();
if (! $claim) {
return response()->json(['error' => 'Claim not found'], 404);
}
if ($claim->status !== 'pending') {
return response()->json(['error' => "Claim already {$claim->status}"], 409);
}
$claim->approve();
Models\NameActivity::log($claim->name, 'claim_approved', [
'claim_id' => $claim->claim_id,
'email' => $claim->email,
]);
return response()->json([
'claim_id' => $claim->claim_id,
'name' => $claim->name,
'status' => 'approved',
]);
}
/**
* POST /v1/names/claims/{id}/reject
*/
public function rejectClaim(string $id): JsonResponse
{
$claim = NameClaim::where('claim_id', $id)->first();
if (! $claim) {
return response()->json(['error' => 'Claim not found'], 404);
}
if ($claim->status !== 'pending') {
return response()->json(['error' => "Claim already {$claim->status}"], 409);
}
$claim->reject();
Models\NameActivity::log($claim->name, 'claim_rejected', [
'claim_id' => $claim->claim_id,
]);
return response()->json([
'claim_id' => $claim->claim_id,
'name' => $claim->name,
'status' => 'rejected',
]);
}
private function isValidName(string $name): bool
{
return (bool) preg_match('/^[a-z0-9][a-z0-9.\-]{0,254}$/', $name);

View file

@ -22,3 +22,5 @@ Route::get('/sunrise/check/{name}', [NamesController::class, 'sunriseCheck']);
// Pre-registration claims (soft launch)
Route::post('/claim', [NamesController::class, 'claim'])->middleware('throttle:10,1');
Route::get('/claims', [NamesController::class, 'listClaims'])->middleware('auth.api');
Route::post('/claims/{id}/approve', [NamesController::class, 'approveClaim'])->middleware('auth.api');
Route::post('/claims/{id}/reject', [NamesController::class, 'rejectClaim'])->middleware('auth.api');