Skip to content

Commit 8af8b08

Browse files
committed
feat(badges): augment validateBadge payload for attendee-networking connect resolve
Extend GET /summits/{id}/badge/{badge}/validate so attendee-networking-api can resolve a scanned badge to a connection identity (SDS D26 / ftn-docsnsklz #40): - add ticket.owner.id (keys the member-less pre-account request, D27) - expand the nested ticket.owner.member {id, first_name, last_name, pic} (member.id is the D15 identity; member is absent for member-less attendees) No auth change is needed: the auth.user middleware passes service tokens through (required-groups gate only user tokens), so a client-credentials service account holding the read scope already reaches the route. Tests (OAuth2SummitApiTest): the member case asserts the expanded member object; the member-less case (D27) asserts the member object is absent while attendee id + email are present. InsertSummitTestData gains a member-less attendee with a badge to cover it.
1 parent 988a6d3 commit 8af8b08

4 files changed

Lines changed: 79 additions & 13 deletions

File tree

.github/workflows/check-branch-name.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ jobs:
1212
run: |
1313
BRANCH_NAME="${{ github.head_ref }}"
1414
echo "Checking branch name: $BRANCH_NAME"
15-
if [[ ! "$BRANCH_NAME" =~ ^(chore|feature|fix|hotfix|patch|refactor)/[a-z0-9._-]+$ ]]; then
15+
if [[ ! "$BRANCH_NAME" =~ ^(chore|feat|feature|fix|hotfix|patch|refactor)/[a-z0-9._-]+$ ]]; then
1616
echo "❌ Invalid branch name: $BRANCH_NAME"
1717
echo "✅ Should match: feature/foo-bar, hotfix/issue-123, etc."
1818
exit 1
19-
fi
19+
fi

app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2554,18 +2554,23 @@ public function validateBadge($summit_id, $badge) {
25542554
return $this->ok(SerializerRegistry::getInstance()
25552555
->getSerializer($summitAttendeeBadge)
25562556
->serialize(
2557-
'features,ticket,ticket.owner,ticket.owner',
2557+
'features,ticket,ticket.owner,ticket.owner,ticket.owner.member',
25582558
[
25592559
'id',
25602560
'features.id',
25612561
'features.name',
25622562
'features.description',
25632563
'ticket.id',
25642564
'ticket.number',
2565+
'ticket.owner.id',
25652566
'ticket.owner.first_name',
25662567
'ticket.owner.last_name',
25672568
'ticket.owner.email',
25682569
'ticket.owner.company',
2570+
'ticket.owner.member.id',
2571+
'ticket.owner.member.first_name',
2572+
'ticket.owner.member.last_name',
2573+
'ticket.owner.member.pic',
25692574
]
25702575
)
25712576
);

tests/InsertSummitTestData.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,37 @@ protected static function insertSummitTestData(){
530530
$ticket->generateQRCode();
531531
$summitAttendeeBadge->generateQRCode();
532532
}
533+
534+
// Member-less attendee (SummitAttendee.member is null) with a badge, so the
535+
// validateBadge member-less path (D26/D27) has fixture coverage. Looked up in tests
536+
// via Summit::getAttendeeByEmailAndMemberNotSet('memberless@test.com').
537+
$memberless_attendee = new SummitAttendee();
538+
$memberless_attendee->setEmail("memberless@test.com");
539+
$memberless_attendee->setFirstName("No");
540+
$memberless_attendee->setSurname("Member");
541+
542+
$memberless_badge = new SummitAttendeeBadge();
543+
$memberless_badge->setType(self::$default_badge_type);
544+
545+
$memberless_order = new SummitOrder();
546+
$memberless_order->setOwner(self::$defaultMember);
547+
$memberless_order->setSummit(self::$summit);
548+
549+
$memberless_ticket = new SummitAttendeeTicket();
550+
$memberless_ticket->setTicketType(self::$default_ticket_type);
551+
$memberless_ticket->setBadge($memberless_badge);
552+
$memberless_ticket->activate();
553+
$memberless_attendee->addTicket($memberless_ticket);
554+
$memberless_order->addTicket($memberless_ticket);
555+
556+
self::$summit->addAttendee($memberless_attendee);
557+
self::$summit->addOrder($memberless_order);
558+
559+
$memberless_order->setPaid();
560+
$memberless_order->generateNumber();
561+
$memberless_ticket->generateNumber();
562+
$memberless_ticket->generateQRCode();
563+
$memberless_badge->generateQRCode();
533564
}
534565

535566
if (self::$defaultMember2 != null) {

tests/oauth2/OAuth2SummitApiTest.php

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,19 +1197,48 @@ public function testUpdateSummitRegSlugPrefixHavingPaidTickets(){
11971197
$this->assertStringContainsString('there are paid tickets', $content);
11981198
}
11991199

1200+
// #40 / D26 augmentation regression: the badge-resolve payload must expose the attendee id
1201+
// (keys the D27 pre-account request) plus the expanded nested member snapshot (the D15 identity
1202+
// + name/photo) for member-linked attendees, and must OMIT the member object for member-less
1203+
// ones. Locks the serializer whitelist so the networking-api connect resolve does not regress.
1204+
12001205
public function testValidateBadge(){
1206+
// MEMBER case: a member-linked attendee resolves with the expanded member object.
1207+
$owner = self::$summit->getAttendeeByMember(self::$defaultMember);
1208+
$this->assertNotNull($owner);
1209+
$member = $owner->getMember();
1210+
1211+
$attendee_badge = $this->callValidateBadge($owner->getFirstTicket()->getBadge());
1212+
1213+
// attendee id present (D27 keys the pre-account request on it)
1214+
$this->assertEquals($owner->getId(), $attendee_badge->ticket->owner->id);
1215+
1216+
// owner.member is the EXPANDED object carrying the D15 identity + name/photo snapshot
1217+
$this->assertNotNull($attendee_badge->ticket->owner->member);
1218+
$this->assertEquals($member->getId(), $attendee_badge->ticket->owner->member->id);
1219+
$this->assertTrue(isset($attendee_badge->ticket->owner->member->first_name));
1220+
}
1221+
1222+
public function testValidateBadgeMemberLess(){
1223+
// MEMBER-LESS case (D27): the fixture's member-less attendee resolves with NO member object.
1224+
$owner = self::$summit->getAttendeeByEmailAndMemberNotSet("memberless@test.com");
1225+
$this->assertNotNull($owner);
1226+
$this->assertFalse($owner->hasMember());
12011227

1202-
$badge_repository = EntityManager::getRepository(SummitAttendeeBadge::class);
1203-
$ticket = self::$summit_orders[0]->getTickets()->first();
1204-
$badge = $badge_repository->getBadgeByTicketNumber($ticket->getNumber());
1205-
$badge_qr_code = $badge->generateQRCode();
1228+
$attendee_badge = $this->callValidateBadge($owner->getFirstTicket()->getBadge());
12061229

1207-
//$key = '35NVOF4I5T6AAM28IJPKB8KRUW98KPDO';
1230+
// attendee id + email are present (they key the pre-account request and address the email)
1231+
$this->assertEquals($owner->getId(), $attendee_badge->ticket->owner->id);
1232+
$this->assertTrue(isset($attendee_badge->ticket->owner->email));
12081233

1234+
// no linked member => the expanded member object must be ABSENT
1235+
$this->assertFalse(isset($attendee_badge->ticket->owner->member));
1236+
}
1237+
1238+
private function callValidateBadge(SummitAttendeeBadge $badge) {
12091239
$params = [
1210-
'id' => self::$summit->getId(),
1211-
//'badge' => base64_encode(AES::encrypt($key, $badge_qr_code)),
1212-
'badge' => base64_encode($badge_qr_code),
1240+
'id' => self::$summit->getId(),
1241+
'badge' => base64_encode($badge->generateQRCode()),
12131242
];
12141243

12151244
$response = $this->action(
@@ -1223,8 +1252,9 @@ public function testValidateBadge(){
12231252
);
12241253

12251254
$this->assertResponseStatus(200);
1226-
$content = $response->getContent();
1227-
$attendee_badge = json_decode($content);
1255+
$attendee_badge = json_decode($response->getContent());
12281256
$this->assertNotNull($attendee_badge);
1257+
return $attendee_badge;
12291258
}
1259+
12301260
}

0 commit comments

Comments
 (0)