diff --git a/server/services/repoAssignMail.js b/server/services/repoAssignMail.js index 6d49ca4..6588e8c 100644 --- a/server/services/repoAssignMail.js +++ b/server/services/repoAssignMail.js @@ -33,6 +33,7 @@ export function shouldSendAssignMail(project, repo, { now = new Date(), createdN /** Erinnerung faellig: Mail ging vor >= 24 h, Art fehlt noch, noch keine Erinnerung. */ export function dueReminder(project, { now = new Date() } = {}) { if (project?.kind || project?.assignReminderSentAt) return false + if (Number(project?.assignMailAttempts || 0) >= MAX_ATTEMPTS) return false const sent = time(project?.assignMailSentAt) if (sent === null) return false return new Date(now).getTime() - sent >= DAY_MS @@ -73,6 +74,8 @@ export async function sendRepoAssignMail(project, { giteaLogin, reminder = false await updateDocument(config.collections.websiteProjects, project.$id, patch) return { sent: false, reason: err.message } } + // assignMailAttempts zaehlt die Versuche der aktuellen Mail: nach Erfolg zurueck auf 0 (R7) + patch.assignMailAttempts = 0 patch[reminder ? 'assignReminderSentAt' : 'assignMailSentAt'] = new Date().toISOString() await updateDocument(config.collections.websiteProjects, project.$id, patch) return { sent: true } diff --git a/test/repoAssignMail.test.js b/test/repoAssignMail.test.js index caf340b..70ab8f7 100644 --- a/test/repoAssignMail.test.js +++ b/test/repoAssignMail.test.js @@ -58,6 +58,8 @@ test('dueReminder: genau nach 24 h, ohne Art, ohne frühere Erinnerung', () => { assert.equal(dueReminder({}, { now: NOW }), false) assert.equal(dueReminder({ ...base, kind: 'app' }, { now: NOW }), false) assert.equal(dueReminder({ ...base, assignReminderSentAt: hoursAgo(1) }, { now: NOW }), false) + assert.equal(dueReminder({ ...base, assignMailAttempts: 3 }, { now: NOW }), false) + assert.equal(dueReminder({ ...base, assignMailAttempts: 2 }, { now: NOW }), true) }) test('T16: rendert ohne Probleme, Betreff mit und ohne Erinnerung', () => { @@ -86,7 +88,7 @@ test('sendRepoAssignMail: Mail mit exaktem Link, setzt assignMailSentAt + Versuc assert.match(sink.sent[0].html, /30\.09\.2026 16:46/) const d = await doc('p1') assert.ok(d.assignMailSentAt) - assert.equal(d.assignMailAttempts, 1) + assert.equal(d.assignMailAttempts, 0, 'Erfolg setzt den Zähler zurück') }) test('sendRepoAssignMail: Erinnerung setzt assignReminderSentAt', async () => { @@ -97,7 +99,7 @@ test('sendRepoAssignMail: Erinnerung setzt assignReminderSentAt', async () => { assert.match(sink.sent[0].subject, /^Erinnerung: Neues Repo zuordnen/) const d = await doc('p1') assert.ok(d.assignReminderSentAt) - assert.equal(d.assignMailAttempts, 2) + assert.equal(d.assignMailAttempts, 0) }) test('sendRepoAssignMail: unbekannter Login → no_employee, kein Zähler', async () => { @@ -119,3 +121,16 @@ test('sendRepoAssignMail: SMTP-Fehler zählt Versuch, setzt kein SentAt, wirft n assert.equal(d.assignMailAttempts, 2) assert.equal(d.assignMailSentAt, undefined) }) + +test('fehlgeschlagene Erinnerung zählt hoch und endet nach 3 Versuchen', async () => { + setMailTransportForTests({ sendMail: async () => { throw new Error('SMTP kaputt') } }) + let project = projectDoc({ $id: 'p2', assignMailSentAt: hoursAgo(25), assignMailAttempts: 0 }) + for (let i = 1; i <= 3; i += 1) { + assert.equal(dueReminder(project, { now: NOW }), true) + const r = await sendRepoAssignMail(project, { giteaLogin: 'knso', reminder: true }) + assert.equal(r.sent, false) + project = { ...project, ...(await doc('p2')) } + assert.equal(project.assignMailAttempts, i) + } + assert.equal(dueReminder(project, { now: NOW }), false) +})