Skip to content

Commit 0b0aa15

Browse files
denbecclaude
andcommitted
Restore configurable Google Wallet class ID and make venue dynamic
Move class suffix back to GOOGLE_WALLET_CLASS_ID env var instead of hardcoding it. Make venue name and address configurable via WalletPassInput, sourced from CMS settings (conference_venue_name, conference_venue_address). Also add venue to Apple Wallet auxiliary fields when available. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 33bfa13 commit 0b0aa15

3 files changed

Lines changed: 69 additions & 36 deletions

File tree

directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/__tests__/test-wallet-passes.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const dummyTicket: WalletPassInput = {
2121
conferenceTitle: 'programmier.con 2026',
2222
conferenceDate: '2026-11-25T08:00:00.000Z',
2323
conferenceEndDate: '2026-11-26T22:00:00.000Z',
24+
venueName: 'Bad Nauheim',
25+
venueAddress: 'Bad Nauheim, Deutschland',
2426
websiteUrl: 'https://programmier.bar',
2527
}
2628

@@ -65,11 +67,15 @@ async function getAccessToken(serviceAccountEmail: string, privateKey: string):
6567

6668
async function upsertGoogleWalletClass(env: Record<string, string>): Promise<void> {
6769
const issuerId = env.GOOGLE_WALLET_ISSUER_ID
70+
const classSuffix = env.GOOGLE_WALLET_CLASS_ID
6871
const email = env.GOOGLE_WALLET_SERVICE_ACCOUNT_EMAIL
6972
const privateKey = Buffer.from(env.GOOGLE_WALLET_PRIVATE_KEY_BASE64, 'base64').toString('utf-8')
7073

71-
// Must match the constant in wallet-pass-generator.ts
72-
const classSuffix = 'programmiercon_ticket_v4'
74+
if (!classSuffix) {
75+
console.error('GOOGLE_WALLET_CLASS_ID env var is required')
76+
return
77+
}
78+
7379
const classId = `${issuerId}.${classSuffix}`
7480

7581
const classDefinition = {
@@ -87,20 +93,24 @@ async function upsertGoogleWalletClass(env: Record<string, string>): Promise<voi
8793
value: dummyTicket.conferenceTitle,
8894
},
8995
},
90-
venue: {
91-
name: {
92-
defaultValue: {
93-
language: 'de',
94-
value: 'Bad Nauheim',
96+
...(dummyTicket.venueName && {
97+
venue: {
98+
name: {
99+
defaultValue: {
100+
language: 'de',
101+
value: dummyTicket.venueName,
102+
},
95103
},
104+
...(dummyTicket.venueAddress && {
105+
address: {
106+
defaultValue: {
107+
language: 'de',
108+
value: dummyTicket.venueAddress,
109+
},
110+
},
111+
}),
96112
},
97-
address: {
98-
defaultValue: {
99-
language: 'de',
100-
value: 'Bad Nauheim, Deutschland',
101-
},
102-
},
103-
},
113+
}),
104114
dateTime: {
105115
start: dummyTicket.conferenceDate,
106116
end: dummyTicket.conferenceEndDate,
@@ -204,6 +214,7 @@ async function main() {
204214
console.log('\n--- Google Wallet ---')
205215
const hasGoogleConfig = !!(
206216
env.GOOGLE_WALLET_ISSUER_ID &&
217+
env.GOOGLE_WALLET_CLASS_ID &&
207218
env.GOOGLE_WALLET_SERVICE_ACCOUNT_EMAIL &&
208219
env.GOOGLE_WALLET_PRIVATE_KEY_BASE64
209220
)
@@ -236,7 +247,7 @@ async function main() {
236247
' Apple: APPLE_WALLET_PASS_TYPE_ID, APPLE_WALLET_TEAM_ID, APPLE_WALLET_SIGNER_CERT_BASE64, APPLE_WALLET_SIGNER_KEY_BASE64, APPLE_WALLET_WWDR_BASE64'
237248
)
238249
console.log(
239-
' Google: GOOGLE_WALLET_ISSUER_ID, GOOGLE_WALLET_SERVICE_ACCOUNT_EMAIL, GOOGLE_WALLET_PRIVATE_KEY_BASE64'
250+
' Google: GOOGLE_WALLET_ISSUER_ID, GOOGLE_WALLET_CLASS_ID, GOOGLE_WALLET_SERVICE_ACCOUNT_EMAIL, GOOGLE_WALLET_PRIVATE_KEY_BASE64'
240251
)
241252
}
242253
}

directus-cms/extensions/directus-extension-programmierbar-bundle/src/shared/wallet-pass-generator.ts

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export interface WalletPassInput {
1111
conferenceTitle: string
1212
conferenceDate: string // ISO date string (start_on)
1313
conferenceEndDate?: string // ISO date string (end_on)
14+
venueName?: string // e.g. "Bad Nauheim"
15+
venueAddress?: string // e.g. "Bad Nauheim, Deutschland"
1416
websiteUrl: string
1517
}
1618

@@ -22,10 +24,9 @@ interface AppleWalletConfig {
2224
wwdr: string | Buffer
2325
}
2426

25-
const GOOGLE_WALLET_CLASS_SUFFIX = 'programmiercon_ticket_v4'
26-
2727
interface GoogleWalletConfig {
2828
issuerId: string
29+
classSuffix: string
2930
serviceAccountEmail: string
3031
privateKey: string
3132
}
@@ -143,11 +144,22 @@ export async function generateAppleWalletPass(
143144
}
144145
)
145146

146-
pass.auxiliaryFields.push({
147-
key: 'ticketCode',
148-
label: 'TICKET-CODE',
149-
value: input.ticketCode,
150-
})
147+
pass.auxiliaryFields.push(
148+
{
149+
key: 'ticketCode',
150+
label: 'TICKET-CODE',
151+
value: input.ticketCode,
152+
},
153+
...(input.venueName
154+
? [
155+
{
156+
key: 'location',
157+
label: 'ORT',
158+
value: input.venueName,
159+
},
160+
]
161+
: [])
162+
)
151163

152164
pass.backFields.push(
153165
{
@@ -169,15 +181,17 @@ export async function generateAppleWalletPass(
169181

170182
function loadGoogleConfig(env: Record<string, string>): GoogleWalletConfig | null {
171183
const issuerId = env.GOOGLE_WALLET_ISSUER_ID
184+
const classSuffix = env.GOOGLE_WALLET_CLASS_ID
172185
const email = env.GOOGLE_WALLET_SERVICE_ACCOUNT_EMAIL
173186
const keyBase64 = env.GOOGLE_WALLET_PRIVATE_KEY_BASE64
174187

175-
if (!issuerId || !email || !keyBase64) {
188+
if (!issuerId || !classSuffix || !email || !keyBase64) {
176189
return null
177190
}
178191

179192
return {
180193
issuerId,
194+
classSuffix,
181195
serviceAccountEmail: email,
182196
privateKey: Buffer.from(keyBase64, 'base64').toString('utf-8'),
183197
}
@@ -210,7 +224,7 @@ export function generateGoogleWalletUrl(
210224

211225
const verifyUrl = `${input.websiteUrl}/ticket/${input.ticketCode}`
212226
const objectId = `${config.issuerId}.${input.ticketCode}`
213-
const classId = `${config.issuerId}.${GOOGLE_WALLET_CLASS_SUFFIX}`
227+
const classId = `${config.issuerId}.${config.classSuffix}`
214228

215229
const eventTicketObject = {
216230
id: objectId,
@@ -261,20 +275,24 @@ export function generateGoogleWalletUrl(
261275
value: input.conferenceTitle,
262276
},
263277
},
264-
venue: {
265-
name: {
266-
defaultValue: {
267-
language: 'de',
268-
value: 'Bad Nauheim',
269-
},
270-
},
271-
address: {
272-
defaultValue: {
273-
language: 'de',
274-
value: 'Bad Nauheim, Deutschland',
278+
...(input.venueName && {
279+
venue: {
280+
name: {
281+
defaultValue: {
282+
language: 'de',
283+
value: input.venueName,
284+
},
275285
},
286+
...(input.venueAddress && {
287+
address: {
288+
defaultValue: {
289+
language: 'de',
290+
value: input.venueAddress,
291+
},
292+
},
293+
}),
276294
},
277-
},
295+
}),
278296
dateTime: {
279297
start: input.conferenceDate,
280298
...(input.conferenceEndDate && { end: input.conferenceEndDate }),

directus-cms/extensions/directus-extension-programmierbar-bundle/src/ticket-profile-completion/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export default defineHook(({ action }, hookContext) => {
5353
})
5454

5555
const websiteUrl = (await getSetting('website_url', context)) || 'https://programmier.bar'
56+
const venueName = await getSetting('conference_venue_name', context)
57+
const venueAddress = await getSetting('conference_venue_address', context)
5658

5759
for (const ticketId of keys) {
5860
logger.info(`${HOOK_NAME}: Processing completed profile for ticket ${ticketId}`)
@@ -96,6 +98,8 @@ export default defineHook(({ action }, hookContext) => {
9698
conferenceTitle: conference.title,
9799
conferenceDate: conference.start_on,
98100
conferenceEndDate: conference.end_on,
101+
venueName: venueName || undefined,
102+
venueAddress: venueAddress || undefined,
99103
websiteUrl,
100104
}
101105

0 commit comments

Comments
 (0)