Initial commit
This commit is contained in:
commit
1af67a06d1
|
|
@ -0,0 +1,55 @@
|
|||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Node.js
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build-Ausgabe (wird im Container neu gebaut)
|
||||
dist
|
||||
|
||||
# Test-Dateien
|
||||
test
|
||||
*.test.ts
|
||||
*.spec.ts
|
||||
coverage
|
||||
|
||||
# IDE und Editor
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS-spezifische Dateien
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Dokumentation (nicht im Container benötigt)
|
||||
*.md
|
||||
!README.md
|
||||
docs
|
||||
|
||||
# Beispiel-Workflows (werden als Volume gemountet)
|
||||
workflows
|
||||
|
||||
# Umgebungsvariablen
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Archive
|
||||
*.tar.gz
|
||||
*.zip
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs
|
||||
|
||||
# Temporäre Dateien
|
||||
tmp
|
||||
temp
|
||||
.tmp
|
||||
.cache
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Docker Umgebungsvariablen für n8n mit LibreBooking Node
|
||||
# Kopiere diese Datei nach .env und passe die Werte an
|
||||
|
||||
# ============================================
|
||||
# n8n Basis-Konfiguration
|
||||
# ============================================
|
||||
|
||||
# Host und Port
|
||||
N8N_HOST=localhost
|
||||
N8N_PORT=5678
|
||||
N8N_PROTOCOL=http
|
||||
|
||||
# Webhook URL (für externe Webhooks)
|
||||
# Für Produktion: https://your-domain.com/
|
||||
WEBHOOK_URL=http://localhost:5678/
|
||||
|
||||
# ============================================
|
||||
# Authentifizierung (für Produktion aktivieren!)
|
||||
# ============================================
|
||||
|
||||
N8N_BASIC_AUTH_ACTIVE=false
|
||||
N8N_BASIC_AUTH_USER=admin
|
||||
N8N_BASIC_AUTH_PASSWORD=changeme_secure_password
|
||||
|
||||
# ============================================
|
||||
# Zeitzone
|
||||
# ============================================
|
||||
|
||||
TZ=Europe/Berlin
|
||||
|
||||
# ============================================
|
||||
# Logging
|
||||
# ============================================
|
||||
|
||||
# Mögliche Werte: silent, error, warn, info, debug
|
||||
N8N_LOG_LEVEL=info
|
||||
|
||||
# ============================================
|
||||
# PostgreSQL (optional, für Produktion empfohlen)
|
||||
# Aktivieren mit: docker-compose --profile with-postgres up -d
|
||||
# ============================================
|
||||
|
||||
POSTGRES_USER=n8n
|
||||
POSTGRES_PASSWORD=n8n_secure_password
|
||||
POSTGRES_DB=n8n
|
||||
|
||||
# Wenn PostgreSQL aktiv, diese Variable in docker-compose.yml hinzufügen:
|
||||
# DB_TYPE=postgresdb
|
||||
# DB_POSTGRESDB_HOST=postgres
|
||||
# DB_POSTGRESDB_PORT=5432
|
||||
# DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
|
||||
# DB_POSTGRESDB_USER=${POSTGRES_USER}
|
||||
# DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
|
||||
|
||||
# ============================================
|
||||
# LibreBooking Konfiguration (Optional)
|
||||
# Diese können auch direkt in n8n als Credentials angelegt werden
|
||||
# ============================================
|
||||
|
||||
# LIBREBOOKING_URL=https://booking.example.com
|
||||
# LIBREBOOKING_USER=api_user
|
||||
# LIBREBOOKING_PASSWORD=api_password
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# n8n LibreBooking Node - Umgebungsvariablen
|
||||
#
|
||||
# Kopiere diese Datei nach .env und passe die Werte an:
|
||||
# cp .env.example .env
|
||||
#
|
||||
|
||||
# n8n Authentifizierung
|
||||
# WICHTIG: Ändere diese Werte für Produktion!
|
||||
N8N_BASIC_AUTH_USER=admin
|
||||
N8N_BASIC_AUTH_PASSWORD=changeme
|
||||
|
||||
# Webhook-URL (für Produktion anpassen)
|
||||
# Beispiel: https://n8n.deine-domain.de/
|
||||
WEBHOOK_URL=http://localhost:5678/
|
||||
|
||||
# Zeitzone
|
||||
TZ=Europe/Berlin
|
||||
|
||||
# Log-Level (debug, info, warn, error)
|
||||
N8N_LOG_LEVEL=info
|
||||
|
||||
# Optional: Datenbank (Standard: SQLite)
|
||||
# DB_TYPE=postgresdb
|
||||
# DB_POSTGRESDB_HOST=localhost
|
||||
# DB_POSTGRESDB_PORT=5432
|
||||
# DB_POSTGRESDB_DATABASE=n8n
|
||||
# DB_POSTGRESDB_USER=n8n
|
||||
# DB_POSTGRESDB_PASSWORD=password
|
||||
|
||||
# Optional: Executions
|
||||
# EXECUTIONS_DATA_SAVE_ON_ERROR=all
|
||||
# EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
|
||||
# EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
node_modules/
|
||||
dist/
|
||||
.env
|
||||
*.log
|
||||
|
||||
# Generated PDFs
|
||||
*.pdf
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# Source files (nur dist wird veröffentlicht)
|
||||
*.ts
|
||||
!*.d.ts
|
||||
tsconfig.json
|
||||
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Tests
|
||||
test/
|
||||
*.test.ts
|
||||
*.spec.ts
|
||||
coverage/
|
||||
jest.config.js
|
||||
|
||||
# Docker
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
.dockerignore
|
||||
|
||||
# Entwicklung
|
||||
.eslintrc.js
|
||||
.eslintrc.json
|
||||
.prettierrc
|
||||
.prettierrc.json
|
||||
.editorconfig
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Dokumentation (README bleibt)
|
||||
CONTRIBUTING.md
|
||||
CHANGELOG.md
|
||||
INSTALLATION.md
|
||||
SCHNELLSTART.md
|
||||
ARCHIV-INFO.md
|
||||
docs/
|
||||
|
||||
# Beispiele
|
||||
workflows/
|
||||
examples/
|
||||
|
||||
# Skripte
|
||||
install.sh
|
||||
install.ps1
|
||||
|
||||
# OS-spezifisch
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Archive
|
||||
*.tar.gz
|
||||
*.zip
|
||||
|
||||
# Logs und temp
|
||||
*.log
|
||||
logs/
|
||||
tmp/
|
||||
temp/
|
||||
.tmp/
|
||||
.cache/
|
||||
|
||||
# Umgebungsvariablen
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# node_modules (sowieso ignoriert, aber sicherheitshalber)
|
||||
node_modules/
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
# LibreBooking n8n Node - Archiv-Information
|
||||
|
||||
Dieses Archiv enthält den vollständigen LibreBooking n8n Node.
|
||||
|
||||
## Archiv entpacken
|
||||
|
||||
### Linux/macOS
|
||||
|
||||
```bash
|
||||
# .tar.gz Archiv entpacken
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```powershell
|
||||
# .zip Archiv entpacken
|
||||
Expand-Archive -Path n8n-nodes-librebooking.zip -DestinationPath .
|
||||
cd n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
Oder: Rechtsklick → "Alle extrahieren..."
|
||||
|
||||
## Installation
|
||||
|
||||
### Schnellste Methode (Linux/Mac)
|
||||
|
||||
```bash
|
||||
chmod +x install.sh
|
||||
./install.sh
|
||||
n8n start
|
||||
```
|
||||
|
||||
### Schnellste Methode (Windows)
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
|
||||
.\install.ps1
|
||||
n8n start
|
||||
```
|
||||
|
||||
### Mit Docker
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
# Browser öffnen: http://localhost:5678
|
||||
```
|
||||
|
||||
## Enthaltene Dateien
|
||||
|
||||
```
|
||||
n8n-nodes-librebooking/
|
||||
├── credentials/ # API-Credentials Definition
|
||||
├── nodes/ # Node-Implementierungen
|
||||
│ ├── LibreBooking/ # Haupt-Node
|
||||
│ └── LibreBookingTrigger/ # Trigger-Node
|
||||
├── custom-nodes/ # Für Docker-Integration (eigenständig)
|
||||
│ ├── credentials/
|
||||
│ ├── nodes/
|
||||
│ ├── package.json
|
||||
│ └── README.md
|
||||
├── workflows/ # Beispiel-Workflows
|
||||
├── test/ # Test-Scripts
|
||||
├── Dockerfile # Docker Image Definition
|
||||
├── Dockerfile.custom-nodes # Für Custom Nodes Integration
|
||||
├── docker-compose.yml # Docker Compose Konfiguration
|
||||
├── docker-compose.override.yml # Override für bestehende Installationen
|
||||
├── docker-compose.example.yml # Vollständiges Beispiel
|
||||
├── install.sh # Installations-Skript (Linux/Mac)
|
||||
├── install.ps1 # Installations-Skript (Windows)
|
||||
├── install-docker.sh # Docker-Integration Skript
|
||||
├── nginx.conf # Reverse Proxy Beispiel
|
||||
├── .env.docker # Docker Umgebungsvariablen
|
||||
├── package.json # npm Paket-Definition
|
||||
├── tsconfig.json # TypeScript Konfiguration
|
||||
├── README.md # Hauptdokumentation
|
||||
├── INSTALLATION.md # Detaillierte Installationsanleitung
|
||||
├── DOCKER-INTEGRATION.md # Docker-Integration Anleitung
|
||||
├── SCHNELLSTART.md # Kurzanleitung
|
||||
├── SCHNELLSTART-DOCKER.md # Docker Kurzanleitung
|
||||
├── CHANGELOG.md # Versionshistorie
|
||||
├── CONTRIBUTING.md # Entwickler-Anleitung
|
||||
└── LICENSE # MIT Lizenz
|
||||
```
|
||||
|
||||
## Docker-Integration (NEU)
|
||||
|
||||
Für bestehende n8n Docker-Installationen:
|
||||
|
||||
```bash
|
||||
# Automatisch
|
||||
./install-docker.sh -p /pfad/zu/n8n
|
||||
|
||||
# Oder manuell
|
||||
cp -r custom-nodes /pfad/zu/n8n/
|
||||
cd /pfad/zu/n8n/custom-nodes && npm install && npm run build
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
📖 Siehe **DOCKER-INTEGRATION.md** für ausführliche Anleitung.
|
||||
|
||||
## Dokumentation
|
||||
|
||||
- **README.md** - Übersicht und Schnellstart
|
||||
- **INSTALLATION.md** - Detaillierte Installationsanleitung
|
||||
- **DOCKER-INTEGRATION.md** - Anleitung für bestehende Docker-Installationen
|
||||
- **SCHNELLSTART.md** - Ultra-Kurzanleitung für Experten
|
||||
- **SCHNELLSTART-DOCKER.md** - Docker-Kurzanleitung
|
||||
- **CONTRIBUTING.md** - Anleitung für Entwickler
|
||||
|
||||
## Support
|
||||
|
||||
Bei Fragen oder Problemen:
|
||||
- GitHub Issues: https://github.com/your-org/n8n-nodes-librebooking/issues
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT License - siehe LICENSE Datei
|
||||
|
||||
---
|
||||
|
||||
*LibreBooking n8n Node v1.0.0*
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
# Changelog
|
||||
|
||||
Alle wichtigen Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
|
||||
|
||||
Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.0.0/),
|
||||
und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Geplant
|
||||
- Webhook-basierter Trigger (falls von LibreBooking unterstützt)
|
||||
- Batch-Operationen für mehrere Reservierungen
|
||||
- Erweiterte Filteroptionen
|
||||
|
||||
## [1.0.0] - 2026-01-25
|
||||
|
||||
### Hinzugefügt
|
||||
|
||||
#### LibreBooking Node
|
||||
- **Reservierung (Reservation)**
|
||||
- Alle Reservierungen abrufen (GetAll)
|
||||
- Reservierung nach Referenznummer abrufen (Get)
|
||||
- Neue Reservierung erstellen (Create)
|
||||
- Reservierung aktualisieren (Update)
|
||||
- Reservierung löschen (Delete)
|
||||
- Reservierung genehmigen (Approve)
|
||||
- Check-In durchführen (CheckIn)
|
||||
- Check-Out durchführen (CheckOut)
|
||||
|
||||
- **Ressource (Resource)**
|
||||
- Alle Ressourcen abrufen (GetAll)
|
||||
- Ressource nach ID abrufen (Get)
|
||||
- Verfügbarkeit prüfen (GetAvailability)
|
||||
- Status abrufen (GetStatus)
|
||||
- Neue Ressource erstellen (Create)
|
||||
- Ressource aktualisieren (Update)
|
||||
- Ressource löschen (Delete)
|
||||
|
||||
- **Zeitplan (Schedule)**
|
||||
- Alle Zeitpläne abrufen (GetAll)
|
||||
- Zeitplan nach ID abrufen (Get)
|
||||
- Slots abrufen (GetSlots)
|
||||
|
||||
- **Benutzer (User)**
|
||||
- Alle Benutzer abrufen (GetAll)
|
||||
- Benutzer nach ID abrufen (Get)
|
||||
- Neuen Benutzer erstellen (Create)
|
||||
- Benutzer aktualisieren (Update)
|
||||
- Benutzer löschen (Delete)
|
||||
|
||||
- **Konto (Account)**
|
||||
- Eigenes Konto abrufen (Get)
|
||||
- Konto aktualisieren (Update)
|
||||
- Passwort ändern (ChangePassword)
|
||||
|
||||
- **Gruppe (Group)**
|
||||
- Alle Gruppen abrufen (GetAll)
|
||||
- Gruppe nach ID abrufen (Get)
|
||||
- Neue Gruppe erstellen (Create)
|
||||
- Gruppe aktualisieren (Update)
|
||||
- Gruppe löschen (Delete)
|
||||
|
||||
- **Zubehör (Accessory)**
|
||||
- Alles Zubehör abrufen (GetAll)
|
||||
- Zubehör nach ID abrufen (Get)
|
||||
- Neues Zubehör erstellen (Create)
|
||||
- Zubehör aktualisieren (Update)
|
||||
- Zubehör löschen (Delete)
|
||||
|
||||
- **Attribut (Attribute)**
|
||||
- Attributkategorien abrufen (GetCategories)
|
||||
- Attribute nach Kategorie abrufen (GetByCategory)
|
||||
|
||||
#### LibreBooking Trigger Node
|
||||
- Polling-basierter Trigger für Reservierungs-Events
|
||||
- Event-Typen:
|
||||
- Neue Reservierung
|
||||
- Geänderte Reservierung
|
||||
- Alle Reservierungen
|
||||
- Filter nach Ressource, Zeitplan und Benutzer
|
||||
- Konfigurierbares Zeitfenster (7-90 Tage)
|
||||
- Deduplizierung von Events
|
||||
|
||||
#### Credentials
|
||||
- LibreBooking API Credentials mit Session-basierter Authentifizierung
|
||||
- Automatische Token-Verwaltung
|
||||
- Verbindungstest integriert
|
||||
|
||||
#### Dokumentation
|
||||
- Vollständige README.md auf Deutsch
|
||||
- Detaillierte INSTALLATION.md
|
||||
- Beispiel-Workflows
|
||||
- API-Dokumentation mit allen Operationen
|
||||
|
||||
#### Entwickler-Tools
|
||||
- Docker-Support mit Dockerfile und docker-compose
|
||||
- Installations-Skripte für Linux/Mac und Windows
|
||||
- Test-Suite für API-Verbindung
|
||||
- ESLint und Prettier Konfiguration
|
||||
|
||||
### Sicherheit
|
||||
- Keine Speicherung von Passwörtern im Klartext
|
||||
- Session-basierte Authentifizierung
|
||||
- Automatisches Sign-Out nach Operationen
|
||||
|
||||
---
|
||||
|
||||
[Unreleased]: https://github.com/DEIN-REPO/n8n-nodes-librebooking/compare/v1.0.0...HEAD
|
||||
[1.0.0]: https://github.com/DEIN-REPO/n8n-nodes-librebooking/releases/tag/v1.0.0
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
# Beitragen zum LibreBooking n8n Node
|
||||
|
||||
Vielen Dank für dein Interesse, zu diesem Projekt beizutragen! 🎉
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Wie kann ich beitragen?](#wie-kann-ich-beitragen)
|
||||
- [Entwicklungsumgebung einrichten](#entwicklungsumgebung-einrichten)
|
||||
- [Code-Richtlinien](#code-richtlinien)
|
||||
- [Pull Request Prozess](#pull-request-prozess)
|
||||
- [Bug Reports](#bug-reports)
|
||||
- [Feature Requests](#feature-requests)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Dieses Projekt folgt einem [Code of Conduct](CODE_OF_CONDUCT.md). Mit deiner Teilnahme erklärst du dich einverstanden, diesen einzuhalten.
|
||||
|
||||
## Wie kann ich beitragen?
|
||||
|
||||
### Bugs melden
|
||||
|
||||
- Überprüfe zunächst, ob der Bug bereits gemeldet wurde
|
||||
- Erstelle ein Issue mit einer klaren Beschreibung
|
||||
- Füge Schritte zur Reproduktion hinzu
|
||||
- Gib deine Umgebung an (OS, Node.js Version, n8n Version)
|
||||
|
||||
### Features vorschlagen
|
||||
|
||||
- Erstelle ein Issue mit dem Label "enhancement"
|
||||
- Beschreibe den Use Case
|
||||
- Erkläre, warum diese Funktion nützlich wäre
|
||||
|
||||
### Code beitragen
|
||||
|
||||
1. Forke das Repository
|
||||
2. Erstelle einen Feature-Branch
|
||||
3. Implementiere deine Änderungen
|
||||
4. Schreibe Tests (falls möglich)
|
||||
5. Erstelle einen Pull Request
|
||||
|
||||
## Entwicklungsumgebung einrichten
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- Node.js 18.x oder höher
|
||||
- npm 8.x oder höher
|
||||
- n8n (global installiert)
|
||||
- Git
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Repository klonen
|
||||
git clone https://github.com/DEIN-REPO/n8n-nodes-librebooking.git
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Dependencies installieren
|
||||
npm install
|
||||
|
||||
# Build ausführen
|
||||
npm run build
|
||||
|
||||
# Für Entwicklung: Watch-Modus
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Lokales Testen
|
||||
|
||||
```bash
|
||||
# Node mit n8n verlinken
|
||||
npm link
|
||||
|
||||
# In n8n-Verzeichnis verlinken
|
||||
cd $(npm root -g)/n8n
|
||||
npm link n8n-nodes-librebooking
|
||||
|
||||
# n8n starten
|
||||
n8n start
|
||||
```
|
||||
|
||||
### Mit Docker testen
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
## Code-Richtlinien
|
||||
|
||||
### TypeScript
|
||||
|
||||
- Verwende strenge Typisierung (`strict: true`)
|
||||
- Vermeide `any` wo möglich
|
||||
- Dokumentiere komplexe Funktionen mit JSDoc
|
||||
|
||||
### Formatierung
|
||||
|
||||
```bash
|
||||
# Code formatieren
|
||||
npm run format
|
||||
|
||||
# Linting prüfen
|
||||
npm run lint
|
||||
|
||||
# Linting mit automatischer Korrektur
|
||||
npm run lintfix
|
||||
```
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Wir folgen [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
feat: Neue Funktion hinzugefügt
|
||||
fix: Bug behoben
|
||||
docs: Dokumentation aktualisiert
|
||||
style: Formatierung geändert (kein Code)
|
||||
refactor: Code umstrukturiert
|
||||
test: Tests hinzugefügt/geändert
|
||||
chore: Build-Prozess/Tools geändert
|
||||
```
|
||||
|
||||
Beispiele:
|
||||
```
|
||||
feat(reservation): Check-In Operation hinzugefügt
|
||||
fix(auth): Session-Token wird jetzt korrekt erneuert
|
||||
docs: Installationsanleitung aktualisiert
|
||||
```
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
```
|
||||
n8n-nodes-librebooking/
|
||||
├── credentials/ # Credential-Definitionen
|
||||
│ └── LibreBookingApi.credentials.ts
|
||||
├── nodes/ # Node-Definitionen
|
||||
│ ├── LibreBooking/
|
||||
│ │ ├── LibreBooking.node.ts
|
||||
│ │ └── librebooking.svg
|
||||
│ └── LibreBookingTrigger/
|
||||
│ ├── LibreBookingTrigger.node.ts
|
||||
│ └── librebooking.svg
|
||||
├── test/ # Tests
|
||||
├── workflows/ # Beispiel-Workflows
|
||||
├── dist/ # Kompilierte Dateien (generiert)
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Pull Request Prozess
|
||||
|
||||
1. **Branch erstellen:**
|
||||
```bash
|
||||
git checkout -b feature/meine-funktion
|
||||
```
|
||||
|
||||
2. **Änderungen implementieren:**
|
||||
- Halte dich an die Code-Richtlinien
|
||||
- Aktualisiere die Dokumentation
|
||||
- Füge Tests hinzu (falls sinnvoll)
|
||||
|
||||
3. **Testen:**
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
# Manuell in n8n testen
|
||||
```
|
||||
|
||||
4. **Commit und Push:**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: Meine neue Funktion"
|
||||
git push origin feature/meine-funktion
|
||||
```
|
||||
|
||||
5. **Pull Request erstellen:**
|
||||
- Beschreibe deine Änderungen
|
||||
- Referenziere relevante Issues
|
||||
- Warte auf Review
|
||||
|
||||
### PR Checkliste
|
||||
|
||||
- [ ] Code folgt den Richtlinien
|
||||
- [ ] Linting/Formatting bestanden
|
||||
- [ ] Build erfolgreich
|
||||
- [ ] Dokumentation aktualisiert
|
||||
- [ ] CHANGELOG.md aktualisiert
|
||||
- [ ] Keine Secrets/Credentials im Code
|
||||
|
||||
## Bug Reports
|
||||
|
||||
### Template
|
||||
|
||||
```markdown
|
||||
## Beschreibung
|
||||
[Klare Beschreibung des Bugs]
|
||||
|
||||
## Schritte zur Reproduktion
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
## Erwartetes Verhalten
|
||||
[Was sollte passieren?]
|
||||
|
||||
## Tatsächliches Verhalten
|
||||
[Was passiert stattdessen?]
|
||||
|
||||
## Umgebung
|
||||
- OS: [z.B. Ubuntu 22.04]
|
||||
- Node.js: [z.B. 20.10.0]
|
||||
- n8n: [z.B. 1.20.0]
|
||||
- LibreBooking: [z.B. 2.8.5]
|
||||
|
||||
## Logs/Screenshots
|
||||
[Falls vorhanden]
|
||||
```
|
||||
|
||||
## Feature Requests
|
||||
|
||||
### Template
|
||||
|
||||
```markdown
|
||||
## Beschreibung
|
||||
[Beschreibe die gewünschte Funktion]
|
||||
|
||||
## Use Case
|
||||
[Warum wird diese Funktion benötigt?]
|
||||
|
||||
## Vorgeschlagene Lösung
|
||||
[Falls du eine Idee hast]
|
||||
|
||||
## Alternativen
|
||||
[Andere Möglichkeiten, die du in Betracht gezogen hast]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Vielen Dank für deinen Beitrag! 🙏
|
||||
|
|
@ -0,0 +1,592 @@
|
|||
# Docker-Integration für LibreBooking n8n Node
|
||||
|
||||
Diese Anleitung beschreibt die Integration des LibreBooking Nodes in eine **bestehende n8n Docker-Installation**.
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
- [Voraussetzungen](#voraussetzungen)
|
||||
- [Methode 1: Automatische Integration mit Skript](#methode-1-automatische-integration-mit-skript)
|
||||
- [Methode 2: Manuelle Integration](#methode-2-manuelle-integration)
|
||||
- [Methode 3: Integration in bestehende docker-compose.yml](#methode-3-integration-in-bestehende-docker-composeyml)
|
||||
- [Methode 4: Dockerfile erweitern](#methode-4-dockerfile-erweitern)
|
||||
- [Verifizierung der Installation](#verifizierung-der-installation)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Updates und Wartung](#updates-und-wartung)
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
### System-Anforderungen
|
||||
|
||||
- **Docker** Version 20.10 oder höher
|
||||
- **Docker Compose** v2.0+ (Plugin) oder docker-compose v1.29+
|
||||
- **Laufende n8n Docker-Installation**
|
||||
- **Zugriff auf das Dateisystem** des Docker-Hosts
|
||||
|
||||
### Prüfen der Voraussetzungen
|
||||
|
||||
```bash
|
||||
# Docker Version prüfen
|
||||
docker --version
|
||||
# Docker version 24.0.x, build xxxxx
|
||||
|
||||
# Docker Compose Version prüfen
|
||||
docker compose version
|
||||
# Docker Compose version v2.x.x
|
||||
|
||||
# Oder für ältere Versionen:
|
||||
docker-compose --version
|
||||
# docker-compose version 1.29.x, build xxxxx
|
||||
|
||||
# n8n Container Status prüfen
|
||||
docker ps | grep n8n
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 1: Automatische Integration mit Skript
|
||||
|
||||
Die einfachste Methode für die Integration in eine bestehende Installation.
|
||||
|
||||
### Schritt 1: Skript ausführbar machen
|
||||
|
||||
```bash
|
||||
chmod +x install-docker.sh
|
||||
```
|
||||
|
||||
### Schritt 2: Skript ausführen
|
||||
|
||||
```bash
|
||||
# Im aktuellen Verzeichnis (wenn dort n8n läuft)
|
||||
./install-docker.sh
|
||||
|
||||
# Oder mit Pfad zur n8n Installation
|
||||
./install-docker.sh -p /pfad/zu/n8n
|
||||
|
||||
# Mit Überschreiben bestehender Dateien
|
||||
./install-docker.sh -f -p /pfad/zu/n8n
|
||||
```
|
||||
|
||||
### Skript-Optionen
|
||||
|
||||
| Option | Beschreibung |
|
||||
|--------|--------------|
|
||||
| `-p, --path PATH` | Pfad zur n8n Docker-Installation |
|
||||
| `-b, --build` | Node im Container bauen |
|
||||
| `-f, --force` | Bestehende Installation überschreiben |
|
||||
| `-h, --help` | Hilfe anzeigen |
|
||||
|
||||
### Was das Skript tut
|
||||
|
||||
1. Prüft Docker und Docker Compose Installation
|
||||
2. Prüft ob n8n Container läuft
|
||||
3. Kopiert `custom-nodes/` Verzeichnis
|
||||
4. Erstellt/aktualisiert `docker-compose.override.yml`
|
||||
5. Setzt korrekte Berechtigungen (UID 1000)
|
||||
6. Startet Container bei Bedarf neu
|
||||
|
||||
---
|
||||
|
||||
## Methode 2: Manuelle Integration
|
||||
|
||||
Für mehr Kontrolle oder spezielle Setups.
|
||||
|
||||
### Schritt 1: Custom Nodes Verzeichnis kopieren
|
||||
|
||||
```bash
|
||||
# Zum n8n Verzeichnis wechseln
|
||||
cd /pfad/zu/ihrer/n8n/installation
|
||||
|
||||
# Custom Nodes kopieren
|
||||
cp -r /pfad/zu/librebooking_n8n_node/custom-nodes ./custom-nodes
|
||||
```
|
||||
|
||||
### Schritt 2: Dependencies installieren und bauen
|
||||
|
||||
```bash
|
||||
cd custom-nodes
|
||||
|
||||
# Node.js Dependencies installieren
|
||||
npm install
|
||||
|
||||
# TypeScript kompilieren
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Schritt 3: docker-compose.override.yml erstellen
|
||||
|
||||
Erstellen Sie eine `docker-compose.override.yml` Datei:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
volumes:
|
||||
# LibreBooking Custom Node einbinden
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
|
||||
environment:
|
||||
# Custom Nodes Pfad
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
# Community Nodes aktivieren
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
```
|
||||
|
||||
### Schritt 4: Berechtigungen setzen
|
||||
|
||||
```bash
|
||||
# n8n läuft als "node" User mit UID 1000
|
||||
sudo chown -R 1000:1000 custom-nodes/
|
||||
```
|
||||
|
||||
### Schritt 5: Container neustarten
|
||||
|
||||
```bash
|
||||
# Mit docker-compose
|
||||
docker-compose restart n8n
|
||||
|
||||
# Oder mit Docker Compose Plugin
|
||||
docker compose restart n8n
|
||||
|
||||
# Bei Problemen: Container komplett neu erstellen
|
||||
docker-compose down && docker-compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 3: Integration in bestehende docker-compose.yml
|
||||
|
||||
Wenn Sie keine Override-Datei verwenden möchten.
|
||||
|
||||
### Bestehende docker-compose.yml erweitern
|
||||
|
||||
Fügen Sie folgende Einträge zu Ihrem n8n Service hinzu:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
# ... Ihre bestehende Konfiguration ...
|
||||
|
||||
volumes:
|
||||
# Bestehende Volumes beibehalten
|
||||
- n8n_data:/home/node/.n8n
|
||||
|
||||
# LibreBooking Node hinzufügen
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
|
||||
environment:
|
||||
# Bestehende Umgebungsvariablen beibehalten
|
||||
- N8N_HOST=0.0.0.0
|
||||
- N8N_PORT=5678
|
||||
|
||||
# Custom Nodes Konfiguration hinzufügen
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
```
|
||||
|
||||
### Vollständiges Beispiel
|
||||
|
||||
Siehe `docker-compose.example.yml` für eine vollständige Konfiguration mit:
|
||||
- PostgreSQL Datenbank (optional)
|
||||
- Redis Queue (optional)
|
||||
- Health Checks
|
||||
- Alle Umgebungsvariablen
|
||||
|
||||
---
|
||||
|
||||
## Methode 4: Dockerfile erweitern
|
||||
|
||||
Für produktive Deployments oder wenn Sie ein eigenes Image benötigen.
|
||||
|
||||
### Einfaches Dockerfile
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile.custom-nodes
|
||||
ARG N8N_VERSION=latest
|
||||
FROM n8nio/n8n:${N8N_VERSION}
|
||||
|
||||
USER root
|
||||
|
||||
# Custom Node Verzeichnis erstellen
|
||||
RUN mkdir -p /home/node/.n8n/custom/n8n-nodes-librebooking && \
|
||||
chown -R node:node /home/node/.n8n/custom
|
||||
|
||||
WORKDIR /home/node/.n8n/custom/n8n-nodes-librebooking
|
||||
|
||||
# Dateien kopieren
|
||||
COPY --chown=node:node custom-nodes/ ./
|
||||
|
||||
# Dependencies installieren und bauen
|
||||
RUN npm install && npm run build
|
||||
|
||||
USER node
|
||||
WORKDIR /home/node
|
||||
|
||||
ENV N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
ENV N8N_COMMUNITY_NODES_ENABLED=true
|
||||
|
||||
EXPOSE 5678
|
||||
CMD ["n8n", "start"]
|
||||
```
|
||||
|
||||
### Image bauen und verwenden
|
||||
|
||||
```bash
|
||||
# Image bauen
|
||||
docker build -f Dockerfile.custom-nodes -t n8n-librebooking .
|
||||
|
||||
# Container starten
|
||||
docker run -d \
|
||||
--name n8n \
|
||||
-p 5678:5678 \
|
||||
-v n8n_data:/home/node/.n8n \
|
||||
n8n-librebooking
|
||||
```
|
||||
|
||||
### Mit docker-compose
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.custom-nodes
|
||||
args:
|
||||
N8N_VERSION: latest
|
||||
# ... weitere Konfiguration
|
||||
```
|
||||
|
||||
### Multi-Stage Build (Optimiert)
|
||||
|
||||
```dockerfile
|
||||
# Build Stage
|
||||
FROM node:18-alpine AS builder
|
||||
WORKDIR /build
|
||||
COPY custom-nodes/ ./
|
||||
RUN npm install && npm run build
|
||||
|
||||
# Production Stage
|
||||
ARG N8N_VERSION=latest
|
||||
FROM n8nio/n8n:${N8N_VERSION}
|
||||
|
||||
USER root
|
||||
RUN mkdir -p /home/node/.n8n/custom/n8n-nodes-librebooking && \
|
||||
chown -R node:node /home/node/.n8n/custom
|
||||
|
||||
# Nur gebaute Dateien kopieren
|
||||
COPY --from=builder --chown=node:node /build/dist /home/node/.n8n/custom/n8n-nodes-librebooking/dist
|
||||
COPY --from=builder --chown=node:node /build/package.json /home/node/.n8n/custom/n8n-nodes-librebooking/
|
||||
|
||||
USER node
|
||||
|
||||
ENV N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
ENV N8N_COMMUNITY_NODES_ENABLED=true
|
||||
|
||||
CMD ["n8n", "start"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verifizierung der Installation
|
||||
|
||||
### 1. Container-Logs prüfen
|
||||
|
||||
```bash
|
||||
# Logs anzeigen
|
||||
docker logs n8n 2>&1 | grep -i "librebooking\|custom\|node"
|
||||
|
||||
# Live Logs verfolgen
|
||||
docker logs -f n8n
|
||||
```
|
||||
|
||||
### 2. In n8n prüfen
|
||||
|
||||
1. Öffnen Sie n8n im Browser (z.B. `http://localhost:5678`)
|
||||
2. Erstellen Sie einen neuen Workflow
|
||||
3. Fügen Sie einen neuen Node hinzu
|
||||
4. Suchen Sie nach "LibreBooking" - zwei Nodes sollten erscheinen:
|
||||
- **LibreBooking** - Hauptnode für alle Operationen
|
||||
- **LibreBooking Trigger** - Trigger für neue Reservierungen
|
||||
|
||||
### 3. Node-Verzeichnis im Container prüfen
|
||||
|
||||
```bash
|
||||
# In Container einloggen
|
||||
docker exec -it n8n /bin/sh
|
||||
|
||||
# Custom Nodes Verzeichnis prüfen
|
||||
ls -la /home/node/.n8n/custom/
|
||||
|
||||
# LibreBooking Node prüfen
|
||||
ls -la /home/node/.n8n/custom/n8n-nodes-librebooking/dist/
|
||||
```
|
||||
|
||||
### 4. Umgebungsvariablen prüfen
|
||||
|
||||
```bash
|
||||
docker exec n8n env | grep N8N_CUSTOM
|
||||
# N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
|
||||
docker exec n8n env | grep COMMUNITY
|
||||
# N8N_COMMUNITY_NODES_ENABLED=true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: Node wird nicht erkannt
|
||||
|
||||
**Symptom:** LibreBooking Node erscheint nicht in der Node-Suche
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **Pfad prüfen:**
|
||||
```bash
|
||||
docker exec n8n ls -la /home/node/.n8n/custom/n8n-nodes-librebooking/
|
||||
```
|
||||
|
||||
2. **Umgebungsvariablen prüfen:**
|
||||
```bash
|
||||
docker exec n8n env | grep -E "N8N_CUSTOM|COMMUNITY"
|
||||
```
|
||||
|
||||
3. **Container komplett neu starten:**
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Logs auf Fehler prüfen:**
|
||||
```bash
|
||||
docker logs n8n 2>&1 | grep -i error
|
||||
```
|
||||
|
||||
### Problem: Permissions-Fehler
|
||||
|
||||
**Symptom:** `EACCES: permission denied` oder ähnliche Fehler
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **Berechtigungen setzen:**
|
||||
```bash
|
||||
sudo chown -R 1000:1000 custom-nodes/
|
||||
sudo chmod -R 755 custom-nodes/
|
||||
```
|
||||
|
||||
2. **Volume mit korrektem User mounten:**
|
||||
```yaml
|
||||
services:
|
||||
n8n:
|
||||
user: "1000:1000"
|
||||
```
|
||||
|
||||
3. **SELinux Context (falls aktiviert):**
|
||||
```bash
|
||||
sudo chcon -R -t svirt_sandbox_file_t custom-nodes/
|
||||
```
|
||||
|
||||
### Problem: Container startet nicht
|
||||
|
||||
**Symptom:** Container crashed oder startet nicht
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **Logs prüfen:**
|
||||
```bash
|
||||
docker logs n8n
|
||||
```
|
||||
|
||||
2. **Ohne Override starten (zum Testen):**
|
||||
```bash
|
||||
mv docker-compose.override.yml docker-compose.override.yml.bak
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Volume-Konflikte prüfen:**
|
||||
```bash
|
||||
docker volume ls
|
||||
docker volume inspect n8n_data
|
||||
```
|
||||
|
||||
### Problem: Node wird geladen aber Fehler bei Ausführung
|
||||
|
||||
**Symptom:** Node ist sichtbar aber Ausführung schlägt fehl
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **Build prüfen:**
|
||||
```bash
|
||||
docker exec n8n ls -la /home/node/.n8n/custom/n8n-nodes-librebooking/dist/
|
||||
```
|
||||
|
||||
2. **Neu bauen:**
|
||||
```bash
|
||||
cd custom-nodes
|
||||
npm run rebuild
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
3. **Dependencies prüfen:**
|
||||
```bash
|
||||
docker exec -it n8n /bin/sh
|
||||
cd /home/node/.n8n/custom/n8n-nodes-librebooking
|
||||
npm ls
|
||||
```
|
||||
|
||||
### Problem: TypeScript Build schlägt fehl
|
||||
|
||||
**Symptom:** `tsc` Fehler beim Bauen
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **Node.js Version prüfen:**
|
||||
```bash
|
||||
node --version # Sollte 18+ sein
|
||||
npm --version
|
||||
```
|
||||
|
||||
2. **Clean Build:**
|
||||
```bash
|
||||
cd custom-nodes
|
||||
rm -rf node_modules dist package-lock.json
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Problem: Webhook URL nicht erreichbar
|
||||
|
||||
**Symptom:** LibreBooking kann Webhooks nicht senden
|
||||
|
||||
**Lösungen:**
|
||||
|
||||
1. **WEBHOOK_URL Umgebungsvariable setzen:**
|
||||
```yaml
|
||||
environment:
|
||||
- WEBHOOK_URL=https://ihre-domain.com/
|
||||
```
|
||||
|
||||
2. **Netzwerk-Konfiguration prüfen:**
|
||||
```bash
|
||||
docker network inspect $(docker network ls -q)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updates und Wartung
|
||||
|
||||
### Node aktualisieren
|
||||
|
||||
```bash
|
||||
# Neue Version herunterladen
|
||||
cd /pfad/zu/neuem/librebooking_n8n_node
|
||||
|
||||
# Custom Nodes ersetzen
|
||||
rm -rf /pfad/zu/n8n/custom-nodes
|
||||
cp -r custom-nodes /pfad/zu/n8n/custom-nodes
|
||||
|
||||
# Neu bauen
|
||||
cd /pfad/zu/n8n/custom-nodes
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Container neustarten
|
||||
cd /pfad/zu/n8n
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
### n8n Version aktualisieren
|
||||
|
||||
```bash
|
||||
# Image aktualisieren
|
||||
docker pull n8nio/n8n:latest
|
||||
|
||||
# Container neu erstellen
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Backup erstellen
|
||||
|
||||
```bash
|
||||
# Docker Volumes sichern
|
||||
docker run --rm \
|
||||
-v n8n_data:/source:ro \
|
||||
-v $(pwd)/backup:/backup \
|
||||
alpine tar cvzf /backup/n8n_data_backup.tar.gz -C /source .
|
||||
|
||||
# Custom Nodes sichern
|
||||
tar cvzf custom-nodes-backup.tar.gz custom-nodes/
|
||||
```
|
||||
|
||||
### Logs rotieren
|
||||
|
||||
```yaml
|
||||
services:
|
||||
n8n:
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Erweiterte Konfiguration
|
||||
|
||||
### Kubernetes Deployment
|
||||
|
||||
Für Kubernetes-Umgebungen kann ein ConfigMap oder PersistentVolume verwendet werden:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: librebooking-node
|
||||
data:
|
||||
# Node-Dateien als ConfigMap
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: n8n
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: n8n
|
||||
volumeMounts:
|
||||
- name: custom-nodes
|
||||
mountPath: /home/node/.n8n/custom/n8n-nodes-librebooking
|
||||
volumes:
|
||||
- name: custom-nodes
|
||||
configMap:
|
||||
name: librebooking-node
|
||||
```
|
||||
|
||||
### Mit Reverse Proxy (Nginx)
|
||||
|
||||
Siehe `nginx.conf` für eine vollständige Nginx-Konfiguration mit:
|
||||
- SSL/TLS Termination
|
||||
- WebSocket Support
|
||||
- Optimierte Timeouts für Webhooks
|
||||
|
||||
---
|
||||
|
||||
## Hilfe und Support
|
||||
|
||||
- **GitHub Issues:** [Repository Issues](https://github.com/ihr-repo/librebooking-n8n-node/issues)
|
||||
- **n8n Community:** [community.n8n.io](https://community.n8n.io)
|
||||
- **LibreBooking Dokumentation:** [LibreBooking Wiki](https://github.com/effgarces/BookedScheduler/wiki)
|
||||
|
||||
---
|
||||
|
||||
*Letzte Aktualisierung: Januar 2026*
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# Dockerfile für n8n mit LibreBooking Node
|
||||
# Basiert auf dem offiziellen n8n Docker Image
|
||||
|
||||
FROM n8nio/n8n:latest
|
||||
|
||||
# Als Root-Benutzer für Installation
|
||||
USER root
|
||||
|
||||
# Arbeitsverzeichnis für den Custom Node
|
||||
WORKDIR /home/node/.n8n/custom
|
||||
|
||||
# Kopiere Node-Dateien
|
||||
COPY package*.json ./
|
||||
COPY tsconfig.json ./
|
||||
COPY index.ts ./
|
||||
COPY credentials/ ./credentials/
|
||||
COPY nodes/ ./nodes/
|
||||
|
||||
# Installiere Dependencies und baue den Node
|
||||
RUN npm install && \
|
||||
npm run build && \
|
||||
chown -R node:node /home/node/.n8n
|
||||
|
||||
# Zurück zum node-Benutzer
|
||||
USER node
|
||||
|
||||
# Arbeitsverzeichnis auf n8n Standard setzen
|
||||
WORKDIR /home/node
|
||||
|
||||
# n8n wird automatisch den Custom Node laden
|
||||
ENV N8N_CUSTOM_EXTENSIONS="/home/node/.n8n/custom"
|
||||
|
||||
# Healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD wget -q --spider http://localhost:5678/healthz || exit 1
|
||||
|
||||
# Standard n8n Port
|
||||
EXPOSE 5678
|
||||
|
||||
# Startbefehl
|
||||
CMD ["n8n", "start"]
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# Dockerfile für Custom Nodes Integration
|
||||
# Verwendet das offizielle n8n Image und fügt den LibreBooking Node hinzu
|
||||
#
|
||||
# Build: docker build -f Dockerfile.custom-nodes -t n8n-librebooking .
|
||||
# Run: docker run -p 5678:5678 n8n-librebooking
|
||||
|
||||
ARG N8N_VERSION=latest
|
||||
FROM n8nio/n8n:${N8N_VERSION}
|
||||
|
||||
# Wechsle zu root für Installationen
|
||||
USER root
|
||||
|
||||
# Erstelle Custom Nodes Verzeichnis
|
||||
RUN mkdir -p /home/node/.n8n/custom/n8n-nodes-librebooking && \
|
||||
chown -R node:node /home/node/.n8n/custom
|
||||
|
||||
# Arbeitsverzeichnis setzen
|
||||
WORKDIR /home/node/.n8n/custom/n8n-nodes-librebooking
|
||||
|
||||
# Kopiere Custom Node Dateien
|
||||
COPY --chown=node:node custom-nodes/package.json .
|
||||
COPY --chown=node:node custom-nodes/tsconfig.json .
|
||||
COPY --chown=node:node custom-nodes/index.ts .
|
||||
COPY --chown=node:node custom-nodes/credentials/ ./credentials/
|
||||
COPY --chown=node:node custom-nodes/nodes/ ./nodes/
|
||||
|
||||
# Installiere Dependencies und baue den Node
|
||||
RUN npm install && npm run build
|
||||
|
||||
# Wechsle zurück zum node User
|
||||
USER node
|
||||
|
||||
# Arbeitsverzeichnis für n8n setzen
|
||||
WORKDIR /home/node
|
||||
|
||||
# Umgebungsvariablen
|
||||
ENV N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom \
|
||||
N8N_COMMUNITY_NODES_ENABLED=true
|
||||
|
||||
# n8n Port
|
||||
EXPOSE 5678
|
||||
|
||||
# Healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD wget -qO- http://localhost:5678/healthz || exit 1
|
||||
|
||||
# Startbefehl
|
||||
CMD ["n8n", "start"]
|
||||
|
|
@ -0,0 +1,553 @@
|
|||
# Installationsanleitung - LibreBooking n8n Node
|
||||
|
||||
Diese Anleitung beschreibt alle verfügbaren Methoden zur Installation des LibreBooking n8n Nodes.
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
- [Voraussetzungen](#voraussetzungen)
|
||||
- [Installation aus Git-Archiv](#installation-aus-git-archiv)
|
||||
- [Methode 1: Automatische Installation mit Skript](#methode-1-automatische-installation-mit-skript)
|
||||
- [Methode 2: Manuelle Installation mit npm](#methode-2-manuelle-installation-mit-npm)
|
||||
- [Methode 3: Installation aus npm Registry](#methode-3-installation-aus-npm-registry)
|
||||
- [Methode 4: Docker Installation](#methode-4-docker-installation)
|
||||
- [Methode 5: n8n Community Nodes](#methode-5-n8n-community-nodes)
|
||||
- [Verifizierung der Installation](#verifizierung-der-installation)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Deinstallation](#deinstallation)
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
### Systemanforderungen
|
||||
|
||||
| Komponente | Mindestversion | Empfohlen |
|
||||
|------------|---------------|-----------|
|
||||
| Node.js | 18.x | 20.x LTS |
|
||||
| npm | 8.x | 10.x |
|
||||
| n8n | 1.0.0 | Neueste |
|
||||
|
||||
### Node.js installieren
|
||||
|
||||
**Linux (Ubuntu/Debian):**
|
||||
```bash
|
||||
# Mit NodeSource Repository (empfohlen)
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# Version prüfen
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
**macOS:**
|
||||
```bash
|
||||
# Mit Homebrew
|
||||
brew install node@20
|
||||
|
||||
# Version prüfen
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
1. Lade Node.js von https://nodejs.org/ herunter
|
||||
2. Wähle die LTS-Version (20.x)
|
||||
3. Führe den Installer aus
|
||||
4. Öffne PowerShell und prüfe: `node --version`
|
||||
|
||||
### n8n installieren
|
||||
|
||||
```bash
|
||||
# Global installieren
|
||||
npm install -g n8n
|
||||
|
||||
# Installation prüfen
|
||||
n8n --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Installation aus Git-Archiv
|
||||
|
||||
### Archiv herunterladen
|
||||
|
||||
1. **GitHub Release herunterladen:**
|
||||
```bash
|
||||
# .tar.gz für Linux/Mac
|
||||
wget https://github.com/DEIN-REPO/n8n-nodes-librebooking/releases/latest/download/n8n-nodes-librebooking.tar.gz
|
||||
|
||||
# .zip für Windows
|
||||
# Über Browser herunterladen
|
||||
```
|
||||
|
||||
2. **Oder direkt von Git:**
|
||||
```bash
|
||||
git clone https://github.com/DEIN-REPO/n8n-nodes-librebooking.git
|
||||
cd n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Archiv entpacken
|
||||
|
||||
**Linux/macOS:**
|
||||
```bash
|
||||
# .tar.gz entpacken
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
# .zip entpacken
|
||||
Expand-Archive -Path n8n-nodes-librebooking.zip -DestinationPath .
|
||||
cd n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 1: Automatische Installation mit Skript
|
||||
|
||||
Die einfachste Methode für die meisten Benutzer.
|
||||
|
||||
### Linux/macOS
|
||||
|
||||
```bash
|
||||
# In das Verzeichnis wechseln
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Skript ausführbar machen (falls nötig)
|
||||
chmod +x install.sh
|
||||
|
||||
# Installation starten
|
||||
./install.sh
|
||||
```
|
||||
|
||||
**Optionen:**
|
||||
```bash
|
||||
./install.sh # Standard-Installation mit npm link
|
||||
./install.sh --no-link # Nur Build, ohne npm link
|
||||
./install.sh --global # Globale Installation
|
||||
./install.sh --help # Hilfe anzeigen
|
||||
```
|
||||
|
||||
### Windows (PowerShell)
|
||||
|
||||
```powershell
|
||||
# In das Verzeichnis wechseln
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Skript ausführen (evtl. Ausführungsrichtlinie anpassen)
|
||||
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
|
||||
.\install.ps1
|
||||
```
|
||||
|
||||
**Optionen:**
|
||||
```powershell
|
||||
.\install.ps1 # Standard-Installation mit npm link
|
||||
.\install.ps1 -NoLink # Nur Build, ohne npm link
|
||||
.\install.ps1 -Global # Globale Installation
|
||||
.\install.ps1 -Help # Hilfe anzeigen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 2: Manuelle Installation mit npm
|
||||
|
||||
Für Benutzer, die mehr Kontrolle über den Installationsprozess möchten.
|
||||
|
||||
### Schritt 1: Dependencies installieren
|
||||
|
||||
```bash
|
||||
cd n8n-nodes-librebooking
|
||||
npm install
|
||||
```
|
||||
|
||||
### Schritt 2: TypeScript kompilieren
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Schritt 3: Node verlinken
|
||||
|
||||
```bash
|
||||
# Node global verfügbar machen
|
||||
npm link
|
||||
|
||||
# Mit n8n verlinken (optional, falls n8n global installiert ist)
|
||||
cd $(npm root -g)/n8n
|
||||
npm link n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Schritt 4: n8n neu starten
|
||||
|
||||
```bash
|
||||
# n8n stoppen (falls läuft)
|
||||
# Ctrl+C oder:
|
||||
pkill -f n8n
|
||||
|
||||
# n8n starten
|
||||
n8n start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 3: Installation aus npm Registry
|
||||
|
||||
> **Hinweis:** Diese Methode ist für eine zukünftige Veröffentlichung auf npm vorgesehen.
|
||||
|
||||
```bash
|
||||
# Global installieren
|
||||
npm install -g n8n-nodes-librebooking
|
||||
|
||||
# Oder lokal in einem Projekt
|
||||
npm install n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
Nach der Veröffentlichung auf npm wird diese Methode die einfachste sein.
|
||||
|
||||
---
|
||||
|
||||
## Methode 4: Docker Installation
|
||||
|
||||
### Voraussetzungen für Docker
|
||||
|
||||
- Docker 20.x oder höher
|
||||
- Docker Compose v2.x (empfohlen)
|
||||
|
||||
**Docker installieren:**
|
||||
- Linux: https://docs.docker.com/engine/install/
|
||||
- macOS: https://docs.docker.com/desktop/mac/install/
|
||||
- Windows: https://docs.docker.com/desktop/windows/install/
|
||||
|
||||
### Mit docker-compose (empfohlen)
|
||||
|
||||
```bash
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Umgebungsvariablen konfigurieren (optional)
|
||||
cp .env.example .env
|
||||
# .env Datei bearbeiten
|
||||
|
||||
# Container bauen und starten
|
||||
docker-compose up -d
|
||||
|
||||
# Logs anzeigen
|
||||
docker-compose logs -f
|
||||
|
||||
# Status prüfen
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
**Umgebungsvariablen (`.env`):**
|
||||
```env
|
||||
# n8n Authentifizierung
|
||||
N8N_BASIC_AUTH_USER=admin
|
||||
N8N_BASIC_AUTH_PASSWORD=sicheres-passwort-hier
|
||||
|
||||
# Webhook-URL (für Produktion)
|
||||
WEBHOOK_URL=https://n8n.deine-domain.de/
|
||||
|
||||
# Zeitzone
|
||||
TZ=Europe/Berlin
|
||||
|
||||
# Log-Level (debug, info, warn, error)
|
||||
N8N_LOG_LEVEL=info
|
||||
```
|
||||
|
||||
**Nützliche docker-compose Befehle:**
|
||||
```bash
|
||||
# Stoppen
|
||||
docker-compose down
|
||||
|
||||
# Neu bauen (nach Änderungen)
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Neustart
|
||||
docker-compose restart
|
||||
|
||||
# Logs eines bestimmten Services
|
||||
docker-compose logs -f n8n
|
||||
|
||||
# In Container Shell
|
||||
docker-compose exec n8n sh
|
||||
```
|
||||
|
||||
### Mit Docker direkt
|
||||
|
||||
```bash
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Image bauen
|
||||
docker build -t n8n-librebooking .
|
||||
|
||||
# Container starten
|
||||
docker run -d \
|
||||
--name n8n-librebooking \
|
||||
-p 5678:5678 \
|
||||
-e N8N_BASIC_AUTH_ACTIVE=true \
|
||||
-e N8N_BASIC_AUTH_USER=admin \
|
||||
-e N8N_BASIC_AUTH_PASSWORD=changeme \
|
||||
-e GENERIC_TIMEZONE=Europe/Berlin \
|
||||
-v n8n_data:/home/node/.n8n \
|
||||
n8n-librebooking
|
||||
```
|
||||
|
||||
**Container verwalten:**
|
||||
```bash
|
||||
# Logs anzeigen
|
||||
docker logs -f n8n-librebooking
|
||||
|
||||
# Stoppen
|
||||
docker stop n8n-librebooking
|
||||
|
||||
# Starten
|
||||
docker start n8n-librebooking
|
||||
|
||||
# Entfernen
|
||||
docker rm -f n8n-librebooking
|
||||
|
||||
# Image entfernen
|
||||
docker rmi n8n-librebooking
|
||||
```
|
||||
|
||||
### Volumes und Konfiguration
|
||||
|
||||
**Wichtige Volumes:**
|
||||
|
||||
| Volume/Pfad | Beschreibung |
|
||||
|-------------|--------------|
|
||||
| `/home/node/.n8n` | n8n Datenverzeichnis (Workflows, Credentials) |
|
||||
| `/home/node/.n8n/custom` | Custom Nodes |
|
||||
| `/home/node/workflows` | Beispiel-Workflows (read-only) |
|
||||
|
||||
**Daten sichern:**
|
||||
```bash
|
||||
# Mit docker-compose
|
||||
docker-compose exec n8n tar -czf /tmp/backup.tar.gz /home/node/.n8n
|
||||
docker cp n8n-librebooking:/tmp/backup.tar.gz ./backup.tar.gz
|
||||
|
||||
# Ohne docker-compose
|
||||
docker cp n8n-librebooking:/home/node/.n8n ./n8n-backup
|
||||
```
|
||||
|
||||
**Daten wiederherstellen:**
|
||||
```bash
|
||||
docker cp ./n8n-backup/. n8n-librebooking:/home/node/.n8n/
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Methode 5: n8n Community Nodes
|
||||
|
||||
> **Hinweis:** Diese Methode wird verfügbar sein, sobald der Node im n8n Community Node Repository veröffentlicht ist.
|
||||
|
||||
1. Öffne n8n im Browser
|
||||
2. Gehe zu **Settings** → **Community Nodes**
|
||||
3. Klicke auf **Install a community node**
|
||||
4. Gib ein: `n8n-nodes-librebooking`
|
||||
5. Klicke auf **Install**
|
||||
6. Starte n8n neu
|
||||
|
||||
---
|
||||
|
||||
## Verifizierung der Installation
|
||||
|
||||
### 1. n8n starten
|
||||
|
||||
```bash
|
||||
# Lokal
|
||||
n8n start
|
||||
|
||||
# Mit Docker
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 2. Browser öffnen
|
||||
|
||||
Öffne http://localhost:5678 im Browser.
|
||||
|
||||
### 3. Node suchen
|
||||
|
||||
1. Erstelle einen neuen Workflow
|
||||
2. Klicke auf das **+** Symbol
|
||||
3. Suche nach "LibreBooking"
|
||||
4. Du solltest zwei Nodes sehen:
|
||||
- **LibreBooking** (für API-Operationen)
|
||||
- **LibreBooking Trigger** (für Events)
|
||||
|
||||
### 4. Credentials einrichten
|
||||
|
||||
1. Klicke auf einen LibreBooking Node
|
||||
2. Unter "Credentials" klicke auf **Create New**
|
||||
3. Wähle **LibreBooking API**
|
||||
4. Fülle aus:
|
||||
- **URL:** Deine LibreBooking URL (z.B. `https://booking.example.com/Web/Services`)
|
||||
- **Username:** Dein Admin-Benutzername
|
||||
- **Password:** Dein Passwort
|
||||
5. Klicke auf **Save**
|
||||
6. Teste die Verbindung
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Häufige Probleme
|
||||
|
||||
#### Node wird nicht angezeigt
|
||||
|
||||
**Problem:** Der LibreBooking Node erscheint nicht in n8n.
|
||||
|
||||
**Lösungen:**
|
||||
```bash
|
||||
# 1. Prüfe, ob der Build erfolgreich war
|
||||
ls -la dist/
|
||||
|
||||
# 2. Prüfe npm link Status
|
||||
npm ls -g --depth=0 | grep librebooking
|
||||
|
||||
# 3. n8n Custom Extensions Pfad prüfen
|
||||
echo $N8N_CUSTOM_EXTENSIONS
|
||||
|
||||
# 4. n8n komplett neu starten
|
||||
pkill -f n8n
|
||||
n8n start
|
||||
```
|
||||
|
||||
#### Build-Fehler
|
||||
|
||||
**Problem:** `npm run build` schlägt fehl.
|
||||
|
||||
**Lösungen:**
|
||||
```bash
|
||||
# Node.js Version prüfen
|
||||
node --version # Sollte >= 18 sein
|
||||
|
||||
# node_modules löschen und neu installieren
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
|
||||
# TypeScript-Fehler anzeigen
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
#### npm link Probleme
|
||||
|
||||
**Problem:** `npm link` funktioniert nicht.
|
||||
|
||||
**Lösungen:**
|
||||
```bash
|
||||
# Als Admin/Root ausführen (Linux/Mac)
|
||||
sudo npm link
|
||||
|
||||
# Windows: PowerShell als Administrator starten
|
||||
|
||||
# Alternativer Pfad für Custom Nodes
|
||||
export N8N_CUSTOM_EXTENSIONS=$(pwd)
|
||||
n8n start
|
||||
```
|
||||
|
||||
#### Docker-Probleme
|
||||
|
||||
**Problem:** Container startet nicht.
|
||||
|
||||
**Lösungen:**
|
||||
```bash
|
||||
# Logs prüfen
|
||||
docker-compose logs n8n
|
||||
|
||||
# Container-Status prüfen
|
||||
docker-compose ps
|
||||
|
||||
# Neu bauen
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### Credential-Fehler
|
||||
|
||||
**Problem:** "Authentication failed" bei Verbindung.
|
||||
|
||||
**Lösungen:**
|
||||
1. Prüfe LibreBooking URL (inkl. `/Web/Services`)
|
||||
2. Prüfe Benutzername und Passwort
|
||||
3. Prüfe ob API in LibreBooking aktiviert ist:
|
||||
- Admin → Konfiguration → API aktivieren
|
||||
4. Teste API manuell:
|
||||
```bash
|
||||
curl -X POST "https://dein-server/Web/Services/Authentication/Authenticate" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
```
|
||||
|
||||
### Logs und Debugging
|
||||
|
||||
**n8n Logs aktivieren:**
|
||||
```bash
|
||||
# Umgebungsvariable setzen
|
||||
export N8N_LOG_LEVEL=debug
|
||||
n8n start
|
||||
|
||||
# Mit Docker
|
||||
docker-compose exec n8n sh -c "N8N_LOG_LEVEL=debug n8n start"
|
||||
```
|
||||
|
||||
**Node-spezifische Logs:**
|
||||
In n8n Workflow-Ausführungen werden Details angezeigt unter "Execution Data".
|
||||
|
||||
---
|
||||
|
||||
## Deinstallation
|
||||
|
||||
### npm link entfernen
|
||||
|
||||
```bash
|
||||
# Im Projektverzeichnis
|
||||
npm unlink
|
||||
|
||||
# Global entfernen
|
||||
npm unlink -g n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Global installiertes Paket entfernen
|
||||
|
||||
```bash
|
||||
npm uninstall -g n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Docker entfernen
|
||||
|
||||
```bash
|
||||
# Container und Volumes entfernen
|
||||
docker-compose down -v
|
||||
|
||||
# Images entfernen
|
||||
docker rmi n8n-librebooking
|
||||
docker rmi n8nio/n8n
|
||||
```
|
||||
|
||||
### Projektverzeichnis löschen
|
||||
|
||||
```bash
|
||||
# Verzeichnis löschen
|
||||
rm -rf n8n-nodes-librebooking
|
||||
|
||||
# Archiv löschen
|
||||
rm n8n-nodes-librebooking.tar.gz
|
||||
rm n8n-nodes-librebooking.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Bei Fragen oder Problemen:
|
||||
|
||||
1. **GitHub Issues:** [Hier Issues erstellen](https://github.com/DEIN-REPO/n8n-nodes-librebooking/issues)
|
||||
2. **Dokumentation:** Siehe [README.md](README.md)
|
||||
3. **LibreBooking API:** https://www.bookedscheduler.com/help/api/
|
||||
|
||||
---
|
||||
|
||||
*Letzte Aktualisierung: Januar 2026*
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 LibreBooking n8n Node Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,618 @@
|
|||
# n8n-nodes-librebooking
|
||||
|
||||
Ein vollständiger n8n Node für die Integration mit [LibreBooking](https://librebooking.org/) - einer Open-Source Ressourcen- und Raumbuchungslösung.
|
||||
|
||||
<!-- Badges -->
|
||||
[](https://www.npmjs.com/package/n8n-nodes-librebooking)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://n8n.io)
|
||||
[](https://librebooking.org)
|
||||
[](https://nodejs.org)
|
||||
[](https://www.typescriptlang.org)
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Schnellstart
|
||||
|
||||
### Option 1: Mit Installations-Skript (empfohlen)
|
||||
|
||||
```bash
|
||||
# Archiv entpacken
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Installieren (Linux/Mac)
|
||||
./install.sh
|
||||
|
||||
# n8n starten
|
||||
n8n start
|
||||
```
|
||||
|
||||
### Option 2: Mit Docker
|
||||
|
||||
```bash
|
||||
# Archiv entpacken und starten
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
docker-compose up -d
|
||||
|
||||
# Browser öffnen: http://localhost:5678
|
||||
```
|
||||
|
||||
### Option 3: Manuell mit npm
|
||||
|
||||
```bash
|
||||
cd n8n-nodes-librebooking
|
||||
npm install && npm run build && npm link
|
||||
n8n start
|
||||
```
|
||||
|
||||
📖 **Detaillierte Anleitung:** Siehe [INSTALLATION.md](INSTALLATION.md)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Inhaltsverzeichnis
|
||||
|
||||
- [Schnellstart](#-schnellstart)
|
||||
- [Funktionen](#-funktionen)
|
||||
- [Installation](#-installation)
|
||||
- [Konfiguration](#️-konfiguration)
|
||||
- [Operationen](#-operationen)
|
||||
- [Beispiele](#-beispiele)
|
||||
- [Trigger Node](#-trigger-node)
|
||||
- [Troubleshooting](#-troubleshooting)
|
||||
- [Entwicklung](#-entwicklung)
|
||||
- [Lizenz](#-lizenz)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Funktionen
|
||||
|
||||
### Regular Node (LibreBooking)
|
||||
- **Reservierungen**: Erstellen, Abrufen, Aktualisieren, Löschen, Genehmigen, Check-In/Check-Out
|
||||
- **Ressourcen**: Verwalten von Räumen, Equipment und anderen buchbaren Ressourcen
|
||||
- **Zeitpläne**: Abrufen von Zeitplänen und verfügbaren Slots
|
||||
- **Benutzer**: Vollständige Benutzerverwaltung (Admin-Rechte erforderlich)
|
||||
- **Konten**: Eigenes Konto verwalten
|
||||
- **Gruppen**: Benutzergruppen mit Rollen und Berechtigungen verwalten
|
||||
- **Zubehör**: Zubehörteile abrufen
|
||||
- **Attribute**: Benutzerdefinierte Felder verwalten
|
||||
|
||||
### Trigger Node (LibreBooking Trigger)
|
||||
- Polling-basierter Trigger für Reservierungs-Events
|
||||
- Erkennung neuer Reservierungen
|
||||
- Erkennung geänderter Reservierungen
|
||||
- Konfigurierbare Filter (Ressource, Zeitplan, Benutzer)
|
||||
- Deduplizierung von Events
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
### Über npm (empfohlen)
|
||||
|
||||
```bash
|
||||
npm install n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Manuelle Installation
|
||||
|
||||
1. Laden Sie das Paket herunter oder klonen Sie das Repository:
|
||||
```bash
|
||||
git clone https://github.com/your-org/n8n-nodes-librebooking.git
|
||||
```
|
||||
|
||||
2. Wechseln Sie ins Verzeichnis und installieren Sie die Abhängigkeiten:
|
||||
```bash
|
||||
cd n8n-nodes-librebooking
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Kompilieren Sie das Projekt:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
4. Verlinken Sie das Paket für lokale Entwicklung:
|
||||
```bash
|
||||
npm link
|
||||
```
|
||||
|
||||
5. Verlinken Sie es in Ihrem n8n Custom-Nodes-Verzeichnis:
|
||||
```bash
|
||||
cd ~/.n8n/custom
|
||||
npm link n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
6. Starten Sie n8n neu:
|
||||
```bash
|
||||
n8n start
|
||||
```
|
||||
|
||||
### Docker-Installation
|
||||
|
||||
Fügen Sie in Ihrem Docker-Compose oder Dockerfile hinzu:
|
||||
|
||||
```dockerfile
|
||||
RUN npm install -g n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
Oder über Umgebungsvariable:
|
||||
```yaml
|
||||
environment:
|
||||
- N8N_CUSTOM_EXTENSIONS=n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### Integration in bestehende Docker-Installation
|
||||
|
||||
Für bestehende n8n Docker-Installationen gibt es mehrere Integrationsmethoden:
|
||||
|
||||
#### Schnellste Methode: Automatisches Skript
|
||||
|
||||
```bash
|
||||
# Ins n8n Verzeichnis wechseln
|
||||
cd /pfad/zu/ihrer/n8n/installation
|
||||
|
||||
# Skript ausführen
|
||||
./install-docker.sh
|
||||
```
|
||||
|
||||
#### Manuelle Methode
|
||||
|
||||
```bash
|
||||
# 1. Custom Nodes kopieren
|
||||
cp -r custom-nodes /pfad/zu/n8n/
|
||||
cd /pfad/zu/n8n/custom-nodes && npm install && npm run build
|
||||
|
||||
# 2. docker-compose.override.yml erstellen
|
||||
cat > docker-compose.override.yml << 'EOF'
|
||||
version: '3.8'
|
||||
services:
|
||||
n8n:
|
||||
volumes:
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
environment:
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
EOF
|
||||
|
||||
# 3. Container neustarten
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
#### Eigenes Docker-Image bauen
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile.custom-nodes -t n8n-librebooking .
|
||||
docker run -d -p 5678:5678 n8n-librebooking
|
||||
```
|
||||
|
||||
📖 **Ausführliche Docker-Anleitung:** Siehe [DOCKER-INTEGRATION.md](DOCKER-INTEGRATION.md)
|
||||
|
||||
🚀 **Docker-Schnellstart:** Siehe [SCHNELLSTART-DOCKER.md](SCHNELLSTART-DOCKER.md)
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Konfiguration
|
||||
|
||||
### Credentials einrichten
|
||||
|
||||
1. Öffnen Sie n8n und gehen Sie zu **Settings** → **Credentials**
|
||||
2. Klicken Sie auf **Add Credential** und wählen Sie **LibreBooking API**
|
||||
3. Füllen Sie die folgenden Felder aus:
|
||||
|
||||
| Feld | Beschreibung | Beispiel |
|
||||
|------|-------------|----------|
|
||||
| **LibreBooking URL** | Die Basis-URL Ihrer LibreBooking-Installation | `https://booking.example.com` |
|
||||
| **Benutzername** | Ihr LibreBooking-Login (E-Mail oder Benutzername) | `admin@example.com` |
|
||||
| **Passwort** | Ihr LibreBooking-Passwort | `•••••••••` |
|
||||
|
||||
> ⚠️ **Wichtig**: Die URL sollte **ohne** `/Web/Services` angegeben werden!
|
||||
|
||||
### API aktivieren
|
||||
|
||||
Stellen Sie sicher, dass die API in Ihrer LibreBooking-Installation aktiviert ist:
|
||||
|
||||
1. Öffnen Sie die `config.php` Ihrer LibreBooking-Installation
|
||||
2. Suchen Sie nach `$conf['settings']['api']['enabled']`
|
||||
3. Setzen Sie den Wert auf `true`
|
||||
|
||||
```php
|
||||
$conf['settings']['api']['enabled'] = 'true';
|
||||
```
|
||||
|
||||
### Credential-Test
|
||||
|
||||
Nach dem Speichern der Credentials können Sie diese testen:
|
||||
- Klicken Sie auf **Test** um die Verbindung zu überprüfen
|
||||
- Bei erfolgreicher Verbindung wird eine Bestätigung angezeigt
|
||||
|
||||
---
|
||||
|
||||
## 📖 Operationen
|
||||
|
||||
### Reservierungen
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Reservierungen mit optionalen Filtern | ❌ |
|
||||
| **Abrufen** | Einzelne Reservierung per Referenznummer | ❌ |
|
||||
| **Erstellen** | Neue Reservierung anlegen | ❌ |
|
||||
| **Aktualisieren** | Bestehende Reservierung ändern | ❌ |
|
||||
| **Löschen** | Reservierung entfernen | ❌ |
|
||||
| **Genehmigen** | Ausstehende Reservierung genehmigen | ❌* |
|
||||
| **Check-In** | In Reservierung einchecken | ❌ |
|
||||
| **Check-Out** | Aus Reservierung auschecken | ❌ |
|
||||
|
||||
*Erfordert Genehmigungsrechte
|
||||
|
||||
#### Filter für "Alle Abrufen"
|
||||
- `userId` - Nach Benutzer filtern
|
||||
- `resourceId` - Nach Ressource filtern
|
||||
- `scheduleId` - Nach Zeitplan filtern
|
||||
- `startDateTime` - Startzeit (ISO 8601)
|
||||
- `endDateTime` - Endzeit (ISO 8601)
|
||||
|
||||
#### Zusätzliche Felder für "Erstellen/Aktualisieren"
|
||||
- `description` - Beschreibung
|
||||
- `participants` - Teilnehmer (Benutzer-IDs)
|
||||
- `invitees` - Eingeladene (Benutzer-IDs)
|
||||
- `resources` - Zusätzliche Ressourcen
|
||||
- `allowParticipation` - Teilnahme erlauben
|
||||
|
||||
### Ressourcen
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Ressourcen | ❌ |
|
||||
| **Abrufen** | Einzelne Ressource per ID | ❌ |
|
||||
| **Verfügbarkeit Prüfen** | Verfügbarkeit einer/aller Ressourcen | ❌ |
|
||||
| **Gruppen Abrufen** | Ressourcen-Gruppenstruktur | ❌ |
|
||||
| **Typen Abrufen** | Verfügbare Ressourcen-Typen | ❌ |
|
||||
| **Status Abrufen** | Verfügbare Status-Werte | ❌ |
|
||||
| **Erstellen** | Neue Ressource anlegen | ✅ |
|
||||
| **Aktualisieren** | Ressource ändern | ✅ |
|
||||
| **Löschen** | Ressource entfernen | ✅ |
|
||||
|
||||
#### Ressourcen-Optionen
|
||||
- `location` - Standort
|
||||
- `contact` - Kontaktinformation
|
||||
- `description` - Beschreibung
|
||||
- `maxParticipants` - Maximale Teilnehmerzahl
|
||||
- `requiresApproval` - Genehmigung erforderlich
|
||||
- `allowMultiday` - Mehrtägige Buchungen
|
||||
- `requiresCheckIn` - Check-In erforderlich
|
||||
- `autoReleaseMinutes` - Auto-Release nach X Minuten
|
||||
- `color` - Anzeigefarbe (Hex)
|
||||
- `statusId` - Status (0=Versteckt, 1=Verfügbar, 2=Nicht verfügbar)
|
||||
|
||||
### Zeitpläne
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Zeitpläne | ❌ |
|
||||
| **Abrufen** | Einzelner Zeitplan mit Perioden | ❌ |
|
||||
| **Slots Abrufen** | Verfügbare Slots eines Zeitplans | ❌ |
|
||||
|
||||
### Benutzer (Admin)
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Benutzer | ❌ |
|
||||
| **Abrufen** | Einzelner Benutzer per ID | ❌ |
|
||||
| **Erstellen** | Neuen Benutzer anlegen | ✅ |
|
||||
| **Aktualisieren** | Benutzer ändern | ✅ |
|
||||
| **Passwort Ändern** | Benutzer-Passwort setzen | ✅ |
|
||||
| **Löschen** | Benutzer entfernen | ✅ |
|
||||
|
||||
### Konten
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Abrufen** | Eigene Kontoinformationen | ❌ |
|
||||
| **Erstellen** | Neues Konto (Registrierung) | ❌ |
|
||||
| **Aktualisieren** | Eigenes Konto ändern | ❌ |
|
||||
| **Passwort Ändern** | Eigenes Passwort ändern | ❌ |
|
||||
|
||||
### Gruppen
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Gruppen | ❌ |
|
||||
| **Abrufen** | Einzelne Gruppe | ❌ |
|
||||
| **Erstellen** | Neue Gruppe anlegen | ✅ |
|
||||
| **Aktualisieren** | Gruppe ändern | ✅ |
|
||||
| **Löschen** | Gruppe entfernen | ✅ |
|
||||
| **Rollen Ändern** | Gruppenrollen setzen | ✅ |
|
||||
| **Berechtigungen Ändern** | Ressourcen-Berechtigungen | ✅ |
|
||||
| **Benutzer Ändern** | Gruppenmitglieder | ✅ |
|
||||
|
||||
#### Rollen-IDs
|
||||
- `1` - Gruppenadministrator
|
||||
- `2` - Anwendungsadministrator
|
||||
- `3` - Ressourcenadministrator
|
||||
- `4` - Zeitplanadministrator
|
||||
|
||||
### Zubehör
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Alle Abrufen** | Liste aller Zubehörteile | ❌ |
|
||||
| **Abrufen** | Einzelnes Zubehörteil | ❌ |
|
||||
|
||||
### Attribute
|
||||
|
||||
| Operation | Beschreibung | Admin-Rechte |
|
||||
|-----------|-------------|--------------|
|
||||
| **Abrufen** | Einzelnes Attribut | ❌ |
|
||||
| **Nach Kategorie Abrufen** | Alle Attribute einer Kategorie | ❌ |
|
||||
| **Erstellen** | Neues Attribut anlegen | ✅ |
|
||||
| **Aktualisieren** | Attribut ändern | ✅ |
|
||||
| **Löschen** | Attribut entfernen | ✅ |
|
||||
|
||||
#### Attribut-Kategorien
|
||||
- `1` - Reservierung
|
||||
- `2` - Benutzer
|
||||
- `4` - Ressource
|
||||
- `5` - Ressourcen-Typ
|
||||
|
||||
#### Attribut-Typen
|
||||
- `1` - Einzeilig (Text)
|
||||
- `2` - Mehrzeilig (Textarea)
|
||||
- `3` - Auswahlliste
|
||||
- `4` - Checkbox
|
||||
- `5` - Datum/Zeit
|
||||
|
||||
---
|
||||
|
||||
## 💡 Beispiele
|
||||
|
||||
### Beispiel 1: Alle Reservierungen der nächsten Woche abrufen
|
||||
|
||||
```json
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "reservation",
|
||||
"operation": "getAll",
|
||||
"filters": {
|
||||
"startDateTime": "={{ $now.toISO() }}",
|
||||
"endDateTime": "={{ $now.plus({days: 7}).toISO() }}"
|
||||
}
|
||||
},
|
||||
"name": "LibreBooking",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [250, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": {
|
||||
"id": "1",
|
||||
"name": "LibreBooking"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Beispiel 2: Neue Reservierung erstellen
|
||||
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "reservation",
|
||||
"operation": "create",
|
||||
"resourceId": 1,
|
||||
"startDateTime": "2026-01-26T10:00:00",
|
||||
"endDateTime": "2026-01-26T11:00:00",
|
||||
"title": "Team Meeting",
|
||||
"additionalFields": {
|
||||
"description": "Wöchentliches Team-Meeting",
|
||||
"participants": "2,3,4"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Beispiel 3: Verfügbarkeit prüfen
|
||||
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "resource",
|
||||
"operation": "getAvailability",
|
||||
"resourceIdOptional": 1,
|
||||
"availabilityDateTime": "2026-01-26T14:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Beispiel 4: Benutzer mit Filter suchen
|
||||
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "user",
|
||||
"operation": "getAll",
|
||||
"userFilters": {
|
||||
"organization": "Marketing",
|
||||
"lastName": "Müller"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Trigger Node
|
||||
|
||||
Der **LibreBooking Trigger** ist ein Polling-basierter Trigger, der auf neue oder geänderte Reservierungen reagiert.
|
||||
|
||||
### Konfiguration
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|-----------|-------------|
|
||||
| **Event** | Art des Events (Neue/Geänderte/Alle Reservierungen) |
|
||||
| **Filter** | Optional: Ressource, Zeitplan, Benutzer |
|
||||
| **Zeitfenster** | Überwachungszeitraum (7/14/30/90 Tage) |
|
||||
| **Detaillierte Daten** | Vollständige Reservierungsdetails abrufen |
|
||||
|
||||
### Event-Typen
|
||||
|
||||
- **Neue Reservierung**: Wird nur bei neuen Reservierungen ausgelöst
|
||||
- **Geänderte Reservierung**: Wird bei Änderungen an bestehenden Reservierungen ausgelöst
|
||||
- **Alle Reservierungen**: Wird bei neuen und geänderten Reservierungen ausgelöst
|
||||
|
||||
### Beispiel-Workflow: Benachrichtigung bei neuer Reservierung
|
||||
|
||||
```
|
||||
[LibreBooking Trigger] → [IF: Ressource = 1] → [Slack: Nachricht senden]
|
||||
```
|
||||
|
||||
### Deduplizierung
|
||||
|
||||
Der Trigger speichert Informationen über bereits verarbeitete Reservierungen und verhindert so doppelte Ausführungen. Bei Änderungen (Titel, Zeit, etc.) wird eine Reservierung als "geändert" erkannt.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Häufige Fehler
|
||||
|
||||
#### "Authentifizierung fehlgeschlagen"
|
||||
- Überprüfen Sie die LibreBooking-URL (ohne `/Web/Services`)
|
||||
- Stellen Sie sicher, dass Benutzername und Passwort korrekt sind
|
||||
- Prüfen Sie, ob die API in LibreBooking aktiviert ist
|
||||
|
||||
#### "Zugriff verweigert" (403)
|
||||
- Die Operation erfordert Administrator-Rechte
|
||||
- Verwenden Sie einen Admin-Account oder wählen Sie eine andere Operation
|
||||
|
||||
#### "Nicht gefunden" (404)
|
||||
- Die angegebene ID (Ressource, Benutzer, etc.) existiert nicht
|
||||
- Überprüfen Sie die Referenznummer bei Reservierungen
|
||||
|
||||
#### "Session abgelaufen"
|
||||
- Der Session-Token ist abgelaufen
|
||||
- Führen Sie den Workflow erneut aus
|
||||
|
||||
### API-Limitierungen
|
||||
|
||||
- LibreBooking hat keine dokumentierten Rate-Limits
|
||||
- Bei vielen Anfragen empfehlen wir Pausen zwischen den Operationen
|
||||
- Der Node authentifiziert sich bei jeder Ausführung neu und meldet sich am Ende ab
|
||||
|
||||
### Debug-Tipps
|
||||
|
||||
1. Aktivieren Sie die n8n-Logs für detaillierte Fehlermeldungen:
|
||||
```bash
|
||||
export N8N_LOG_LEVEL=debug
|
||||
n8n start
|
||||
```
|
||||
|
||||
2. Testen Sie die API direkt im Browser:
|
||||
```
|
||||
https://your-librebooking.com/Web/Services/index.php
|
||||
```
|
||||
|
||||
3. Überprüfen Sie die Zeitzonen-Einstellungen in LibreBooking und n8n
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Entwicklung
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- Node.js 18.17.0 oder höher
|
||||
- npm 9.x oder höher
|
||||
- n8n (für Tests)
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Repository klonen
|
||||
git clone https://github.com/your-org/n8n-nodes-librebooking.git
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Abhängigkeiten installieren
|
||||
npm install
|
||||
|
||||
# TypeScript kompilieren
|
||||
npm run build
|
||||
|
||||
# Für Entwicklung (Watch-Modus)
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
```
|
||||
n8n-nodes-librebooking/
|
||||
├── credentials/
|
||||
│ └── LibreBookingApi.credentials.ts
|
||||
├── nodes/
|
||||
│ ├── LibreBooking/
|
||||
│ │ ├── LibreBooking.node.ts
|
||||
│ │ └── librebooking.svg
|
||||
│ └── LibreBookingTrigger/
|
||||
│ ├── LibreBookingTrigger.node.ts
|
||||
│ └── librebooking.svg
|
||||
├── workflows/
|
||||
│ └── example-workflows.json
|
||||
├── test/
|
||||
│ └── test-api.ts
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### Tests ausführen
|
||||
|
||||
```bash
|
||||
# API-Test mit echten Credentials
|
||||
npm test
|
||||
```
|
||||
|
||||
### Linting
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run lint:fix
|
||||
```
|
||||
|
||||
### Build für Produktion
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📄 Lizenz
|
||||
|
||||
MIT License - siehe [LICENSE](LICENSE) Datei
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Beitragen
|
||||
|
||||
Beiträge sind willkommen! Bitte öffnen Sie einen Issue oder Pull Request.
|
||||
|
||||
1. Fork des Repositories
|
||||
2. Feature-Branch erstellen (`git checkout -b feature/AmazingFeature`)
|
||||
3. Änderungen committen (`git commit -m 'Add AmazingFeature'`)
|
||||
4. Branch pushen (`git push origin feature/AmazingFeature`)
|
||||
5. Pull Request öffnen
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **Issues**: [GitHub Issues](https://github.com/your-org/n8n-nodes-librebooking/issues)
|
||||
- **LibreBooking Dokumentation**: [https://librebooking.org/docs](https://librebooking.org/docs)
|
||||
- **n8n Community**: [https://community.n8n.io](https://community.n8n.io)
|
||||
|
||||
---
|
||||
|
||||
**Erstellt mit ❤️ für die n8n und LibreBooking Community**
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
# Schnellstart: Docker-Integration
|
||||
|
||||
Ultra-kurze Anleitung für erfahrene Docker-Nutzer.
|
||||
|
||||
---
|
||||
|
||||
## Automatische Installation (Empfohlen)
|
||||
|
||||
```bash
|
||||
# Ins n8n Verzeichnis wechseln
|
||||
cd /pfad/zu/deiner/n8n/installation
|
||||
|
||||
# Skript ausführen
|
||||
./install-docker.sh
|
||||
|
||||
# Oder mit Pfad
|
||||
./install-docker.sh -p /opt/n8n
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manuelle Installation (3 Schritte)
|
||||
|
||||
### 1. Custom Nodes kopieren
|
||||
|
||||
```bash
|
||||
cp -r custom-nodes /pfad/zu/n8n/
|
||||
cd /pfad/zu/n8n/custom-nodes
|
||||
npm install && npm run build
|
||||
```
|
||||
|
||||
### 2. Override-Datei erstellen
|
||||
|
||||
```bash
|
||||
cat > docker-compose.override.yml << 'EOF'
|
||||
version: '3.8'
|
||||
services:
|
||||
n8n:
|
||||
volumes:
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
environment:
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
EOF
|
||||
```
|
||||
|
||||
### 3. Neustarten
|
||||
|
||||
```bash
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Neues Setup mit Docker
|
||||
|
||||
```bash
|
||||
# Beispiel-Konfiguration verwenden
|
||||
cp docker-compose.example.yml docker-compose.yml
|
||||
cp .env.docker .env
|
||||
|
||||
# .env anpassen, dann starten
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Eigenes Image bauen
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile.custom-nodes -t n8n-librebooking .
|
||||
docker run -d -p 5678:5678 n8n-librebooking
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verifizierung
|
||||
|
||||
```bash
|
||||
# Node prüfen
|
||||
docker exec n8n ls /home/node/.n8n/custom/n8n-nodes-librebooking/dist/
|
||||
|
||||
# In n8n: Nach "LibreBooking" suchen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bei Problemen
|
||||
|
||||
```bash
|
||||
# Berechtigungen
|
||||
sudo chown -R 1000:1000 custom-nodes/
|
||||
|
||||
# Logs
|
||||
docker logs n8n | grep -i error
|
||||
|
||||
# Neustart
|
||||
docker-compose down && docker-compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
📖 **Ausführliche Anleitung:** [DOCKER-INTEGRATION.md](DOCKER-INTEGRATION.md)
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# Schnellstart - LibreBooking n8n Node
|
||||
|
||||
Diese Anleitung ist für erfahrene Benutzer, die schnell loslegen möchten.
|
||||
|
||||
## Option A: Mit Skript (empfohlen)
|
||||
|
||||
```bash
|
||||
# Archiv entpacken
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Installieren
|
||||
./install.sh
|
||||
|
||||
# n8n starten
|
||||
n8n start
|
||||
```
|
||||
|
||||
## Option B: Mit Docker
|
||||
|
||||
```bash
|
||||
# Archiv entpacken
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
|
||||
# Container starten
|
||||
docker-compose up -d
|
||||
|
||||
# Browser öffnen
|
||||
open http://localhost:5678
|
||||
```
|
||||
|
||||
## Option C: Manuell
|
||||
|
||||
```bash
|
||||
tar -xzf n8n-nodes-librebooking.tar.gz
|
||||
cd n8n-nodes-librebooking
|
||||
npm install
|
||||
npm run build
|
||||
npm link
|
||||
n8n start
|
||||
```
|
||||
|
||||
## Credentials einrichten
|
||||
|
||||
1. Öffne http://localhost:5678
|
||||
2. Erstelle neuen Workflow
|
||||
3. Füge "LibreBooking" Node hinzu
|
||||
4. Erstelle neue Credentials:
|
||||
- **URL:** `https://dein-server/Web/Services`
|
||||
- **Username:** Admin-Benutzer
|
||||
- **Password:** Passwort
|
||||
|
||||
## Fertig!
|
||||
|
||||
Der LibreBooking Node ist jetzt verfügbar.
|
||||
|
||||
---
|
||||
|
||||
Für detaillierte Anleitungen siehe [INSTALLATION.md](INSTALLATION.md)
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* LibreBooking API Credentials
|
||||
*
|
||||
* LibreBooking verwendet Session-basierte Authentifizierung.
|
||||
* Der Node holt bei jeder Ausführung einen neuen Session-Token.
|
||||
*/
|
||||
export class LibreBookingApi implements ICredentialType {
|
||||
name = 'libreBookingApi';
|
||||
displayName = 'LibreBooking API';
|
||||
documentationUrl = 'https://librebooking.org/docs/api';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'LibreBooking URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://booking.example.com',
|
||||
required: true,
|
||||
description: 'Die Basis-URL Ihrer LibreBooking-Installation (ohne /Web/Services)',
|
||||
},
|
||||
{
|
||||
displayName: 'Benutzername',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Ihr LibreBooking-Benutzername oder E-Mail-Adresse',
|
||||
},
|
||||
{
|
||||
displayName: 'Passwort',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Ihr LibreBooking-Passwort',
|
||||
},
|
||||
];
|
||||
|
||||
// Test-Request um die Credentials zu validieren
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.url}}',
|
||||
url: '/Web/Services/index.php/Authentication/Authenticate',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
username: '={{$credentials.username}}',
|
||||
password: '={{$credentials.password}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# LibreBooking n8n Node - Custom Nodes Version
|
||||
|
||||
Diese Version ist speziell für die Integration in bestehende n8n Docker-Installationen optimiert.
|
||||
|
||||
## Schnellinstallation
|
||||
|
||||
### 1. Verzeichnis in n8n Custom Nodes kopieren
|
||||
|
||||
```bash
|
||||
cp -r custom-nodes /pfad/zu/n8n/.n8n/custom/n8n-nodes-librebooking
|
||||
```
|
||||
|
||||
### 2. Dependencies installieren und bauen
|
||||
|
||||
```bash
|
||||
cd /pfad/zu/n8n/.n8n/custom/n8n-nodes-librebooking
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 3. n8n neustarten
|
||||
|
||||
```bash
|
||||
docker-compose restart n8n
|
||||
```
|
||||
|
||||
## Enthaltene Dateien
|
||||
|
||||
- `credentials/` - API Credentials Definition
|
||||
- `nodes/` - LibreBooking und LibreBookingTrigger Nodes
|
||||
- `package.json` - Vereinfachte Package-Konfiguration
|
||||
- `tsconfig.json` - TypeScript Konfiguration
|
||||
|
||||
## Weitere Informationen
|
||||
|
||||
Siehe die ausführliche Dokumentation:
|
||||
- `DOCKER-INTEGRATION.md` - Detaillierte Docker-Anleitung
|
||||
- `README.md` - Vollständige Dokumentation
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT License
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* LibreBooking API Credentials
|
||||
*
|
||||
* LibreBooking verwendet Session-basierte Authentifizierung.
|
||||
* Der Node holt bei jeder Ausführung einen neuen Session-Token.
|
||||
*/
|
||||
export class LibreBookingApi implements ICredentialType {
|
||||
name = 'libreBookingApi';
|
||||
displayName = 'LibreBooking API';
|
||||
documentationUrl = 'https://librebooking.org/docs/api';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'LibreBooking URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://booking.example.com',
|
||||
required: true,
|
||||
description: 'Die Basis-URL Ihrer LibreBooking-Installation (ohne /Web/Services)',
|
||||
},
|
||||
{
|
||||
displayName: 'Benutzername',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Ihr LibreBooking-Benutzername oder E-Mail-Adresse',
|
||||
},
|
||||
{
|
||||
displayName: 'Passwort',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Ihr LibreBooking-Passwort',
|
||||
},
|
||||
];
|
||||
|
||||
// Test-Request um die Credentials zu validieren
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.url}}',
|
||||
url: '/Web/Services/index.php/Authentication/Authenticate',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
username: '={{$credentials.username}}',
|
||||
password: '={{$credentials.password}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// LibreBooking n8n Node - Entry Point
|
||||
export { LibreBooking } from './nodes/LibreBooking/LibreBooking.node';
|
||||
export { LibreBookingTrigger } from './nodes/LibreBookingTrigger/LibreBookingTrigger.node';
|
||||
export { LibreBookingApi } from './credentials/LibreBookingApi.credentials';
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="60" height="60">
|
||||
<!-- Background -->
|
||||
<rect width="60" height="60" rx="8" fill="#2C3E50"/>
|
||||
|
||||
<!-- Calendar base -->
|
||||
<rect x="10" y="15" width="40" height="35" rx="3" fill="#ECF0F1" stroke="#3498DB" stroke-width="2"/>
|
||||
|
||||
<!-- Calendar header -->
|
||||
<rect x="10" y="15" width="40" height="10" rx="3" fill="#3498DB"/>
|
||||
<rect x="10" y="22" width="40" height="3" fill="#3498DB"/>
|
||||
|
||||
<!-- Calendar rings -->
|
||||
<rect x="18" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
<rect x="38" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<line x1="10" y1="33" x2="50" y2="33" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="10" y1="41" x2="50" y2="41" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="23" y1="25" x2="23" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="37" y1="25" x2="37" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
|
||||
<!-- Booking indicator -->
|
||||
<rect x="25" y="35" width="10" height="4" rx="1" fill="#27AE60"/>
|
||||
|
||||
<!-- Check mark -->
|
||||
<path d="M39 27 L42 30 L48 22" stroke="#FFFFFF" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,352 @@
|
|||
import {
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IPollFunctions,
|
||||
INodeExecutionData,
|
||||
NodeApiError,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
interface LibreBookingSession {
|
||||
sessionToken: string;
|
||||
userId: number;
|
||||
sessionExpires: string;
|
||||
}
|
||||
|
||||
interface ReservationData {
|
||||
referenceNumber: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
title: string;
|
||||
resourceId: number;
|
||||
userId: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentifizierung bei LibreBooking
|
||||
*/
|
||||
async function authenticateTrigger(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
username: string,
|
||||
password: string,
|
||||
): Promise<LibreBookingSession> {
|
||||
try {
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/Web/Services/index.php/Authentication/Authenticate`,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: { username, password },
|
||||
json: true,
|
||||
});
|
||||
|
||||
if (!response.isAuthenticated) {
|
||||
throw new NodeOperationError(
|
||||
pollFunctions.getNode(),
|
||||
'Authentifizierung fehlgeschlagen',
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
sessionToken: response.sessionToken,
|
||||
userId: response.userId,
|
||||
sessionExpires: response.sessionExpires,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new NodeApiError(pollFunctions.getNode(), error, {
|
||||
message: 'Authentifizierung fehlgeschlagen',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abmeldung
|
||||
*/
|
||||
async function signOutTrigger(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await pollFunctions.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/Web/Services/index.php/Authentication/SignOut`,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: {
|
||||
userId: session.userId,
|
||||
sessionToken: session.sessionToken,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
} catch (error) {
|
||||
// Ignoriere SignOut-Fehler
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reservierungen abrufen
|
||||
*/
|
||||
async function getReservations(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
startDateTime: string,
|
||||
endDateTime: string,
|
||||
filters: any,
|
||||
): Promise<ReservationData[]> {
|
||||
const qs: any = {
|
||||
startDateTime,
|
||||
endDateTime,
|
||||
};
|
||||
|
||||
if (filters.resourceId) qs.resourceId = filters.resourceId;
|
||||
if (filters.scheduleId) qs.scheduleId = filters.scheduleId;
|
||||
if (filters.userId) qs.userId = filters.userId;
|
||||
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'GET',
|
||||
url: `${baseUrl}/Web/Services/index.php/Reservations/`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
},
|
||||
qs,
|
||||
json: true,
|
||||
});
|
||||
|
||||
return response.reservations || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaillierte Reservierungsdaten abrufen
|
||||
*/
|
||||
async function getReservationDetails(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
referenceNumber: string,
|
||||
): Promise<any> {
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'GET',
|
||||
url: `${baseUrl}/Web/Services/index.php/Reservations/${referenceNumber}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeitfenster berechnen
|
||||
*/
|
||||
function getTimeWindow(timeWindow: string): { start: string; end: string } {
|
||||
const now = new Date();
|
||||
const start = now.toISOString();
|
||||
|
||||
let endDate = new Date(now);
|
||||
switch (timeWindow) {
|
||||
case '7days':
|
||||
endDate.setDate(endDate.getDate() + 7);
|
||||
break;
|
||||
case '14days':
|
||||
endDate.setDate(endDate.getDate() + 14);
|
||||
break;
|
||||
case '30days':
|
||||
endDate.setDate(endDate.getDate() + 30);
|
||||
break;
|
||||
case '90days':
|
||||
endDate.setDate(endDate.getDate() + 90);
|
||||
break;
|
||||
default:
|
||||
endDate.setDate(endDate.getDate() + 14);
|
||||
}
|
||||
|
||||
return {
|
||||
start,
|
||||
end: endDate.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Eindeutigen Schlüssel für Reservierung generieren
|
||||
*/
|
||||
function getReservationKey(reservation: ReservationData): string {
|
||||
return `${reservation.referenceNumber}_${reservation.startDate}_${reservation.endDate}_${reservation.title || ''}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* LibreBooking Trigger Node
|
||||
*/
|
||||
export class LibreBookingTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'LibreBooking Trigger',
|
||||
name: 'libreBookingTrigger',
|
||||
icon: 'file:librebooking.svg',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Wird bei neuen oder geänderten Reservierungen in LibreBooking ausgelöst',
|
||||
subtitle: '={{$parameter["event"]}}',
|
||||
defaults: {
|
||||
name: 'LibreBooking Trigger',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'libreBookingApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
polling: true,
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Event',
|
||||
name: 'event',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Neue Reservierung', value: 'newReservation', description: 'Wird bei neuen Reservierungen ausgelöst' },
|
||||
{ name: 'Geänderte Reservierung', value: 'updatedReservation', description: 'Wird bei geänderten Reservierungen ausgelöst' },
|
||||
{ name: 'Alle Reservierungen', value: 'allReservations', description: 'Wird bei neuen und geänderten Reservierungen ausgelöst' },
|
||||
],
|
||||
default: 'newReservation',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Filter hinzufügen',
|
||||
default: {},
|
||||
options: [
|
||||
{ displayName: 'Ressourcen-ID', name: 'resourceId', type: 'number', default: '' },
|
||||
{ displayName: 'Zeitplan-ID', name: 'scheduleId', type: 'number', default: '' },
|
||||
{ displayName: 'Benutzer-ID', name: 'userId', type: 'number', default: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Zeitfenster',
|
||||
name: 'timeWindow',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Nächste 7 Tage', value: '7days' },
|
||||
{ name: 'Nächste 14 Tage', value: '14days' },
|
||||
{ name: 'Nächste 30 Tage', value: '30days' },
|
||||
{ name: 'Nächste 90 Tage', value: '90days' },
|
||||
],
|
||||
default: '14days',
|
||||
},
|
||||
{
|
||||
displayName: 'Optionen',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Option hinzufügen',
|
||||
default: {},
|
||||
options: [
|
||||
{ displayName: 'Detaillierte Daten Abrufen', name: 'fetchDetails', type: 'boolean', default: false },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
|
||||
const credentials = await this.getCredentials('libreBookingApi');
|
||||
const baseUrl = (credentials.url as string).replace(/\/$/, '');
|
||||
const username = credentials.username as string;
|
||||
const password = credentials.password as string;
|
||||
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
const filters = this.getNodeParameter('filters', {}) as any;
|
||||
const timeWindow = this.getNodeParameter('timeWindow', '14days') as string;
|
||||
const options = this.getNodeParameter('options', {}) as any;
|
||||
|
||||
const workflowStaticData = this.getWorkflowStaticData('node');
|
||||
const previousReservations = (workflowStaticData.reservations as Record<string, string>) || {};
|
||||
|
||||
let session: LibreBookingSession;
|
||||
try {
|
||||
session = await authenticateTrigger(this, baseUrl, username, password);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
const { start, end } = getTimeWindow(timeWindow);
|
||||
|
||||
const reservations = await getReservations(
|
||||
this,
|
||||
baseUrl,
|
||||
session,
|
||||
start,
|
||||
end,
|
||||
filters,
|
||||
);
|
||||
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const currentReservations: Record<string, string> = {};
|
||||
|
||||
for (const reservation of reservations) {
|
||||
const refNumber = reservation.referenceNumber;
|
||||
const reservationKey = getReservationKey(reservation);
|
||||
currentReservations[refNumber] = reservationKey;
|
||||
|
||||
const isNew = !previousReservations[refNumber];
|
||||
const isUpdated = previousReservations[refNumber] && previousReservations[refNumber] !== reservationKey;
|
||||
|
||||
let shouldTrigger = false;
|
||||
let eventType = '';
|
||||
|
||||
if (event === 'newReservation' && isNew) {
|
||||
shouldTrigger = true;
|
||||
eventType = 'new';
|
||||
} else if (event === 'updatedReservation' && isUpdated) {
|
||||
shouldTrigger = true;
|
||||
eventType = 'updated';
|
||||
} else if (event === 'allReservations' && (isNew || isUpdated)) {
|
||||
shouldTrigger = true;
|
||||
eventType = isNew ? 'new' : 'updated';
|
||||
}
|
||||
|
||||
if (shouldTrigger) {
|
||||
let reservationData = reservation;
|
||||
|
||||
if (options.fetchDetails) {
|
||||
try {
|
||||
reservationData = await getReservationDetails(
|
||||
this,
|
||||
baseUrl,
|
||||
session,
|
||||
refNumber,
|
||||
);
|
||||
} catch (error) {
|
||||
reservationData = reservation;
|
||||
}
|
||||
}
|
||||
|
||||
returnData.push({
|
||||
json: {
|
||||
...reservationData,
|
||||
_eventType: eventType,
|
||||
_triggeredAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
workflowStaticData.reservations = currentReservations;
|
||||
|
||||
if (returnData.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
|
||||
} finally {
|
||||
await signOutTrigger(this, baseUrl, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="60" height="60">
|
||||
<!-- Background -->
|
||||
<rect width="60" height="60" rx="8" fill="#2C3E50"/>
|
||||
|
||||
<!-- Calendar base -->
|
||||
<rect x="10" y="15" width="40" height="35" rx="3" fill="#ECF0F1" stroke="#3498DB" stroke-width="2"/>
|
||||
|
||||
<!-- Calendar header -->
|
||||
<rect x="10" y="15" width="40" height="10" rx="3" fill="#3498DB"/>
|
||||
<rect x="10" y="22" width="40" height="3" fill="#3498DB"/>
|
||||
|
||||
<!-- Calendar rings -->
|
||||
<rect x="18" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
<rect x="38" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<line x1="10" y1="33" x2="50" y2="33" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="10" y1="41" x2="50" y2="41" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="23" y1="25" x2="23" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="37" y1="25" x2="37" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
|
||||
<!-- Booking indicator -->
|
||||
<rect x="25" y="35" width="10" height="4" rx="1" fill="#27AE60"/>
|
||||
|
||||
<!-- Check mark -->
|
||||
<path d="M39 27 L42 30 L48 22" stroke="#FFFFFF" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "n8n-nodes-librebooking",
|
||||
"version": "1.0.0",
|
||||
"description": "LibreBooking n8n Community Node - Custom Nodes Version für Docker Integration",
|
||||
"keywords": [
|
||||
"n8n-community-node-package",
|
||||
"librebooking",
|
||||
"booking",
|
||||
"reservation"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc && npm run copy-icons",
|
||||
"copy-icons": "mkdir -p dist/nodes/LibreBooking dist/nodes/LibreBookingTrigger && cp nodes/LibreBooking/*.svg dist/nodes/LibreBooking/ && cp nodes/LibreBookingTrigger/*.svg dist/nodes/LibreBookingTrigger/",
|
||||
"clean": "rm -rf dist",
|
||||
"rebuild": "npm run clean && npm run build"
|
||||
},
|
||||
"n8n": {
|
||||
"n8nNodesApiVersion": 1,
|
||||
"credentials": [
|
||||
"dist/credentials/LibreBookingApi.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/LibreBooking/LibreBooking.node.js",
|
||||
"dist/nodes/LibreBookingTrigger/LibreBookingTrigger.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": ">=1.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2019",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2019", "ES2020.Promise"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": ".",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false
|
||||
},
|
||||
"include": [
|
||||
"nodes/**/*.ts",
|
||||
"credentials/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# Vollständige Docker Compose Beispiel-Konfiguration
|
||||
# n8n mit LibreBooking Node - Ready to Use
|
||||
#
|
||||
# Verwendung:
|
||||
# 1. cp docker-compose.example.yml docker-compose.yml
|
||||
# 2. cp .env.docker .env
|
||||
# 3. .env Datei anpassen
|
||||
# 4. docker-compose up -d
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
# Verwende das vorgefertigte Image mit LibreBooking Node
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.custom-nodes
|
||||
args:
|
||||
N8N_VERSION: latest
|
||||
|
||||
# Oder nutze das offizielle Image mit Volume-Mount:
|
||||
# image: n8nio/n8n:latest
|
||||
|
||||
container_name: n8n-librebooking
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
- "${N8N_PORT:-5678}:5678"
|
||||
|
||||
environment:
|
||||
# Basis-Konfiguration
|
||||
- N8N_HOST=${N8N_HOST:-localhost}
|
||||
- N8N_PORT=5678
|
||||
- N8N_PROTOCOL=${N8N_PROTOCOL:-http}
|
||||
- WEBHOOK_URL=${WEBHOOK_URL:-http://localhost:5678/}
|
||||
|
||||
# Authentifizierung (aktivieren für Produktion!)
|
||||
- N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE:-false}
|
||||
- N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER:-admin}
|
||||
- N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD:-changeme}
|
||||
|
||||
# Custom Nodes
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
|
||||
# Zeitzone
|
||||
- GENERIC_TIMEZONE=${TZ:-Europe/Berlin}
|
||||
- TZ=${TZ:-Europe/Berlin}
|
||||
|
||||
# Logging
|
||||
- N8N_LOG_LEVEL=${N8N_LOG_LEVEL:-info}
|
||||
|
||||
# Execution Settings
|
||||
- EXECUTIONS_DATA_SAVE_ON_ERROR=all
|
||||
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
|
||||
- EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true
|
||||
|
||||
volumes:
|
||||
# Persistente n8n Daten
|
||||
- n8n_data:/home/node/.n8n
|
||||
|
||||
# Custom Nodes (wenn nicht im Image gebaut)
|
||||
# - ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:5678/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
- n8n_network
|
||||
|
||||
# Optional: PostgreSQL Datenbank für n8n
|
||||
# Für Produktion empfohlen statt SQLite
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: n8n-postgres
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- with-postgres
|
||||
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER:-n8n}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-n8n_password}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-n8n}
|
||||
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-n8n}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
- n8n_network
|
||||
|
||||
# Optional: Redis für Queue Mode
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: n8n-redis
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- with-redis
|
||||
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
- n8n_network
|
||||
|
||||
volumes:
|
||||
n8n_data:
|
||||
driver: local
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
n8n_network:
|
||||
driver: bridge
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Docker Compose Override für bestehende n8n Installationen
|
||||
# Diese Datei erweitert eine bestehende docker-compose.yml um den LibreBooking Node
|
||||
#
|
||||
# Verwendung:
|
||||
# 1. Diese Datei in das Verzeichnis mit der bestehenden docker-compose.yml kopieren
|
||||
# 2. custom-nodes Verzeichnis in das gleiche Verzeichnis kopieren
|
||||
# 3. docker-compose up -d ausführen
|
||||
#
|
||||
# HINWEIS: Diese Datei wird automatisch mit der bestehenden docker-compose.yml zusammengeführt
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
# Zusätzliche Volumes für Custom Nodes
|
||||
volumes:
|
||||
# LibreBooking Custom Node - Variante 1: Vorgebauter Node
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
|
||||
# Alternative: Nur das dist-Verzeichnis (wenn bereits gebaut)
|
||||
# - ./custom-nodes/dist:/home/node/.n8n/custom/n8n-nodes-librebooking/dist:ro
|
||||
# - ./custom-nodes/package.json:/home/node/.n8n/custom/n8n-nodes-librebooking/package.json:ro
|
||||
|
||||
# Zusätzliche Umgebungsvariablen
|
||||
environment:
|
||||
# Pfad für Custom Nodes (normalerweise bereits gesetzt)
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
# Aktiviert erweiterte Node-Typen
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
# Optional: Debug-Logging für Node-Entwicklung
|
||||
# - N8N_LOG_LEVEL=debug
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# Docker Compose für n8n mit LibreBooking Node
|
||||
#
|
||||
# Verwendung:
|
||||
# docker-compose up -d # Im Hintergrund starten
|
||||
# docker-compose logs -f # Logs anzeigen
|
||||
# docker-compose down # Stoppen und entfernen
|
||||
# docker-compose build --no-cache # Neu bauen
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: n8n-librebooking
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5678:5678"
|
||||
environment:
|
||||
# Basis-Konfiguration
|
||||
- N8N_BASIC_AUTH_ACTIVE=true
|
||||
- N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER:-admin}
|
||||
- N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD:-changeme}
|
||||
|
||||
# Webhook-URL (für Produktionsumgebung anpassen)
|
||||
- WEBHOOK_URL=${WEBHOOK_URL:-http://localhost:5678/}
|
||||
|
||||
# Timezone
|
||||
- GENERIC_TIMEZONE=${TZ:-Europe/Berlin}
|
||||
- TZ=${TZ:-Europe/Berlin}
|
||||
|
||||
# Custom Extensions
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
|
||||
# Optional: Logging
|
||||
- N8N_LOG_LEVEL=${N8N_LOG_LEVEL:-info}
|
||||
|
||||
# Optional: Executions
|
||||
- EXECUTIONS_DATA_SAVE_ON_ERROR=all
|
||||
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
|
||||
- EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true
|
||||
volumes:
|
||||
# Persistente Daten
|
||||
- n8n_data:/home/node/.n8n
|
||||
# Workflow-Dateien (optional)
|
||||
- ./workflows:/home/node/workflows:ro
|
||||
networks:
|
||||
- n8n-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5678/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
volumes:
|
||||
n8n_data:
|
||||
driver: local
|
||||
name: n8n-librebooking-data
|
||||
|
||||
networks:
|
||||
n8n-network:
|
||||
driver: bridge
|
||||
name: n8n-librebooking-network
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// n8n-nodes-librebooking
|
||||
// Entry point for the LibreBooking n8n node package
|
||||
|
||||
export * from './nodes/LibreBooking/LibreBooking.node';
|
||||
export * from './nodes/LibreBookingTrigger/LibreBookingTrigger.node';
|
||||
export * from './credentials/LibreBookingApi.credentials';
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
#!/bin/bash
|
||||
|
||||
# =============================================================================
|
||||
# LibreBooking n8n Node - Docker Integration Script
|
||||
# =============================================================================
|
||||
# Automatische Integration des LibreBooking Nodes in bestehende n8n Docker-Installationen
|
||||
#
|
||||
# Verwendung: ./install-docker.sh [OPTIONS]
|
||||
#
|
||||
# Optionen:
|
||||
# -p, --path PATH Pfad zur n8n Docker-Installation (Standard: aktuelles Verzeichnis)
|
||||
# -b, --build Node im Container bauen statt vorgebaut kopieren
|
||||
# -f, --force Bestehende Installation überschreiben
|
||||
# -h, --help Diese Hilfe anzeigen
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# Farben für Ausgabe
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Standardwerte
|
||||
N8N_PATH="."
|
||||
FORCE=false
|
||||
BUILD_IN_CONTAINER=false
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Hilfsfunktionen
|
||||
print_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[✓]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[!]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[FEHLER]${NC} $1"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "LibreBooking n8n Node - Docker Integration Script"
|
||||
echo ""
|
||||
echo "Verwendung: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Optionen:"
|
||||
echo " -p, --path PATH Pfad zur n8n Docker-Installation"
|
||||
echo " -b, --build Node im Container bauen"
|
||||
echo " -f, --force Bestehende Installation überschreiben"
|
||||
echo " -h, --help Diese Hilfe anzeigen"
|
||||
echo ""
|
||||
echo "Beispiele:"
|
||||
echo " $0 # Installation im aktuellen Verzeichnis"
|
||||
echo " $0 -p /opt/n8n # Installation in /opt/n8n"
|
||||
echo " $0 -f -p /home/user/n8n # Installation mit Überschreiben"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Argumente parsen
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-p|--path)
|
||||
N8N_PATH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-b|--build)
|
||||
BUILD_IN_CONTAINER=true
|
||||
shift
|
||||
;;
|
||||
-f|--force)
|
||||
FORCE=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
print_error "Unbekannte Option: $1"
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " LibreBooking n8n Node - Docker Setup"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# Voraussetzungen prüfen
|
||||
# =============================================================================
|
||||
|
||||
print_info "Prüfe Voraussetzungen..."
|
||||
|
||||
# Docker prüfen
|
||||
if ! command -v docker &> /dev/null; then
|
||||
print_error "Docker ist nicht installiert!"
|
||||
echo " Bitte installieren Sie Docker: https://docs.docker.com/get-docker/"
|
||||
exit 1
|
||||
fi
|
||||
print_success "Docker gefunden: $(docker --version)"
|
||||
|
||||
# Docker Compose prüfen
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
COMPOSE_CMD="docker-compose"
|
||||
print_success "docker-compose gefunden: $(docker-compose --version)"
|
||||
elif docker compose version &> /dev/null; then
|
||||
COMPOSE_CMD="docker compose"
|
||||
print_success "docker compose gefunden: $(docker compose version)"
|
||||
else
|
||||
print_error "Docker Compose ist nicht installiert!"
|
||||
echo " Bitte installieren Sie Docker Compose"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Zielpfad prüfen
|
||||
if [ ! -d "$N8N_PATH" ]; then
|
||||
print_error "Verzeichnis existiert nicht: $N8N_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
N8N_PATH=$(cd "$N8N_PATH" && pwd)
|
||||
print_info "Zielverzeichnis: $N8N_PATH"
|
||||
|
||||
# docker-compose.yml prüfen
|
||||
if [ ! -f "$N8N_PATH/docker-compose.yml" ] && [ ! -f "$N8N_PATH/docker-compose.yaml" ]; then
|
||||
print_warning "Keine docker-compose.yml gefunden in $N8N_PATH"
|
||||
echo ""
|
||||
read -p "Soll eine Beispiel-Konfiguration erstellt werden? (j/n): " CREATE_EXAMPLE
|
||||
if [[ "$CREATE_EXAMPLE" =~ ^[jJyY]$ ]]; then
|
||||
print_info "Kopiere Beispiel-Konfiguration..."
|
||||
cp "$SCRIPT_DIR/docker-compose.example.yml" "$N8N_PATH/docker-compose.yml"
|
||||
cp "$SCRIPT_DIR/.env.docker" "$N8N_PATH/.env"
|
||||
print_success "Beispiel-Konfiguration erstellt"
|
||||
print_warning "Bitte $N8N_PATH/.env anpassen!"
|
||||
else
|
||||
print_error "Abbruch: Keine docker-compose.yml vorhanden"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# n8n Status prüfen
|
||||
# =============================================================================
|
||||
|
||||
print_info "Prüfe n8n Container Status..."
|
||||
|
||||
cd "$N8N_PATH"
|
||||
|
||||
N8N_RUNNING=false
|
||||
if $COMPOSE_CMD ps 2>/dev/null | grep -q "n8n.*Up"; then
|
||||
N8N_RUNNING=true
|
||||
print_success "n8n Container läuft"
|
||||
else
|
||||
print_warning "n8n Container läuft nicht (wird später gestartet)"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Custom Nodes Verzeichnis vorbereiten
|
||||
# =============================================================================
|
||||
|
||||
print_info "Bereite Custom Nodes Verzeichnis vor..."
|
||||
|
||||
CUSTOM_NODES_DIR="$N8N_PATH/custom-nodes"
|
||||
|
||||
# Prüfen ob bereits installiert
|
||||
if [ -d "$CUSTOM_NODES_DIR" ]; then
|
||||
if [ "$FORCE" = true ]; then
|
||||
print_warning "Bestehendes custom-nodes Verzeichnis wird überschrieben"
|
||||
rm -rf "$CUSTOM_NODES_DIR"
|
||||
else
|
||||
print_warning "custom-nodes Verzeichnis existiert bereits"
|
||||
read -p "Überschreiben? (j/n): " OVERWRITE
|
||||
if [[ "$OVERWRITE" =~ ^[jJyY]$ ]]; then
|
||||
rm -rf "$CUSTOM_NODES_DIR"
|
||||
else
|
||||
print_info "Behalte bestehendes Verzeichnis"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Custom Nodes kopieren
|
||||
if [ ! -d "$CUSTOM_NODES_DIR" ]; then
|
||||
cp -r "$SCRIPT_DIR/custom-nodes" "$CUSTOM_NODES_DIR"
|
||||
print_success "Custom Nodes kopiert nach: $CUSTOM_NODES_DIR"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Node bauen (wenn nicht bereits gebaut)
|
||||
# =============================================================================
|
||||
|
||||
if [ ! -d "$CUSTOM_NODES_DIR/dist" ] || [ "$BUILD_IN_CONTAINER" = true ]; then
|
||||
print_info "Baue LibreBooking Node..."
|
||||
|
||||
cd "$CUSTOM_NODES_DIR"
|
||||
|
||||
# Prüfen ob node/npm vorhanden
|
||||
if command -v npm &> /dev/null; then
|
||||
npm install 2>/dev/null || print_warning "npm install hatte Warnungen"
|
||||
npm run build 2>/dev/null || {
|
||||
print_warning "Build fehlgeschlagen, versuche alternativen Ansatz..."
|
||||
# Manueller Build
|
||||
npx tsc 2>/dev/null || true
|
||||
mkdir -p dist/nodes/LibreBooking dist/nodes/LibreBookingTrigger
|
||||
cp nodes/LibreBooking/*.svg dist/nodes/LibreBooking/ 2>/dev/null || true
|
||||
cp nodes/LibreBookingTrigger/*.svg dist/nodes/LibreBookingTrigger/ 2>/dev/null || true
|
||||
}
|
||||
print_success "Node erfolgreich gebaut"
|
||||
else
|
||||
print_warning "npm nicht gefunden - Node wird beim Container-Start gebaut"
|
||||
print_info "Erstelle Build-Skript für Container..."
|
||||
cat > "$CUSTOM_NODES_DIR/build.sh" << 'BUILDEOF'
|
||||
#!/bin/sh
|
||||
cd /home/node/.n8n/custom/n8n-nodes-librebooking
|
||||
npm install
|
||||
npm run build
|
||||
BUILDEOF
|
||||
chmod +x "$CUSTOM_NODES_DIR/build.sh"
|
||||
fi
|
||||
|
||||
cd "$N8N_PATH"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Docker Compose Override erstellen/aktualisieren
|
||||
# =============================================================================
|
||||
|
||||
print_info "Erstelle docker-compose.override.yml..."
|
||||
|
||||
OVERRIDE_FILE="$N8N_PATH/docker-compose.override.yml"
|
||||
|
||||
if [ -f "$OVERRIDE_FILE" ]; then
|
||||
print_warning "docker-compose.override.yml existiert bereits"
|
||||
|
||||
# Prüfen ob LibreBooking bereits konfiguriert
|
||||
if grep -q "n8n-nodes-librebooking" "$OVERRIDE_FILE"; then
|
||||
print_success "LibreBooking bereits in override.yml konfiguriert"
|
||||
else
|
||||
print_info "Füge LibreBooking Konfiguration hinzu..."
|
||||
# Backup erstellen
|
||||
cp "$OVERRIDE_FILE" "${OVERRIDE_FILE}.backup"
|
||||
|
||||
# Hinzufügen (vereinfacht - für komplexe Fälle manuell anpassen)
|
||||
cat >> "$OVERRIDE_FILE" << 'OVERRIDEEOF'
|
||||
|
||||
# LibreBooking Node (automatisch hinzugefügt)
|
||||
# Falls Konflikte auftreten, bitte manuell anpassen
|
||||
# Siehe DOCKER-INTEGRATION.md für Details
|
||||
OVERRIDEEOF
|
||||
print_warning "Bitte $OVERRIDE_FILE manuell prüfen!"
|
||||
fi
|
||||
else
|
||||
# Neue Override-Datei erstellen
|
||||
cat > "$OVERRIDE_FILE" << 'OVERRIDEEOF'
|
||||
# Docker Compose Override für LibreBooking n8n Node
|
||||
# Automatisch generiert von install-docker.sh
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
n8n:
|
||||
volumes:
|
||||
# LibreBooking Custom Node
|
||||
- ./custom-nodes:/home/node/.n8n/custom/n8n-nodes-librebooking:ro
|
||||
|
||||
environment:
|
||||
# Custom Nodes aktivieren
|
||||
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
||||
- N8N_COMMUNITY_NODES_ENABLED=true
|
||||
OVERRIDEEOF
|
||||
print_success "docker-compose.override.yml erstellt"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Berechtigungen setzen
|
||||
# =============================================================================
|
||||
|
||||
print_info "Setze Berechtigungen..."
|
||||
|
||||
# n8n läuft oft als node User mit UID 1000
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
chown -R 1000:1000 "$CUSTOM_NODES_DIR" 2>/dev/null || print_warning "Konnte Berechtigungen nicht setzen"
|
||||
else
|
||||
# Versuche mit sudo falls verfügbar
|
||||
if command -v sudo &> /dev/null; then
|
||||
sudo chown -R 1000:1000 "$CUSTOM_NODES_DIR" 2>/dev/null || print_warning "Konnte Berechtigungen nicht setzen (sudo fehlgeschlagen)"
|
||||
fi
|
||||
fi
|
||||
|
||||
print_success "Berechtigungen konfiguriert"
|
||||
|
||||
# =============================================================================
|
||||
# Container neustarten
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
read -p "Soll der n8n Container jetzt neu gestartet werden? (j/n): " RESTART
|
||||
|
||||
if [[ "$RESTART" =~ ^[jJyY]$ ]]; then
|
||||
print_info "Starte n8n Container neu..."
|
||||
|
||||
if [ "$N8N_RUNNING" = true ]; then
|
||||
$COMPOSE_CMD restart n8n 2>/dev/null || $COMPOSE_CMD restart
|
||||
else
|
||||
$COMPOSE_CMD up -d n8n 2>/dev/null || $COMPOSE_CMD up -d
|
||||
fi
|
||||
|
||||
# Warten bis Container bereit
|
||||
print_info "Warte auf Container-Start..."
|
||||
sleep 5
|
||||
|
||||
# Status prüfen
|
||||
if $COMPOSE_CMD ps | grep -q "n8n.*Up"; then
|
||||
print_success "n8n Container läuft!"
|
||||
else
|
||||
print_warning "Container-Status unklar - bitte manuell prüfen"
|
||||
fi
|
||||
else
|
||||
print_info "Container nicht neu gestartet"
|
||||
echo " Führen Sie später aus: cd $N8N_PATH && $COMPOSE_CMD restart"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Abschluss
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
print_success "Installation abgeschlossen!"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "Nächste Schritte:"
|
||||
echo "1. Öffnen Sie n8n in Ihrem Browser"
|
||||
echo "2. Gehen Sie zu: Settings > Community Nodes"
|
||||
echo "3. Der 'LibreBooking' Node sollte sichtbar sein"
|
||||
echo "4. Erstellen Sie neue Credentials für LibreBooking"
|
||||
echo ""
|
||||
echo "Bei Problemen siehe: DOCKER-INTEGRATION.md"
|
||||
echo ""
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
#
|
||||
# LibreBooking n8n Node - Installations-Skript für Windows (PowerShell)
|
||||
#
|
||||
# Verwendung:
|
||||
# .\install.ps1
|
||||
#
|
||||
# Optionen:
|
||||
# -NoLink Überspringt npm link (nur Build)
|
||||
# -Global Installiert global statt npm link
|
||||
# -Help Zeigt diese Hilfe an
|
||||
#
|
||||
|
||||
param(
|
||||
[switch]$NoLink,
|
||||
[switch]$Global,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
# Konfiguration
|
||||
$MIN_NODE_VERSION = 18
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Funktionen
|
||||
function Write-ColorOutput {
|
||||
param(
|
||||
[string]$Message,
|
||||
[string]$Color = "White"
|
||||
)
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
|
||||
function Write-Header {
|
||||
Write-ColorOutput "" "Blue"
|
||||
Write-ColorOutput "=============================================" "Blue"
|
||||
Write-ColorOutput " LibreBooking n8n Node Installer" "Blue"
|
||||
Write-ColorOutput "=============================================" "Blue"
|
||||
Write-ColorOutput "" "Blue"
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-ColorOutput "✓ $Message" "Green"
|
||||
}
|
||||
|
||||
function Write-Warning-Msg {
|
||||
param([string]$Message)
|
||||
Write-ColorOutput "⚠ $Message" "Yellow"
|
||||
}
|
||||
|
||||
function Write-Error-Msg {
|
||||
param([string]$Message)
|
||||
Write-ColorOutput "✗ $Message" "Red"
|
||||
}
|
||||
|
||||
function Write-Info {
|
||||
param([string]$Message)
|
||||
Write-ColorOutput "ℹ $Message" "Cyan"
|
||||
}
|
||||
|
||||
function Show-Help {
|
||||
Write-Host "Verwendung: .\install.ps1 [OPTIONEN]"
|
||||
Write-Host ""
|
||||
Write-Host "Optionen:"
|
||||
Write-Host " -NoLink Überspringt npm link (nur Build)"
|
||||
Write-Host " -Global Installiert global mit npm install -g"
|
||||
Write-Host " -Help Zeigt diese Hilfe an"
|
||||
Write-Host ""
|
||||
Write-Host "Beispiele:"
|
||||
Write-Host " .\install.ps1 # Standard-Installation mit npm link"
|
||||
Write-Host " .\install.ps1 -NoLink # Nur Dependencies installieren und Build"
|
||||
Write-Host " .\install.ps1 -Global # Globale Installation"
|
||||
exit 0
|
||||
}
|
||||
|
||||
function Test-Command {
|
||||
param([string]$Command)
|
||||
try {
|
||||
$null = Get-Command $Command -ErrorAction Stop
|
||||
return $true
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Get-NodeVersion {
|
||||
$version = (node -v) -replace 'v', ''
|
||||
return [int]($version.Split('.')[0])
|
||||
}
|
||||
|
||||
# Hilfe anzeigen
|
||||
if ($Help) {
|
||||
Show-Help
|
||||
}
|
||||
|
||||
# Start
|
||||
Write-Header
|
||||
|
||||
# 1. Node.js prüfen
|
||||
Write-Host ""
|
||||
Write-Info "Prüfe Voraussetzungen..."
|
||||
Write-Host ""
|
||||
|
||||
if (-not (Test-Command "node")) {
|
||||
Write-Error-Msg "Node.js ist nicht installiert!"
|
||||
Write-Host " Bitte installiere Node.js v$MIN_NODE_VERSION oder höher:"
|
||||
Write-Host " https://nodejs.org/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$nodeVersion = Get-NodeVersion
|
||||
if ($nodeVersion -lt $MIN_NODE_VERSION) {
|
||||
Write-Error-Msg "Node.js Version $nodeVersion ist zu alt!"
|
||||
Write-Host " Mindestens Version $MIN_NODE_VERSION benötigt."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$nodeFullVersion = (node -v) -replace 'v', ''
|
||||
Write-Success "Node.js v$nodeFullVersion gefunden"
|
||||
|
||||
# 2. npm prüfen
|
||||
if (-not (Test-Command "npm")) {
|
||||
Write-Error-Msg "npm ist nicht installiert!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$npmVersion = npm -v
|
||||
Write-Success "npm v$npmVersion gefunden"
|
||||
|
||||
# 3. n8n prüfen (optional)
|
||||
if (Test-Command "n8n") {
|
||||
try {
|
||||
$n8nVersion = n8n --version 2>$null
|
||||
Write-Success "n8n $n8nVersion gefunden"
|
||||
}
|
||||
catch {
|
||||
Write-Success "n8n installiert"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Warning-Msg "n8n ist nicht global installiert."
|
||||
Write-Host " Für npm link muss n8n global installiert sein:"
|
||||
Write-Host " npm install -g n8n"
|
||||
Write-Host ""
|
||||
|
||||
if (-not $NoLink -and -not $Global) {
|
||||
$response = Read-Host "Möchtest du trotzdem fortfahren? (j/N)"
|
||||
if ($response -notmatch '^[Jj]$') {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Dependencies installieren
|
||||
Write-Host ""
|
||||
Write-Info "Installiere Dependencies..."
|
||||
|
||||
try {
|
||||
npm install
|
||||
Write-Success "Dependencies installiert"
|
||||
}
|
||||
catch {
|
||||
Write-Error-Msg "Fehler bei npm install: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 5. TypeScript kompilieren
|
||||
Write-Host ""
|
||||
Write-Info "Kompiliere TypeScript..."
|
||||
|
||||
try {
|
||||
npm run build
|
||||
Write-Success "Build erfolgreich"
|
||||
}
|
||||
catch {
|
||||
Write-Error-Msg "Fehler beim Build: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 6. npm link oder global install
|
||||
if ($Global) {
|
||||
Write-Host ""
|
||||
Write-Info "Installiere global..."
|
||||
|
||||
try {
|
||||
npm install -g .
|
||||
Write-Success "Global installiert"
|
||||
}
|
||||
catch {
|
||||
Write-Error-Msg "Fehler bei globaler Installation: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
elseif (-not $NoLink) {
|
||||
Write-Host ""
|
||||
Write-Info "Verlinke mit npm link..."
|
||||
|
||||
try {
|
||||
npm link
|
||||
Write-Success "npm link erfolgreich"
|
||||
|
||||
# Versuche mit n8n zu verlinken
|
||||
if (Test-Command "n8n") {
|
||||
$n8nPath = Join-Path (npm root -g) "n8n"
|
||||
if (Test-Path $n8nPath) {
|
||||
Write-Info "Verlinke mit n8n..."
|
||||
Push-Location $n8nPath
|
||||
try {
|
||||
npm link n8n-nodes-librebooking 2>$null
|
||||
Write-Success "Mit n8n verlinkt"
|
||||
}
|
||||
catch {
|
||||
Write-Warning-Msg "Konnte nicht automatisch mit n8n verlinken"
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error-Msg "Fehler bei npm link: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Abschluss
|
||||
Write-Host ""
|
||||
Write-ColorOutput "=============================================" "Green"
|
||||
Write-ColorOutput " Installation erfolgreich abgeschlossen!" "Green"
|
||||
Write-ColorOutput "=============================================" "Green"
|
||||
Write-Host ""
|
||||
Write-Host "Nächste Schritte:"
|
||||
Write-Host ""
|
||||
|
||||
if ($NoLink) {
|
||||
Write-Host " 1. Führe 'npm link' aus, um den Node zu verlinken"
|
||||
Write-Host " 2. Starte n8n neu: n8n start"
|
||||
}
|
||||
else {
|
||||
Write-Host " 1. Starte n8n neu: n8n start"
|
||||
Write-Host " (oder mit Docker: docker-compose restart)"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " 2. Öffne n8n im Browser: http://localhost:5678"
|
||||
Write-Host " 3. Der LibreBooking Node sollte verfügbar sein"
|
||||
Write-Host ""
|
||||
Write-Host "Bei Problemen siehe INSTALLATION.md oder README.md"
|
||||
Write-Host ""
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# LibreBooking n8n Node - Installations-Skript für Linux/Mac
|
||||
#
|
||||
# Verwendung:
|
||||
# chmod +x install.sh
|
||||
# ./install.sh
|
||||
#
|
||||
# Optionen:
|
||||
# --no-link Überspringt npm link (nur Build)
|
||||
# --global Installiert global statt npm link
|
||||
# --help Zeigt diese Hilfe an
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Farben für Ausgabe
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Konfiguration
|
||||
MIN_NODE_VERSION=18
|
||||
REQUIRED_NPM_VERSION=8
|
||||
|
||||
# Optionen
|
||||
SKIP_LINK=false
|
||||
GLOBAL_INSTALL=false
|
||||
|
||||
# Funktionen
|
||||
print_header() {
|
||||
echo -e "${BLUE}"
|
||||
echo "============================================="
|
||||
echo " LibreBooking n8n Node Installer"
|
||||
echo "============================================="
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ $1${NC}"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "Verwendung: ./install.sh [OPTIONEN]"
|
||||
echo ""
|
||||
echo "Optionen:"
|
||||
echo " --no-link Überspringt npm link (nur Build)"
|
||||
echo " --global Installiert global mit npm install -g"
|
||||
echo " --help Zeigt diese Hilfe an"
|
||||
echo ""
|
||||
echo "Beispiele:"
|
||||
echo " ./install.sh # Standard-Installation mit npm link"
|
||||
echo " ./install.sh --no-link # Nur Dependencies installieren und Build"
|
||||
echo " ./install.sh --global # Globale Installation"
|
||||
exit 0
|
||||
}
|
||||
|
||||
check_command() {
|
||||
if command -v $1 &> /dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_node_version() {
|
||||
node -v | sed 's/v//' | cut -d. -f1
|
||||
}
|
||||
|
||||
get_npm_version() {
|
||||
npm -v | cut -d. -f1
|
||||
}
|
||||
|
||||
# Parameter verarbeiten
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--no-link)
|
||||
SKIP_LINK=true
|
||||
;;
|
||||
--global)
|
||||
GLOBAL_INSTALL=true
|
||||
;;
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
print_error "Unbekannte Option: $arg"
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Start
|
||||
print_header
|
||||
|
||||
# 1. Node.js prüfen
|
||||
echo ""
|
||||
print_info "Prüfe Voraussetzungen..."
|
||||
echo ""
|
||||
|
||||
if ! check_command node; then
|
||||
print_error "Node.js ist nicht installiert!"
|
||||
echo " Bitte installiere Node.js v${MIN_NODE_VERSION} oder höher:"
|
||||
echo " https://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_VERSION=$(get_node_version)
|
||||
if [ "$NODE_VERSION" -lt "$MIN_NODE_VERSION" ]; then
|
||||
print_error "Node.js Version $NODE_VERSION ist zu alt!"
|
||||
echo " Mindestens Version ${MIN_NODE_VERSION} benötigt."
|
||||
exit 1
|
||||
fi
|
||||
print_success "Node.js v$(node -v | sed 's/v//') gefunden"
|
||||
|
||||
# 2. npm prüfen
|
||||
if ! check_command npm; then
|
||||
print_error "npm ist nicht installiert!"
|
||||
exit 1
|
||||
fi
|
||||
print_success "npm v$(npm -v) gefunden"
|
||||
|
||||
# 3. n8n prüfen (optional, aber empfohlen)
|
||||
if check_command n8n; then
|
||||
print_success "n8n $(n8n --version 2>/dev/null || echo 'installiert') gefunden"
|
||||
else
|
||||
print_warning "n8n ist nicht global installiert."
|
||||
echo " Für npm link muss n8n global installiert sein:"
|
||||
echo " npm install -g n8n"
|
||||
echo ""
|
||||
if [ "$SKIP_LINK" = false ] && [ "$GLOBAL_INSTALL" = false ]; then
|
||||
read -p "Möchtest du trotzdem fortfahren? (j/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Jj]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. Dependencies installieren
|
||||
echo ""
|
||||
print_info "Installiere Dependencies..."
|
||||
npm install
|
||||
print_success "Dependencies installiert"
|
||||
|
||||
# 5. TypeScript kompilieren
|
||||
echo ""
|
||||
print_info "Kompiliere TypeScript..."
|
||||
npm run build
|
||||
print_success "Build erfolgreich"
|
||||
|
||||
# 6. npm link oder global install
|
||||
if [ "$GLOBAL_INSTALL" = true ]; then
|
||||
echo ""
|
||||
print_info "Installiere global..."
|
||||
npm install -g .
|
||||
print_success "Global installiert"
|
||||
elif [ "$SKIP_LINK" = false ]; then
|
||||
echo ""
|
||||
print_info "Verlinke mit npm link..."
|
||||
npm link
|
||||
print_success "npm link erfolgreich"
|
||||
|
||||
# Prüfen ob n8n vorhanden und linken
|
||||
if check_command n8n; then
|
||||
N8N_PATH=$(npm root -g)/n8n
|
||||
if [ -d "$N8N_PATH" ]; then
|
||||
print_info "Verlinke mit n8n..."
|
||||
cd "$N8N_PATH" 2>/dev/null && npm link n8n-nodes-librebooking 2>/dev/null && cd - > /dev/null
|
||||
print_success "Mit n8n verlinkt"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Abschluss
|
||||
echo ""
|
||||
echo -e "${GREEN}=============================================${NC}"
|
||||
echo -e "${GREEN} Installation erfolgreich abgeschlossen!${NC}"
|
||||
echo -e "${GREEN}=============================================${NC}"
|
||||
echo ""
|
||||
echo "Nächste Schritte:"
|
||||
echo ""
|
||||
if [ "$SKIP_LINK" = true ]; then
|
||||
echo " 1. Führe 'npm link' aus, um den Node zu verlinken"
|
||||
echo " 2. Starte n8n neu: n8n start"
|
||||
else
|
||||
echo " 1. Starte n8n neu: n8n start"
|
||||
echo " (oder mit Docker: docker-compose restart)"
|
||||
fi
|
||||
echo ""
|
||||
echo " 2. Öffne n8n im Browser: http://localhost:5678"
|
||||
echo " 3. Der LibreBooking Node sollte verfügbar sein"
|
||||
echo ""
|
||||
echo "Bei Problemen siehe INSTALLATION.md oder README.md"
|
||||
echo ""
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# Nginx Reverse Proxy Konfiguration für n8n mit LibreBooking
|
||||
# Beispielkonfiguration für HTTPS Zugang
|
||||
#
|
||||
# Verwendung:
|
||||
# 1. Diese Datei nach /etc/nginx/sites-available/n8n kopieren
|
||||
# 2. ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
|
||||
# 3. SSL-Zertifikate einrichten (z.B. mit Certbot)
|
||||
# 4. nginx -t && systemctl reload nginx
|
||||
|
||||
# Upstream für n8n
|
||||
upstream n8n_backend {
|
||||
server 127.0.0.1:5678;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP -> HTTPS Redirect
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name n8n.example.com;
|
||||
|
||||
# ACME Challenge für Let's Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS Server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name n8n.example.com;
|
||||
|
||||
# SSL-Zertifikate (Let's Encrypt Beispiel)
|
||||
ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;
|
||||
|
||||
# SSL-Einstellungen (moderne Konfiguration)
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
|
||||
# HSTS
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/n8n_access.log;
|
||||
error_log /var/log/nginx/n8n_error.log;
|
||||
|
||||
# Proxy-Einstellungen
|
||||
location / {
|
||||
proxy_pass http://n8n_backend;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# WebSocket Support (wichtig für n8n Editor)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Standard Proxy Headers
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# Timeouts (erhöht für lange Workflow-Ausführungen)
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
# Buffer-Einstellungen
|
||||
proxy_buffering off;
|
||||
proxy_buffer_size 4k;
|
||||
|
||||
# Client-Upload Limit (anpassen nach Bedarf)
|
||||
client_max_body_size 50M;
|
||||
}
|
||||
|
||||
# Webhook-spezifische Einstellungen
|
||||
location /webhook/ {
|
||||
proxy_pass http://n8n_backend;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Erhöhte Timeouts für Webhooks
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
|
||||
proxy_buffering off;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
|
||||
# Health Check Endpoint
|
||||
location /healthz {
|
||||
proxy_pass http://n8n_backend/healthz;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
|
||||
# Optional: Monitoring/Metrics Server Block
|
||||
# server {
|
||||
# listen 127.0.0.1:9090;
|
||||
# server_name localhost;
|
||||
#
|
||||
# location /nginx_status {
|
||||
# stub_status on;
|
||||
# allow 127.0.0.1;
|
||||
# deny all;
|
||||
# }
|
||||
# }
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="60" height="60">
|
||||
<!-- Background -->
|
||||
<rect width="60" height="60" rx="8" fill="#2C3E50"/>
|
||||
|
||||
<!-- Calendar base -->
|
||||
<rect x="10" y="15" width="40" height="35" rx="3" fill="#ECF0F1" stroke="#3498DB" stroke-width="2"/>
|
||||
|
||||
<!-- Calendar header -->
|
||||
<rect x="10" y="15" width="40" height="10" rx="3" fill="#3498DB"/>
|
||||
<rect x="10" y="22" width="40" height="3" fill="#3498DB"/>
|
||||
|
||||
<!-- Calendar rings -->
|
||||
<rect x="18" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
<rect x="38" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<line x1="10" y1="33" x2="50" y2="33" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="10" y1="41" x2="50" y2="41" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="23" y1="25" x2="23" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="37" y1="25" x2="37" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
|
||||
<!-- Booking indicator -->
|
||||
<rect x="25" y="35" width="10" height="4" rx="1" fill="#27AE60"/>
|
||||
|
||||
<!-- Check mark -->
|
||||
<path d="M39 27 L42 30 L48 22" stroke="#FFFFFF" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,352 @@
|
|||
import {
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IPollFunctions,
|
||||
INodeExecutionData,
|
||||
NodeApiError,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
interface LibreBookingSession {
|
||||
sessionToken: string;
|
||||
userId: number;
|
||||
sessionExpires: string;
|
||||
}
|
||||
|
||||
interface ReservationData {
|
||||
referenceNumber: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
title: string;
|
||||
resourceId: number;
|
||||
userId: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentifizierung bei LibreBooking
|
||||
*/
|
||||
async function authenticateTrigger(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
username: string,
|
||||
password: string,
|
||||
): Promise<LibreBookingSession> {
|
||||
try {
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/Web/Services/index.php/Authentication/Authenticate`,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: { username, password },
|
||||
json: true,
|
||||
});
|
||||
|
||||
if (!response.isAuthenticated) {
|
||||
throw new NodeOperationError(
|
||||
pollFunctions.getNode(),
|
||||
'Authentifizierung fehlgeschlagen',
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
sessionToken: response.sessionToken,
|
||||
userId: response.userId,
|
||||
sessionExpires: response.sessionExpires,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new NodeApiError(pollFunctions.getNode(), error, {
|
||||
message: 'Authentifizierung fehlgeschlagen',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abmeldung
|
||||
*/
|
||||
async function signOutTrigger(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await pollFunctions.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/Web/Services/index.php/Authentication/SignOut`,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: {
|
||||
userId: session.userId,
|
||||
sessionToken: session.sessionToken,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
} catch (error) {
|
||||
// Ignoriere SignOut-Fehler
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reservierungen abrufen
|
||||
*/
|
||||
async function getReservations(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
startDateTime: string,
|
||||
endDateTime: string,
|
||||
filters: any,
|
||||
): Promise<ReservationData[]> {
|
||||
const qs: any = {
|
||||
startDateTime,
|
||||
endDateTime,
|
||||
};
|
||||
|
||||
if (filters.resourceId) qs.resourceId = filters.resourceId;
|
||||
if (filters.scheduleId) qs.scheduleId = filters.scheduleId;
|
||||
if (filters.userId) qs.userId = filters.userId;
|
||||
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'GET',
|
||||
url: `${baseUrl}/Web/Services/index.php/Reservations/`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
},
|
||||
qs,
|
||||
json: true,
|
||||
});
|
||||
|
||||
return response.reservations || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaillierte Reservierungsdaten abrufen
|
||||
*/
|
||||
async function getReservationDetails(
|
||||
pollFunctions: IPollFunctions,
|
||||
baseUrl: string,
|
||||
session: LibreBookingSession,
|
||||
referenceNumber: string,
|
||||
): Promise<any> {
|
||||
const response = await pollFunctions.helpers.httpRequest({
|
||||
method: 'GET',
|
||||
url: `${baseUrl}/Web/Services/index.php/Reservations/${referenceNumber}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeitfenster berechnen
|
||||
*/
|
||||
function getTimeWindow(timeWindow: string): { start: string; end: string } {
|
||||
const now = new Date();
|
||||
const start = now.toISOString();
|
||||
|
||||
let endDate = new Date(now);
|
||||
switch (timeWindow) {
|
||||
case '7days':
|
||||
endDate.setDate(endDate.getDate() + 7);
|
||||
break;
|
||||
case '14days':
|
||||
endDate.setDate(endDate.getDate() + 14);
|
||||
break;
|
||||
case '30days':
|
||||
endDate.setDate(endDate.getDate() + 30);
|
||||
break;
|
||||
case '90days':
|
||||
endDate.setDate(endDate.getDate() + 90);
|
||||
break;
|
||||
default:
|
||||
endDate.setDate(endDate.getDate() + 14);
|
||||
}
|
||||
|
||||
return {
|
||||
start,
|
||||
end: endDate.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Eindeutigen Schlüssel für Reservierung generieren
|
||||
*/
|
||||
function getReservationKey(reservation: ReservationData): string {
|
||||
return `${reservation.referenceNumber}_${reservation.startDate}_${reservation.endDate}_${reservation.title || ''}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* LibreBooking Trigger Node
|
||||
*/
|
||||
export class LibreBookingTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'LibreBooking Trigger',
|
||||
name: 'libreBookingTrigger',
|
||||
icon: 'file:librebooking.svg',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Wird bei neuen oder geänderten Reservierungen in LibreBooking ausgelöst',
|
||||
subtitle: '={{$parameter["event"]}}',
|
||||
defaults: {
|
||||
name: 'LibreBooking Trigger',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'libreBookingApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
polling: true,
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Event',
|
||||
name: 'event',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Neue Reservierung', value: 'newReservation', description: 'Wird bei neuen Reservierungen ausgelöst' },
|
||||
{ name: 'Geänderte Reservierung', value: 'updatedReservation', description: 'Wird bei geänderten Reservierungen ausgelöst' },
|
||||
{ name: 'Alle Reservierungen', value: 'allReservations', description: 'Wird bei neuen und geänderten Reservierungen ausgelöst' },
|
||||
],
|
||||
default: 'newReservation',
|
||||
},
|
||||
{
|
||||
displayName: 'Filter',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Filter hinzufügen',
|
||||
default: {},
|
||||
options: [
|
||||
{ displayName: 'Ressourcen-ID', name: 'resourceId', type: 'number', default: '' },
|
||||
{ displayName: 'Zeitplan-ID', name: 'scheduleId', type: 'number', default: '' },
|
||||
{ displayName: 'Benutzer-ID', name: 'userId', type: 'number', default: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Zeitfenster',
|
||||
name: 'timeWindow',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Nächste 7 Tage', value: '7days' },
|
||||
{ name: 'Nächste 14 Tage', value: '14days' },
|
||||
{ name: 'Nächste 30 Tage', value: '30days' },
|
||||
{ name: 'Nächste 90 Tage', value: '90days' },
|
||||
],
|
||||
default: '14days',
|
||||
},
|
||||
{
|
||||
displayName: 'Optionen',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Option hinzufügen',
|
||||
default: {},
|
||||
options: [
|
||||
{ displayName: 'Detaillierte Daten Abrufen', name: 'fetchDetails', type: 'boolean', default: false },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
|
||||
const credentials = await this.getCredentials('libreBookingApi');
|
||||
const baseUrl = (credentials.url as string).replace(/\/$/, '');
|
||||
const username = credentials.username as string;
|
||||
const password = credentials.password as string;
|
||||
|
||||
const event = this.getNodeParameter('event') as string;
|
||||
const filters = this.getNodeParameter('filters', {}) as any;
|
||||
const timeWindow = this.getNodeParameter('timeWindow', '14days') as string;
|
||||
const options = this.getNodeParameter('options', {}) as any;
|
||||
|
||||
const workflowStaticData = this.getWorkflowStaticData('node');
|
||||
const previousReservations = (workflowStaticData.reservations as Record<string, string>) || {};
|
||||
|
||||
let session: LibreBookingSession;
|
||||
try {
|
||||
session = await authenticateTrigger(this, baseUrl, username, password);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
const { start, end } = getTimeWindow(timeWindow);
|
||||
|
||||
const reservations = await getReservations(
|
||||
this,
|
||||
baseUrl,
|
||||
session,
|
||||
start,
|
||||
end,
|
||||
filters,
|
||||
);
|
||||
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const currentReservations: Record<string, string> = {};
|
||||
|
||||
for (const reservation of reservations) {
|
||||
const refNumber = reservation.referenceNumber;
|
||||
const reservationKey = getReservationKey(reservation);
|
||||
currentReservations[refNumber] = reservationKey;
|
||||
|
||||
const isNew = !previousReservations[refNumber];
|
||||
const isUpdated = previousReservations[refNumber] && previousReservations[refNumber] !== reservationKey;
|
||||
|
||||
let shouldTrigger = false;
|
||||
let eventType = '';
|
||||
|
||||
if (event === 'newReservation' && isNew) {
|
||||
shouldTrigger = true;
|
||||
eventType = 'new';
|
||||
} else if (event === 'updatedReservation' && isUpdated) {
|
||||
shouldTrigger = true;
|
||||
eventType = 'updated';
|
||||
} else if (event === 'allReservations' && (isNew || isUpdated)) {
|
||||
shouldTrigger = true;
|
||||
eventType = isNew ? 'new' : 'updated';
|
||||
}
|
||||
|
||||
if (shouldTrigger) {
|
||||
let reservationData = reservation;
|
||||
|
||||
if (options.fetchDetails) {
|
||||
try {
|
||||
reservationData = await getReservationDetails(
|
||||
this,
|
||||
baseUrl,
|
||||
session,
|
||||
refNumber,
|
||||
);
|
||||
} catch (error) {
|
||||
reservationData = reservation;
|
||||
}
|
||||
}
|
||||
|
||||
returnData.push({
|
||||
json: {
|
||||
...reservationData,
|
||||
_eventType: eventType,
|
||||
_triggeredAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
workflowStaticData.reservations = currentReservations;
|
||||
|
||||
if (returnData.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
|
||||
} finally {
|
||||
await signOutTrigger(this, baseUrl, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="60" height="60">
|
||||
<!-- Background -->
|
||||
<rect width="60" height="60" rx="8" fill="#2C3E50"/>
|
||||
|
||||
<!-- Calendar base -->
|
||||
<rect x="10" y="15" width="40" height="35" rx="3" fill="#ECF0F1" stroke="#3498DB" stroke-width="2"/>
|
||||
|
||||
<!-- Calendar header -->
|
||||
<rect x="10" y="15" width="40" height="10" rx="3" fill="#3498DB"/>
|
||||
<rect x="10" y="22" width="40" height="3" fill="#3498DB"/>
|
||||
|
||||
<!-- Calendar rings -->
|
||||
<rect x="18" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
<rect x="38" y="12" width="4" height="8" rx="1" fill="#2C3E50"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<line x1="10" y1="33" x2="50" y2="33" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="10" y1="41" x2="50" y2="41" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="23" y1="25" x2="23" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
<line x1="37" y1="25" x2="37" y2="50" stroke="#BDC3C7" stroke-width="1"/>
|
||||
|
||||
<!-- Booking indicator -->
|
||||
<rect x="25" y="35" width="10" height="4" rx="1" fill="#27AE60"/>
|
||||
|
||||
<!-- Check mark -->
|
||||
<path d="M39 27 L42 30 L48 22" stroke="#FFFFFF" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"name": "n8n-nodes-librebooking",
|
||||
"version": "1.0.0",
|
||||
"description": "n8n Node für LibreBooking - Ressourcen- und Reservierungsverwaltung",
|
||||
"keywords": [
|
||||
"n8n-community-node-package",
|
||||
"n8n",
|
||||
"n8n-node",
|
||||
"workflow",
|
||||
"automation",
|
||||
"librebooking",
|
||||
"booking",
|
||||
"reservation",
|
||||
"resource-management",
|
||||
"room-booking",
|
||||
"raumbuchung",
|
||||
"terminbuchung",
|
||||
"open-source"
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/your-org/n8n-nodes-librebooking#readme",
|
||||
"author": {
|
||||
"name": "LibreBooking n8n Integration",
|
||||
"email": "support@example.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/your-org/n8n-nodes-librebooking.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/your-org/n8n-nodes-librebooking/issues"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc && npm run copy:icons",
|
||||
"copy:icons": "cp nodes/LibreBooking/librebooking.svg dist/nodes/LibreBooking/ && cp nodes/LibreBookingTrigger/librebooking.svg dist/nodes/LibreBookingTrigger/",
|
||||
"dev": "tsc --watch",
|
||||
"clean": "rm -rf dist node_modules",
|
||||
"rebuild": "npm run clean && npm install && npm run build",
|
||||
"format": "prettier nodes credentials --write",
|
||||
"lint": "eslint nodes credentials --ext .ts",
|
||||
"lint:fix": "eslint nodes credentials --ext .ts --fix",
|
||||
"prepack": "npm run build",
|
||||
"prepublishOnly": "npm run lint && npm run build",
|
||||
"postinstall": "echo 'Installation abgeschlossen. Führe npm run build aus.'",
|
||||
"test": "ts-node test/test-api.ts",
|
||||
"link:n8n": "npm link && echo 'Node verlinkt. Starte n8n neu mit: n8n start'",
|
||||
"unlink": "npm unlink -g n8n-nodes-librebooking"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"n8n": {
|
||||
"n8nNodesApiVersion": 1,
|
||||
"credentials": [
|
||||
"dist/credentials/LibreBookingApi.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/LibreBooking/LibreBooking.node.js",
|
||||
"dist/nodes/LibreBookingTrigger/LibreBookingTrigger.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
||||
"@typescript-eslint/parser": "^6.13.0",
|
||||
"eslint": "^8.54.0",
|
||||
"n8n-workflow": "^1.20.0",
|
||||
"prettier": "^3.1.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": "*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* LibreBooking API Test-Skript
|
||||
*
|
||||
* Testet die Authentifizierung und grundlegende API-Operationen
|
||||
* mit den bereitgestellten Test-Credentials.
|
||||
*
|
||||
* Ausführen mit: npx ts-node test/test-api.ts
|
||||
*/
|
||||
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
// Test-Credentials
|
||||
const TEST_CONFIG = {
|
||||
url: 'https://librebooking.zell-cloud.de',
|
||||
username: 'sebastian.zell@zell-aufmass.de',
|
||||
password: 'wanUQ4uVqU6lfP',
|
||||
};
|
||||
|
||||
interface LibreBookingSession {
|
||||
sessionToken: string;
|
||||
userId: number;
|
||||
sessionExpires: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP/HTTPS Request Helper
|
||||
*/
|
||||
async function makeRequest(
|
||||
url: string,
|
||||
method: string,
|
||||
headers: Record<string, string>,
|
||||
body?: any
|
||||
): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new URL(url);
|
||||
const isHttps = urlObj.protocol === 'https:';
|
||||
const lib = isHttps ? https : http;
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port || (isHttps ? 443 : 80),
|
||||
path: urlObj.pathname + urlObj.search,
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...headers,
|
||||
},
|
||||
};
|
||||
|
||||
const req = lib.request(options, (res: any) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk: string) => (data += chunk));
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
resolve({ statusCode: res.statusCode, data: jsonData });
|
||||
} catch (e) {
|
||||
resolve({ statusCode: res.statusCode, data });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', reject);
|
||||
|
||||
if (body) {
|
||||
req.write(JSON.stringify(body));
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentifizierung testen
|
||||
*/
|
||||
async function testAuthentication(): Promise<LibreBookingSession | null> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 1: Authentifizierung');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Authentication/Authenticate`,
|
||||
'POST',
|
||||
{},
|
||||
{
|
||||
username: TEST_CONFIG.username,
|
||||
password: TEST_CONFIG.password,
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200 && response.data.isAuthenticated) {
|
||||
console.log('✅ Authentifizierung erfolgreich!');
|
||||
console.log(` Session Token: ${response.data.sessionToken.substring(0, 20)}...`);
|
||||
console.log(` User ID: ${response.data.userId}`);
|
||||
console.log(` Session läuft ab: ${response.data.sessionExpires}`);
|
||||
return {
|
||||
sessionToken: response.data.sessionToken,
|
||||
userId: response.data.userId,
|
||||
sessionExpires: response.data.sessionExpires,
|
||||
};
|
||||
} else {
|
||||
console.log('❌ Authentifizierung fehlgeschlagen!');
|
||||
console.log(' Response:', JSON.stringify(response.data, null, 2));
|
||||
return null;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('❌ Fehler bei der Authentifizierung:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Reservierungen abrufen
|
||||
*/
|
||||
async function testGetReservations(session: LibreBookingSession): Promise<void> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 2: Reservierungen abrufen');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Reservations/`,
|
||||
'GET',
|
||||
{
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const reservations = response.data.reservations || [];
|
||||
console.log(`✅ ${reservations.length} Reservierung(en) gefunden`);
|
||||
|
||||
if (reservations.length > 0) {
|
||||
console.log('\n Erste 3 Reservierungen:');
|
||||
reservations.slice(0, 3).forEach((res: any, idx: number) => {
|
||||
console.log(` ${idx + 1}. ${res.title || 'Ohne Titel'}`);
|
||||
console.log(` Referenz: ${res.referenceNumber}`);
|
||||
console.log(` Ressource: ${res.resourceName}`);
|
||||
console.log(` Zeit: ${res.startDate} - ${res.endDate}`);
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log(`❌ Fehler beim Abrufen: Status ${response.statusCode}`);
|
||||
console.log(' Response:', JSON.stringify(response.data, null, 2));
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('❌ Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Ressourcen abrufen
|
||||
*/
|
||||
async function testGetResources(session: LibreBookingSession): Promise<void> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 3: Ressourcen abrufen');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Resources/`,
|
||||
'GET',
|
||||
{
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const resources = response.data.resources || [];
|
||||
console.log(`✅ ${resources.length} Ressource(n) gefunden`);
|
||||
|
||||
resources.forEach((res: any, idx: number) => {
|
||||
console.log(` ${idx + 1}. ${res.name} (ID: ${res.resourceId})`);
|
||||
if (res.location) console.log(` Standort: ${res.location}`);
|
||||
console.log(` Status: ${res.statusId === 1 ? 'Verfügbar' : res.statusId === 0 ? 'Versteckt' : 'Nicht verfügbar'}`);
|
||||
});
|
||||
} else {
|
||||
console.log(`❌ Fehler beim Abrufen: Status ${response.statusCode}`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('❌ Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Zeitpläne abrufen
|
||||
*/
|
||||
async function testGetSchedules(session: LibreBookingSession): Promise<void> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 4: Zeitpläne abrufen');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Schedules/`,
|
||||
'GET',
|
||||
{
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const schedules = response.data.schedules || [];
|
||||
console.log(`✅ ${schedules.length} Zeitplan/Zeitpläne gefunden`);
|
||||
|
||||
schedules.forEach((schedule: any, idx: number) => {
|
||||
console.log(` ${idx + 1}. ${schedule.name} (ID: ${schedule.id})`);
|
||||
console.log(` Zeitzone: ${schedule.timezone}`);
|
||||
console.log(` Standard: ${schedule.isDefault ? 'Ja' : 'Nein'}`);
|
||||
});
|
||||
} else {
|
||||
console.log(`❌ Fehler beim Abrufen: Status ${response.statusCode}`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('❌ Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Benutzer abrufen
|
||||
*/
|
||||
async function testGetUsers(session: LibreBookingSession): Promise<void> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 5: Benutzer abrufen');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Users/`,
|
||||
'GET',
|
||||
{
|
||||
'X-Booked-SessionToken': session.sessionToken,
|
||||
'X-Booked-UserId': session.userId.toString(),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const users = response.data.users || [];
|
||||
console.log(`✅ ${users.length} Benutzer gefunden`);
|
||||
|
||||
users.slice(0, 5).forEach((user: any, idx: number) => {
|
||||
console.log(` ${idx + 1}. ${user.firstName} ${user.lastName}`);
|
||||
console.log(` E-Mail: ${user.emailAddress}`);
|
||||
console.log(` ID: ${user.id}`);
|
||||
});
|
||||
|
||||
if (users.length > 5) {
|
||||
console.log(` ... und ${users.length - 5} weitere`);
|
||||
}
|
||||
} else {
|
||||
console.log(`❌ Fehler beim Abrufen: Status ${response.statusCode}`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('❌ Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abmelden
|
||||
*/
|
||||
async function testSignOut(session: LibreBookingSession): Promise<void> {
|
||||
console.log('\n========================================');
|
||||
console.log('TEST 6: Abmelden');
|
||||
console.log('========================================');
|
||||
|
||||
try {
|
||||
const response = await makeRequest(
|
||||
`${TEST_CONFIG.url}/Web/Services/index.php/Authentication/SignOut`,
|
||||
'POST',
|
||||
{},
|
||||
{
|
||||
userId: session.userId,
|
||||
sessionToken: session.sessionToken,
|
||||
}
|
||||
);
|
||||
|
||||
if (response.statusCode === 200 || response.statusCode === 204) {
|
||||
console.log('✅ Erfolgreich abgemeldet');
|
||||
} else {
|
||||
console.log(`⚠️ Abmeldung mit Status ${response.statusCode} abgeschlossen`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('⚠️ Abmeldung fehlgeschlagen (kann ignoriert werden):', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptfunktion
|
||||
*/
|
||||
async function runTests(): Promise<void> {
|
||||
console.log('\n📝 LibreBooking API Test');
|
||||
console.log('======================================');
|
||||
console.log(`URL: ${TEST_CONFIG.url}`);
|
||||
console.log(`User: ${TEST_CONFIG.username}`);
|
||||
console.log('======================================');
|
||||
|
||||
// Test 1: Authentifizierung
|
||||
const session = await testAuthentication();
|
||||
|
||||
if (!session) {
|
||||
console.log('\n❌ Tests abgebrochen - Authentifizierung fehlgeschlagen');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Test 2-5: API-Endpunkte
|
||||
await testGetReservations(session);
|
||||
await testGetResources(session);
|
||||
await testGetSchedules(session);
|
||||
await testGetUsers(session);
|
||||
|
||||
// Test 6: Abmelden
|
||||
await testSignOut(session);
|
||||
|
||||
console.log('\n========================================');
|
||||
console.log('✅ Alle Tests abgeschlossen!');
|
||||
console.log('========================================\n');
|
||||
}
|
||||
|
||||
// Tests ausführen
|
||||
runTests().catch(console.error);
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2019",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2019", "ES2020.Promise"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": ".",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false
|
||||
},
|
||||
"include": [
|
||||
"nodes/**/*.ts",
|
||||
"credentials/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
{
|
||||
"name": "LibreBooking Beispiel-Workflows",
|
||||
"description": "Sammlung von Beispiel-Workflows für den LibreBooking n8n Node",
|
||||
"workflows": [
|
||||
{
|
||||
"name": "1. Alle Reservierungen abrufen",
|
||||
"description": "Ruft alle Reservierungen der nächsten 14 Tage ab",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"name": "Start",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "reservation",
|
||||
"operation": "getAll",
|
||||
"filters": {}
|
||||
},
|
||||
"name": "Alle Reservierungen",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [300, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [[{"node": "Alle Reservierungen", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2. Neue Reservierung erstellen",
|
||||
"description": "Erstellt eine neue Reservierung für morgen 10:00-11:00 Uhr",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"name": "Start",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "reservation",
|
||||
"operation": "create",
|
||||
"resourceId": 1,
|
||||
"startDateTime": "={{ $now.plus({days: 1}).set({hour: 10, minute: 0, second: 0}).toISO() }}",
|
||||
"endDateTime": "={{ $now.plus({days: 1}).set({hour: 11, minute: 0, second: 0}).toISO() }}",
|
||||
"title": "Automatisch erstellte Reservierung",
|
||||
"additionalFields": {
|
||||
"description": "Diese Reservierung wurde automatisch über n8n erstellt"
|
||||
}
|
||||
},
|
||||
"name": "Reservierung erstellen",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [300, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [[{"node": "Reservierung erstellen", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "3. Ressourcen-Verfügbarkeit prüfen",
|
||||
"description": "Prüft die Verfügbarkeit aller Ressourcen",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"name": "Start",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "resource",
|
||||
"operation": "getAvailability"
|
||||
},
|
||||
"name": "Verfügbarkeit prüfen",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [300, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"boolean": [
|
||||
{
|
||||
"value1": "={{ $json.available }}",
|
||||
"value2": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "Nur Verfügbare",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 1,
|
||||
"position": [500, 300]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [[{"node": "Verfügbarkeit prüfen", "type": "main", "index": 0}]]
|
||||
},
|
||||
"Verfügbarkeit prüfen": {
|
||||
"main": [[{"node": "Nur Verfügbare", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4. Benutzer-Übersicht",
|
||||
"description": "Ruft alle Benutzer ab und formatiert sie",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"name": "Start",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "user",
|
||||
"operation": "getAll",
|
||||
"userFilters": {}
|
||||
},
|
||||
"name": "Alle Benutzer",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [300, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "runOnceForEachItem",
|
||||
"jsCode": "return {\n json: {\n name: `${$json.firstName} ${$json.lastName}`,\n email: $json.emailAddress,\n organization: $json.organization || 'Keine',\n lastLogin: $json.lastLogin\n }\n};"
|
||||
},
|
||||
"name": "Formatieren",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [500, 300]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [[{"node": "Alle Benutzer", "type": "main", "index": 0}]]
|
||||
},
|
||||
"Alle Benutzer": {
|
||||
"main": [[{"node": "Formatieren", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5. Trigger: Neue Reservierungen überwachen",
|
||||
"description": "Trigger-Workflow der bei neuen Reservierungen auslöst",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"event": "newReservation",
|
||||
"filters": {},
|
||||
"timeWindow": "14days",
|
||||
"options": {
|
||||
"fetchDetails": true
|
||||
}
|
||||
},
|
||||
"name": "LibreBooking Trigger",
|
||||
"type": "n8n-nodes-librebooking.libreBookingTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "runOnceForEachItem",
|
||||
"jsCode": "const reservation = $json;\nreturn {\n json: {\n message: `Neue Reservierung: ${reservation.title || 'Ohne Titel'}`,\n resource: reservation.resourceName,\n start: reservation.startDate,\n end: reservation.endDate,\n user: `${reservation.firstName} ${reservation.lastName}`\n }\n};"
|
||||
},
|
||||
"name": "Nachricht formatieren",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [300, 300]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"LibreBooking Trigger": {
|
||||
"main": [[{"node": "Nachricht formatieren", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6. Täglicher Reservierungsbericht",
|
||||
"description": "Sendet täglich eine Übersicht der heutigen Reservierungen",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"field": "cronExpression",
|
||||
"expression": "0 8 * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": "Täglich 8:00",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [100, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "reservation",
|
||||
"operation": "getAll",
|
||||
"filters": {
|
||||
"startDateTime": "={{ $now.startOf('day').toISO() }}",
|
||||
"endDateTime": "={{ $now.endOf('day').toISO() }}"
|
||||
}
|
||||
},
|
||||
"name": "Heutige Reservierungen",
|
||||
"type": "n8n-nodes-librebooking.libreBooking",
|
||||
"typeVersion": 1,
|
||||
"position": [300, 300],
|
||||
"credentials": {
|
||||
"libreBookingApi": "LibreBooking Account"
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"aggregate": "aggregateAllItemData"
|
||||
},
|
||||
"name": "Zusammenfassen",
|
||||
"type": "n8n-nodes-base.aggregate",
|
||||
"typeVersion": 1,
|
||||
"position": [500, 300]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Täglich 8:00": {
|
||||
"main": [[{"node": "Heutige Reservierungen", "type": "main", "index": 0}]]
|
||||
},
|
||||
"Heutige Reservierungen": {
|
||||
"main": [[{"node": "Zusammenfassen", "type": "main", "index": 0}]]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue