Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions database/tests/data/e2e/30_events.sql
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,20 @@ insert into event (
now() + interval '59 days 2 hours',
1,
true
), (
'55555555-5555-5555-5555-555555555537',
'Dashboard Waitlist Invite Lab',
'alpha-dashboard-waitlist-invite-lab',
'Future event with spare seats dedicated to dashboard waitlist invitation coverage.',
'UTC',
'33333333-3333-3333-3333-333333333331',
'virtual',
'44444444-4444-4444-4444-444444444441',
true,
now() + interval '58 days',
now() + interval '58 days 2 hours',
3,
true
);

-- Events reserved for cancellation lifecycle and canceled invitation history coverage.
Expand Down
48 changes: 48 additions & 0 deletions database/tests/data/e2e/60_enrollment.sql
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,22 @@ values (
20,
'Ended sales pass',
'Zero-price pass whose only sales window has ended.'
), (
'56555555-5555-5555-5555-555555555537',
true,
'55555555-5555-5555-5555-555555555537',
1,
1,
'General Admission',
'Sold-out tier whose queue feeds dashboard waitlist invitation coverage.'
), (
'56555555-5555-5555-5555-555555555538',
true,
'55555555-5555-5555-5555-555555555537',
2,
3,
'Late Admission',
'Free tier with spare seats organizers assign from the waitlist.'
);

