@@ -36,6 +36,7 @@ const guestColumns = [
36
36
'admission_tier' ,
37
37
'created' ,
38
38
'updated' ,
39
+ 'updated_by' ,
39
40
'created_by' ,
40
41
'created_reason' ,
41
42
'status' ,
@@ -130,7 +131,7 @@ export async function getCurrentGuestTicketQrCode(guestId) {
130
131
export async function updateGuest ( id , updates ) {
131
132
for ( const u in updates ) {
132
133
// Update whitelist
133
- if ( ! [ 'status' , 'firstName' , 'lastName' , 'updatedBy' , 'meta' ] . includes ( u ) ) throw new GuestsServiceError ( 'Invalid guest data' , 'INVALID' ) ;
134
+ if ( ! [ 'status' , 'firstName' , 'lastName' , 'updatedBy' , 'meta' , 'admissionTier' ] . includes ( u ) ) throw new GuestsServiceError ( 'Invalid guest data' , 'INVALID' ) ;
134
135
}
135
136
136
137
if ( Object . keys ( updates ) . length === 1 && updates . updatedBy ) throw new GuestsServiceError ( 'Invalid guest data' , 'INVALID' ) ;
@@ -147,9 +148,39 @@ export async function updateGuest(id, updates) {
147
148
148
149
if ( Object . keys ( updates ) . length === 1 && updates . updatedBy ) throw new GuestsServiceError ( 'Invalid product data' , 'INVALID' ) ;
149
150
150
- let guest ;
151
+ // Prevent accidental downgrading of a guest below their purchased tier
152
+ let minimumAdmissionTier ;
153
+ if ( updates . admissionTier ) {
154
+ try {
155
+ [ minimumAdmissionTier ] = await sql `
156
+ SELECT p.admission_tier
157
+ FROM guests AS g
158
+ LEFT JOIN order_items AS oi
159
+ ON g.order_id = oi.order_id
160
+ LEFT JOIN products AS p
161
+ ON oi.product_id = p.id
162
+ AND g.event_id = p.event_id
163
+ WHERE g.id = ${ id }
164
+ AND p.id IS NOT NULL
165
+ ` ;
166
+ } catch ( e ) {
167
+ throw new GuestsServiceError ( 'Could not query guest' , 'UNKNOWN' , e ) ;
168
+ }
169
+
170
+ if ( ! minimumAdmissionTier ) throw new GuestsServiceError ( 'Guest not found' , 'NOT_FOUND' ) ;
171
+
172
+ // TODO: make this a tiered access list similar to user roles so we can support multiple levels in the future
173
+ if (
174
+ minimumAdmissionTier . admissionTier === 'vip' &&
175
+ updates . admissionTier === 'general'
176
+ ) {
177
+ throw new GuestsServiceError ( 'Cannot downgrade VIP guest to general admission' , 'INVALID' ) ;
178
+ }
179
+ }
180
+
181
+ let updatedGuest ;
151
182
try {
152
- [ guest ] = await sql `
183
+ [ updatedGuest ] = await sql `
153
184
UPDATE guests
154
185
SET ${ sql ( updates ) } , updated = now()
155
186
WHERE id = ${ id }
@@ -159,9 +190,9 @@ export async function updateGuest(id, updates) {
159
190
throw new GuestsServiceError ( 'Could not update guest' , 'UNKNOWN' , e ) ;
160
191
}
161
192
162
- if ( ! guest ) throw new GuestsServiceError ( 'guest not found' , 'NOT_FOUND' ) ;
193
+ if ( ! updatedGuest ) throw new GuestsServiceError ( 'guest not found' , 'NOT_FOUND' ) ;
163
194
164
- return guest ;
195
+ return updatedGuest ;
165
196
}
166
197
167
198
export async function archiveGuest ( id , updatedBy ) {
0 commit comments