From 4a54d31bd0cba2c4e559b7a62fb22efc85d5ea1f Mon Sep 17 00:00:00 2001 From: Joachim Hummel Date: Fri, 17 Apr 2026 09:55:45 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20updateCampaignStatus=20=C3=BCberschreibt?= =?UTF-8?q?=20keine=20bestehenden=20Scheduling-Daten,=20fehlende=20Tests?= =?UTF-8?q?=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/db/campaigns.test.ts | 23 +++++++++++++++++++++++ src/server/db/campaigns.ts | 19 ++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/server/db/campaigns.test.ts b/src/server/db/campaigns.test.ts index 74c475e..f25d59e 100644 --- a/src/server/db/campaigns.test.ts +++ b/src/server/db/campaigns.test.ts @@ -102,6 +102,13 @@ describe('updateCampaign', () => { const result = await updateCampaign('tenant1', 'uuid-1', {}) expect(result.ok).toBe(false) }) + + it('gibt err zurück wenn Kampagne nicht im Draft-Status', async () => { + mockClient.query.mockResolvedValueOnce([]) + const result = await updateCampaign('tenant1', 'uuid-1', { name: 'Neu' }) + expect(result.ok).toBe(false) + if (!result.ok) expect(result.error.message).toContain('Draft-Status') + }) }) describe('updateCampaignStatus', () => { @@ -119,4 +126,20 @@ describe('updateCampaignStatus', () => { const result = await updateCampaignStatus('tenant1', 'uuid-1', 'sent') expect(result.ok).toBe(false) }) + + it('setzt scheduledAt ohne cron_expression zu überschreiben', async () => { + const scheduled = new Date('2026-05-01T09:00:00Z') + mockClient.query.mockResolvedValueOnce([{ ...mockRow, status: 'scheduled', scheduled_at: scheduled }]) + const result = await updateCampaignStatus('tenant1', 'uuid-1', 'scheduled', { scheduledAt: scheduled }) + expect(result.ok).toBe(true) + expect(mockClient.query).toHaveBeenCalledWith( + expect.stringContaining('scheduled_at'), + expect.arrayContaining([scheduled]) + ) + // cron_expression darf NICHT im Query sein + expect(mockClient.query).not.toHaveBeenCalledWith( + expect.stringContaining('cron_expression'), + expect.anything() + ) + }) }) diff --git a/src/server/db/campaigns.ts b/src/server/db/campaigns.ts index 67bdfac..e723fff 100644 --- a/src/server/db/campaigns.ts +++ b/src/server/db/campaigns.ts @@ -99,12 +99,25 @@ export async function updateCampaignStatus( status: CampaignStatus, extra?: { scheduledAt?: Date; cronExpression?: string } ): Promise> { + const fields: string[] = ['status = $1'] + const values: unknown[] = [status] + let idx = 2 + + if (extra?.scheduledAt !== undefined) { + fields.push(`scheduled_at = $${idx++}`) + values.push(extra.scheduledAt) + } + if (extra?.cronExpression !== undefined) { + fields.push(`cron_expression = $${idx++}`) + values.push(extra.cronExpression) + } + + values.push(id) try { const rows = await withTenant(tenantId, (client) => client.query( - `UPDATE campaigns SET status = $1, scheduled_at = $2, cron_expression = $3 - WHERE id = $4 RETURNING *`, - [status, extra?.scheduledAt ?? null, extra?.cronExpression ?? null, id] + `UPDATE campaigns SET ${fields.join(', ')} WHERE id = $${idx} RETURNING *`, + values ) ) if (rows.length === 0) return err(new Error('Kampagne nicht gefunden'))