insert into event_ticket_type (
Expand Down Expand Up @@ -510,6 +526,17 @@ values (
'55555555-5555-5555-5555-555555555526',
(select event_ticket_type_id from event_ticket_type where event_id = '55555555-5555-5555-5555-555555555526' order by "order" limit 1),
'77777777-7777-7777-7777-777777777707'
), (
'55555555-5555-5555-5555-555555555537',
'56555555-5555-5555-5555-555555555537',
'77777777-7777-7777-7777-777777777707'
);

-- Confirmed attendee whose waitlist offer was already claimed on the invite lab event.
insert into event_attendee (event_id, user_id)
values (
'55555555-5555-5555-5555-555555555537',
'77777777-7777-7777-7777-777777777705'
);

insert into event_attendee (event_id, user_id, manually_invited, status)
Expand Down Expand Up @@ -744,6 +771,15 @@ values (
'waitlist',
'expired',
'77777777-7777-7777-7777-777777777701'
), (
'59555555-5555-5555-5555-555555555537',
current_timestamp - interval '2 days',
'55555555-5555-5555-5555-555555555537',
'56555555-5555-5555-5555-555555555537',
current_timestamp - interval '1 day',
'waitlist',
'expired',
'77777777-7777-7777-7777-777777777708'
), (
'59555555-5555-5555-5555-555555555528',
current_timestamp - interval '2 days',
Expand Down Expand Up @@ -807,6 +843,18 @@ values (
'checkout_pending',
'Private paid offer',
'77777777-7777-7777-7777-777777777708'
), (
'59555555-5555-5555-5555-555555555538',
0,
null,
0,
'55555555-5555-5555-5555-555555555537',
'56555555-5555-5555-5555-555555555537',
current_timestamp + interval '3 days',
'waitlist',
'completed',
'General Admission',
'77777777-7777-7777-7777-777777777705'
);

-- Canceled invitation retained for attendee history regression coverage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
-- ============================================================================

begin;
select plan(58);
select plan(60);

-- ============================================================================
-- VARIABLES
Expand Down Expand Up @@ -37,6 +37,8 @@ select plan(58);
\set expiredReservationOfferID '3a130000-0000-0000-0000-000000000041'
\set expiredReservationOfferUserID '3a130000-0000-0000-0000-000000000042'
\set expiredReservationPromotedUserID '3a130000-0000-0000-0000-000000000043'
\set expiredWaitlistOfferID '3a130000-0000-0000-0000-00000000007b'
\set expiredWaitlistOfferUserID '3a130000-0000-0000-0000-00000000007a'
\set groupCategoryID '3a130000-0000-0000-0000-000000000008'
\set groupID '3a130000-0000-0000-0000-000000000009'
\set inProgressEventID '3a130000-0000-0000-0000-000000000025'
Expand Down Expand Up @@ -186,6 +188,7 @@ select fx_user(:'unverifiedUserID', jsonb_build_object(
'username', 'unverified-invite-event-attendee'
));
select fx_user(:'waitlistedUserID', jsonb_build_object('username', 'waitlisted'));
select fx_user(:'expiredWaitlistOfferUserID', jsonb_build_object('username', 'expired-waitlist-offer'));

-- Events
select fx_event(:'capacityEventID', :'groupID', :'eventCategoryID', jsonb_build_object(
Expand Down Expand Up @@ -459,6 +462,27 @@ values (
:'queueConflictWaitlistUserID'
);

-- Expired waitlist promotion that organizers can reissue from the waitlist page
insert into admission_offer (
admission_offer_id,
created_at,
event_id,
event_ticket_type_id,
expires_at,
source,
status,
user_id
) values (
:'expiredWaitlistOfferID',
current_timestamp - interval '2 days',
:'eventID',
(select event_ticket_type_id from event_ticket_type where event_id = :'eventID' limit 1),
current_timestamp - interval '1 day',
'waitlist',
'expired',
:'expiredWaitlistOfferUserID'
);

-- Active ticket offer occupying the sold-out ticketed tier
insert into admission_offer (
event_id,
Expand Down Expand Up @@ -713,6 +737,34 @@ select is(
'Should remove the invited user from the waitlist'
);

-- Should reissue an invitation to a user whose waitlist offer expired
select is(
invite_event_attendee(
:'actorID', :'groupID', :'eventID', :'expiredWaitlistOfferUserID', null, :'simpleTicketTypeID'
) ->> 'outcome',
'offer-created',
'Should create a new organizer offer for a user whose waitlist offer expired'
);

select results_eq(
format(
$$
select source, status
from admission_offer
where event_id = %L::uuid
and user_id = %L::uuid
order by created_at
$$,
:'eventID', :'expiredWaitlistOfferUserID'
),
$$
values
('waitlist', 'expired'),
('organizer_invitation', 'pending')
$$,
'Should keep the expired waitlist offer history next to the reissued organizer offer'
);

-- Should pre-register an email invitee and keep them out of normal registration state
select ok(
invite_event_attendee(
Expand Down
2 changes: 1 addition & 1 deletion ocg-server/src/handlers/dashboard/group/waitlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(crate) async fn list_page(
&user.user_id,
GroupPermission::EventsWrite
),
db.get_event_summary(community_id, group_id, event_id),
db.get_event_summary_dashboard(community_id, group_id, event_id),
db.search_event_waitlist(group_id, event_id, &filters)
)?;

Expand Down
6 changes: 3 additions & 3 deletions ocg-server/src/handlers/dashboard/group/waitlist/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async fn test_list_page_success() {
user_id,
GroupPermission::EventsWrite,
);
db.expect_get_event_summary()
db.expect_get_event_summary_dashboard()
.times(1)
.withf(move |cid, gid, eid| *cid == community_id && *gid == group_id && *eid == event_id)
.returning(move |_, _, _| Ok(event.clone()));
Expand Down Expand Up @@ -208,7 +208,7 @@ async fn test_list_page_with_pagination_params() {
user_id,
GroupPermission::EventsWrite,
);
db.expect_get_event_summary()
db.expect_get_event_summary_dashboard()
.times(1)
.withf(move |cid, gid, eid| *cid == community_id && *gid == group_id && *eid == event_id)
.returning(move |_, _, _| Ok(event.clone()));
Expand Down Expand Up @@ -278,7 +278,7 @@ async fn test_list_page_with_search_query() {
user_id,
GroupPermission::EventsWrite,
);
db.expect_get_event_summary()
db.expect_get_event_summary_dashboard()
.times(1)
.withf(move |cid, gid, eid| *cid == community_id && *gid == group_id && *eid == event_id)
.returning(move |_, _, _| Ok(event.clone()));
Expand Down
60 changes: 60 additions & 0 deletions ocg-server/src/templates/dashboard/group/waitlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,63 @@ pub(crate) struct ListPage {
/// Text search query used to filter waitlist entries.
pub ts_query: Option<String>,
}

// Helpers.

/// Returns a stable identifier for a waitlist row's actions menu.
///
/// Offer history rows are keyed by their offer, and queued rows by the user
/// and ticket tier, so a user appearing in both keeps distinct menus.
pub(crate) fn waitlist_row_key(entry: &WaitlistEntry) -> String {
match entry.admission_offer_id {
Some(admission_offer_id) => format!("waitlist-offer-{admission_offer_id}"),
None => format!(
"waitlist-queue-{}-{}",
entry.user.user_id, entry.event_ticket_type_id
),
}
}

#[cfg(test)]
mod tests {
use chrono::Utc;
use uuid::Uuid;

use super::waitlist_row_key;
use crate::types::{dashboard::group::waitlist::WaitlistEntry, user::User};

fn entry(admission_offer_id: Option<Uuid>) -> WaitlistEntry {
WaitlistEntry {
created_at: Utc::now(),
event_ticket_type_id: Uuid::nil(),
ticket_title: "General".to_string(),
user: User {
user_id: Uuid::max(),
username: "jane".to_string(),
..User::default()
},
admission_offer_id,
admission_offer_status: None,
offer_expires_at: None,
waitlist_position: None,
}
}

#[test]
fn test_waitlist_row_key_uses_offer_for_history_rows() {
let offer_id = Uuid::from_u128(7);

assert_eq!(
waitlist_row_key(&entry(Some(offer_id))),
format!("waitlist-offer-{offer_id}")
);
}

#[test]
fn test_waitlist_row_key_uses_user_and_tier_for_queued_rows() {
assert_eq!(
waitlist_row_key(&entry(None)),
format!("waitlist-queue-{}-{}", Uuid::max(), Uuid::nil())
);
}
}
Loading
Loading