714f731ac9
Neue Felder loginHintDirectory/loginHintLocal (Platzhalter, Pflicht, max. 1000), Migration 20260930170000 (nullable, leer = Standard aus @tessera/shared). Knopf Passwort festlegen und Gueltigkeitshinweis bleiben fest; local-no-link wird nie erzeugt und bleibt fest. Vorschau springt beim Bearbeiten auf die passende Kontoart. Lokal im Browser nachgewiesen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { DEFAULT_WELCOME_MAIL_TEXTS, type WelcomeMailTexts } from '@tessera/shared';
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
import { forTenant } from '../prisma/prisma-tenant.extension';
|
|
|
|
/**
|
|
* WelcomeMailTemplateService — eigene Vorlage der Willkommensmail
|
|
* (Administrator → Willkommensmail).
|
|
*
|
|
* Hoechstens eine Vorlage je Mandant (Tabelle "WelcomeMailTemplate",
|
|
* `tenantId` eindeutig). Gespeichert werden nur die sechs Texte; Kopf,
|
|
* Zugangsdaten, Knoepfe und Fusszeile bleiben fest in
|
|
* `welcome-mail.template.ts`. Fehlt die Vorlage, gelten
|
|
* `DEFAULT_WELCOME_MAIL_TEXTS` aus `@tessera/shared`. Die zwei
|
|
* Anmeldehinweise kamen spaeter hinzu (Spalten nullable): fehlt ein Wert in
|
|
* einer aelteren Vorlage, gilt fuer ihn der Standardtext.
|
|
*
|
|
* Mandantenbindung: jeder Zugriff laeuft ueber `forTenant(prisma, tenantId)`.
|
|
* Beim Versand ist `tenantId` der Mandant des ZIEL-Benutzers
|
|
* (`WelcomeMailService.send`), in der Verwaltung der Mandant des
|
|
* angemeldeten Administrators (`WelcomeMailTemplateController`). Die
|
|
* Platzhalter-Pruefung liegt im DTO (400 bei unbekanntem Platzhalter).
|
|
*/
|
|
|
|
/** Antwort von GET /welcome-mail-template. */
|
|
export interface WelcomeMailTemplateState {
|
|
/** `true` = eigene Vorlage gespeichert, `false` = Standardtexte. */
|
|
custom: boolean;
|
|
/** Wirksame Texte (eigene Vorlage oder Standard) — Vorbelegung im Formular. */
|
|
texts: WelcomeMailTexts;
|
|
/** Standardtexte fuer "Auf Standard zuruecksetzen". */
|
|
defaults: WelcomeMailTexts;
|
|
updatedAt: Date | null;
|
|
updatedBy: string | null;
|
|
}
|
|
|
|
const TEXT_SELECT = {
|
|
subject: true,
|
|
heading: true,
|
|
intro: true,
|
|
loginHintDirectory: true,
|
|
loginHintLocal: true,
|
|
closing: true,
|
|
updatedAt: true,
|
|
updatedBy: true,
|
|
} as const;
|
|
|
|
@Injectable()
|
|
export class WelcomeMailTemplateService {
|
|
constructor(private readonly prisma: PrismaService) {}
|
|
|
|
async getState(tenantId: string): Promise<WelcomeMailTemplateState> {
|
|
const tenantPrisma = forTenant(this.prisma, tenantId);
|
|
const row = await tenantPrisma.welcomeMailTemplate.findUnique({
|
|
where: { tenantId },
|
|
select: TEXT_SELECT,
|
|
});
|
|
const defaults = { ...DEFAULT_WELCOME_MAIL_TEXTS };
|
|
if (!row) {
|
|
return { custom: false, texts: defaults, defaults, updatedAt: null, updatedBy: null };
|
|
}
|
|
return {
|
|
custom: true,
|
|
texts: {
|
|
subject: row.subject,
|
|
heading: row.heading,
|
|
intro: row.intro,
|
|
loginHintDirectory: row.loginHintDirectory?.trim()
|
|
? row.loginHintDirectory
|
|
: defaults.loginHintDirectory,
|
|
loginHintLocal: row.loginHintLocal?.trim() ? row.loginHintLocal : defaults.loginHintLocal,
|
|
closing: row.closing,
|
|
},
|
|
defaults,
|
|
updatedAt: row.updatedAt,
|
|
updatedBy: row.updatedBy,
|
|
};
|
|
}
|
|
|
|
/** Texte fuer den Versand: eigene Vorlage des Mandanten, sonst `null` (= Standard). */
|
|
async getCustomTexts(tenantId: string): Promise<WelcomeMailTexts | null> {
|
|
const state = await this.getState(tenantId);
|
|
return state.custom ? state.texts : null;
|
|
}
|
|
|
|
/** Name des Mandanten fuer `{{firma}}`; leer, wenn der Mandant fehlt. */
|
|
async getTenantName(tenantId: string): Promise<string> {
|
|
const tenantPrisma = forTenant(this.prisma, tenantId);
|
|
const tenant = await tenantPrisma.tenant.findUnique({
|
|
where: { id: tenantId },
|
|
select: { name: true },
|
|
});
|
|
return tenant?.name ?? '';
|
|
}
|
|
|
|
async save(
|
|
tenantId: string,
|
|
texts: WelcomeMailTexts,
|
|
updatedBy: string,
|
|
): Promise<WelcomeMailTemplateState> {
|
|
const tenantPrisma = forTenant(this.prisma, tenantId);
|
|
const data = {
|
|
subject: texts.subject,
|
|
heading: texts.heading,
|
|
intro: texts.intro,
|
|
loginHintDirectory: texts.loginHintDirectory,
|
|
loginHintLocal: texts.loginHintLocal,
|
|
closing: texts.closing,
|
|
updatedBy,
|
|
};
|
|
await tenantPrisma.welcomeMailTemplate.upsert({
|
|
where: { tenantId },
|
|
create: { tenantId, ...data },
|
|
update: data,
|
|
});
|
|
return this.getState(tenantId);
|
|
}
|
|
|
|
/** "Auf Standard zuruecksetzen": loescht die eigene Vorlage (idempotent). */
|
|
async reset(tenantId: string): Promise<WelcomeMailTemplateState> {
|
|
const tenantPrisma = forTenant(this.prisma, tenantId);
|
|
await tenantPrisma.welcomeMailTemplate.deleteMany({ where: { tenantId } });
|
|
return this.getState(tenantId);
|
|
}
|
|
}
|