Skip to content

Commit c3f8df7

Browse files
caseylockerclaude
andcommitted
fix(promo-codes): harden CSV domain import and migration rollback safety
CSV import — blank allowed_email_domains cells produced [''] after explode, which passed the empty() check on the array but caused matchesEmailDomain() to reject every email (empty pattern is skipped, no match found, returns false). Now trims whitespace, filters empty strings, and unsets the key if no valid domains remain. Migration down() — replaced DELETE with UPDATE to remap domain-authorized rows to base types (discount→SummitRegistrationDiscountCode, promo→SummitRegistrationPromoCode). DELETE would silently cascade through SummitAttendeeTicket.PromoCodeID (ON DELETE CASCADE), destroying ticket history. UPDATE preserves FK references while safely narrowing the ENUM. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ae261a7 commit c3f8df7

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

app/Services/Model/Imp/SummitPromoCodeService.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,10 @@ public function importPromoCodes(Summit $summit, UploadedFile $csv_file, ?Member
643643
}
644644

645645
if(isset($row['allowed_email_domains'])){
646-
$row['allowed_email_domains'] = explode('|', $row['allowed_email_domains']);
646+
$domains = array_map('trim', explode('|', $row['allowed_email_domains']));
647+
$domains = array_values(array_filter($domains, fn($d) => $d !== ''));
648+
$row['allowed_email_domains'] = !empty($domains) ? $domains : null;
649+
if(is_null($row['allowed_email_domains'])) unset($row['allowed_email_domains']);
647650
}
648651

649652
if(isset($row['ticket_types_rules']) && (isset($row['amount']) || isset($row['rate']))){
@@ -750,7 +753,10 @@ public function importSponsorPromoCodes(Summit $summit, UploadedFile $csv_file,
750753
}
751754

752755
if(isset($row['allowed_email_domains'])){
753-
$row['allowed_email_domains'] = explode('|', $row['allowed_email_domains']);
756+
$domains = array_map('trim', explode('|', $row['allowed_email_domains']));
757+
$domains = array_values(array_filter($domains, fn($d) => $d !== ''));
758+
$row['allowed_email_domains'] = !empty($domains) ? $domains : null;
759+
if(is_null($row['allowed_email_domains'])) unset($row['allowed_email_domains']);
754760
}
755761

756762
if(isset($row['ticket_types_rules']) && (isset($row['amount']) || isset($row['rate']))){

database/migrations/model/Version20260401150000.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,17 @@ public function down(Schema $schema): void
100100
$this->addSql("DROP TABLE IF EXISTS DomainAuthorizedSummitRegistrationPromoCode");
101101
$this->addSql("DROP TABLE IF EXISTS DomainAuthorizedSummitRegistrationDiscountCode");
102102

103-
// 4b. Delete orphaned base-table rows before narrowing the ENUM
104-
$this->addSql("DELETE FROM SummitRegistrationPromoCode WHERE ClassName IN (
105-
'DomainAuthorizedSummitRegistrationDiscountCode',
106-
'DomainAuthorizedSummitRegistrationPromoCode'
107-
)");
103+
// 4b. Remap domain-authorized rows to base types to preserve FK references
104+
// (SummitAttendeeTicket.PromoCodeID cascades on delete, so DELETE would destroy ticket history)
105+
$this->addSql("UPDATE SummitRegistrationPromoCode
106+
SET ClassName = CASE ClassName
107+
WHEN 'DomainAuthorizedSummitRegistrationDiscountCode' THEN 'SummitRegistrationDiscountCode'
108+
WHEN 'DomainAuthorizedSummitRegistrationPromoCode' THEN 'SummitRegistrationPromoCode'
109+
END
110+
WHERE ClassName IN (
111+
'DomainAuthorizedSummitRegistrationDiscountCode',
112+
'DomainAuthorizedSummitRegistrationPromoCode'
113+
)");
108114

109115
// 5. Revert the ClassName discriminator ENUM to the original 12 values
110116
$this->addSql("ALTER TABLE SummitRegistrationPromoCode MODIFY ClassName ENUM(

0 commit comments

Comments
 (0)