Stressfrei-Adressen: Duplikate beim Anlegen ablehnen
Bug: dieselbe E-Mail-Adresse konnte beim selben Kunden mehrfach angelegt werden – im Screenshot zwei identische Einträge nach einem Doppel-Submit. - createEmail: findFirst auf (customerId, email) case-insensitive, bei Treffer ApiError(409). Eigene Meldung für inaktive Duplikate (Hinweis: alten Eintrag reaktivieren statt neu anlegen). - updateEmail: gleicher Check beim Umbenennen, NOT id-Exclude. - Controller: catch-Blöcke honorieren ApiError.statusCode (vorher pauschal 400) → 409 kommt sauber an die UI durch. - Frontend: updateMutation bekam onError, damit der Fehler nicht schlucken bleibt.
This commit is contained in:
@@ -84,7 +84,8 @@ export async function createEmail(req: Request, res: Response): Promise<void> {
|
||||
});
|
||||
res.status(201).json({ success: true, data: email } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
const status = error instanceof ApiError ? error.statusCode : 400;
|
||||
res.status(status).json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Stressfrei-Wechseln Adresse',
|
||||
} as ApiResponse);
|
||||
@@ -104,7 +105,8 @@ export async function updateEmail(req: AuthRequest, res: Response): Promise<void
|
||||
});
|
||||
res.json({ success: true, data: email } as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
const status = error instanceof ApiError ? error.statusCode : 400;
|
||||
res.status(status).json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Stressfrei-Wechseln Adresse',
|
||||
} as ApiResponse);
|
||||
|
||||
@@ -152,6 +152,27 @@ export interface CreateEmailData {
|
||||
export async function createEmail(data: CreateEmailData) {
|
||||
const { provisionAtProvider, createMailbox, ...emailData } = data;
|
||||
|
||||
// Duplikatscheck: pro Kunde darf eine Stressfrei-Adresse nur einmal
|
||||
// existieren. Case-insensitive, weil RFC-localpart-Großschreibung in
|
||||
// der Praxis nie semantischen Unterschied macht und der Provider eh
|
||||
// einheitlich lowercased.
|
||||
const normalized = data.email.trim().toLowerCase();
|
||||
const conflict = await prisma.stressfreiEmail.findFirst({
|
||||
where: {
|
||||
customerId: data.customerId,
|
||||
email: { equals: normalized },
|
||||
},
|
||||
select: { id: true, isActive: true },
|
||||
});
|
||||
if (conflict) {
|
||||
const hint = conflict.isActive
|
||||
? 'Diese E-Mail-Adresse ist bei diesem Kunden bereits angelegt.'
|
||||
: 'Diese E-Mail-Adresse existiert bei diesem Kunden bereits (deaktiviert). Bitte reaktiviere den vorhandenen Eintrag, statt einen neuen anzulegen.';
|
||||
throw new ApiError(409, hint);
|
||||
}
|
||||
// Wert in DB ist eh schon lowercase – wir setzen es einheitlich.
|
||||
emailData.email = normalized;
|
||||
|
||||
// Falls beim Provider anlegen gewünscht
|
||||
if (provisionAtProvider) {
|
||||
// Kunde laden für Weiterleitung
|
||||
@@ -222,6 +243,34 @@ export async function updateEmail(
|
||||
isActive?: boolean;
|
||||
}
|
||||
) {
|
||||
// Beim Umbenennen der E-Mail-Adresse erneut Kollisionscheck. Sonst
|
||||
// kann man eine zweite Adresse mit identischer Mail beim selben Kunden
|
||||
// anlegen (Umweg um den Create-Check).
|
||||
if (typeof data.email === 'string' && data.email.trim() !== '') {
|
||||
const normalized = data.email.trim().toLowerCase();
|
||||
const current = await prisma.stressfreiEmail.findUnique({
|
||||
where: { id },
|
||||
select: { customerId: true, email: true },
|
||||
});
|
||||
if (!current) {
|
||||
throw new ApiError(404, 'StressfreiEmail nicht gefunden');
|
||||
}
|
||||
if (normalized !== current.email.toLowerCase()) {
|
||||
const conflict = await prisma.stressfreiEmail.findFirst({
|
||||
where: {
|
||||
customerId: current.customerId,
|
||||
email: { equals: normalized },
|
||||
NOT: { id },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (conflict) {
|
||||
throw new ApiError(409, 'Diese E-Mail-Adresse ist bei diesem Kunden bereits angelegt.');
|
||||
}
|
||||
}
|
||||
data.email = normalized;
|
||||
}
|
||||
|
||||
return prisma.stressfreiEmail.update({
|
||||
where: { id },
|
||||
data,
|
||||
|
||||
Reference in New Issue
Block a user