Compare commits

..

38 Commits

Author SHA1 Message Date
duffyduck 50b0e56a84 update todo.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:18:33 +02:00
duffyduck 29eceef26b PDF-Auftragsvorlagen-System, Objekttyp/Lage-Felder, Eigentümer-Fallback bei Bankverbindung
- PDF-Template-Editor in Einstellungen: Vorlagen hochladen, Formularfelder automatisch auslesen, CRM-Felder zuordnen
- PDF-Vorschau mit annotierten Feldnamen, seitenweise Sortierung der Felder
- Auftrag generieren aus Vertragsdaten (Button im Vertrags-Detail)
- Dynamische Rufnummern-Felder mit Vorwahl-Extraktion und konfigurierbarer Maximalanzahl
- Nicht zugeordnete Felder bleiben editierbar im generierten PDF
- Eigentümer-Felder mit Namens-Kombinationen (Firma+Name etc.) und Fallback auf Kundendaten
- Stressfrei-E-Mail als Feld-Option im Template-Editor
- Objekttyp, Lage und Lage des Anschlusses als neue Felder bei Festnetz-Verträgen (DSL, Glasfaser, Kabel)
- Bankverbindung-Fallback: wenn keine am Vertrag verknüpft, wird automatisch die neueste aktive des Kunden genommen

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:16:47 +02:00
duffyduck 5e9e553882 delete test pdf 2026-03-27 12:12:22 +01:00
duffyduck 5b85bea4eb email datenschztz erst alles bestätigt bei allen hebeln 2026-03-27 12:03:20 +01:00
duffyduck 3dd4f7b656 added place to telecommunication, added contract documents, added invoice to other contracts 2026-03-25 16:55:48 +01:00
duffyduck eaa94e766a impressum datenschutz added 2026-03-25 15:25:34 +01:00
duffyduck 219e1930f7 complete new audit system 2026-03-21 18:23:54 +01:00
duffyduck 4f359df161 Datenschutz vollmacht fixed, two time counter added 2026-03-21 16:42:31 +01:00
duffyduck 0121c82412 fixed back button with source, and customer in customer lsit clickable 2026-03-21 12:16:04 +01:00
duffyduck a9643206bb fixed all back buttons 2026-03-21 12:03:32 +01:00
duffyduck f2876f877e gdpr audit implemented, email log, vollmachten, pdf delete cancel data privacy and vollmachten, removed message no id card in engergy car, and other contracts that are not telecom contracts, added insert counter for engery 2026-03-21 11:59:53 +01:00
duffyduck 89cf92eaf5 added docker setup 2026-02-08 19:59:49 +01:00
duffyduck dd4d57fa1b added recovery entires, changed recovery icon 2026-02-08 19:43:46 +01:00
duffyduck e348e86c60 added contract history 2026-02-08 19:24:37 +01:00
duffyduck ee4f1aacdd added date at support ticket, new order support tickets, delete edit support ticktes only from enploye and admins 2026-02-08 18:26:34 +01:00
duffyduck 06489299d5 contractnumber provider added, old provider number field only if no previous contact exist 2026-02-08 14:34:56 +01:00
duffyduck 4442ab08b3 readme updated 2026-02-08 13:14:24 +01:00
duffyduck efe8ac25cb snooze vor expired, contracts, display snoozed contracts if an item is missing, un snooze implemented, fixed invoice upload bug 2026-02-08 13:08:58 +01:00
duffyduck 3a9fcc5ec9 fixed issue stressfrei adress as username not filled oin cockpit 2026-02-08 09:09:00 +01:00
duffyduck d400c90e6a updated readme.md 2026-02-08 01:21:00 +01:00
duffyduck aee48a8ccb added invoices and status in cockpit, created info button for contract status types 2026-02-08 01:18:12 +01:00
duffyduck 1ad4fe0819 addes cost and usage calculation 2026-02-06 00:14:38 +01:00
duffyduck b281801cdb added extra field kwh at m3, expand cost field to 10 komma, added maloid,counter add dialog, auto set unit 2026-02-05 20:34:45 +01:00
duffyduck af2f444a24 contractmodaldetail date format and before contract and next contract question to add 2026-02-04 21:17:13 +01:00
duffyduck 2d052c76d9 save email as pdf likae attachment version 2 2026-02-04 19:49:09 +01:00
duffyduck d98c97a81f remove uploads from repo but keep empty folder 2026-02-04 19:19:18 +01:00
duffyduck 06d45734ce save email as pdf like an attachment 2026-02-04 19:18:32 +01:00
duffyduck b968e6b46d added tree view to customer portal, in employe its uses still list 2026-02-04 16:30:49 +01:00
duffyduck 312e879221 seperate delivery and billig adresses in contract added 2026-02-04 08:48:25 +01:00
duffyduck fdef6d1d3b fixed, bankcard, adresses, id card, tarif name dropdown menu in edit mode 2026-02-04 08:37:46 +01:00
duffyduck 2b23ed64c4 added new view in contracts customer and contracts 2026-02-04 00:52:04 +01:00
duffyduck 97b4670643 save attachment from email in customer data and - or contracts 2026-02-03 23:58:00 +01:00
duffyduck 9a014c100b update readme.md 2026-02-03 23:08:08 +01:00
duffyduck 6f3ab288ed all email views the same 2026-02-03 23:04:42 +01:00
duffyduck ee8bd7a8f7 optimize password view in stressfrei addresses 2026-02-03 15:43:00 +01:00
duffyduck e4fdfbc95f added backup and email client 2026-02-01 00:02:35 +01:00
duffyduck ff857be01a imapclient feature plan 2026-01-29 01:34:43 +01:00
Stefan Hacker 31f807fbd0 first commit 2026-01-29 01:16:54 +01:00
13559 changed files with 2731722 additions and 11984 deletions
-9
View File
@@ -46,15 +46,6 @@ backups
backend/uploads
backend/backups
# Daten-Verzeichnis (Bind-Mounts zur Laufzeit, nicht im Build-Context)
data/
# Plesk-Test (nicht für Container)
plesktest/
# Backup-Klone des Repos
opencrm-backup-*/
# Prisma migrations (included, but not dev db)
*.db
*.db-journal
-76
View File
@@ -1,76 +0,0 @@
# OpenCRM zentrale Konfiguration
# ==================================
# Kopiere diese Datei zu .env und passe die Werte an.
# Diese .env wird sowohl vom Backend (npm run dev) als auch von Docker
# Compose verwendet.
# ============== PORTS (extern erreichbar auf dem Host) ==============
OPENCRM_PORT=3010 # Backend + Frontend (alles unter einer URL)
ADMINER_PORT=8090 # Adminer (Datenbank-UI). 8081 ist häufig schon belegt.
DB_PORT=3306 # MariaDB extern (für lokale Tools/Dev). 0 = nicht freigeben.
# ============== DATEN-PFADE (Bind-Mounts) ==============
# Relativ zum Projektverzeichnis. Werden zur Laufzeit angelegt.
DATA_DIR=./data
DB_DATA_DIR=./data/db
UPLOADS_DIR=./data/uploads
FACTORY_DEFAULTS_DIR=./data/factory-defaults
BACKUPS_DIR=./data/backups
# ============== DATENBANK ==============
# Der App-User (DB_USER) wird beim ersten Start automatisch von MariaDB
# angelegt (über MARIADB_USER/MARIADB_PASSWORD im docker-compose) mit
# GRANT ALL PRIVILEGES auf ${DB_NAME}.*. Damit nutzt das Backend NICHT root.
# DB_ROOT_PASSWORD ist nur für Adminer / Notfall-Wartung.
DB_HOST=localhost # Im Container überschreibt docker-compose das auf "db"
DB_NAME=opencrm
DB_USER=opencrm
DB_PASSWORD=change-this-password
DB_ROOT_PASSWORD=change-this-root-password
# Connection-String wird aus den DB_*-Komponenten zusammengebaut (dotenv-expand).
# Manuell überschreiben nur wenn Sonderfälle (z.B. extra Query-Parameter).
# Hinweis: für lokales Dev mit MariaDB im Container nutze DB_HOST=localhost,
# weil docker-compose den DB-Port auf 127.0.0.1:DB_PORT mappt.
DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
# ============== SECURITY ==============
# JWT-Secret: min. 32 Zeichen. Generieren: openssl rand -hex 64
JWT_SECRET=change-this-to-a-very-long-random-secret-please-rotate-before-production
JWT_EXPIRES_IN=7d
# Encryption-Key für Portal-Credentials: GENAU 64 Hex-Zeichen.
# Generieren: openssl rand -hex 32
ENCRYPTION_KEY=change-this-to-64-hex-characters-please-rotate-before-production-xx
# Server
NODE_ENV=development
PORT=3001 # Backend-internal Port (Dev: localhost:3001)
LISTEN_ADDR=0.0.0.0 # In Docker = 0.0.0.0, in Bare-Metal-Production = 127.0.0.1
# CORS nur in Production setzen, wenn Frontend auf separater Domain läuft.
# Beispiel: CORS_ORIGINS=https://crm.deine-domain.de
# CORS_ORIGINS=
# HTTPS-only-Header (HSTS + upgrade-insecure-requests) NUR aktivieren, wenn
# wirklich ein TLS-Proxy (Caddy/Traefik/Nginx) vor OpenCRM steht. Sonst sperrt
# sich der Browser bei direktem http://ip:port-Zugriff selbst aus
# (ERR_SSL_PROTOCOL_ERROR auf den Assets).
HTTPS_ENABLED=false
# ============== ADMINER (DB-UI) ==============
# Theme-Auswahl. Verfügbare Designs im offiziellen adminer:latest Image:
# adminer-dark, brade, bueltge, dracula, esterka, flat, galkaev,
# haeckel, hever, konya, lavender-light, lucas-sandery, mancave,
# mvt, nette, ng9, nicu, pappu687, paranoiq, pepa-linha, pokorny,
# price, rmsoft, rmsoft_blue, rmsoft_blue-dark, win98
# Empfehlung: dracula (dark) oder adminer-dark beide modern.
ADMINER_DESIGN=dracula
# ============== SEED ==============
# Bei leerer DB seedet der Container automatisch (legt admin@admin.com / admin
# + Stammdaten an) nichts zu konfigurieren.
# Nur wenn man eine NICHT-leere DB nochmal forciert seeden will (z.B. nach
# Reset / Stammdaten-Update), kurz auf 'true' setzen, neu starten, dann
# wieder zurück.
RUN_SEED=false
-41
View File
@@ -1,41 +0,0 @@
# Root-Gitignore: gemeinsame Patterns für Repo-Root + nested Verzeichnisse
# (backend/, frontend/, docker/ haben zusätzlich eigene .gitignore-Files)
# Environment echte Secrets blocken, .env.example weiter mittracken
.env
.env.local
.env.*.local
!.env.example
# OS
.DS_Store
Thumbs.db
# IDE
.idea/
.vscode/
*.swp
*.swo
# Logs
*.log
npm-debug.log*
# Temp
tmp/
*.tmp
*.bak
# Docker-Bind-Mounts: Inhalt nicht tracken, Verzeichnisstruktur via .gitkeep behalten
data/db/*
!data/db/.gitkeep
data/uploads/*
!data/uploads/.gitkeep
data/factory-defaults/*
!data/factory-defaults/.gitkeep
data/backups/*
!data/backups/.gitkeep
# Factory-Defaults-Drop-Box (Export-ZIPs zwischen dev/prod hin und her)
factory-exports/*
!factory-exports/.gitkeep
+13 -408
View File
@@ -2,8 +2,6 @@
Web-basiertes CRM-System für Kundenverwaltung mit Verträgen (Energie, Telekommunikation, KFZ-Versicherung).
**Version: 1.1.0** ([Changelog](#changelog))
## Features
- **Kundenverwaltung**: Privat- und Geschäftskunden mit Stammdaten
@@ -13,9 +11,6 @@ Web-basiertes CRM-System für Kundenverwaltung mit Verträgen (Energie, Telekomm
- **Zähler**: Strom-/Gaszähler mit Zählerstandhistorie
- **Rechnungen**: Rechnungsverwaltung für Energieverträge mit Dokumenten-Upload
- **Vertrags-Cockpit**: Dashboard zur Überwachung offener Aufgaben (fehlende Dokumente, Rechnungen)
- **Auto-Vertragsstatus**: Lieferbestätigung-Upload setzt `DRAFT``ACTIVE` (mit Vertragsbeginn),
Kündigungsbestätigung-Upload setzt `ACTIVE``CANCELLED` (mit Datum),
nightly-Cron setzt `ACTIVE`-Verträge mit abgelaufenem `endDate` auf `EXPIRED`
- **Verträge**:
- Energie (Strom, Gas)
- Telekommunikation (DSL, Glasfaser, Mobilfunk, TV)
@@ -25,14 +20,7 @@ Web-basiertes CRM-System für Kundenverwaltung mit Verträgen (Energie, Telekomm
- **Email-Provisionierung**: Automatische E-Mail-Weiterleitung bei Plesk/cPanel/DirectAdmin
- **Berechtigungssystem**: Admin, Mitarbeiter, Nur-Lesen, Kundenportal
- **Verschlüsselte Zugangsdaten**: Portal-Passwörter AES-256-GCM verschlüsselt
- **DSGVO-Compliance**: Audit-Logging mit Hash-Chain-Integritätsprüfung,
Einwilligungsverwaltung, Datenexport, Löschanfragen
- **Sicherheits-Monitoring**: Realtime-Logging von Login-Fehlversuchen, IDOR-Abwehr,
SSRF-Blocks, JWT-Manipulation; Threshold-Detection (Brute-Force, IDOR-Probing) mit
Sofort-E-Mail-Alerts und stündlichem Digest siehe Einstellungen → Monitoring
- **Production-Hardening**: 10 dokumentierte Hardening-Runden inkl. CORS, Helmet,
IDOR-Schutz, Rate-Limiting, SSRF/DNS-Rebinding-Block, Per-File-Ownership-Check, mehr
in [docs/SECURITY-HARDENING.md](docs/SECURITY-HARDENING.md)
- **DSGVO-Compliance**: Audit-Logging, Einwilligungsverwaltung, Datenexport, Löschanfragen
- **Developer-Tools**: Datenbank-Browser und interaktives ER-Diagramm
## Tech Stack
@@ -47,62 +35,32 @@ Web-basiertes CRM-System für Kundenverwaltung mit Verträgen (Energie, Telekomm
> - Express 4.x → `@types/express@^4.17.x`
> - Express 5.x → `@types/express@^5.x` (erst bei offiziellem Release empfohlen)
## Quick-Start mit Docker (empfohlen)
Komplettes Setup mit MariaDB + OpenCRM + Adminer (DB-UI) in 3 Befehlen:
```bash
git clone <repository-url>
cd opencrm
cp .env.example .env # Werte anpassen, Secrets rotieren!
docker compose up -d
```
Browser:
- **CRM**: http://localhost:3010 (Login: `admin@admin.com` / `admin`)
- **Datenbank-UI** (Adminer): http://localhost:8081 (Server: `db`, User: `root`, DB: `opencrm`)
Alle persistenten Daten liegen in `./data/`:
| Pfad | Inhalt |
|------|--------|
| `./data/db/` | MariaDB-Datafiles |
| `./data/uploads/` | User-Uploads (PDFs, Bilder) |
| `./data/factory-defaults/` | Stammdaten-Kataloge |
| `./data/backups/` | DB-Backups (`npm run db:backup`) |
Ports + Pfade konfigurierst du in `./.env` (Default-Werte siehe `.env.example`).
> **Erste Inbetriebnahme:** In der `.env` einmalig `RUN_SEED=true` setzen,
> `docker compose up -d` ausführen, dann wieder auf `false`. Danach existiert
> der initiale Admin-User `admin@admin.com` / `admin`.
## Voraussetzungen
- Docker & Docker Compose v2
- Für Backend-Entwicklung außerhalb von Docker: Node.js 20+ und npm
- Node.js 18+ (empfohlen: 20+)
- Docker & Docker Compose
- npm
## Installation für Entwicklung (ohne Container)
## Installation
### 1. Repository klonen
```bash
git clone <repository-url>
cd opencrm
cp .env.example .env # Konfiguration anpassen
```
### 2. MariaDB-Container starten
### 2. MariaDB-Datenbank starten
```bash
docker compose up -d db
docker-compose up -d
```
Das startet nur die Datenbank (mit Daten in `./data/db/`).
Konfiguration kommt aus `./.env`:
- **Port:** wie in `DB_PORT` (Standard: 3306, intern auf 127.0.0.1)
- **Datenbank/User/Passwort:** wie in `DB_*`-Variablen
Dies startet einen MariaDB-Container mit:
- **Port:** 3306
- **Datenbank:** opencrm
- **Root-Passwort:** rootpassword
- **Benutzer:** opencrm / opencrm123
Warte ca. 10 Sekunden bis die Datenbank bereit ist.
@@ -182,39 +140,6 @@ Nach dem Seed sind folgende Zugangsdaten verfügbar:
- **E-Mail:** admin@admin.com
- **Passwort:** admin
> **Wichtig:** Vor dem ersten Production-Deployment das Default-Passwort sofort
> ändern und Secrets rotieren siehe [Production-Deployment](#production-deployment).
## Production-Deployment
Vor dem öffentlichen Schalten der Instanz muss in der Production-`.env`:
```env
NODE_ENV=production
# Pflicht-Rotation per `openssl rand` neu generieren!
JWT_SECRET=$(openssl rand -hex 64) # min. 32 Zeichen
ENCRYPTION_KEY=$(openssl rand -hex 32) # genau 64 Hex-Zeichen
# Backend nur lokal lauschen lassen, public-Verkehr läuft über Reverse-Proxy
LISTEN_ADDR=127.0.0.1
# Bei separatem Frontend-Host: erlaubte Origins
CORS_ORIGINS=https://crm.deine-domain.de
```
Plus:
- **Reverse-Proxy** (Nginx/Plesk) so konfigurieren, dass `X-Forwarded-For` hart auf
die echte Client-IP gesetzt wird (nicht nur angefügt) sonst Rate-Limit-Bypass möglich.
- **Default-Admin-Passwort ändern** (admin@admin.com / admin).
- **Manuelle Test-Checkliste** aus [docs/TESTING.md](docs/TESTING.md) einmal komplett
durchklicken.
- **Monitoring konfigurieren**: Einstellungen → Sicherheits-Monitoring → Alert-E-Mail
hinterlegen, Test-Alert senden, Digest aktivieren.
- Vollständige Hardening-Story + restliche Trade-offs:
[docs/SECURITY-HARDENING.md](docs/SECURITY-HARDENING.md)
## Developer-Tools aktivieren
Die Developer-Tools (Datenbankstruktur, ER-Diagramm) sind standardmäßig für Admins verfügbar. Falls der Menüpunkt nicht erscheint:
@@ -245,84 +170,12 @@ Das System unterstützt die automatische Erstellung von E-Mail-Weiterleitungen a
- **Name**: Bezeichnung (z.B. "Plesk Hauptserver")
- **Typ**: Plesk/cPanel/DirectAdmin
- **API-URL**: Server-URL (z.B. `https://server.de:8443`)
- **API-Key** _(empfohlen bei Plesk)_: Key aus Plesk (siehe unten), alternativ Benutzername/Passwort
- **Benutzername/Passwort**: Nur wenn kein API-Key vorhanden
- **Benutzername/Passwort**: API-Zugangsdaten
- **Domain**: E-Mail-Domain (z.B. `stressfrei-wechseln.de`)
- **Standard-Weiterleitung**: Zusätzliche Weiterleitungsadresse (optional)
3. Provider als "Standard" und "Aktiv" markieren
4. Verbindung testen
### Plesk: API-Key anlegen
Der API-Key ist die empfohlene Authentifizierungsmethode (sicherer als Passwort, kann pro
Anwendung vergeben und widerrufen werden).
**Variante 1: Über die Plesk-Oberfläche (einfachster Weg)**
1. In Plesk als Admin einloggen
2. Oben rechts auf den **eigenen Namen** → **"Mein Profil"** (oder direkt URL `/admin/my-profile/`)
3. Tab **"API-Token"** oder **"API-Schlüssel"** öffnen
4. **"API-Schlüssel erstellen"** (bzw. "Add API Key")
5. Beschreibung vergeben (z.B. "OpenCRM")
6. Den angezeigten Schlüssel **sofort kopieren** er wird nur einmal angezeigt!
7. Im CRM bei "API-Key" einfügen
> **Hinweis:** Bei manchen Plesk-Versionen ist die Option unter
> **Tools & Einstellungen** → **API-Schlüssel** oder **Werkzeuge & Einstellungen** →
> **API-Tokens** zu finden. Wenn der Menüpunkt fehlt, muss ggf. die **REST API**
> Extension installiert werden (siehe Variante 2).
**Variante 2: Über die Kommandozeile (SSH als root)**
Falls der API-Key-Button in Plesk nicht vorhanden ist, lässt er sich auch per SSH erstellen:
```bash
# API-Key generieren (läuft nicht ab)
# WICHTIG: -ip-address weglassen, wenn der Key von beliebigen IPs genutzt werden soll!
plesk bin secret_key --create -description "OpenCRM"
# Alternativ mit IP-Einschränkung (nur Zugriffe von dieser IP sind erlaubt):
plesk bin secret_key --create -ip-address <IP-DES-CRM-SERVERS> -description "OpenCRM"
```
> **Achtung:** `-ip-address 0.0.0.0` funktioniert **nicht** wie bei anderen Tools!
> Plesk prüft exakt gegen die eingetragene IP. Für "alle IPs erlauben" muss der
> `-ip-address`-Parameter komplett weggelassen werden.
Der Befehl gibt den Key direkt zurück. Diesen kopieren und im CRM eintragen.
**Alle API-Keys anzeigen:**
```bash
plesk bin secret_key --list
```
**API-Key löschen:**
```bash
plesk bin secret_key --delete <KEY>
```
### Plesk: REST API aktivieren (falls nicht vorhanden)
Bei älteren Plesk-Versionen oder Custom-Installationen kann es sein, dass die
REST API fehlt. Dann:
1. **Tools & Einstellungen** → **Updates** → **Erweiterungen hinzufügen/entfernen**
2. Nach **"REST API"** suchen und installieren
3. Plesk-Neustart (meist nicht nötig, aber zur Sicherheit)
### Plesk: Firewall-Hinweis
Der CRM-Server muss den **Plesk-Port 8443** (Standard) erreichen können. Bei Plesk-Firewall:
1. **Tools & Einstellungen** → **Firewall**
2. **"Plesk-Dienst Panel"** (Port 8443) für die IP des CRM-Servers erlauben
Bei reiner Linux-Firewall (ufw/firewalld):
```bash
# Beispiel ufw
ufw allow from <CRM-SERVER-IP> to any port 8443
```
### Verwendung
Beim Anlegen einer Stressfrei-Wechseln Adresse im Kundenbereich erscheint die Checkbox **"Beim E-Mail-Provider anlegen"**, wenn:
@@ -1063,254 +916,6 @@ Folgende Felder werden in Audit-Logs gefiltert:
- API-Response wird nicht blockiert
- Before/After-Werte über Prisma Middleware
## Factory-Defaults: Stammdaten-Kataloge teilen
Das **Factory-Defaults**-System erlaubt den Export und Import von
Stammdaten-Katalogen (Anbieter, Tarife, PDF-Auftragsvorlagen, HTML-Standardtexte)
zwischen verschiedenen OpenCRM-Installationen. Es ist bewusst **streng abgegrenzt**
zu Datenbank-Backups:
### Abgrenzung
| | Factory-Defaults | Datenbank-Backup |
|---|---|---|
| Anbieter, Tarife, Kündigungsfristen, Laufzeiten, Kategorien | ✅ | ✅ |
| PDF-Auftragsvorlagen (inkl. Dateien + Feldzuordnungen) | ✅ | ✅ |
| HTML-Standardtexte: Datenschutzerklärung, Impressum, Vollmacht-Vorlage, Website-Datenschutz | ✅ | ✅ |
| **Kundendaten, Verträge, Dokumente** | ❌ | ✅ |
| **Emails, SMTP-/IMAP-Zugangsdaten** | ❌ | ✅ |
| **Secrets, JWT, Encryption-Keys, User-Accounts** | ❌ | ✅ |
| Zwischen verschiedenen Installationen teilbar | ✅ | ❌ (zu firmen-spezifisch) |
> **Kurz:** Factory-Defaults = generische Stammdaten + rechtliche Standardtexte,
> Backup = die komplette Instanz.
### Drei Wege, eine ZIP zu transportieren
Es gibt drei Pfade, je nachdem wo die ZIP gerade liegen soll:
| Wo | Pfad | Wann |
|---|---|---|
| **Laufende DB einer Instanz** | UI-Upload oder `./factory-import.sh` | Bestehende Live-Instanz updaten |
| **Drop-Box im Repo** (`factory-exports/`) | `./factory-export.sh` legt ab, `./factory-import.sh` liest | Transfer zwischen dev und prod via `scp` |
| **Werkseinstellung im Image** (`backend/factory-defaults/`) | `./factory-import.sh --save-as-builtin` oder manuell entpacken | Neue VMs sollen die Defaults beim allerersten Start mitbringen |
Alle drei sind unabhängig, **alle drei zusammen** decken den typischen Workflow ab.
### Export
**Variante A UI:**
1. **Einstellungen** → **Factory-Defaults** öffnen
2. Button **„Factory-Defaults exportieren"** klicken
3. ZIP wird als `factory-defaults-YYYY-MM-DD.zip` heruntergeladen
**Variante B CLI (für scp-Transfers):**
```bash
./factory-export.sh # → factory-exports/factory-defaults-…zip
OPENCRM_URL=https://crm.prod.example.de \
OPENCRM_EMAIL=admin@example.de ./factory-export.sh # gegen Prod-Instanz
```
Ohne `OPENCRM_PASSWORD` wird das Passwort interaktiv abgefragt. Der Zielordner
`factory-exports/` ist gitignored die ZIPs landen also nicht ins Repo.
**ZIP-Struktur:**
```
factory-defaults-2026-05-07-1949.zip
├── manifest.json # Version + Datum + Counts
├── providers/providers.json
├── contract-meta/
│ ├── cancellation-periods.json
│ ├── contract-durations.json
│ └── contract-categories.json
├── pdf-templates/
│ ├── pdf-templates.json
│ └── *.pdf # Die eigentlichen PDF-Dateien
└── app-settings/
└── app-settings.json # HTML-Templates (Whitelist-only)
```
### Import
**Variante A UI:**
1. **Einstellungen** → **Factory-Defaults**
2. Bereich **Import** → **„ZIP hochladen"** → Datei wählen
3. Erfolgs-Box zeigt Counts pro Kategorie
**Variante B CLI:**
```bash
./factory-import.sh # nimmt jüngste ZIP aus factory-exports/
./factory-import.sh ./factory-exports/foo.zip # explizite ZIP
./factory-import.sh --save-as-builtin # zusätzlich ins Image-Default
./factory-import.sh --save-as-builtin ./foo.zip # entpacken (siehe unten)
```
Konfigurierbar per ENV: `OPENCRM_URL`, `OPENCRM_EMAIL`, `OPENCRM_PASSWORD`.
**Variante C Container-Bare-Metal (für Migration / mehrere ZIPs zusammenführen):**
```bash
# Inhalt der ZIP nach backend/factory-defaults/ entpacken (Unterordner beibehalten)
cd backend && npm run seed:defaults
```
**Beispiel-Output:**
```
✓ Anbieter: 10
✓ Tarife: 4
✓ Kündigungsfristen: 18
✓ Laufzeiten: 18
✓ Vertragskategorien: 8
✓ PDF-Vorlagen: 2
✓ HTML-Templates: 2
```
### `--save-as-builtin`: ZIP zur Werkseinstellung machen
Mit `--save-as-builtin` entpackt `factory-import.sh` die ZIP nach **erfolgreichem
DB-Import** zusätzlich in `backend/factory-defaults/`. Beim nächsten
`docker-compose up --build` landen die Defaults im Image. Frisch hochgezogene
VMs bringen sie dann beim ersten Start automatisch mit (Auto-Seed-Pfad im
Container-Entrypoint).
```bash
# typischer Sync prod → dev → Image-Default
ssh prod './factory-export.sh'
scp prod:opencrm/factory-exports/factory-defaults-*.zip factory-exports/
./factory-import.sh --save-as-builtin
docker-compose up -d --build # neuer Build, neue VMs starten direkt mit Defaults
```
Der Inhalt von `backend/factory-defaults/` wird beim `--save-as-builtin` vorher
geleert (außer `README.md` und `.gitkeep`), damit nichts Veraltetes liegen
bleibt.
### Mehrere ZIPs kombinieren (CLI-only, Variante C)
`backend/factory-defaults/` darf mehrere `*.json` pro Unterordner haben
`npm run seed:defaults` merged sie automatisch:
```
backend/factory-defaults/
providers/
verivox.json # 40 Anbieter aus Verivox-Paket
check24.json # 30 Anbieter aus Check24-Paket
eigene.json # 5 eigene Anbieter
```
Bei gleichem Unique-Key gewinnt der zuletzt gelesene Eintrag. Der UI-/HTTP-Import
nimmt nur eine ZIP entgegen für Merges nutze `npm run seed:defaults`.
### Idempotenz
Alle Pfade nutzen Prisma `upsert`:
- **Neue Einträge** werden angelegt
- **Bestehende Einträge** (per unique Key: `name` / `code` / `key`) werden aktualisiert
- Nichts wird gelöscht
Du kannst Imports also beliebig oft hintereinander ausführen, ohne Datenverlust
oder Duplikate.
### PDF-Dateien
Beim Import werden PDF-Vorlagen aus dem ZIP nach `uploads/pdf-templates/`
kopiert (mit eindeutigem Suffix) und die `templatePath`-Spalte entsprechend
gesetzt. Beim Re-Import wird die alte Datei in `uploads/` entsorgt und durch
die neue ersetzt.
### AppSettings-Whitelist
Beim Import werden nur die Keys mit AppSetting-Schreibzugriff gewährt, die auch
exportiert werden aktuell:
- `privacyPolicyHtml`
- `imprintHtml`
- `authorizationTemplateHtml`
- `websitePrivacyPolicyHtml`
Andere Keys (SMTP, JWT, etc.) werden mit einer Warnung ignoriert. Whitelist ist
in [`backend/src/services/factoryDefaults.service.ts`](backend/src/services/factoryDefaults.service.ts)
zentral gepflegt.
### Auto-Seed beim Erst-Deploy
Bei einer **frischen** Installation (leere DB) spielt der Container-Entrypoint
nach dem Prisma-Seed automatisch das Built-in-Verzeichnis ein:
```
[entrypoint] DB ist leer (User-Count=0) Auto-Seed wird ausgeführt
[entrypoint] Spiele eingebaute Factory-Defaults ein…
✓ Anbieter: 10, Tarife: 4
```
Bei bestehenden Installs passiert das **nicht** nur frische DBs.
### Berechtigungen
| Aktion | Berechtigung |
|--------|--------------|
| Factory-Defaults Vorschau | `settings:read` |
| Factory-Defaults Export (UI/CLI) | `settings:update` |
| Factory-Defaults Import (UI/CLI) | `settings:update` |
| Werkseinstellungen ändern (`--save-as-builtin` / `npm run seed:defaults`) | Server-Zugang (SSH/Shell) |
### Typische Einsatzzwecke
- **Neue VM aufsetzen**: ZIP einmalig nach `backend/factory-defaults/` entpacken
(oder per `--save-as-builtin`), dann `docker-compose up --build` die
Werkseinstellungen sind beim ersten Start automatisch drin.
- **Prod-Stand zurück nach dev synchronisieren**: `./factory-export.sh` auf prod,
`scp` ins dev, `./factory-import.sh --save-as-builtin` lokal damit ist
sowohl die dev-DB aktuell als auch der nächste Image-Build.
- **Vorlagen-Paket teilen**: Eine ZIP mit nur PDF-Vorlagen weitergeben
(andere Ordner aus der ZIP entfernen vor dem Entpacken).
- **Anbieter-Paket teilen**: ZIP mit nur `providers/` weitergeben
- **Versionskontrolle**: Die entpackten JSON-Dateien unter Versionskontrolle
stellen (außerhalb von `backend/factory-defaults/`, da der Ordner gitignored ist)
## Changelog
### 1.1.0 (2026-05-01)
**Production-readiness** die Version, die wirklich öffentlich gehen darf.
- 🛡 **Security-Hardening**: 10 Runden statisches + dynamisches Audit, vollständig
dokumentiert in [docs/SECURITY-HARDENING.md](docs/SECURITY-HARDENING.md)
(CORS/Helmet/JWT, IDOR-Schutz an 30+ Endpoints, Mass-Assignment-Whitelists,
Zip-Slip, Path-Traversal, Login-Timing-Side-Channel, XFF-Rate-Limit-Bypass,
Customer-Liste-Leak, SSRF + DNS-Rebinding, Per-File-Ownership statt
freiem `/api/uploads`, JWT-Logout, Audit-Log-Hash-Chain).
- 🚨 **Sicherheits-Monitoring**: neue `SecurityEvent`-Tabelle + Hooks an Login,
Logout, Rate-Limit-Hit, IDOR-Abwehr, SSRF-Block, Password-Reset, JWT-Reject.
Threshold-Detection (Brute-Force, IDOR-Probing, SSRF-Probing) erzeugt
CRITICAL-Events. **Sofort-E-Mail-Alerts** für CRITICAL + **stündlicher Digest**
für HIGH/MEDIUM. UI in Einstellungen → Monitoring mit Filter, Pagination,
Log-leeren (mit optionalem Tage-Filter) und Test-Alert-Button.
- 🔄 **Auto-Vertragsstatus**:
- Lieferbestätigung-Upload → `DRAFT` → `ACTIVE` + `startDate`
- Kündigungsbestätigung-Upload → `ACTIVE` → `CANCELLED` + `cancellationConfirmationDate`
(mit Datums-Modal beim Upload)
- Nightly-Cron 02:00: alle `ACTIVE`-Verträge mit `endDate < heute` → `EXPIRED`
- 🔐 **Lazy bcrypt-Rehash**: Bestandshashes mit Cost 10 werden beim nächsten
Login transparent auf Cost 12 geupgradet.
- 🚪 **Logout-Endpoint** `POST /api/auth/logout`: invalidiert JWTs serverseitig
über `tokenInvalidatedAt`.
- 📦 **`npm audit fix`**: 8 transitive Vulnerabilities gefixt (lodash,
path-to-regexp, undici, minimatch).
### 1.0.0
Erste Release-Version.
- Kunden-, Vertrags-, Adress-, Bankkarten-, Ausweis- und Zählerverwaltung
- Energie-/Telekommunikations-/KFZ-Verträge mit typspezifischen Details
- Vertrags-Cockpit mit Rechnungsprüfung
- E-Mail-Client mit Anhang-Verwaltung
- DSGVO-Compliance: Audit-Log, Einwilligungen, Datenexport, Löschanfragen
- PDF-Auftragsvorlagen-System mit visueller Feldzuordnung
- Factory-Defaults für Stammdaten-Kataloge
- Mandantenfähigkeit über `customerEmailLabel` pro Provider
- Passwort-Reset-Flow + Rate-Limiting + Auto-Geburtstagsgrüße
## Lizenz
MIT
+13
View File
@@ -0,0 +1,13 @@
# Database - Root für Migrationen, opencrm-User für Runtime
DATABASE_URL="mysql://root:rootpassword@localhost:3306/opencrm"
# JWT
JWT_SECRET="change-this-to-a-very-long-random-secret-in-production"
JWT_EXPIRES_IN="7d"
# Encryption (for portal credentials) - generate with: openssl rand -hex 32
ENCRYPTION_KEY="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
# Server
PORT=3001
NODE_ENV=development
-6
View File
@@ -1,9 +1,3 @@
# Backend nutzt seit v1.1 die zentrale Root-.env im Projektverzeichnis.
# → siehe ../.env.example für alle Variablen
#
# Diese Datei bleibt als Legacy-Fallback: wenn /.env nicht existiert,
# liest das Backend backend/.env (z.B. für isolierte Backend-Tests).
# Database
DATABASE_URL="mysql://user:password@localhost:3306/opencrm"
+1 -7
View File
@@ -4,11 +4,10 @@ node_modules/
# Build
dist/
# Environment echte Secrets blocken, .env.example weiter mittracken
# Environment
.env
.env.local
.env.*.local
!.env.example
# Database Backups (can be large, keep folder structure)
prisma/backups/*
@@ -18,11 +17,6 @@ prisma/backups/*
uploads/*
!uploads/.gitkeep
# Factory Defaults (firmen-spezifische Kataloge, bleiben lokal)
factory-defaults/*
!factory-defaults/.gitkeep
!factory-defaults/README.md
# Logs
*.log
npm-debug.log*
-71
View File
@@ -1,71 +0,0 @@
# Multi-Stage Build: Frontend bauen, dann Backend bauen, dann schlankes Runtime-Image
# ---------------------------------------------------------------------------------
# Alle Stages auf node:20-slim (Debian-basiert) dann passt die Prisma-Query-
# Engine (glibc + openssl) zur Runtime.
# ============== STAGE 1: Frontend bauen ==============
FROM node:20-slim AS frontend-builder
WORKDIR /build/frontend
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci --no-audit --no-fund --prefer-offline
COPY frontend/ ./
RUN npm run build
# Output: /build/frontend/dist/
# ============== STAGE 2: Backend bauen (TS → JS) ==============
FROM node:20-slim AS backend-builder
WORKDIR /build/backend
RUN apt-get update && apt-get install -y --no-install-recommends openssl \
&& rm -rf /var/lib/apt/lists/*
COPY backend/package.json backend/package-lock.json ./
RUN npm ci --no-audit --no-fund --prefer-offline
COPY backend/prisma ./prisma
RUN npx prisma generate
COPY backend/tsconfig.json ./
COPY backend/src ./src
RUN npx tsc
# Output: /build/backend/dist/
# ============== STAGE 3: Runtime ==============
# Debian-slim statt Alpine: Prisma-Engines erwarten libssl 1.1, das in Alpine 3.19+
# nicht mehr verfügbar ist. Slim hat openssl 3 ABI-kompatibel + native binaries.
FROM node:20-slim
WORKDIR /app
# OpenSSL für Prisma-Query-Engine + wget für Healthcheck
RUN apt-get update && apt-get install -y --no-install-recommends openssl wget \
&& rm -rf /var/lib/apt/lists/*
# Nur Production-Dependencies + Prisma-Client
COPY backend/package.json backend/package-lock.json ./
RUN npm ci --omit=dev --no-audit --no-fund --prefer-offline && npm cache clean --force
# Build-Artefakte aus Stage 2
COPY --from=backend-builder /build/backend/dist ./dist
COPY --from=backend-builder /build/backend/node_modules/.prisma ./node_modules/.prisma
COPY --from=backend-builder /build/backend/node_modules/@prisma ./node_modules/@prisma
COPY backend/prisma ./prisma
# Frontend-Build ins public/-Verzeichnis (wird in production-Mode statisch ausgeliefert)
COPY --from=frontend-builder /build/frontend/dist ./public
# Eingebaute Werkseinstellungen ins Image: bei Erstinstallation (leerer DB) zieht
# der Entrypoint sie via tsx scripts/seed-factory-defaults.ts ein. Liegt in einem
# eigenen Pfad `factory-defaults/` selbst kann über Bind-Mount überlagert werden.
COPY backend/factory-defaults /app/factory-defaults-builtin
COPY backend/scripts /app/scripts
# Daten-Verzeichnisse (werden via Bind-Mount überlagert; hier nur als Fallback)
RUN mkdir -p uploads factory-defaults prisma/backups
# Healthcheck
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget --quiet --tries=1 --spider "http://localhost:${PORT:-3001}/api/health" || exit 1
# Beim Start: prisma db push (idempotent), dann node
COPY backend/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "dist/index.js"]
+7
View File
@@ -0,0 +1,7 @@
import { Response } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function getAllSettings(req: AuthRequest, res: Response): Promise<void>;
export declare function getPublicSettings(req: AuthRequest, res: Response): Promise<void>;
export declare function updateSetting(req: AuthRequest, res: Response): Promise<void>;
export declare function updateSettings(req: AuthRequest, res: Response): Promise<void>;
//# sourceMappingURL=appSetting.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"appSetting.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/appSetting.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAInC,OAAO,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE7D,wBAAsB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUtF;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoClF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCnF"}
+142
View File
@@ -0,0 +1,142 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllSettings = getAllSettings;
exports.getPublicSettings = getPublicSettings;
exports.updateSetting = updateSetting;
exports.updateSettings = updateSettings;
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const appSettingService = __importStar(require("../services/appSetting.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getAllSettings(req, res) {
try {
const settings = await appSettingService.getAllSettings();
res.json({ success: true, data: settings });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Einstellungen',
});
}
}
async function getPublicSettings(req, res) {
try {
const settings = await appSettingService.getPublicSettings();
res.json({ success: true, data: settings });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Einstellungen',
});
}
}
async function updateSetting(req, res) {
try {
const { key } = req.params;
const { value } = req.body;
if (value === undefined) {
res.status(400).json({
success: false,
error: 'Wert ist erforderlich',
});
return;
}
// Vorherigen Stand laden für Audit
const before = await prisma_js_1.default.appSetting.findUnique({ where: { key } });
const oldValue = before?.value ?? '-';
const newValue = String(value);
await appSettingService.setSetting(key, newValue);
const label = oldValue !== newValue
? `Einstellung "${key}" geändert: ${oldValue}${newValue}`
: `Einstellung "${key}" geändert`;
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'AppSetting',
resourceId: key,
label,
details: oldValue !== newValue ? { [key]: { von: oldValue, nach: newValue } } : undefined,
});
res.json({ success: true, message: 'Einstellung gespeichert' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Speichern der Einstellung',
});
}
}
async function updateSettings(req, res) {
try {
const settings = req.body;
if (!settings || typeof settings !== 'object') {
res.status(400).json({
success: false,
error: 'Einstellungen sind erforderlich',
});
return;
}
// Vorherige Werte laden für Audit
const changes = {};
for (const [key, value] of Object.entries(settings)) {
const before = await prisma_js_1.default.appSetting.findUnique({ where: { key } });
const oldValue = before?.value ?? '-';
const newValue = String(value);
if (oldValue !== newValue) {
changes[key] = { von: oldValue, nach: newValue };
}
await appSettingService.setSetting(key, newValue);
}
const changeList = Object.entries(changes).map(([k, c]) => `${k}: ${c.von}${c.nach}`).join(', ');
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'AppSetting',
label: changeList
? `Einstellungen aktualisiert: ${changeList}`
: `Einstellungen aktualisiert (${Object.keys(settings).join(', ')})`,
details: Object.keys(changes).length > 0 ? changes : undefined,
});
res.json({ success: true, message: 'Einstellungen gespeichert' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Speichern der Einstellungen',
});
}
}
//# sourceMappingURL=appSetting.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"appSetting.controller.js","sourceRoot":"","sources":["../../src/controllers/appSetting.controller.ts"],"names":[],"mappings":"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"}
+7
View File
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function login(req: Request, res: Response): Promise<void>;
export declare function customerLogin(req: Request, res: Response): Promise<void>;
export declare function me(req: AuthRequest, res: Response): Promise<void>;
export declare function register(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=auth.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/auth.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAe,MAAM,mBAAmB,CAAC;AAG7D,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBtE;AAGD,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB9E;AAED,wBAAsB,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDvE;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BzE"}
+158
View File
@@ -0,0 +1,158 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.login = login;
exports.customerLogin = customerLogin;
exports.me = me;
exports.register = register;
const authService = __importStar(require("../services/auth.service.js"));
// Mitarbeiter-Login
async function login(req, res) {
try {
const { email, password } = req.body;
if (!email || !password) {
res.status(400).json({
success: false,
error: 'E-Mail und Passwort erforderlich',
});
return;
}
const result = await authService.login(email, password);
res.json({ success: true, data: result });
}
catch (error) {
res.status(401).json({
success: false,
error: error instanceof Error ? error.message : 'Anmeldung fehlgeschlagen',
});
}
}
// Kundenportal-Login
async function customerLogin(req, res) {
try {
const { email, password } = req.body;
if (!email || !password) {
res.status(400).json({
success: false,
error: 'E-Mail und Passwort erforderlich',
});
return;
}
const result = await authService.customerLogin(email, password);
res.json({ success: true, data: result });
}
catch (error) {
res.status(401).json({
success: false,
error: error instanceof Error ? error.message : 'Anmeldung fehlgeschlagen',
});
}
}
async function me(req, res) {
try {
if (!req.user) {
res.status(401).json({
success: false,
error: 'Nicht authentifiziert',
});
return;
}
// Kundenportal-Login
if (req.user.isCustomerPortal && req.user.customerId) {
const customer = await authService.getCustomerPortalUser(req.user.customerId);
if (!customer) {
res.status(404).json({
success: false,
error: 'Kunde nicht gefunden',
});
return;
}
res.json({ success: true, data: customer });
return;
}
// Mitarbeiter-Login
if (!req.user.userId) {
res.status(401).json({
success: false,
error: 'Ungültige Authentifizierung',
});
return;
}
const user = await authService.getUserById(req.user.userId);
if (!user) {
res.status(404).json({
success: false,
error: 'Benutzer nicht gefunden',
});
return;
}
res.json({ success: true, data: user });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Benutzerdaten',
});
}
}
async function register(req, res) {
try {
const { email, password, firstName, lastName, roleIds } = req.body;
if (!email || !password || !firstName || !lastName) {
res.status(400).json({
success: false,
error: 'Alle Pflichtfelder müssen ausgefüllt sein',
});
return;
}
const user = await authService.createUser({
email,
password,
firstName,
lastName,
roleIds: roleIds || [2], // Default to employee role
});
res.status(201).json({ success: true, data: user });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error
? error.message
: 'Benutzer konnte nicht erstellt werden',
});
}
}
//# sourceMappingURL=auth.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/controllers/auth.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getCancellationPeriods(req: Request, res: Response): Promise<void>;
export declare function getCancellationPeriod(req: Request, res: Response): Promise<void>;
export declare function createCancellationPeriod(req: Request, res: Response): Promise<void>;
export declare function updateCancellationPeriod(req: Request, res: Response): Promise<void>;
export declare function deleteCancellationPeriod(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=cancellation-period.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"cancellation-period.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/cancellation-period.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvF;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBtF;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBzF"}
@@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCancellationPeriods = getCancellationPeriods;
exports.getCancellationPeriod = getCancellationPeriod;
exports.createCancellationPeriod = createCancellationPeriod;
exports.updateCancellationPeriod = updateCancellationPeriod;
exports.deleteCancellationPeriod = deleteCancellationPeriod;
const cancellationPeriodService = __importStar(require("../services/cancellation-period.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getCancellationPeriods(req, res) {
try {
const includeInactive = req.query.includeInactive === 'true';
const periods = await cancellationPeriodService.getAllCancellationPeriods(includeInactive);
res.json({ success: true, data: periods });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Kündigungsfristen',
});
}
}
async function getCancellationPeriod(req, res) {
try {
const period = await cancellationPeriodService.getCancellationPeriodById(parseInt(req.params.id));
if (!period) {
res.status(404).json({
success: false,
error: 'Kündigungsfrist nicht gefunden',
});
return;
}
res.json({ success: true, data: period });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Kündigungsfrist',
});
}
}
async function createCancellationPeriod(req, res) {
try {
const period = await cancellationPeriodService.createCancellationPeriod(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'CancellationPeriod',
resourceId: period.id.toString(),
label: `Kündigungsfrist ${period.description} angelegt`,
});
res.status(201).json({ success: true, data: period });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Kündigungsfrist',
});
}
}
async function updateCancellationPeriod(req, res) {
try {
const period = await cancellationPeriodService.updateCancellationPeriod(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'CancellationPeriod',
resourceId: period.id.toString(),
label: `Kündigungsfrist ${period.description} aktualisiert`,
});
res.json({ success: true, data: period });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Kündigungsfrist',
});
}
}
async function deleteCancellationPeriod(req, res) {
try {
const periodId = parseInt(req.params.id);
const period = await cancellationPeriodService.getCancellationPeriodById(periodId);
await cancellationPeriodService.deleteCancellationPeriod(periodId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'CancellationPeriod',
resourceId: periodId.toString(),
label: `Kündigungsfrist ${period?.description || periodId} gelöscht`,
});
res.json({ success: true, message: 'Kündigungsfrist gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Kündigungsfrist',
});
}
}
//# sourceMappingURL=cancellation-period.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"cancellation-period.controller.js","sourceRoot":"","sources":["../../src/controllers/cancellation-period.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getContractDurations(req: Request, res: Response): Promise<void>;
export declare function getContractDuration(req: Request, res: Response): Promise<void>;
export declare function createContractDuration(req: Request, res: Response): Promise<void>;
export declare function updateContractDuration(req: Request, res: Response): Promise<void>;
export declare function deleteContractDuration(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=contract-duration.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"contract-duration.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/contract-duration.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrF;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBpF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAevF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAevF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvF"}
+128
View File
@@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContractDurations = getContractDurations;
exports.getContractDuration = getContractDuration;
exports.createContractDuration = createContractDuration;
exports.updateContractDuration = updateContractDuration;
exports.deleteContractDuration = deleteContractDuration;
const contractDurationService = __importStar(require("../services/contract-duration.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getContractDurations(req, res) {
try {
const includeInactive = req.query.includeInactive === 'true';
const durations = await contractDurationService.getAllContractDurations(includeInactive);
res.json({ success: true, data: durations });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Laufzeiten',
});
}
}
async function getContractDuration(req, res) {
try {
const duration = await contractDurationService.getContractDurationById(parseInt(req.params.id));
if (!duration) {
res.status(404).json({
success: false,
error: 'Laufzeit nicht gefunden',
});
return;
}
res.json({ success: true, data: duration });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Laufzeit',
});
}
}
async function createContractDuration(req, res) {
try {
const duration = await contractDurationService.createContractDuration(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractDuration',
resourceId: duration.id.toString(),
label: `Laufzeit ${duration.description} angelegt`,
});
res.status(201).json({ success: true, data: duration });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Laufzeit',
});
}
}
async function updateContractDuration(req, res) {
try {
const duration = await contractDurationService.updateContractDuration(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractDuration',
resourceId: duration.id.toString(),
label: `Laufzeit ${duration.description} aktualisiert`,
});
res.json({ success: true, data: duration });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Laufzeit',
});
}
}
async function deleteContractDuration(req, res) {
try {
const durationId = parseInt(req.params.id);
const duration = await contractDurationService.getContractDurationById(durationId);
await contractDurationService.deleteContractDuration(durationId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractDuration',
resourceId: durationId.toString(),
label: `Laufzeit ${duration?.description || durationId} gelöscht`,
});
res.json({ success: true, message: 'Laufzeit gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Laufzeit',
});
}
}
//# sourceMappingURL=contract-duration.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"contract-duration.controller.js","sourceRoot":"","sources":["../../src/controllers/contract-duration.controller.ts"],"names":[],"mappings":"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"}
+20
View File
@@ -0,0 +1,20 @@
import { Request, Response } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function getContracts(req: AuthRequest, res: Response): Promise<void>;
export declare function getContract(req: AuthRequest, res: Response): Promise<void>;
export declare function createContract(req: Request, res: Response): Promise<void>;
export declare function updateContract(req: AuthRequest, res: Response): Promise<void>;
export declare function deleteContract(req: Request, res: Response): Promise<void>;
export declare function createFollowUp(req: AuthRequest, res: Response): Promise<void>;
export declare function getContractPassword(req: Request, res: Response): Promise<void>;
export declare function getSimCardCredentials(req: Request, res: Response): Promise<void>;
export declare function getInternetCredentials(req: Request, res: Response): Promise<void>;
export declare function getSipCredentials(req: Request, res: Response): Promise<void>;
export declare function getCockpit(req: AuthRequest, res: Response): Promise<void>;
export declare function addSuccessorMeter(req: AuthRequest, res: Response): Promise<void>;
export declare function removeContractMeter(req: AuthRequest, res: Response): Promise<void>;
export declare function getContractDocuments(req: AuthRequest, res: Response): Promise<void>;
export declare function uploadContractDocument(req: AuthRequest, res: Response): Promise<void>;
export declare function deleteContractDocument(req: AuthRequest, res: Response): Promise<void>;
export declare function snoozeContract(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=contract.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"contract.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/contract.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM5C,OAAO,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG7D,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDjF;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqChF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEnF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CnF;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBpF;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUtF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlF;AAID,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/E;AAID,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA+DtF;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxF;AAID,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWzF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C3F;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC3F;AAID,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C/E"}
+563
View File
@@ -0,0 +1,563 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContracts = getContracts;
exports.getContract = getContract;
exports.createContract = createContract;
exports.updateContract = updateContract;
exports.deleteContract = deleteContract;
exports.createFollowUp = createFollowUp;
exports.getContractPassword = getContractPassword;
exports.getSimCardCredentials = getSimCardCredentials;
exports.getInternetCredentials = getInternetCredentials;
exports.getSipCredentials = getSipCredentials;
exports.getCockpit = getCockpit;
exports.addSuccessorMeter = addSuccessorMeter;
exports.removeContractMeter = removeContractMeter;
exports.getContractDocuments = getContractDocuments;
exports.uploadContractDocument = uploadContractDocument;
exports.deleteContractDocument = deleteContractDocument;
exports.snoozeContract = snoozeContract;
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const contractService = __importStar(require("../services/contract.service.js"));
const contractCockpitService = __importStar(require("../services/contractCockpit.service.js"));
const contractHistoryService = __importStar(require("../services/contractHistory.service.js"));
const authorizationService = __importStar(require("../services/authorization.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getContracts(req, res) {
try {
const { customerId, type, status, search, page, limit, tree } = req.query;
// Baumstruktur für Kundenansicht
if (tree === 'true' && customerId) {
const treeData = await contractService.getContractTreeForCustomer(parseInt(customerId));
res.json({ success: true, data: treeData });
return;
}
// Für Kundenportal-Benutzer: nur eigene + vertretene Kunden MIT Vollmacht
let customerIds;
if (req.user?.isCustomerPortal && req.user.customerId) {
// Eigene Customer-ID immer
customerIds = [req.user.customerId];
// Vertretene Kunden nur wenn Vollmacht erteilt
const representedIds = req.user.representedCustomerIds || [];
for (const repCustId of representedIds) {
const hasAuth = await authorizationService.hasAuthorization(repCustId, req.user.customerId);
if (hasAuth) {
customerIds.push(repCustId);
}
}
}
const result = await contractService.getAllContracts({
customerId: customerId ? parseInt(customerId) : undefined,
customerIds, // Wird nur für Kundenportal-Benutzer gesetzt
type: type,
status: status,
search: search,
page: page ? parseInt(page) : undefined,
limit: limit ? parseInt(limit) : undefined,
});
res.json({
success: true,
data: result.contracts,
pagination: result.pagination,
});
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Verträge',
});
}
}
async function getContract(req, res) {
try {
const contract = await contractService.getContractById(parseInt(req.params.id));
if (!contract) {
res.status(404).json({
success: false,
error: 'Vertrag nicht gefunden',
});
return;
}
// Für Kundenportal-Benutzer: Zugriff nur auf eigene + vertretene Kunden MIT Vollmacht
if (req.user?.isCustomerPortal && req.user.customerId) {
const allowedCustomerIds = [req.user.customerId];
const representedIds = req.user.representedCustomerIds || [];
for (const repCustId of representedIds) {
const hasAuth = await authorizationService.hasAuthorization(repCustId, req.user.customerId);
if (hasAuth) {
allowedCustomerIds.push(repCustId);
}
}
if (!allowedCustomerIds.includes(contract.customerId)) {
res.status(403).json({
success: false,
error: 'Kein Zugriff auf diesen Vertrag',
});
return;
}
}
res.json({ success: true, data: contract });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Vertrags',
});
}
}
async function createContract(req, res) {
try {
const contract = await contractService.createContract(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Contract',
resourceId: contract.id.toString(),
label: `Vertrag ${contract.contractNumber} angelegt`,
customerId: contract.customerId,
});
res.status(201).json({ success: true, data: contract });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Vertrags',
});
}
}
async function updateContract(req, res) {
try {
const contractId = parseInt(req.params.id);
// Vorherigen Stand laden für Audit-Vergleich
const before = await prisma_js_1.default.contract.findUnique({
where: { id: contractId },
include: { energyDetails: true, internetDetails: true, mobileDetails: true, tvDetails: true, carInsuranceDetails: true },
});
const contract = await contractService.updateContract(contractId, req.body);
// Geänderte Felder ermitteln
const changes = {};
const fieldLabels = {
status: 'Status', startDate: 'Vertragsbeginn', endDate: 'Vertragsende',
portalUsername: 'Portal-Benutzername', customerNumberAtProvider: 'Kundennummer beim Anbieter',
providerId: 'Anbieter', tariffId: 'Tarif', cancellationPeriodId: 'Kündigungsfrist',
contractDurationId: 'Vertragslaufzeit', platformId: 'Vertriebsplattform',
cancellationDate: 'Kündigungsdatum', cancellationSentDate: 'Kündigung gesendet am',
identityDocumentId: 'Ausweis', bankCardId: 'Bankverbindung', addressId: 'Adresse',
commission: 'Provision', notes: 'Notizen',
};
const energyLabels = {
meterId: 'Zähler', maloId: 'MaLo-ID', annualConsumption: 'Jahresverbrauch',
basePrice: 'Grundpreis', unitPrice: 'Arbeitspreis', unitPriceNt: 'NT-Arbeitspreis', bonus: 'Bonus',
};
// Hauptfelder vergleichen
const body = req.body;
if (before) {
for (const [key, newVal] of Object.entries(body)) {
if (['energyDetails', 'internetDetails', 'mobileDetails', 'tvDetails', 'carInsuranceDetails', 'password'].includes(key))
continue;
const oldVal = before[key];
const norm = (v) => (v === null || v === undefined || v === '' ? null : v);
if (JSON.stringify(norm(oldVal)) !== JSON.stringify(norm(newVal))) {
const label = fieldLabels[key] || key;
changes[label] = { von: oldVal ?? '-', nach: newVal ?? '-' };
}
}
// Energie-Details vergleichen
if (body.energyDetails && before.energyDetails) {
for (const [key, newVal] of Object.entries(body.energyDetails)) {
const oldVal = before.energyDetails[key];
const norm = (v) => (v === null || v === undefined || v === '' ? null : v);
if (JSON.stringify(norm(oldVal)) !== JSON.stringify(norm(newVal))) {
const label = energyLabels[key] || key;
changes[label] = { von: oldVal ?? '-', nach: newVal ?? '-' };
}
}
}
}
const changeList = Object.entries(changes).map(([f, c]) => `${f}: ${c.von}${c.nach}`).join(', ');
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Contract',
resourceId: contractId.toString(),
label: changeList
? `Vertrag ${before?.contractNumber || contractId} aktualisiert: ${changeList}`
: `Vertrag ${before?.contractNumber || contractId} aktualisiert`,
details: Object.keys(changes).length > 0 ? changes : undefined,
customerId: before?.customerId,
});
res.json({ success: true, data: contract });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Vertrags',
});
}
}
async function deleteContract(req, res) {
try {
const contractId = parseInt(req.params.id);
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId }, select: { contractNumber: true, customerId: true } });
await contractService.deleteContract(contractId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'Contract',
resourceId: contractId.toString(),
label: `Vertrag ${contract?.contractNumber} gelöscht`,
customerId: contract?.customerId,
});
res.json({ success: true, message: 'Vertrag gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Vertrags',
});
}
}
async function createFollowUp(req, res) {
try {
const previousContractId = parseInt(req.params.id);
// Vorgängervertrag laden für Vertragsnummer
const previousContract = await prisma_js_1.default.contract.findUnique({
where: { id: previousContractId },
select: { contractNumber: true },
});
if (!previousContract) {
res.status(404).json({ success: false, error: 'Vorgängervertrag nicht gefunden' });
return;
}
const contract = await contractService.createFollowUpContract(previousContractId);
const createdBy = req.user?.email || 'unbekannt';
// Historie-Eintrag für den Vorgängervertrag erstellen
await contractHistoryService.createFollowUpHistoryEntry(previousContractId, contract.contractNumber, createdBy);
// Historie-Eintrag für den neuen Folgevertrag erstellen
await contractHistoryService.createNewContractFromPredecessorEntry(contract.id, previousContract.contractNumber, createdBy);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Contract',
resourceId: contract.id.toString(),
label: `Folgevertrag erstellt für ${previousContract.contractNumber}`,
customerId: contract.customerId,
});
res.status(201).json({ success: true, data: contract });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Folgevertrags',
});
}
}
async function getContractPassword(req, res) {
try {
const password = await contractService.getContractPassword(parseInt(req.params.id));
if (password === null) {
res.status(404).json({
success: false,
error: 'Kein Passwort hinterlegt',
});
return;
}
res.json({ success: true, data: { password } });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Entschlüsseln des Passworts',
});
}
}
async function getSimCardCredentials(req, res) {
try {
const credentials = await contractService.getSimCardCredentials(parseInt(req.params.simCardId));
res.json({ success: true, data: credentials });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Entschlüsseln der SIM-Karten-Daten',
});
}
}
async function getInternetCredentials(req, res) {
try {
const credentials = await contractService.getInternetCredentials(parseInt(req.params.id));
res.json({ success: true, data: credentials });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Entschlüsseln des Internet-Passworts',
});
}
}
async function getSipCredentials(req, res) {
try {
const credentials = await contractService.getSipCredentials(parseInt(req.params.phoneNumberId));
res.json({ success: true, data: credentials });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Entschlüsseln des SIP-Passworts',
});
}
}
// ==================== VERTRAGS-COCKPIT ====================
async function getCockpit(req, res) {
try {
const cockpitData = await contractCockpitService.getCockpitData();
res.json({ success: true, data: cockpitData });
}
catch (error) {
console.error('Cockpit error:', error);
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Vertrags-Cockpits',
});
}
}
// ==================== FOLGEZÄHLER ====================
async function addSuccessorMeter(req, res) {
try {
const contractId = parseInt(req.params.id);
const { meterId, installedAt, finalReadingPrevious } = req.body;
const contract = await prisma_js_1.default.contract.findUnique({
where: { id: contractId },
include: { energyDetails: { include: { contractMeters: { orderBy: { position: 'asc' } } } } },
});
if (!contract?.energyDetails) {
res.status(404).json({ success: false, error: 'Energievertrag nicht gefunden' });
return;
}
const ecdId = contract.energyDetails.id;
const existingMeters = contract.energyDetails.contractMeters;
const nextPosition = existingMeters.length > 0
? Math.max(...existingMeters.map(m => m.position)) + 1
: 0;
// Vorherigen Zähler als gewechselt markieren
if (existingMeters.length > 0 && finalReadingPrevious !== undefined) {
const prevMeter = existingMeters[existingMeters.length - 1];
await prisma_js_1.default.contractMeter.update({
where: { id: prevMeter.id },
data: {
removedAt: installedAt ? new Date(installedAt) : new Date(),
finalReading: parseFloat(finalReadingPrevious),
},
});
}
const contractMeter = await prisma_js_1.default.contractMeter.create({
data: {
energyContractDetailsId: ecdId,
meterId: parseInt(meterId),
position: nextPosition,
installedAt: installedAt ? new Date(installedAt) : new Date(),
},
include: { meter: { include: { readings: true } } },
});
// Aktuellen Zähler am Vertrag aktualisieren
await prisma_js_1.default.energyContractDetails.update({
where: { id: ecdId },
data: { meterId: parseInt(meterId) },
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractMeter',
resourceId: contractMeter.id.toString(),
label: `Folgezähler hinzugefügt zu Vertrag #${contractId}`,
customerId: contract.customerId,
});
res.json({ success: true, data: contractMeter });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Hinzufügen des Folgezählers',
});
}
}
async function removeContractMeter(req, res) {
try {
const contractMeterId = parseInt(req.params.contractMeterId);
const contractId = parseInt(req.params.id);
await prisma_js_1.default.contractMeter.delete({ where: { id: contractMeterId } });
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractMeter',
resourceId: contractMeterId.toString(),
label: `Folgezähler entfernt von Vertrag #${contractId}`,
});
res.json({ success: true, data: null });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Entfernen',
});
}
}
// ==================== VERTRAGSDOKUMENTE ====================
async function getContractDocuments(req, res) {
try {
const contractId = parseInt(req.params.id);
const documents = await prisma_js_1.default.contractDocument.findMany({
where: { contractId },
orderBy: { createdAt: 'desc' },
});
res.json({ success: true, data: documents });
}
catch (error) {
res.status(500).json({ success: false, error: 'Fehler beim Laden der Dokumente' });
}
}
async function uploadContractDocument(req, res) {
try {
const contractId = parseInt(req.params.id);
const { documentType, notes } = req.body;
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
if (!documentType) {
res.status(400).json({ success: false, error: 'Dokumenttyp erforderlich' });
return;
}
const documentPath = `/uploads/contract-documents/${req.file.filename}`;
const doc = await prisma_js_1.default.contractDocument.create({
data: {
contractId,
documentType,
documentPath,
originalName: req.file.originalname,
notes: notes || null,
uploadedBy: req.user?.email,
},
});
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId }, select: { contractNumber: true, customerId: true } });
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractDocument',
resourceId: doc.id.toString(),
label: `Dokument "${documentType}" hochgeladen für Vertrag ${contract?.contractNumber}`,
details: { typ: documentType, datei: req.file.originalname },
customerId: contract?.customerId,
});
res.status(201).json({ success: true, data: doc });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Hochladen',
});
}
}
async function deleteContractDocument(req, res) {
try {
const documentId = parseInt(req.params.documentId);
const contractId = parseInt(req.params.id);
const doc = await prisma_js_1.default.contractDocument.findUnique({ where: { id: documentId } });
if (!doc || doc.contractId !== contractId) {
res.status(404).json({ success: false, error: 'Dokument nicht gefunden' });
return;
}
// Datei löschen
const fs = await import('fs');
const path = await import('path');
const filePath = path.join(process.cwd(), doc.documentPath);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
await prisma_js_1.default.contractDocument.delete({ where: { id: documentId } });
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId }, select: { contractNumber: true, customerId: true } });
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractDocument',
resourceId: documentId.toString(),
label: `Dokument "${doc.documentType}" gelöscht von Vertrag ${contract?.contractNumber}`,
details: { typ: doc.documentType, datei: doc.originalName },
customerId: contract?.customerId,
});
res.json({ success: true, message: 'Dokument gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen',
});
}
}
// ==================== SNOOZE (VERTRAG ZURÜCKSTELLEN) ====================
async function snoozeContract(req, res) {
try {
const id = parseInt(req.params.id);
const { nextReviewDate, months } = req.body;
let reviewDate = null;
if (nextReviewDate) {
// Explizites Datum angegeben
reviewDate = new Date(nextReviewDate);
}
else if (months) {
// Monate angegeben → berechne Datum
reviewDate = new Date();
reviewDate.setMonth(reviewDate.getMonth() + months);
}
// Wenn beides leer → nextReviewDate wird auf null gesetzt (Snooze aufheben)
const updated = await prisma_js_1.default.contract.update({
where: { id },
data: { nextReviewDate: reviewDate },
select: {
id: true,
contractNumber: true,
nextReviewDate: true,
},
});
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Contract',
resourceId: id.toString(),
label: `Vertrag ${updated.contractNumber} zurückgestellt`,
});
res.json({
success: true,
data: updated,
message: reviewDate
? `Vertrag zurückgestellt bis ${reviewDate.toLocaleDateString('de-DE')}`
: 'Zurückstellung aufgehoben',
});
}
catch (error) {
console.error('Snooze error:', error);
res.status(500).json({
success: false,
error: 'Fehler beim Zurückstellen des Vertrags',
});
}
}
//# sourceMappingURL=contract.controller.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getContractCategories(req: Request, res: Response): Promise<void>;
export declare function getContractCategory(req: Request, res: Response): Promise<void>;
export declare function createContractCategory(req: Request, res: Response): Promise<void>;
export declare function updateContractCategory(req: Request, res: Response): Promise<void>;
export declare function deleteContractCategory(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=contractCategory.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"contractCategory.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/contractCategory.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtF;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBpF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAevF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAevF;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvF"}
+128
View File
@@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContractCategories = getContractCategories;
exports.getContractCategory = getContractCategory;
exports.createContractCategory = createContractCategory;
exports.updateContractCategory = updateContractCategory;
exports.deleteContractCategory = deleteContractCategory;
const contractCategoryService = __importStar(require("../services/contractCategory.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getContractCategories(req, res) {
try {
const includeInactive = req.query.includeInactive === 'true';
const categories = await contractCategoryService.getAllContractCategories(includeInactive);
res.json({ success: true, data: categories });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Vertragskategorien',
});
}
}
async function getContractCategory(req, res) {
try {
const category = await contractCategoryService.getContractCategoryById(parseInt(req.params.id));
if (!category) {
res.status(404).json({
success: false,
error: 'Vertragskategorie nicht gefunden',
});
return;
}
res.json({ success: true, data: category });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Vertragskategorie',
});
}
}
async function createContractCategory(req, res) {
try {
const category = await contractCategoryService.createContractCategory(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractCategory',
resourceId: category.id.toString(),
label: `Vertragskategorie ${category.name} angelegt`,
});
res.status(201).json({ success: true, data: category });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Vertragskategorie',
});
}
}
async function updateContractCategory(req, res) {
try {
const category = await contractCategoryService.updateContractCategory(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractCategory',
resourceId: category.id.toString(),
label: `Vertragskategorie ${category.name} aktualisiert`,
});
res.json({ success: true, data: category });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Vertragskategorie',
});
}
}
async function deleteContractCategory(req, res) {
try {
const categoryId = parseInt(req.params.id);
const category = await contractCategoryService.getContractCategoryById(categoryId);
await contractCategoryService.deleteContractCategory(categoryId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractCategory',
resourceId: categoryId.toString(),
label: `Vertragskategorie ${category?.name || categoryId} gelöscht`,
});
res.json({ success: true, message: 'Vertragskategorie gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Vertragskategorie',
});
}
}
//# sourceMappingURL=contractCategory.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"contractCategory.controller.js","sourceRoot":"","sources":["../../src/controllers/contractCategory.controller.ts"],"names":[],"mappings":"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"}
+18
View File
@@ -0,0 +1,18 @@
import { Response } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function getAllTasks(req: AuthRequest, res: Response): Promise<void>;
export declare function getTaskStats(req: AuthRequest, res: Response): Promise<void>;
export declare function getTasks(req: AuthRequest, res: Response): Promise<void>;
export declare function createTask(req: AuthRequest, res: Response): Promise<void>;
export declare function createSupportTicket(req: AuthRequest, res: Response): Promise<void>;
export declare function updateTask(req: AuthRequest, res: Response): Promise<void>;
export declare function completeTask(req: AuthRequest, res: Response): Promise<void>;
export declare function reopenTask(req: AuthRequest, res: Response): Promise<void>;
export declare function deleteTask(req: AuthRequest, res: Response): Promise<void>;
export declare function createSubtask(req: AuthRequest, res: Response): Promise<void>;
export declare function createCustomerReply(req: AuthRequest, res: Response): Promise<void>;
export declare function updateSubtask(req: AuthRequest, res: Response): Promise<void>;
export declare function completeSubtask(req: AuthRequest, res: Response): Promise<void>;
export declare function reopenSubtask(req: AuthRequest, res: Response): Promise<void>;
export declare function deleteSubtask(req: AuthRequest, res: Response): Promise<void>;
//# sourceMappingURL=contractTask.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"contractTask.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/contractTask.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMnC,OAAO,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAI7D,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BhF;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BjF;AAID,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD7E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC/E;AAGD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoExF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB/E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/E;AAID,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkClF;AAGD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqExF;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BlF;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlF;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlF"}
+510
View File
@@ -0,0 +1,510 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllTasks = getAllTasks;
exports.getTaskStats = getTaskStats;
exports.getTasks = getTasks;
exports.createTask = createTask;
exports.createSupportTicket = createSupportTicket;
exports.updateTask = updateTask;
exports.completeTask = completeTask;
exports.reopenTask = reopenTask;
exports.deleteTask = deleteTask;
exports.createSubtask = createSubtask;
exports.createCustomerReply = createCustomerReply;
exports.updateSubtask = updateSubtask;
exports.completeSubtask = completeSubtask;
exports.reopenSubtask = reopenSubtask;
exports.deleteSubtask = deleteSubtask;
const contractTaskService = __importStar(require("../services/contractTask.service.js"));
const contractService = __importStar(require("../services/contract.service.js"));
const customerService = __importStar(require("../services/customer.service.js"));
const appSettingService = __importStar(require("../services/appSetting.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
// ==================== ALL TASKS (Dashboard & Task List) ====================
async function getAllTasks(req, res) {
try {
const { status, customerId } = req.query;
// Für Kundenportal: Filter auf erlaubte Kunden
let customerPortalCustomerIds;
let customerPortalEmails;
if (req.user?.isCustomerPortal && req.user.customerId) {
customerPortalCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
const customers = await customerService.getCustomersByIds(customerPortalCustomerIds);
customerPortalEmails = customers
.map((c) => c.portalEmail)
.filter((email) => !!email);
}
const tasks = await contractTaskService.getAllTasks({
status: status,
customerId: customerId ? parseInt(customerId) : undefined,
customerPortalCustomerIds,
customerPortalEmails,
});
res.json({ success: true, data: tasks });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Aufgaben',
});
}
}
async function getTaskStats(req, res) {
try {
// Für Kundenportal: Filter auf erlaubte Kunden
let customerPortalCustomerIds;
let customerPortalEmails;
if (req.user?.isCustomerPortal && req.user.customerId) {
customerPortalCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
const customers = await customerService.getCustomersByIds(customerPortalCustomerIds);
customerPortalEmails = customers
.map((c) => c.portalEmail)
.filter((email) => !!email);
}
const stats = await contractTaskService.getTaskStats({
customerPortalCustomerIds,
customerPortalEmails,
});
res.json({ success: true, data: stats });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Statistik',
});
}
}
// ==================== TASKS BY CONTRACT ====================
async function getTasks(req, res) {
try {
const contractId = parseInt(req.params.contractId);
const { status } = req.query;
// Prüfe Zugriff auf den Vertrag
const contract = await contractService.getContractById(contractId);
if (!contract) {
res.status(404).json({
success: false,
error: 'Vertrag nicht gefunden',
});
return;
}
// Für Kundenportal: Zugriffsprüfung
if (req.user?.isCustomerPortal && req.user.customerId) {
const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
if (!allowedCustomerIds.includes(contract.customerId)) {
res.status(403).json({
success: false,
error: 'Kein Zugriff auf diesen Vertrag',
});
return;
}
}
// Für Kundenportal-Benutzer: Lade E-Mails der erlaubten Kunden
let customerPortalEmails;
if (req.user?.isCustomerPortal && req.user.customerId) {
const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
const customers = await customerService.getCustomersByIds(allowedCustomerIds);
customerPortalEmails = customers
.map((c) => c.portalEmail)
.filter((email) => !!email);
}
const tasks = await contractTaskService.getTasksByContract({
contractId,
status: status,
customerPortalEmails,
});
res.json({ success: true, data: tasks });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Aufgaben',
});
}
}
async function createTask(req, res) {
try {
const contractId = parseInt(req.params.contractId);
const { title, description, visibleInPortal } = req.body;
if (!title) {
res.status(400).json({
success: false,
error: 'Titel ist erforderlich',
});
return;
}
const createdBy = req.user?.email;
// Für Kundenportal-Benutzer: visibleInPortal wird automatisch auf true gesetzt
const finalVisibleInPortal = req.user?.isCustomerPortal ? true : visibleInPortal;
const task = await contractTaskService.createTask({
contractId,
title,
description,
visibleInPortal: finalVisibleInPortal,
createdBy,
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractTask',
resourceId: task.id.toString(),
label: `Aufgabe "${title}" erstellt`,
});
res.status(201).json({ success: true, data: task });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Aufgabe',
});
}
}
// Für Kundenportal-Benutzer: Support-Anfrage erstellen (ohne contracts:update Permission)
async function createSupportTicket(req, res) {
try {
// Prüfe ob Support-Tickets aktiviert sind
const supportEnabled = await appSettingService.getSettingBool('customerSupportTicketsEnabled');
if (!supportEnabled) {
res.status(403).json({
success: false,
error: 'Support-Anfragen sind nicht aktiviert',
});
return;
}
const contractId = parseInt(req.params.contractId);
const { title, description } = req.body;
if (!title) {
res.status(400).json({
success: false,
error: 'Titel ist erforderlich',
});
return;
}
// Prüfe Zugriff auf den Vertrag
const contract = await contractService.getContractById(contractId);
if (!contract) {
res.status(404).json({
success: false,
error: 'Vertrag nicht gefunden',
});
return;
}
// Zugriffsprüfung für Kundenportal
if (req.user?.customerId) {
const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
if (!allowedCustomerIds.includes(contract.customerId)) {
res.status(403).json({
success: false,
error: 'Kein Zugriff auf diesen Vertrag',
});
return;
}
}
const createdBy = req.user?.email;
const task = await contractTaskService.createTask({
contractId,
title,
description,
visibleInPortal: true, // Immer sichtbar im Portal
createdBy,
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractTask',
resourceId: task.id.toString(),
label: `Support-Anfrage "${title}" erstellt`,
});
res.status(201).json({ success: true, data: task });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Support-Anfrage',
});
}
}
async function updateTask(req, res) {
try {
const taskId = parseInt(req.params.taskId);
const { title, description, visibleInPortal } = req.body;
const task = await contractTaskService.updateTask(taskId, {
title,
description,
visibleInPortal,
});
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractTask',
resourceId: taskId.toString(),
label: `Aufgabe aktualisiert`,
});
res.json({ success: true, data: task });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Aufgabe',
});
}
}
async function completeTask(req, res) {
try {
const taskId = parseInt(req.params.taskId);
const task = await contractTaskService.completeTask(taskId);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractTask',
resourceId: taskId.toString(),
label: `Aufgabe abgeschlossen`,
});
res.json({ success: true, data: task });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Abschließen der Aufgabe',
});
}
}
async function reopenTask(req, res) {
try {
const taskId = parseInt(req.params.taskId);
const task = await contractTaskService.reopenTask(taskId);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractTask',
resourceId: taskId.toString(),
label: `Aufgabe wiedereröffnet`,
});
res.json({ success: true, data: task });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Wiedereröffnen der Aufgabe',
});
}
}
async function deleteTask(req, res) {
try {
const taskId = parseInt(req.params.taskId);
await contractTaskService.deleteTask(taskId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractTask',
resourceId: taskId.toString(),
label: `Aufgabe gelöscht`,
});
res.json({ success: true, message: 'Aufgabe gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Aufgabe',
});
}
}
// ==================== SUBTASKS ====================
async function createSubtask(req, res) {
try {
const taskId = parseInt(req.params.taskId);
const { title } = req.body;
if (!title) {
res.status(400).json({
success: false,
error: 'Titel ist erforderlich',
});
return;
}
const createdBy = req.user?.email;
const subtask = await contractTaskService.createSubtask({
taskId,
title,
createdBy,
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractSubtask',
resourceId: subtask.id.toString(),
label: `Unteraufgabe "${title}" erstellt`,
});
res.status(201).json({ success: true, data: subtask });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Unteraufgabe',
});
}
}
// Kundenportal: Antwort auf eigenes Ticket erstellen
async function createCustomerReply(req, res) {
try {
const taskId = parseInt(req.params.taskId);
const { title } = req.body;
if (!title) {
res.status(400).json({
success: false,
error: 'Antwort ist erforderlich',
});
return;
}
// Hole den Task
const task = await contractTaskService.getTaskById(taskId);
if (!task) {
res.status(404).json({
success: false,
error: 'Anfrage nicht gefunden',
});
return;
}
// Prüfe ob der Kunde berechtigt ist (eigenes Ticket oder freigegebener Kunde)
if (req.user?.isCustomerPortal && req.user.customerId) {
const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])];
const customers = await customerService.getCustomersByIds(allowedCustomerIds);
const allowedEmails = customers
.map((c) => c.portalEmail)
.filter((email) => !!email);
// Task muss entweder visibleInPortal sein ODER vom Kunden erstellt worden sein
const isOwnTask = task.createdBy && allowedEmails.includes(task.createdBy);
if (!task.visibleInPortal && !isOwnTask) {
res.status(403).json({
success: false,
error: 'Kein Zugriff auf diese Anfrage',
});
return;
}
}
else {
res.status(403).json({
success: false,
error: 'Nur für Kundenportal-Benutzer',
});
return;
}
const createdBy = req.user?.email;
const subtask = await contractTaskService.createSubtask({
taskId,
title,
createdBy,
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'ContractSubtask',
resourceId: subtask.id.toString(),
label: `Kundenantwort erstellt`,
});
res.status(201).json({ success: true, data: subtask });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Antwort',
});
}
}
async function updateSubtask(req, res) {
try {
const subtaskId = parseInt(req.params.subtaskId);
const { title } = req.body;
if (!title) {
res.status(400).json({
success: false,
error: 'Titel ist erforderlich',
});
return;
}
const subtask = await contractTaskService.updateSubtask(subtaskId, { title });
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractSubtask',
resourceId: subtaskId.toString(),
label: `Unteraufgabe aktualisiert`,
});
res.json({ success: true, data: subtask });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Unteraufgabe',
});
}
}
async function completeSubtask(req, res) {
try {
const subtaskId = parseInt(req.params.subtaskId);
const subtask = await contractTaskService.completeSubtask(subtaskId);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractSubtask',
resourceId: subtaskId.toString(),
label: `Unteraufgabe abgeschlossen`,
});
res.json({ success: true, data: subtask });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Abschließen der Unteraufgabe',
});
}
}
async function reopenSubtask(req, res) {
try {
const subtaskId = parseInt(req.params.subtaskId);
const subtask = await contractTaskService.reopenSubtask(subtaskId);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'ContractSubtask',
resourceId: subtaskId.toString(),
label: `Unteraufgabe wiedereröffnet`,
});
res.json({ success: true, data: subtask });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Wiedereröffnen der Unteraufgabe',
});
}
}
async function deleteSubtask(req, res) {
try {
const subtaskId = parseInt(req.params.subtaskId);
await contractTaskService.deleteSubtask(subtaskId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'ContractSubtask',
resourceId: subtaskId.toString(),
label: `Unteraufgabe gelöscht`,
});
res.json({ success: true, message: 'Unteraufgabe gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Unteraufgabe',
});
}
}
//# sourceMappingURL=contractTask.controller.js.map
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
import { Request, Response } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function getCustomers(req: Request, res: Response): Promise<void>;
export declare function getCustomer(req: Request, res: Response): Promise<void>;
export declare function createCustomer(req: Request, res: Response): Promise<void>;
export declare function updateCustomer(req: Request, res: Response): Promise<void>;
export declare function deleteCustomer(req: Request, res: Response): Promise<void>;
export declare function getAddresses(req: Request, res: Response): Promise<void>;
export declare function createAddress(req: Request, res: Response): Promise<void>;
export declare function updateAddress(req: Request, res: Response): Promise<void>;
export declare function deleteAddress(req: Request, res: Response): Promise<void>;
export declare function getBankCards(req: Request, res: Response): Promise<void>;
export declare function createBankCard(req: Request, res: Response): Promise<void>;
export declare function updateBankCard(req: Request, res: Response): Promise<void>;
export declare function deleteBankCard(req: Request, res: Response): Promise<void>;
export declare function getDocuments(req: Request, res: Response): Promise<void>;
export declare function createDocument(req: Request, res: Response): Promise<void>;
export declare function updateDocument(req: Request, res: Response): Promise<void>;
export declare function deleteDocument(req: Request, res: Response): Promise<void>;
export declare function getMeters(req: Request, res: Response): Promise<void>;
export declare function createMeter(req: Request, res: Response): Promise<void>;
export declare function updateMeter(req: Request, res: Response): Promise<void>;
export declare function deleteMeter(req: Request, res: Response): Promise<void>;
export declare function getMeterReadings(req: Request, res: Response): Promise<void>;
export declare function addMeterReading(req: Request, res: Response): Promise<void>;
export declare function updateMeterReading(req: Request, res: Response): Promise<void>;
export declare function deleteMeterReading(req: Request, res: Response): Promise<void>;
export declare function reportMeterReading(req: AuthRequest, res: Response): Promise<void>;
export declare function getMyMeters(req: AuthRequest, res: Response): Promise<void>;
export declare function markReadingTransferred(req: AuthRequest, res: Response): Promise<void>;
export declare function getPortalSettings(req: Request, res: Response): Promise<void>;
export declare function updatePortalSettings(req: Request, res: Response): Promise<void>;
export declare function setPortalPassword(req: Request, res: Response): Promise<void>;
export declare function getPortalPassword(req: Request, res: Response): Promise<void>;
export declare function getRepresentatives(req: Request, res: Response): Promise<void>;
export declare function addRepresentative(req: Request, res: Response): Promise<void>;
export declare function removeRepresentative(req: Request, res: Response): Promise<void>;
export declare function searchForRepresentative(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=customer.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"customer.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/customer.controller.ts"],"names":[],"mappings":"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"}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
import { Request, Response } from 'express';
export declare function getProviderConfigs(req: Request, res: Response): Promise<void>;
export declare function getProviderConfig(req: Request, res: Response): Promise<void>;
export declare function createProviderConfig(req: Request, res: Response): Promise<void>;
export declare function updateProviderConfig(req: Request, res: Response): Promise<void>;
export declare function deleteProviderConfig(req: Request, res: Response): Promise<void>;
export declare function testConnection(req: Request, res: Response): Promise<void>;
export declare function checkEmailExists(req: Request, res: Response): Promise<void>;
export declare function provisionEmail(req: Request, res: Response): Promise<void>;
export declare function deprovisionEmail(req: Request, res: Response): Promise<void>;
export declare function getProviderDomain(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=emailProvider.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"emailProvider.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/emailProvider.controller.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAO5C,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlF;AAED,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAerF;AAED,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrF;AAED,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBrF;AAID,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB/E;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB/E;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWjF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlF"}
+218
View File
@@ -0,0 +1,218 @@
"use strict";
// ==================== EMAIL PROVIDER CONTROLLER ====================
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getProviderConfigs = getProviderConfigs;
exports.getProviderConfig = getProviderConfig;
exports.createProviderConfig = createProviderConfig;
exports.updateProviderConfig = updateProviderConfig;
exports.deleteProviderConfig = deleteProviderConfig;
exports.testConnection = testConnection;
exports.checkEmailExists = checkEmailExists;
exports.provisionEmail = provisionEmail;
exports.deprovisionEmail = deprovisionEmail;
exports.getProviderDomain = getProviderDomain;
const emailProviderService = __importStar(require("../services/emailProvider/emailProviderService.js"));
const audit_service_js_1 = require("../services/audit.service.js");
// ==================== CONFIG CRUD ====================
async function getProviderConfigs(req, res) {
try {
const configs = await emailProviderService.getAllProviderConfigs();
res.json({ success: true, data: configs });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Email-Provider',
});
}
}
async function getProviderConfig(req, res) {
try {
const id = parseInt(req.params.id);
const config = await emailProviderService.getProviderConfigById(id);
if (!config) {
res.status(404).json({
success: false,
error: 'Email-Provider nicht gefunden',
});
return;
}
res.json({ success: true, data: config });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Email-Providers',
});
}
}
async function createProviderConfig(req, res) {
try {
const config = await emailProviderService.createProviderConfig(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'EmailProviderConfig',
resourceId: config.id.toString(),
label: `E-Mail-Provider ${config.name} angelegt`,
});
res.status(201).json({ success: true, data: config });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Email-Providers',
});
}
}
async function updateProviderConfig(req, res) {
try {
const id = parseInt(req.params.id);
const config = await emailProviderService.updateProviderConfig(id, req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'EmailProviderConfig',
resourceId: id.toString(),
label: `E-Mail-Provider ${config.name} aktualisiert`,
});
res.json({ success: true, data: config });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Email-Providers',
});
}
}
async function deleteProviderConfig(req, res) {
try {
const id = parseInt(req.params.id);
const config = await emailProviderService.getProviderConfigById(id);
await emailProviderService.deleteProviderConfig(id);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'EmailProviderConfig',
resourceId: id.toString(),
label: `E-Mail-Provider ${config?.name || id} gelöscht`,
});
res.json({ success: true, message: 'Email-Provider gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Email-Providers',
});
}
}
// ==================== EMAIL OPERATIONS ====================
async function testConnection(req, res) {
try {
// Option 1: Provider-ID für gespeicherten Provider
const id = req.body?.id ? parseInt(req.body.id) : undefined;
// Option 2: Testdaten aus Body (für Test im Modal mit ungespeicherten Daten)
const testData = req.body && req.body.type ? {
type: req.body.type,
apiUrl: req.body.apiUrl,
apiKey: req.body.apiKey || undefined,
username: req.body.username || undefined,
password: req.body.password || undefined,
domain: req.body.domain,
} : undefined;
const result = await emailProviderService.testProviderConnection({ id, testData });
res.json({ success: result.success, data: result });
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Verbindungstest fehlgeschlagen',
});
}
}
async function checkEmailExists(req, res) {
try {
const { localPart } = req.params;
const result = await emailProviderService.checkEmailExists(localPart);
res.json({ success: true, data: result });
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler bei der E-Mail-Prüfung',
});
}
}
async function provisionEmail(req, res) {
try {
const { localPart, customerEmail } = req.body;
if (!localPart || !customerEmail) {
res.status(400).json({
success: false,
error: 'localPart und customerEmail sind erforderlich',
});
return;
}
const result = await emailProviderService.provisionEmail(localPart, customerEmail);
res.json({ success: result.success, data: result });
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler bei der E-Mail-Provisionierung',
});
}
}
async function deprovisionEmail(req, res) {
try {
const { localPart } = req.params;
const result = await emailProviderService.deprovisionEmail(localPart);
res.json({ success: result.success, data: result });
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der E-Mail',
});
}
}
async function getProviderDomain(req, res) {
try {
const domain = await emailProviderService.getProviderDomain();
res.json({ success: true, data: { domain } });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Domain',
});
}
}
//# sourceMappingURL=emailProvider.controller.js.map
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getPlatforms(req: Request, res: Response): Promise<void>;
export declare function getPlatform(req: Request, res: Response): Promise<void>;
export declare function createPlatform(req: Request, res: Response): Promise<void>;
export declare function updatePlatform(req: Request, res: Response): Promise<void>;
export declare function deletePlatform(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=platform.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"platform.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/platform.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E"}
+128
View File
@@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPlatforms = getPlatforms;
exports.getPlatform = getPlatform;
exports.createPlatform = createPlatform;
exports.updatePlatform = updatePlatform;
exports.deletePlatform = deletePlatform;
const platformService = __importStar(require("../services/platform.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getPlatforms(req, res) {
try {
const includeInactive = req.query.includeInactive === 'true';
const platforms = await platformService.getAllPlatforms(includeInactive);
res.json({ success: true, data: platforms });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Vertriebsplattformen',
});
}
}
async function getPlatform(req, res) {
try {
const platform = await platformService.getPlatformById(parseInt(req.params.id));
if (!platform) {
res.status(404).json({
success: false,
error: 'Vertriebsplattform nicht gefunden',
});
return;
}
res.json({ success: true, data: platform });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Vertriebsplattform',
});
}
}
async function createPlatform(req, res) {
try {
const platform = await platformService.createPlatform(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Platform',
resourceId: platform.id.toString(),
label: `Vertriebsplattform ${platform.name} angelegt`,
});
res.status(201).json({ success: true, data: platform });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Vertriebsplattform',
});
}
}
async function updatePlatform(req, res) {
try {
const platform = await platformService.updatePlatform(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Platform',
resourceId: platform.id.toString(),
label: `Vertriebsplattform ${platform.name} aktualisiert`,
});
res.json({ success: true, data: platform });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Vertriebsplattform',
});
}
}
async function deletePlatform(req, res) {
try {
const platformId = parseInt(req.params.id);
const platform = await platformService.getPlatformById(platformId);
await platformService.deletePlatform(platformId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'Platform',
resourceId: platformId.toString(),
label: `Vertriebsplattform ${platform?.name || platformId} gelöscht`,
});
res.json({ success: true, message: 'Vertriebsplattform gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Vertriebsplattform',
});
}
}
//# sourceMappingURL=platform.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"platform.controller.js","sourceRoot":"","sources":["../../src/controllers/platform.controller.ts"],"names":[],"mappings":"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"}
+7
View File
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getProviders(req: Request, res: Response): Promise<void>;
export declare function getProvider(req: Request, res: Response): Promise<void>;
export declare function createProvider(req: Request, res: Response): Promise<void>;
export declare function updateProvider(req: Request, res: Response): Promise<void>;
export declare function deleteProvider(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=provider.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"provider.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/provider.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E"}
+128
View File
@@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getProviders = getProviders;
exports.getProvider = getProvider;
exports.createProvider = createProvider;
exports.updateProvider = updateProvider;
exports.deleteProvider = deleteProvider;
const providerService = __importStar(require("../services/provider.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getProviders(req, res) {
try {
const includeInactive = req.query.includeInactive === 'true';
const providers = await providerService.getAllProviders(includeInactive);
res.json({ success: true, data: providers });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Anbieter',
});
}
}
async function getProvider(req, res) {
try {
const provider = await providerService.getProviderById(parseInt(req.params.id));
if (!provider) {
res.status(404).json({
success: false,
error: 'Anbieter nicht gefunden',
});
return;
}
res.json({ success: true, data: provider });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Anbieters',
});
}
}
async function createProvider(req, res) {
try {
const provider = await providerService.createProvider(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Provider',
resourceId: provider.id.toString(),
label: `Anbieter ${provider.name} angelegt`,
});
res.status(201).json({ success: true, data: provider });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Anbieters',
});
}
}
async function updateProvider(req, res) {
try {
const provider = await providerService.updateProvider(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Provider',
resourceId: provider.id.toString(),
label: `Anbieter ${provider.name} aktualisiert`,
});
res.json({ success: true, data: provider });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Anbieters',
});
}
}
async function deleteProvider(req, res) {
try {
const providerId = parseInt(req.params.id);
const provider = await providerService.getProviderById(providerId);
await providerService.deleteProvider(providerId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'Provider',
resourceId: providerId.toString(),
label: `Anbieter ${provider?.name || providerId} gelöscht`,
});
res.json({ success: true, message: 'Anbieter gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Anbieters',
});
}
}
//# sourceMappingURL=provider.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"provider.controller.js","sourceRoot":"","sources":["../../src/controllers/provider.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
import { Request, Response } from 'express';
export declare function getEmailsByCustomer(req: Request, res: Response): Promise<void>;
export declare function getEmail(req: Request, res: Response): Promise<void>;
export declare function createEmail(req: Request, res: Response): Promise<void>;
export declare function updateEmail(req: Request, res: Response): Promise<void>;
export declare function deleteEmail(req: Request, res: Response): Promise<void>;
export declare function resetPassword(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=stressfreiEmail.controller.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"stressfreiEmail.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/stressfreiEmail.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpF;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBzE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB5E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5E;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB9E"}
+157
View File
@@ -0,0 +1,157 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEmailsByCustomer = getEmailsByCustomer;
exports.getEmail = getEmail;
exports.createEmail = createEmail;
exports.updateEmail = updateEmail;
exports.deleteEmail = deleteEmail;
exports.resetPassword = resetPassword;
const stressfreiEmailService = __importStar(require("../services/stressfreiEmail.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getEmailsByCustomer(req, res) {
try {
const customerId = parseInt(req.params.customerId);
const includeInactive = req.query.includeInactive === 'true';
const emails = await stressfreiEmailService.getEmailsByCustomerId(customerId, includeInactive);
res.json({ success: true, data: emails });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Stressfrei-Wechseln Adressen',
});
}
}
async function getEmail(req, res) {
try {
const email = await stressfreiEmailService.getEmailById(parseInt(req.params.id));
if (!email) {
res.status(404).json({
success: false,
error: 'Stressfrei-Wechseln Adresse nicht gefunden',
});
return;
}
res.json({ success: true, data: email });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Stressfrei-Wechseln Adresse',
});
}
}
async function createEmail(req, res) {
try {
const customerId = parseInt(req.params.customerId);
const email = await stressfreiEmailService.createEmail({
...req.body,
customerId,
});
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'StressfreiEmail',
resourceId: email.id.toString(),
label: `Stressfrei-Wechseln Adresse angelegt für Kunde #${customerId}`,
customerId,
});
res.status(201).json({ success: true, data: email });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Stressfrei-Wechseln Adresse',
});
}
}
async function updateEmail(req, res) {
try {
const email = await stressfreiEmailService.updateEmail(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'StressfreiEmail',
resourceId: email.id.toString(),
label: `Stressfrei-Wechseln Adresse aktualisiert`,
});
res.json({ success: true, data: email });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Stressfrei-Wechseln Adresse',
});
}
}
async function deleteEmail(req, res) {
try {
const emailId = parseInt(req.params.id);
await stressfreiEmailService.deleteEmail(emailId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'StressfreiEmail',
resourceId: emailId.toString(),
label: `Stressfrei-Wechseln Adresse gelöscht`,
});
res.json({ success: true, message: 'Stressfrei-Wechseln Adresse gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Stressfrei-Wechseln Adresse',
});
}
}
async function resetPassword(req, res) {
try {
const result = await stressfreiEmailService.resetMailboxPassword(parseInt(req.params.id));
if (!result.success) {
res.status(400).json({
success: false,
error: result.error,
});
return;
}
res.json({
success: true,
data: { password: result.password },
message: 'Passwort wurde zurückgesetzt',
});
}
catch (error) {
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Zurücksetzen des Passworts',
});
}
}
//# sourceMappingURL=stressfreiEmail.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"stressfreiEmail.controller.js","sourceRoot":"","sources":["../../src/controllers/stressfreiEmail.controller.ts"],"names":[],"mappings":"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"}
+7
View File
@@ -0,0 +1,7 @@
import { Request, Response } from 'express';
export declare function getTariffs(req: Request, res: Response): Promise<void>;
export declare function getTariff(req: Request, res: Response): Promise<void>;
export declare function createTariff(req: Request, res: Response): Promise<void>;
export declare function updateTariff(req: Request, res: Response): Promise<void>;
export declare function deleteTariff(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=tariff.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"tariff.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/tariff.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAK5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3E;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB1E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB7E"}
+130
View File
@@ -0,0 +1,130 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTariffs = getTariffs;
exports.getTariff = getTariff;
exports.createTariff = createTariff;
exports.updateTariff = updateTariff;
exports.deleteTariff = deleteTariff;
const tariffService = __importStar(require("../services/tariff.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
async function getTariffs(req, res) {
try {
const providerId = parseInt(req.params.providerId);
const includeInactive = req.query.includeInactive === 'true';
const tariffs = await tariffService.getTariffsByProvider(providerId, includeInactive);
res.json({ success: true, data: tariffs });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Tarife',
});
}
}
async function getTariff(req, res) {
try {
const tariff = await tariffService.getTariffById(parseInt(req.params.id));
if (!tariff) {
res.status(404).json({
success: false,
error: 'Tarif nicht gefunden',
});
return;
}
res.json({ success: true, data: tariff });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Tarifs',
});
}
}
async function createTariff(req, res) {
try {
const providerId = parseInt(req.params.providerId);
const tariff = await tariffService.createTariff({ ...req.body, providerId });
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Tariff',
resourceId: tariff.id.toString(),
label: `Tarif ${tariff.name} angelegt`,
});
res.status(201).json({ success: true, data: tariff });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Tarifs',
});
}
}
async function updateTariff(req, res) {
try {
const tariff = await tariffService.updateTariff(parseInt(req.params.id), req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Tariff',
resourceId: tariff.id.toString(),
label: `Tarif ${tariff.name} aktualisiert`,
});
res.json({ success: true, data: tariff });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Tarifs',
});
}
}
async function deleteTariff(req, res) {
try {
const tariffId = parseInt(req.params.id);
const tariff = await tariffService.getTariffById(tariffId);
await tariffService.deleteTariff(tariffId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'Tariff',
resourceId: tariffId.toString(),
label: `Tarif ${tariff?.name || tariffId} gelöscht`,
});
res.json({ success: true, message: 'Tarif gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Tarifs',
});
}
}
//# sourceMappingURL=tariff.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"tariff.controller.js","sourceRoot":"","sources":["../../src/controllers/tariff.controller.ts"],"names":[],"mappings":"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"}
+13
View File
@@ -0,0 +1,13 @@
import { Request, Response } from 'express';
export declare function getUsers(req: Request, res: Response): Promise<void>;
export declare function getUser(req: Request, res: Response): Promise<void>;
export declare function createUser(req: Request, res: Response): Promise<void>;
export declare function updateUser(req: Request, res: Response): Promise<void>;
export declare function deleteUser(req: Request, res: Response): Promise<void>;
export declare function getRoles(req: Request, res: Response): Promise<void>;
export declare function getRole(req: Request, res: Response): Promise<void>;
export declare function createRole(req: Request, res: Response): Promise<void>;
export declare function updateRole(req: Request, res: Response): Promise<void>;
export declare function deleteRole(req: Request, res: Response): Promise<void>;
export declare function getPermissions(req: Request, res: Response): Promise<void>;
//# sourceMappingURL=user.controller.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"user.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/user.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAO5C,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzE;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxE;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe3E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoD3E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB3E;AAGD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAUzE;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxE;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAe3E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB3E;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB3E;AAGD,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/E"}
+288
View File
@@ -0,0 +1,288 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUsers = getUsers;
exports.getUser = getUser;
exports.createUser = createUser;
exports.updateUser = updateUser;
exports.deleteUser = deleteUser;
exports.getRoles = getRoles;
exports.getRole = getRole;
exports.createRole = createRole;
exports.updateRole = updateRole;
exports.deleteRole = deleteRole;
exports.getPermissions = getPermissions;
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const userService = __importStar(require("../services/user.service.js"));
const audit_service_js_1 = require("../services/audit.service.js");
// Users
async function getUsers(req, res) {
try {
const { search, isActive, roleId, page, limit } = req.query;
const result = await userService.getAllUsers({
search: search,
isActive: isActive !== undefined ? isActive === 'true' : undefined,
roleId: roleId ? parseInt(roleId) : undefined,
page: page ? parseInt(page) : undefined,
limit: limit ? parseInt(limit) : undefined,
});
res.json({
success: true,
data: result.users,
pagination: result.pagination,
});
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Benutzer',
});
}
}
async function getUser(req, res) {
try {
const user = await userService.getUserById(parseInt(req.params.id));
if (!user) {
res.status(404).json({
success: false,
error: 'Benutzer nicht gefunden',
});
return;
}
res.json({ success: true, data: user });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden des Benutzers',
});
}
}
async function createUser(req, res) {
try {
const user = await userService.createUser(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'User',
resourceId: user.id.toString(),
label: `Benutzer ${user.firstName} ${user.lastName} angelegt`,
});
res.status(201).json({ success: true, data: user });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Benutzers',
});
}
}
async function updateUser(req, res) {
try {
const userId = parseInt(req.params.id);
const data = req.body;
// Vorherigen Stand laden für Audit
const before = await prisma_js_1.default.user.findUnique({ where: { id: userId } });
const user = await userService.updateUser(userId, data);
if (user) {
// Audit: Geänderte Felder ermitteln und loggen
if (before) {
const changes = {};
const fieldLabels = {
email: 'E-Mail', firstName: 'Vorname', lastName: 'Nachname', isActive: 'Aktiv',
};
for (const [key, newVal] of Object.entries(data)) {
if (['id', 'createdAt', 'updatedAt'].includes(key))
continue;
const oldVal = before[key];
const norm = (v) => (v === null || v === undefined || v === '' ? null : v);
if (JSON.stringify(norm(oldVal)) !== JSON.stringify(norm(newVal))) {
const label = fieldLabels[key] || key;
const formatVal = (v) => {
if (v === null || v === undefined || v === '')
return '-';
if (typeof v === 'boolean')
return v ? 'Ja' : 'Nein';
return String(v);
};
changes[label] = { von: formatVal(oldVal), nach: formatVal(newVal) };
}
}
const changeList = Object.entries(changes).map(([f, c]) => `${f}: ${c.von}${c.nach}`).join(', ');
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'User',
resourceId: user.id.toString(),
label: changeList ? `Benutzer ${user.firstName} ${user.lastName} aktualisiert: ${changeList}` : `Benutzer ${user.firstName} ${user.lastName} aktualisiert`,
details: Object.keys(changes).length > 0 ? changes : undefined,
});
}
else {
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'User',
resourceId: user.id.toString(),
label: `Benutzer ${user.firstName} ${user.lastName} aktualisiert`,
});
}
}
res.json({ success: true, data: user });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Benutzers',
});
}
}
async function deleteUser(req, res) {
try {
const userId = parseInt(req.params.id);
const userBefore = await userService.getUserById(userId);
await userService.deleteUser(userId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'User',
resourceId: userId.toString(),
label: `Benutzer ${userBefore?.firstName || ''} ${userBefore?.lastName || ''} gelöscht`,
});
res.json({ success: true, message: 'Benutzer gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Benutzers',
});
}
}
// Roles
async function getRoles(req, res) {
try {
const roles = await userService.getAllRoles();
res.json({ success: true, data: roles });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Rollen',
});
}
}
async function getRole(req, res) {
try {
const role = await userService.getRoleById(parseInt(req.params.id));
if (!role) {
res.status(404).json({
success: false,
error: 'Rolle nicht gefunden',
});
return;
}
res.json({ success: true, data: role });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Rolle',
});
}
}
async function createRole(req, res) {
try {
const role = await userService.createRole(req.body);
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'Role',
resourceId: role.id.toString(),
label: `Rolle ${role.name} angelegt`,
});
res.status(201).json({ success: true, data: role });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Erstellen der Rolle',
});
}
}
async function updateRole(req, res) {
try {
const role = await userService.updateRole(parseInt(req.params.id), req.body);
if (role) {
await (0, audit_service_js_1.logChange)({
req, action: 'UPDATE', resourceType: 'Role',
resourceId: role.id.toString(),
label: `Rolle ${role.name} aktualisiert`,
});
}
res.json({ success: true, data: role });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren der Rolle',
});
}
}
async function deleteRole(req, res) {
try {
const roleId = parseInt(req.params.id);
const role = await userService.getRoleById(roleId);
await userService.deleteRole(roleId);
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'Role',
resourceId: roleId.toString(),
label: `Rolle ${role?.name || roleId} gelöscht`,
});
res.json({ success: true, message: 'Rolle gelöscht' });
}
catch (error) {
res.status(400).json({
success: false,
error: error instanceof Error ? error.message : 'Fehler beim Löschen der Rolle',
});
}
}
// Permissions
async function getPermissions(req, res) {
try {
const permissions = await userService.getAllPermissions();
res.json({ success: true, data: permissions });
}
catch (error) {
res.status(500).json({
success: false,
error: 'Fehler beim Laden der Berechtigungen',
});
}
}
//# sourceMappingURL=user.controller.js.map
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
+107
View File
@@ -0,0 +1,107 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const cors_1 = __importDefault(require("cors"));
const path_1 = __importDefault(require("path"));
const dotenv_1 = __importDefault(require("dotenv"));
const auth_routes_js_1 = __importDefault(require("./routes/auth.routes.js"));
const customer_routes_js_1 = __importDefault(require("./routes/customer.routes.js"));
const address_routes_js_1 = __importDefault(require("./routes/address.routes.js"));
const bankcard_routes_js_1 = __importDefault(require("./routes/bankcard.routes.js"));
const document_routes_js_1 = __importDefault(require("./routes/document.routes.js"));
const meter_routes_js_1 = __importDefault(require("./routes/meter.routes.js"));
const stressfreiEmail_routes_js_1 = __importDefault(require("./routes/stressfreiEmail.routes.js"));
const contract_routes_js_1 = __importDefault(require("./routes/contract.routes.js"));
const platform_routes_js_1 = __importDefault(require("./routes/platform.routes.js"));
const cancellation_period_routes_js_1 = __importDefault(require("./routes/cancellation-period.routes.js"));
const contract_duration_routes_js_1 = __importDefault(require("./routes/contract-duration.routes.js"));
const provider_routes_js_1 = __importDefault(require("./routes/provider.routes.js"));
const tariff_routes_js_1 = __importDefault(require("./routes/tariff.routes.js"));
const user_routes_js_1 = __importDefault(require("./routes/user.routes.js"));
const upload_routes_js_1 = __importDefault(require("./routes/upload.routes.js"));
const developer_routes_js_1 = __importDefault(require("./routes/developer.routes.js"));
const contractCategory_routes_js_1 = __importDefault(require("./routes/contractCategory.routes.js"));
const contractTask_routes_js_1 = __importDefault(require("./routes/contractTask.routes.js"));
const appSetting_routes_js_1 = __importDefault(require("./routes/appSetting.routes.js"));
const emailProvider_routes_js_1 = __importDefault(require("./routes/emailProvider.routes.js"));
const cachedEmail_routes_js_1 = __importDefault(require("./routes/cachedEmail.routes.js"));
const invoice_routes_js_1 = __importDefault(require("./routes/invoice.routes.js"));
const contractHistory_routes_js_1 = __importDefault(require("./routes/contractHistory.routes.js"));
const auditLog_routes_js_1 = __importDefault(require("./routes/auditLog.routes.js"));
const gdpr_routes_js_1 = __importDefault(require("./routes/gdpr.routes.js"));
const consent_public_routes_js_1 = __importDefault(require("./routes/consent-public.routes.js"));
const emailLog_routes_js_1 = __importDefault(require("./routes/emailLog.routes.js"));
const pdfTemplate_routes_js_1 = __importDefault(require("./routes/pdfTemplate.routes.js"));
const auditContext_js_1 = require("./middleware/auditContext.js");
const audit_js_1 = require("./middleware/audit.js");
dotenv_1.default.config();
const app = (0, express_1.default)();
const PORT = process.env.PORT || 3001;
// Middleware
app.use((0, cors_1.default)());
app.use(express_1.default.json());
// Audit-Logging Middleware (DSGVO-konform)
app.use(auditContext_js_1.auditContextMiddleware);
app.use(audit_js_1.auditMiddleware);
// Statische Dateien für Uploads
app.use('/api/uploads', express_1.default.static(path_1.default.join(process.cwd(), 'uploads')));
// Öffentliche Routes (OHNE Authentifizierung)
app.use('/api/public/consent', consent_public_routes_js_1.default);
// Routes
app.use('/api/auth', auth_routes_js_1.default);
app.use('/api/customers', customer_routes_js_1.default);
app.use('/api/addresses', address_routes_js_1.default);
app.use('/api/bank-cards', bankcard_routes_js_1.default);
app.use('/api/documents', document_routes_js_1.default);
app.use('/api/meters', meter_routes_js_1.default);
app.use('/api/stressfrei-emails', stressfreiEmail_routes_js_1.default);
app.use('/api/contracts', contract_routes_js_1.default);
app.use('/api/platforms', platform_routes_js_1.default);
app.use('/api/cancellation-periods', cancellation_period_routes_js_1.default);
app.use('/api/contract-durations', contract_duration_routes_js_1.default);
app.use('/api/providers', provider_routes_js_1.default);
app.use('/api/tariffs', tariff_routes_js_1.default);
app.use('/api/users', user_routes_js_1.default);
app.use('/api/upload', upload_routes_js_1.default);
app.use('/api/developer', developer_routes_js_1.default);
app.use('/api/contract-categories', contractCategory_routes_js_1.default);
app.use('/api', contractTask_routes_js_1.default);
app.use('/api/settings', appSetting_routes_js_1.default);
app.use('/api/email-providers', emailProvider_routes_js_1.default);
app.use('/api', cachedEmail_routes_js_1.default);
app.use('/api/energy-details', invoice_routes_js_1.default);
app.use('/api', contractHistory_routes_js_1.default);
app.use('/api/audit-logs', auditLog_routes_js_1.default);
app.use('/api/gdpr', gdpr_routes_js_1.default);
app.use('/api/email-logs', emailLog_routes_js_1.default);
app.use('/api/pdf-templates', pdfTemplate_routes_js_1.default);
// Health check
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Production: Serve frontend static files
if (process.env.NODE_ENV === 'production') {
const publicPath = path_1.default.join(process.cwd(), 'public');
// Serve static files
app.use(express_1.default.static(publicPath));
// SPA fallback: serve index.html for all non-API routes
app.get('*', (req, res, next) => {
// Skip API routes
if (req.path.startsWith('/api')) {
return next();
}
res.sendFile(path_1.default.join(publicPath, 'index.html'));
});
}
// Error handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ success: false, error: 'Interner Serverfehler' });
});
app.listen(PORT, () => {
console.log(`Server läuft auf Port ${PORT}`);
});
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
+6
View File
@@ -0,0 +1,6 @@
import { Response, NextFunction } from 'express';
import { AuthRequest } from '../types/index.js';
export declare function authenticate(req: AuthRequest, res: Response, next: NextFunction): Promise<void>;
export declare function requirePermission(...requiredPermissions: string[]): (req: AuthRequest, res: Response, next: NextFunction) => void;
export declare function requireCustomerAccess(req: AuthRequest, res: Response, next: NextFunction): void;
//# sourceMappingURL=auth.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAE5D,wBAAsB,YAAY,CAChC,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAuDf;AAED,wBAAgB,iBAAiB,CAAC,GAAG,mBAAmB,EAAE,MAAM,EAAE,IACxD,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAuBnE;AAGD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,IAAI,CAiCN"}
+105
View File
@@ -0,0 +1,105 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.authenticate = authenticate;
exports.requirePermission = requirePermission;
exports.requireCustomerAccess = requireCustomerAccess;
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
async function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
// Token aus Header oder Query-Parameter (für Downloads)
let token = null;
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.split(' ')[1];
}
else if (req.query.token && typeof req.query.token === 'string') {
// Fallback für Downloads: Token als Query-Parameter
token = req.query.token;
}
if (!token) {
res.status(401).json({ success: false, error: 'Nicht authentifiziert' });
return;
}
try {
const decoded = jsonwebtoken_1.default.verify(token, process.env.JWT_SECRET || 'fallback-secret');
// Prüfen ob Token durch Rechteänderung invalidiert wurde (nur für Mitarbeiter)
if (decoded.userId && decoded.iat) {
const user = await prisma_js_1.default.user.findUnique({
where: { id: decoded.userId },
select: { tokenInvalidatedAt: true, isActive: true },
});
// Benutzer nicht gefunden oder deaktiviert
if (!user || !user.isActive) {
res.status(401).json({ success: false, error: 'Benutzer nicht mehr aktiv' });
return;
}
// Token wurde vor der Invalidierung ausgestellt
if (user.tokenInvalidatedAt) {
const tokenIssuedAt = decoded.iat * 1000; // iat ist in Sekunden, Date ist in Millisekunden
if (tokenIssuedAt < user.tokenInvalidatedAt.getTime()) {
res.status(401).json({
success: false,
error: 'Ihre Berechtigungen wurden geändert. Bitte melden Sie sich erneut an.',
});
return;
}
}
}
req.user = decoded;
next();
}
catch {
res.status(401).json({ success: false, error: 'Ungültiger Token' });
}
}
function requirePermission(...requiredPermissions) {
return (req, res, next) => {
if (!req.user) {
res.status(401).json({ success: false, error: 'Nicht authentifiziert' });
return;
}
const userPermissions = req.user.permissions || [];
// Check if user has any of the required permissions
const hasPermission = requiredPermissions.some((perm) => userPermissions.includes(perm));
if (!hasPermission) {
res.status(403).json({
success: false,
error: 'Keine Berechtigung für diese Aktion',
});
return;
}
next();
};
}
// Middleware to check if user can access specific customer data
function requireCustomerAccess(req, res, next) {
if (!req.user) {
res.status(401).json({ success: false, error: 'Nicht authentifiziert' });
return;
}
const userPermissions = req.user.permissions || [];
// Admins and employees can access all customers
if (userPermissions.includes('customers:read') ||
userPermissions.includes('customers:update')) {
next();
return;
}
// Customers can only access their own data + represented customers
const customerId = parseInt(req.params.customerId || req.params.id);
const allowedIds = [
req.user.customerId,
...(req.user.representedCustomerIds || []),
].filter(Boolean);
if (allowedIds.includes(customerId)) {
next();
return;
}
res.status(403).json({
success: false,
error: 'Kein Zugriff auf diese Kundendaten',
});
}
//# sourceMappingURL=auth.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":";;;;;AAKA,oCA2DC;AAED,8CAwBC;AAGD,sDAqCC;AAjID,gEAA+B;AAC/B,iEAAsC;AAG/B,KAAK,UAAU,YAAY,CAChC,GAAgB,EAChB,GAAa,EACb,IAAkB;IAElB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IAE7C,wDAAwD;IACxD,IAAI,KAAK,GAAkB,IAAI,CAAC;IAEhC,IAAI,UAAU,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnD,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;SAAM,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAClE,oDAAoD;QACpD,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CACxB,KAAK,EACL,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,iBAAiB,CAC9B,CAAC;QAEhB,+EAA+E;QAC/E,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,MAAM,mBAAM,CAAC,IAAI,CAAC,UAAU,CAAC;gBACxC,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE;gBAC7B,MAAM,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;aACrD,CAAC,CAAC;YAEH,2CAA2C;YAC3C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;gBAC7E,OAAO;YACT,CAAC;YAED,gDAAgD;YAChD,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,iDAAiD;gBAC3F,IAAI,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC;oBACtD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;wBACnB,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,uEAAuE;qBAC/E,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC;QACnB,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAgB,iBAAiB,CAAC,GAAG,mBAA6B;IAChE,OAAO,CAAC,GAAgB,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QACnE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,MAAM,eAAe,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;QAEnD,oDAAoD;QACpD,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACtD,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAC/B,CAAC;QAEF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,qCAAqC;aAC7C,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,SAAgB,qBAAqB,CACnC,GAAgB,EAChB,GAAa,EACb,IAAkB;IAElB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;IAEnD,gDAAgD;IAChD,IACE,eAAe,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAC1C,eAAe,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC5C,CAAC;QACD,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,mEAAmE;IACnE,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG;QACjB,GAAG,CAAC,IAAI,CAAC,UAAU;QACnB,GAAG,CAAE,GAAG,CAAC,IAAY,CAAC,sBAAsB,IAAI,EAAE,CAAC;KACpD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElB,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACpC,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,oCAAoC;KAC5C,CAAC,CAAC;AACL,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=address.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"address.routes.d.ts","sourceRoot":"","sources":["../../src/routes/address.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAKxB,eAAe,MAAM,CAAC"}
+43
View File
@@ -0,0 +1,43 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const customerController = __importStar(require("../controllers/customer.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
router.put('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), customerController.updateAddress);
router.delete('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:delete'), customerController.deleteAddress);
exports.default = router;
//# sourceMappingURL=address.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"address.routes.js","sourceRoot":"","sources":["../../src/routes/address.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,0FAA4E;AAC5E,mDAAwE;AAExE,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;AAC1G,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;AAE7G,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=appSetting.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"appSetting.routes.d.ts","sourceRoot":"","sources":["../../src/routes/appSetting.routes.ts"],"names":[],"mappings":"AAmBA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAmFxB,eAAe,MAAM,CAAC"}
+82
View File
@@ -0,0 +1,82 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const multer_1 = __importDefault(require("multer"));
const appSettingController = __importStar(require("../controllers/appSetting.controller.js"));
const backupController = __importStar(require("../controllers/backup.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
// Multer für Backup-Upload (in Memory speichern)
const backupUpload = (0, multer_1.default)({
storage: multer_1.default.memoryStorage(),
limits: { fileSize: 500 * 1024 * 1024 }, // 500MB max
fileFilter: (req, file, cb) => {
if (file.mimetype === 'application/zip' || file.originalname.endsWith('.zip')) {
cb(null, true);
}
else {
cb(new Error('Nur ZIP-Dateien sind erlaubt'));
}
},
});
const router = (0, express_1.Router)();
// Öffentliche Einstellungen (für alle authentifizierten Benutzer, inkl. Kunden)
router.get('/public', auth_js_1.authenticate, appSettingController.getPublicSettings);
// Alle Einstellungen (nur Admin)
router.get('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:read'), appSettingController.getAllSettings);
// Einzelne Einstellung aktualisieren (nur Admin)
router.put('/:key', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), appSettingController.updateSetting);
// Mehrere Einstellungen aktualisieren (nur Admin)
router.put('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), appSettingController.updateSettings);
// ==================== BACKUP & RESTORE ====================
// Liste aller Backups
router.get('/backups', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.listBackups);
// Neues Backup erstellen
router.post('/backup', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.createBackup);
// Backup wiederherstellen
router.post('/backup/:name/restore', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.restoreBackup);
// Backup löschen
router.delete('/backup/:name', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.deleteBackup);
// Backup als ZIP herunterladen
router.get('/backup/:name/download', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.downloadBackup);
// Backup-ZIP hochladen
router.post('/backup/upload', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupUpload.single('backup'), backupController.uploadBackup);
// Werkseinstellungen (alles löschen)
router.post('/factory-reset', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('settings:update'), backupController.factoryReset);
exports.default = router;
//# sourceMappingURL=appSetting.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"appSetting.routes.js","sourceRoot":"","sources":["../../src/routes/appSetting.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,oDAA4B;AAC5B,8FAAgF;AAChF,sFAAwE;AACxE,mDAAwE;AAExE,iDAAiD;AACjD,MAAM,YAAY,GAAG,IAAA,gBAAM,EAAC;IAC1B,OAAO,EAAE,gBAAM,CAAC,aAAa,EAAE;IAC/B,MAAM,EAAE,EAAE,QAAQ,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,YAAY;IACrD,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;QAC5B,IAAI,IAAI,CAAC,QAAQ,KAAK,iBAAiB,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9E,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,gFAAgF;AAChF,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,sBAAY,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAE5E,iCAAiC;AACjC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,eAAe,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAC;AAEvG,iDAAiD;AACjD,MAAM,CAAC,GAAG,CACR,OAAO,EACP,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,oBAAoB,CAAC,aAAa,CACnC,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,GAAG,CACR,GAAG,EACH,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,oBAAoB,CAAC,cAAc,CACpC,CAAC;AAEF,6DAA6D;AAE7D,sBAAsB;AACtB,MAAM,CAAC,GAAG,CACR,UAAU,EACV,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,WAAW,CAC7B,CAAC;AAEF,yBAAyB;AACzB,MAAM,CAAC,IAAI,CACT,SAAS,EACT,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,YAAY,CAC9B,CAAC;AAEF,0BAA0B;AAC1B,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,aAAa,CAC/B,CAAC;AAEF,iBAAiB;AACjB,MAAM,CAAC,MAAM,CACX,eAAe,EACf,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,YAAY,CAC9B,CAAC;AAEF,+BAA+B;AAC/B,MAAM,CAAC,GAAG,CACR,wBAAwB,EACxB,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,cAAc,CAChC,CAAC;AAEF,uBAAuB;AACvB,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC7B,gBAAgB,CAAC,YAAY,CAC9B,CAAC;AAEF,qCAAqC;AACrC,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,sBAAY,EACZ,IAAA,2BAAiB,EAAC,iBAAiB,CAAC,EACpC,gBAAgB,CAAC,YAAY,CAC9B,CAAC;AAEF,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=auth.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.routes.d.ts","sourceRoot":"","sources":["../../src/routes/auth.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAOxB,eAAe,MAAM,CAAC"}
+45
View File
@@ -0,0 +1,45 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const authController = __importStar(require("../controllers/auth.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
router.post('/login', authController.login);
router.post('/customer-login', authController.customerLogin); // Kundenportal-Login
router.get('/me', auth_js_1.authenticate, authController.me);
router.post('/register', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('users:create'), authController.register);
exports.default = router;
//# sourceMappingURL=auth.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth.routes.js","sourceRoot":"","sources":["../../src/routes/auth.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,kFAAoE;AACpE,mDAAwE;AAExE,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;AAC5C,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAE,qBAAqB;AACpF,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,sBAAY,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;AACnD,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,cAAc,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;AAEnG,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=bankcard.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bankcard.routes.d.ts","sourceRoot":"","sources":["../../src/routes/bankcard.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAKxB,eAAe,MAAM,CAAC"}
+43
View File
@@ -0,0 +1,43 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const customerController = __importStar(require("../controllers/customer.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
router.put('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), customerController.updateBankCard);
router.delete('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:delete'), customerController.deleteBankCard);
exports.default = router;
//# sourceMappingURL=bankcard.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bankcard.routes.js","sourceRoot":"","sources":["../../src/routes/bankcard.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,0FAA4E;AAC5E,mDAAwE;AAExE,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;AAC3G,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;AAE9G,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=cancellation-period.routes.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"cancellation-period.routes.d.ts","sourceRoot":"","sources":["../../src/routes/cancellation-period.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAQxB,eAAe,MAAM,CAAC"}
+46
View File
@@ -0,0 +1,46 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const cancellationPeriodController = __importStar(require("../controllers/cancellation-period.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
router.get('/', auth_js_1.authenticate, cancellationPeriodController.getCancellationPeriods);
router.post('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:create'), cancellationPeriodController.createCancellationPeriod);
router.get('/:id', auth_js_1.authenticate, cancellationPeriodController.getCancellationPeriod);
router.put('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:update'), cancellationPeriodController.updateCancellationPeriod);
router.delete('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:delete'), cancellationPeriodController.deleteCancellationPeriod);
exports.default = router;
//# sourceMappingURL=cancellation-period.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"cancellation-period.routes.js","sourceRoot":"","sources":["../../src/routes/cancellation-period.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,+GAAiG;AACjG,mDAAwE;AAExE,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,sBAAY,EAAE,4BAA4B,CAAC,sBAAsB,CAAC,CAAC;AACnF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,4BAA4B,CAAC,wBAAwB,CAAC,CAAC;AAC7H,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,4BAA4B,CAAC,qBAAqB,CAAC,CAAC;AACrF,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,4BAA4B,CAAC,wBAAwB,CAAC,CAAC;AAC/H,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,4BAA4B,CAAC,wBAAwB,CAAC,CAAC;AAElI,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=contract-duration.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"contract-duration.routes.d.ts","sourceRoot":"","sources":["../../src/routes/contract-duration.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAQxB,eAAe,MAAM,CAAC"}
+46
View File
@@ -0,0 +1,46 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const contractDurationController = __importStar(require("../controllers/contract-duration.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
router.get('/', auth_js_1.authenticate, contractDurationController.getContractDurations);
router.post('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:create'), contractDurationController.createContractDuration);
router.get('/:id', auth_js_1.authenticate, contractDurationController.getContractDuration);
router.put('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:update'), contractDurationController.updateContractDuration);
router.delete('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('platforms:delete'), contractDurationController.deleteContractDuration);
exports.default = router;
//# sourceMappingURL=contract-duration.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"contract-duration.routes.js","sourceRoot":"","sources":["../../src/routes/contract-duration.routes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAiC;AACjC,2GAA6F;AAC7F,mDAAwE;AAExE,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,sBAAY,EAAE,0BAA0B,CAAC,oBAAoB,CAAC,CAAC;AAC/E,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC,sBAAsB,CAAC,CAAC;AACzH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,0BAA0B,CAAC,mBAAmB,CAAC,CAAC;AACjF,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC,sBAAsB,CAAC,CAAC;AAC3H,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAY,EAAE,IAAA,2BAAiB,EAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC,sBAAsB,CAAC,CAAC;AAE9H,kBAAe,MAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
declare const router: import("express-serve-static-core").Router;
export default router;
//# sourceMappingURL=contract.routes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"contract.routes.d.ts","sourceRoot":"","sources":["../../src/routes/contract.routes.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAgExB,eAAe,MAAM,CAAC"}
+99
View File
@@ -0,0 +1,99 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const multer_1 = __importDefault(require("multer"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const contractController = __importStar(require("../controllers/contract.controller.js"));
const invoiceController = __importStar(require("../controllers/invoice.controller.js"));
const auth_js_1 = require("../middleware/auth.js");
const router = (0, express_1.Router)();
// Multer für Vertragsdokumente
const docUploadsDir = path_1.default.join(process.cwd(), 'uploads', 'contract-documents');
if (!fs_1.default.existsSync(docUploadsDir)) {
fs_1.default.mkdirSync(docUploadsDir, { recursive: true });
}
const docUpload = (0, multer_1.default)({
storage: multer_1.default.diskStorage({
destination: (_req, _file, cb) => cb(null, docUploadsDir),
filename: (_req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
cb(null, `doc-${uniqueSuffix}${path_1.default.extname(file.originalname)}`);
},
}),
fileFilter: (_req, file, cb) => {
const allowed = ['application/pdf', 'image/jpeg', 'image/png', 'image/jpg'];
if (allowed.includes(file.mimetype))
cb(null, true);
else
cb(new Error('Nur PDF, JPG und PNG Dateien sind erlaubt'));
},
limits: { fileSize: 10 * 1024 * 1024 },
});
router.get('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getContracts);
router.post('/', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:create'), contractController.createContract);
// Vertrags-Cockpit (muss VOR /:id stehen!)
router.get('/cockpit', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getCockpit);
router.get('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getContract);
router.put('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), contractController.updateContract);
router.delete('/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:delete'), contractController.deleteContract);
// Follow-up contract
router.post('/:id/follow-up', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:create'), contractController.createFollowUp);
// Snooze (Vertrag zurückstellen)
router.patch('/:id/snooze', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), contractController.snoozeContract);
// Rechnungen (für alle Vertragstypen)
router.get('/:id/invoices', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), invoiceController.getInvoicesByContract);
router.post('/:id/invoices', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), invoiceController.addInvoiceByContract);
// Vertragsdokumente
router.get('/:id/documents', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getContractDocuments);
router.post('/:id/documents', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), docUpload.single('file'), contractController.uploadContractDocument);
router.delete('/:id/documents/:documentId', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), contractController.deleteContractDocument);
// Folgezähler
router.post('/:id/successor-meter', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), contractController.addSuccessorMeter);
router.delete('/:id/contract-meter/:contractMeterId', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), contractController.removeContractMeter);
// Get decrypted password
router.get('/:id/password', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getContractPassword);
// Get decrypted SimCard PIN/PUK
router.get('/simcard/:simCardId/credentials', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getSimCardCredentials);
// Get decrypted Internet password
router.get('/:id/internet-credentials', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getInternetCredentials);
// Get decrypted SIP password
router.get('/phonenumber/:phoneNumberId/sip-credentials', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:read'), contractController.getSipCredentials);
exports.default = router;
//# sourceMappingURL=contract.routes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"contract.routes.js","sourceRoot":"","sources":["../../src/routes/contract.routes.ts"],"names":[],"mappings":"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"}

Some files were not shown because too many files have changed in this diff Show More