diff --git a/src/core/jobs.ts b/src/core/jobs.ts index 4a57361..0d433ac 100644 --- a/src/core/jobs.ts +++ b/src/core/jobs.ts @@ -814,7 +814,7 @@ export async function editJob(pool: pg.Pool, id: string, input: JobInput): Promi salary_period = $12, salary_equity = $13, salary_unpaid = $14, tags = $15, stack = $16, requirements = $17, responsibilities = $18, agent_policy = $19, expires_at = $20, pay_lines = $21, pay_method = $22, - updated_at = now() + apply_schema = $23, updated_at = now() where id = $1`, [ id, @@ -839,6 +839,7 @@ export async function editJob(pool: pg.Pool, id: string, input: JobInput): Promi input.expiresAt, JSON.stringify(input.pay.lines), input.pay.method, + JSON.stringify(input.apply.schema), ], ); return getJobById(pool, id); @@ -911,6 +912,7 @@ export async function patchJob( if (fields.has('requirements')) set('requirements', input.requirements); if (fields.has('responsibilities')) set('responsibilities', input.responsibilities); if (fields.has('agentPolicy')) set('agent_policy', input.agentPolicy); + if (fields.has('applySchema')) set('apply_schema', JSON.stringify(input.apply.schema)); if (fields.has('expiresAt')) set('expires_at', input.expiresAt); if (fields.has('pay')) { const salary = salaryFromPay(input.pay); diff --git a/src/server/routes/api.ts b/src/server/routes/api.ts index b6f9a1f..531c785 100644 --- a/src/server/routes/api.ts +++ b/src/server/routes/api.ts @@ -270,6 +270,7 @@ const JOB_PATCH_FIELDS: Record = { requirements: 'requirements', responsibilities: 'responsibilities', agentPolicy: 'agentPolicy', + applySchema: 'applySchema', expiresAt: 'expiresAt', }; diff --git a/test/api.test.ts b/test/api.test.ts index 3de094e..0401190 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -3197,6 +3197,19 @@ describe('the API', { skip: reason === '' ? false : `no database: ${reason}` }, assert.deepEqual(edited.job.apply.schema.fields, [ { name: 'portfolio', label: 'Portfolio link', type: 'url', required: true, maxLength: 500 }, ]); + + // Sending applySchema replaces it; it used to be validated and dropped. + const rescoped = (await ( + await patch( + `/api/v1/jobs/${created.job.slug}`, + { applySchema: { fields: [{ name: 'github', label: 'GitHub', type: 'url', required: true }] } }, + auth, + ) + ).json()) as { job: { apply: { schema: { fields: { name: string }[] } } } }; + assert.deepEqual( + rescoped.job.apply.schema.fields.map((field) => field.name), + ['github'], + ); }); test("editing someone else's listing is refused", async () => { diff --git a/test/job-patch-fields.test.ts b/test/job-patch-fields.test.ts index 5fa752a..248f7bb 100644 --- a/test/job-patch-fields.test.ts +++ b/test/job-patch-fields.test.ts @@ -180,3 +180,20 @@ test('a patch with no recognised fields issues no update', async () => { assert.ok(!queries.some((sql) => sql.trim().startsWith('update jobs'))); assert.equal(result?.title, 'Backend Engineer'); }); + +test('a patch that sends applySchema writes it', async () => { + const job = jobRow(); + const queries: string[] = []; + const schema = { fields: [{ name: 'portfolio', label: 'Portfolio', type: 'url' as const, required: true }] }; + await patchJob( + fakePool(job, queries) as never, + 'job-1', + input({ apply: { via: 'board', schema } as JobInput['apply'] }), + new Set(['applySchema']), + ); + + const sql = updateSql(queries); + assert.match(sql, /apply_schema = \$\d+/); + assert.ok(!sql.includes('title ='), 'an applySchema patch must not rewrite the title'); + assert.deepEqual(JSON.parse(job['apply_schema'] as string), schema); +});