@@ -72,22 +72,61 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
7272 const { id } = req . query ;
7373
7474 // Handle catch-all route - id is an array, we want the first element
75- const pageId = Array . isArray ( id ) ? id [ 0 ] : id ;
75+ const idParam = Array . isArray ( id ) ? id [ 0 ] : id ;
7676
77- if ( ! pageId || typeof pageId !== 'string' ) {
77+ if ( ! idParam || typeof idParam !== 'string' ) {
7878 return res . status ( 400 ) . json ( { error : 'Invalid page ID' } ) ;
7979 }
8080
81+ // Parse id-password format
82+ const idParts = idParam . split ( '-' ) ;
83+ if ( idParts . length < 2 ) {
84+ return res . status ( 400 ) . json ( { error : 'Invalid page ID format. Expected id-password format' } ) ;
85+ }
86+
87+ const password = idParts . pop ( ) ; // Get the last part as password
88+ const pageId = idParts . join ( '-' ) ; // Join remaining parts as page ID
89+
90+ if ( ! pageId || ! password ) {
91+ return res . status ( 400 ) . json ( { error : 'Invalid page ID or password format' } ) ;
92+ }
93+
8194 if ( method === 'GET' ) {
82- return handleGet ( req , res , pageId ) ;
95+ return handleGet ( req , res , pageId , password ) ;
8396 } else if ( method === 'PATCH' ) {
84- return handlePatch ( req , res , pageId ) ;
97+ return handlePatch ( req , res , pageId , password ) ;
8598 } else {
8699 return res . status ( 405 ) . json ( { error : 'Method not allowed' } ) ;
87100 }
88101}
89102
90103
104+ // Helper function to validate password against page properties
105+ async function validatePassword ( pageProperties : any , providedPassword : string ) : Promise < boolean > {
106+ const formPassword = pageProperties [ "Form password" ] ;
107+ if ( ! formPassword ) {
108+ return false ; // No password set on the page
109+ }
110+
111+ // Extract password value based on property type
112+ let storedPassword = '' ;
113+ if ( formPassword . type === 'rich_text' ) {
114+ storedPassword = formPassword . rich_text ?. [ 0 ] ?. plain_text || '' ;
115+ } else if ( formPassword . type === 'title' ) {
116+ storedPassword = formPassword . title ?. [ 0 ] ?. plain_text || '' ;
117+ } else if ( formPassword . type === 'select' ) {
118+ storedPassword = formPassword . select ?. name || '' ;
119+ } else if ( formPassword . type === 'formula' ) {
120+ // Handle formula type - convert number to string for comparison
121+ const formulaResult = formPassword . formula ;
122+ if ( formulaResult && formulaResult . type === 'number' ) {
123+ storedPassword = formulaResult . number ?. toString ( ) || '' ;
124+ }
125+ }
126+
127+ return storedPassword === providedPassword ;
128+ }
129+
91130// Helper function to fetch supporter data from rollup
92131async function fetchSupporterFromRollup ( pageProperties : any , notion : Client ) : Promise < string > {
93132 // Look for "Parent item" relation in the current page properties
@@ -121,7 +160,7 @@ async function fetchSupporterFromRollup(pageProperties: any, notion: Client): Pr
121160}
122161
123162// GET: Fetch page data for the given id
124- async function handleGet ( req : NextApiRequest , res : NextApiResponse , pageId : string ) {
163+ async function handleGet ( req : NextApiRequest , res : NextApiResponse , pageId : string , password : string ) {
125164 const supporter = ! req . query ?. supporter ? false : true ;
126165 const notion = new Client ( { auth : process . env . NOTION_SECRET } ) ;
127166 try {
@@ -132,6 +171,12 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse, pageId: stri
132171 return res . status ( 400 ) . json ( { error : 'Invalid page object' } ) ;
133172 }
134173
174+ // Validate password before proceeding
175+ const isPasswordValid = await validatePassword ( page . properties , password ) ;
176+ if ( ! isPasswordValid ) {
177+ return res . status ( 401 ) . json ( { error : 'Invalid or missing password' } ) ;
178+ }
179+
135180
136181 // Get database schema to access field descriptions
137182 let databaseSchema : any = null ;
@@ -303,8 +348,45 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse, pageId: stri
303348 break ;
304349 case 'relation' :
305350 if ( propertyAny . type === 'relation' ) {
306- // return list of ids
307- fieldValue = propertyAny . relation ?. map ( ( item : any ) => `${ item . id ?. replaceAll ( '-' , '' ) } ` ) . join ( ',' ) || '' ;
351+ // For quests, we need to get the password for each quest if supporter is true
352+ if ( supporter && propertyAny . relation && propertyAny . relation . length > 0 ) {
353+ // Get passwords for each quest
354+ const questIdsWithPasswords = await Promise . all (
355+ propertyAny . relation . map ( async ( item : any ) => {
356+ try {
357+ const questPage = await notion . pages . retrieve ( { page_id : item . id } ) ;
358+ const questProperties = ( questPage as any ) . properties ;
359+
360+ // Get the password from the quest page
361+ const questPassword = questProperties [ "Form password" ] ;
362+ let password = '' ;
363+
364+ if ( questPassword ) {
365+ if ( questPassword . type === 'formula' && questPassword . formula ?. type === 'number' ) {
366+ password = questPassword . formula . number ?. toString ( ) || '' ;
367+ } else if ( questPassword . type === 'rich_text' ) {
368+ password = questPassword . rich_text ?. [ 0 ] ?. plain_text || '' ;
369+ } else if ( questPassword . type === 'title' ) {
370+ password = questPassword . title ?. [ 0 ] ?. plain_text || '' ;
371+ } else if ( questPassword . type === 'select' ) {
372+ password = questPassword . select ?. name || '' ;
373+ }
374+ }
375+
376+ // Return id-password format
377+ return password ? `${ item . id ?. replaceAll ( '-' , '' ) } -${ password } ` : item . id ?. replaceAll ( '-' , '' ) ;
378+ } catch ( error ) {
379+ console . error ( 'Failed to fetch quest password:' , error ) ;
380+ // Fallback to just the ID if password fetch fails
381+ return item . id ?. replaceAll ( '-' , '' ) ;
382+ }
383+ } )
384+ ) ;
385+ fieldValue = questIdsWithPasswords . join ( ',' ) ;
386+ } else {
387+ // return list of ids without passwords
388+ fieldValue = propertyAny . relation ?. map ( ( item : any ) => `${ item . id ?. replaceAll ( '-' , '' ) } ` ) . join ( ',' ) || '' ;
389+ }
308390 fieldType = 'quests' ;
309391 }
310392 break ;
@@ -428,15 +510,16 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse, pageId: stri
428510 config : {
429511 isLocked,
430512 isOk
431- }
513+ } ,
514+ accreditationInsuranceGuideUrl : process . env . ACCREDITATION_INSURANCE_GUIDE || ''
432515 } ) ;
433516 } catch ( error ) {
434517 return res . status ( 500 ) . json ( { error : 'Failed to fetch page data' } ) ;
435518 }
436519}
437520
438521// PATCH: Update page with submitted form data
439- async function handlePatch ( req : NextApiRequest , res : NextApiResponse , pageId : string ) {
522+ async function handlePatch ( req : NextApiRequest , res : NextApiResponse , pageId : string , password : string ) {
440523 const notion = new Client ( { auth : process . env . NOTION_SECRET } ) ;
441524 try {
442525 const formData = req . body ;
@@ -449,6 +532,12 @@ async function handlePatch(req: NextApiRequest, res: NextApiResponse, pageId: st
449532 return res . status ( 400 ) . json ( { error : 'Invalid page object' } ) ;
450533 }
451534
535+ // Validate password before proceeding
536+ const isPasswordValid = await validatePassword ( page . properties , password ) ;
537+ if ( ! isPasswordValid ) {
538+ return res . status ( 401 ) . json ( { error : 'Invalid or missing password' } ) ;
539+ }
540+
452541 // Check if any [config] field contains [lock] to prevent updates
453542 let isLocked = false ;
454543 for ( const [ propertyName , property ] of Object . entries ( page . properties ) ) {
@@ -570,6 +659,11 @@ async function handlePatch(req: NextApiRequest, res: NextApiResponse, pageId: st
570659 // updates[propertyName] = { title: value ? [{ text: { content: value } }] : [] };
571660 // break;
572661 }
662+
663+ // Special handling for Insurance field - also update "Insurance link" field
664+ if ( fieldName === 'Insurance' && value ) {
665+ updates [ "Insurance link" ] = { rich_text : value ? [ { text : { content : value } } ] : [ ] }
666+ }
573667 }
574668
575669 await notion . pages . update ( {
0 commit comments