Skip to content

fix(promo-codes): restrict implicit "apply to all" to Audience=All only#541

Draft
caseylocker wants to merge 2 commits into
mainfrom
feature/promo-code-apply-to-all-audience-restriction
Draft

fix(promo-codes): restrict implicit "apply to all" to Audience=All only#541
caseylocker wants to merge 2 commits into
mainfrom
feature/promo-code-apply-to-all-audience-restriction

Conversation

@caseylocker
Copy link
Copy Markdown
Contributor

Summary

Tightens SummitRegistrationPromoCode::canBeAppliedTo() so the implicit "apply to all" branch (empty allowed_ticket_types) only matches ticket types with Audience = All. Other audiences (WithInvitation, WithoutInvitation, WithPromoCode) must be opted in via explicit allowed_ticket_types membership.

What changed

  • app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationPromoCode.php:483-495 — empty-collection branch returns $ticketType->getAudience() === SummitTicketType::Audience_All. Subclass overrides (SummitRegistrationDiscountCode::canBeAppliedTo, DomainAuthorizedSummitRegistrationDiscountCode::canBeAppliedTo) delegate to the patched base — no override changes needed.
  • tests/Unit/Services/PromoCodeCanBeAppliedToAudienceTest.php — new unit tests, dataProvider over all 4 audiences × {empty, present, absent} + a smoke test for the domain-authorized override.
  • doc/promo-code-apply-to-all-audience-restriction.md — dedicated SDS.
  • app/Models/Foundation/Summit/Registration/PromoCodes/DomainAuthorizedSummitRegistrationDiscountCode.php:73 — tightened a stale comment now that the empty branch is audience-conditional.

Caller audit

canBeAppliedTo() is the single gate for every production path:

  • RegularPromoCodeTicketTypesStrategy::applyPromo2TicketType() line 82
  • SummitOrderService.php:812 and :1093 (order/checkout pipeline)
  • RegularTicketTypePromoCodeValidationStrategy.php:91

No code path independently treats empty allowed_ticket_types as "applies to all audiences" for promo codes. The out-of-scope sibling SummitAttendee.php:1367 is a different domain (invitations).

Behavior change (intentional)

Existing discount codes with empty allowed_ticket_types that today implicitly cover WithInvitation / WithoutInvitation tickets will stop covering them after deploy. This is called out in the ticket: "Existing discount codes with 'Apply to all' checked continue to work correctly for Audience = All ticket types — no regression."

AC5 wording note

The ClickUp acceptance criterion #5 says "submitting apply_to_all_ticket_types = true resolves to Audience = All only, regardless of frontend." No such payload field exists in this API — it's a conceptual name. The actual enforcement is canBeAppliedTo(), the single gate every consumer flows through. A hostile client cannot bypass it because there's no apply_to_all_* field to honor or ignore.

Test plan

  • Unit: ./vendor/bin/phpunit tests/Unit/Services/PromoCodeCanBeAppliedToAudienceTest.php — pass
  • Unit suite: full tests/Unit/Services/ passes (53 tests, 77 assertions, no deprecations)
  • Integration: docker test DB on the implementer workspace is broken for unrelated reasons (migrations table missing columns). Reviewer with a working env: please run tests/oauth2/OAuth2SummitOrdersApiTest.php, OAuth2SummitTicketTypesApiTest.php, OAuth2PromoCodesApiTest.php. The existing testGetAllowedTicketTypesApplyingRegularDiscountCodeToAllOfThem in OAuth2SummitTicketTypesApiTest.php:218 may need updating — it removes types 1/2/3 from allowed_ticket_types then asserts the discount applies; that's exactly the path we tightened.
  • Manual: against staging, create a SUMMIT_DISCOUNT_CODE with empty rules, verify it does NOT apply to a WithPromoCode ticket type; add the WithPromoCode type to allowed_ticket_types, verify it then applies.

When SummitRegistrationPromoCode::allowed_ticket_types is empty, canBeAppliedTo()
previously returned true for any ticket type — including WithPromoCode-audience
tickets that are deliberately hidden from the public. This change tightens the
implicit-sweep branch to require Audience = All; non-All audiences must be
opted in via explicit allowed_ticket_types membership.

Adds 11 unit tests (4 audience values × empty/explicit) and a smoke test
confirming DomainAuthorizedSummitRegistrationDiscountCode's override still
applies to its explicitly-allowed WithPromoCode tickets.

Refs: ClickUp 86b9vrpxp; parent feature SDS doc/promo-codes-for-early-registration-access.md
…case

testNonEmptyAllowedTicketTypesNotContainingTicketReturnsFalse previously
only ran for Audience=All. Convert it to a DataProvider so a regression
that accidentally returns true on the absent-from-list path for
WithInvitation / WithoutInvitation / WithPromoCode also gets caught.

Also tighten the stale "returns true when allowed_ticket_types is empty"
comment in DomainAuthorizedSummitRegistrationDiscountCode::addTicketTypeRule
to reflect the post-fix conditional, and refresh the SDS line-number cites
to match the current method body.

Refs: ClickUp 86b9vrpxp; Codex review of 8defe88.
@caseylocker caseylocker self-assigned this May 11, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 793b8eb6-084e-4262-9d85-c1345d57df2e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/promo-code-apply-to-all-audience-restriction

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-541/

This page is automatically updated on each push to this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant