feat(intake): record whether the submitter asked for a cut-out (#281)
The public intake POST now reads a `removeBackground` multipart field and stores it on the new `item_drafts.remove_background` column. The checkbox on the submission page is ticked by default, so a client that sends nothing gets `true` — only the exact string `'false'` opts out, so a stray or unexpected value is treated as consent rather than a silent refusal. The GET now also reports `backgroundRemoval: isRembgConfigured()` alongside the label, so the submission page knows up front whether the feature exists in this environment at all. Neither handler calls the sidecar or the AI — this task only records intent for the drafting worker to act on later, and the existing ordering of `requireUsableLink` and `requireCapacity` ahead of `uploadImages` is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,13 @@ async function issueLink(label = 'Sarah', maxSubmissions?: number | null): Promi
|
||||
return res.body.token as string;
|
||||
}
|
||||
|
||||
/** A submission with optional extra multipart fields beside the photo. */
|
||||
function postPhoto(token: string, fields: Record<string, string> = {}) {
|
||||
const req = request(app).post(`/api/intake/${token}`);
|
||||
for (const [name, value] of Object.entries(fields)) void req.field(name, value);
|
||||
return req.attach('images', PNG, 'a.png');
|
||||
}
|
||||
|
||||
describe('checking a link before showing the form', () => {
|
||||
it('names the link so the page can greet the sender', async () => {
|
||||
const token = await issueLink('Sarah');
|
||||
@@ -207,3 +214,62 @@ describe('a submitted item does not reach the storefront', () => {
|
||||
expect(res.body).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the background-removal intent', () => {
|
||||
// Ticked by default on the page, so absent means yes. An older client or a
|
||||
// curl call then behaves like the current default rather than silently
|
||||
// opting out of something every other submission gets.
|
||||
it('defaults to true when the field is not sent', async () => {
|
||||
const token = await issueLink();
|
||||
await postPhoto(token);
|
||||
|
||||
const { rows } = await pool.query<{ remove_background: boolean }>(
|
||||
`SELECT remove_background FROM item_drafts ORDER BY id DESC LIMIT 1`
|
||||
);
|
||||
expect(rows[0]?.remove_background).toBe(true);
|
||||
});
|
||||
|
||||
it('records a submitter who unticked it', async () => {
|
||||
const token = await issueLink();
|
||||
await postPhoto(token, { removeBackground: 'false' });
|
||||
|
||||
const { rows } = await pool.query<{ remove_background: boolean }>(
|
||||
`SELECT remove_background FROM item_drafts ORDER BY id DESC LIMIT 1`
|
||||
);
|
||||
expect(rows[0]?.remove_background).toBe(false);
|
||||
});
|
||||
|
||||
// Only the exact string opts out. A stray value is not a considered "no",
|
||||
// and reading it as one would quietly deny somebody something they asked for.
|
||||
it('treats anything other than "false" as consent', async () => {
|
||||
const token = await issueLink();
|
||||
await postPhoto(token, { removeBackground: 'no' });
|
||||
|
||||
const { rows } = await pool.query<{ remove_background: boolean }>(
|
||||
`SELECT remove_background FROM item_drafts ORDER BY id DESC LIMIT 1`
|
||||
);
|
||||
expect(rows[0]?.remove_background).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('what the submission page is told', () => {
|
||||
it('says the feature is off when there is no sidecar', async () => {
|
||||
delete process.env.REMBG_URL;
|
||||
const token = await issueLink();
|
||||
|
||||
const res = await request(app).get(`/api/intake/${token}`);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.backgroundRemoval).toBe(false);
|
||||
});
|
||||
|
||||
it('says it is on when there is one', async () => {
|
||||
process.env.REMBG_URL = 'http://rembg-syn:7000';
|
||||
const token = await issueLink();
|
||||
|
||||
const res = await request(app).get(`/api/intake/${token}`);
|
||||
|
||||
expect(res.body.backgroundRemoval).toBe(true);
|
||||
delete process.env.REMBG_URL;
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user