Tags: OpenStackweb/summit-api
Tags
fix: dispatch original entity id in DeletedEventDTO, not a post-flush… … getId() (#575) Doctrine nulls an entity's identifier field via reflection after a hard delete is flushed (UnitOfWork::executeDeletions). DeletedEventDTO::fromEntity() was being called after the owning transaction closed, so it read that stale, zeroed id and dispatched 'id' => 0 in the domain event payload. Added DeletedEventDTO::fromId() and switched the affected dispatch call sites to build the DTO from the id captured before removal: - SummitSponsorshipService::removeSponsorship / removeAddOn - SummitSponsorService::deleteSponsor - SummitMediaFileTypeService::delete Also applied the same fromId() call in SummitService::deleteSummit for consistency, though that path only flips a soft-delete flag (no em->remove()), so it never actually reproduced the zeroed-id bug. Added regression tests for all four dispatch paths, verified against the pre-fix code to confirm they fail with the original id => 0 defect (SummitService's stays green either way, per the note above).
fix: prevent TypeError when renaming a SummitMediaFileType to a new u… …nique name SummitMediaFileTypeService::update() reused the $type variable for a name-uniqueness check, overwriting the entity fetched via getById($id). When the payload's new name did not already exist in the DB, getByName() returned null, clobbering $type and causing SummitMediaFileTypeFactory::populate() to blow up with: TypeError: populate(): Argument #1 ($type) must be of type models\summit\SummitMediaFileType, null given The uniqueness check now uses its own $existing_type variable instead of overwriting the entity being updated.
fix: prevent TypeError when renaming a SummitMediaFileType to a new u… …nique name SummitMediaFileTypeService::update() reused the $type variable for a name-uniqueness check, overwriting the entity fetched via getById($id). When the payload's new name did not already exist in the DB, getByName() returned null, clobbering $type and causing SummitMediaFileTypeFactory::populate() to blow up with: TypeError: populate(): Argument #1 ($type) must be of type models\summit\SummitMediaFileType, null given The uniqueness check now uses its own $existing_type variable instead of overwriting the entity being updated.
fix: don't force ENGINE=MEMORY on speaker/member activity count temp … …tables Production MySQL (hardened/managed instances, e.g. DigitalOcean) disables the MEMORY storage engine, so CREATE TEMPORARY TABLE ... ENGINE=MEMORY fails with SQLSTATE[HY000]: 3161 "Storage engine MEMORY is disabled". This broke DoctrineSpeakerRepository::getUniqueActivitiesCountBySummit (getSpeakersActivitiesCount endpoint) and the identical pattern in DoctrineMemberRepository::getUniqueActivitiesCountBySummit. Drop the explicit ENGINE=MEMORY clause so the temp tables use the server's default engine (InnoDB), which isn't disabled. Added regression tests that capture the emitted DDL via MySQL's general query log and assert ENGINE=MEMORY is never present, since disabled_storage_engines itself is a restart-only sysvar and can't be toggled live in a test.
Hotfix/attendee regenerate qr code (#572) * fix: remap local docker-compose host ports to avoid conflicts with sibling stacks otel-collector, elasticsearch, and rabbitmq_sponsor_services published the same host ports as openstackid's and purchases-api's local stacks (9200/9300, 1888/8888/8889/13133/4317/4318/55679, 5672/15672), which broke docker compose up when multiple FN local stacks ran side by side. Container-internal ports are unchanged; only host-side mappings moved. * fix(badges): generate-on-read + reassignment QR staleness (ClickUp 86baxuvj3) GET /summits/{id}/attendees/me?expand=tickets.badge now regenerates the caller's badge QR code on every read (AttendeeService::regenerateAttendeeBadgesQRCodes), so "My QR" renders even for never-printed badges. Fixes badge QR staleness on ticket reassignment across all three writers: AttendeeService::reassignAttendeeTicket, reassignAttendeeTicketByMember, and SummitOrderService::updateTicket. A ticket fetched via an exclusive lock does not populate Doctrine's inverse-side badge association, so hasBadge()/getBadge() are unreliable afterward - resolved via a shared ResolvesLockedTicketBadge trait that looks the badge up independently by ticket number and re-attaches it. Also fixes a latent duplicate-badge-row risk in updateTicket's badge_type_id branch, and adds try/catch guards around badge generation so one bad badge (broken legacy ticket/order/summit chain) can't 500 an otherwise-successful read or abort the rest of a generation batch. Resolves fntechgit/ftn-docsnsklz#70. * fix(badges): remove unnecessary ResolvesLockedTicketBadge workaround The previous commit shipped a trait working around a claimed Doctrine behavior ("exclusive-lock fetch doesn't populate inverse-side to-one associations") that does not actually exist. Verified with isolated, instrumented tests (SQL capture, object-identity checks, UnitOfWork state checks): $ticket->hasBadge()/getBadge() work correctly on a ticket fetched via getByIdExclusiveLock(), with no workaround needed. The earlier misleading result was caused by two unrelated confounds in diagnostic testing: mixing two different EntityManager instances (the LaravelDoctrine facade vs a test fixture's own self::$em), and a pre-existing test fixture bug (InsertSummitTestData reuses one SummitAttendeeBadge object across 5 tickets, so attendee->getTickets() ->first() is not reliably the ticket that badge's DB row points to). Reverts all four call sites (AttendeeService::reassignAttendeeTicket, reassignAttendeeTicketByMember, and both branches of SummitOrderService::updateTicket) to plain hasBadge()/getBadge(). Keeps the try/catch guard around generateQRCode(), which is unrelated and still valid. Deletes the ResolvesLockedTicketBadge trait. Full targeted suite re-verified: 45/46 pass (same pre-existing, unrelated failure as before). * fix(badges): only regenerate badge QR when tickets.badge is expanded Per CodeRabbit review on PR #572 (discussion_r3587418919): getOwnAttendee was invoking regenerateAttendeeBadgesQRCodes() unconditionally, exclusively locking and regenerating every active badge even on requests that never expand tickets.badge and therefore never serialize badge data at all. Now only calls it when 'tickets.badge' is present in the expand param. Keeps the always-regenerate behavior (no skip-if-already-has-QR) per explicit prior decision - this only scopes *when* it runs, not whether existing QR codes are trusted. Added testGetOwnAttendeeDoesNotGenerateBadgeQRCodeWhenBadgeNotExpanded, verified RED (failed against the unconditional call) before GREEN. Full targeted suite re-verified: 46/47 pass (same pre-existing failure). * docs(badges): fix typo in getOwnAttendee swagger description Per PR #572 review (discussion_r3587772934, @romanetar): "que" was a Spanish word leaked into the English OpenAPI description. Also updated the wording to reflect the actual current behavior (regeneration only happens when tickets.badge is expanded).
feature (registration): add order extra question answers to ticket CS… …V import (#567) * feat(registration): add order extra question answers to ticket CSV import Adds extra_question:{question name} column support to the ticket data import, template endpoint and OpenAPI docs. Answers are upserted through the existing ExtraQuestionAnswerHolder persistence path; unknown questions, order-scoped questions, disallowed questions, empty values and locked answers are logged and skipped without failing the row. List type questions accept value name/label/id ('|' separated for CheckBoxList) and store value ids. Co-Authored-By: Claude Fable 5 <[email protected]> * test(registration): fix badge-features import test fixture assumptions The import re-reads tickets with HINT_REFRESH, so it sees DB state: the fixture's assigned tickets share one badge entity whose FK points at only the last of them. Use an unassigned ticket, which gets its own DB-consistent badge from SummitTicketType::applyTo. Co-Authored-By: Claude Fable 5 <[email protected]> * fix(registration): normalize list answer ordering + guard import row on answer persistence Per CodeRabbit review: sort list-question value ids so the same selection in a different order is not treated as a changed answer, and catch ValidationException from the extra-question persistence path so one bad payload cannot strand the remaining import rows. Co-Authored-By: Claude Fable 5 <[email protected]> * refactor(registration): review fixes for extra-question CSV import Per review: process badge data before extra questions and flush + evict the badge-features result cache so same-row badge/feature grants are visible to the question permission gates; split the upsert into resolve/merge helpers; ctype_digit for raw value ids; targeted cache forget in tests. Adds regression tests for the same-row feature grant (new + existing attendee), order-scoped skip, locked-answer skip, and badge creation for badge-less tickets (folds in #568). Co-Authored-By: Claude Fable 5 <[email protected]> * test(registration): badge-less ticket requires a summit without a default badge type SummitTicketType::getBadgeType falls back to the summit default badge type, so on the main fixture summit applyTo always builds a badge and a badge-less ticket cannot be constructed. Build the scenario on the second fixture summit, which has no badge types — the real case the badge creation fix covers. Co-Authored-By: Claude Fable 5 <[email protected]> * test(registration): set support email on summit2 fixture path SummitAttendeeTicketEmail's constructor requires the summit support email; the second fixture summit never sets one, so the ticket reassignment path threw during the badge-less import test. Co-Authored-By: Claude Fable 5 <[email protected]> * fix(registration): dedupe resolved list-question value ids on ticket import Duplicated CSV tokens (drag-fill artifacts, or the same choice spelled as name/label/raw id) resolve to the same value id: they falsely tripped the single-value guard on radio/combo questions and persisted duplicated id strings for CheckBoxList, which also resisted later correction under the answer-change lock. Adds both regression tests from review. Co-Authored-By: Claude Fable 5 <[email protected]> --------- Co-authored-by: Claude Fable 5 <[email protected]>
fix(members): stop stale access-token group claim from stripping out-… …of-band groups (#553) * fix(members): stop stale access-token group claim from stripping out-of-band groups getCurrentUser() ran synchronizeGroups() on every request using the access-token user_groups claim, a snapshot taken at token issuance. That path removed any group not present in the (stale) claim and not in a hardcoded skip-list, so a group added out-of-band after login (e.g. sponsors-services added via the PublishUserUpdated webhook) was re-stripped by the next /members/me request reusing the old token. - synchronizeGroups() gains $allow_removals (default true); the per-request path (ResourceServerContext::checkGroups) now passes false, making it additive-only. Removals remain on the authoritative live-IDP webhook path only. - Fix the throttle cache: GET read a per-group key while SET wrote a key without the group list, so it never hit and the add/remove logic ran on every request. Keys are now unified (sorted, mode-tagged). - Add MemberServiceTest regression coverage for both additive and full-sync modes. * fix(members): hash group-set in sync throttle key to avoid collisions Addresses CodeRabbit PR #553: an underscore-joined group list is ambiguous (["a_b","c"] and ["a","b_c"] collide), which could wrongly short-circuit a sync for the wrong group set for the TTL window. Fingerprint the sorted set with sha1(json_encode()) instead.
fix(promo-codes): preserve ticket_types_rules on discount code update (… …#552) A discount code PUT echoes back the whole serialized object, so the payload carries the leftover top-level amount/rate alongside ticket_types_rules. SummitPromoCodeFactory::populate applied setAmount()/setRate(), which clear the ticket_types_rules collection (orphanRemoval) and deleted the existing rules on update. Ignore the top-level amount/rate when ticket_types_rules are present so the per-ticket-type rules survive. - factory: skip amount/rate when ticket_types_rules present - add SummitPromoCodeFactoryTest for the regression and flat-rate path - remove stale DomainAuthorizedPromoCodeTest cases asserting the addTicketTypeRule/removeTicketTypeRule overrides deleted in 497839b; sync SDS Truth #4 and design notes - ci(push.yml): pass tests/Unit/Services and tests/Repositories positionally (were given to --filter, matching zero tests)
PreviousNext