diff --git a/README.md b/README.md index 7a50150..95deda2 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,15 @@ Eine einfache und effiziente Kundensuche für medisoftware Kunden. - 🏥 Unterscheidung zwischen MEDISOFT und MEDICONSULT Kunden - 🎨 Farbliche Hervorhebung der Kundentypen (blau für MEDISOFT, orange für MEDICONSULT) - 📍 Verbesserte Adress-Links mit Location- und Route-Icons +- 📤 CSV-Export der Suchergebnisse +- 📥 CSV-Import für Kundendaten +- 📖 Integrierte README-Anzeige +- 🍔 Intuitives Hamburger-Menü +- 📱 VCF-Export für Kontakte ## Version -Aktuelle Version: 1.2.16 +Aktuelle Version: 1.2.17 ## Installation @@ -52,7 +57,8 @@ Die Anwendung kann über folgende Umgebungsvariablen konfiguriert werden: - `FLASK_ENV`: Die Flask-Umgebung (development/production) - `SECRET_KEY`: Der geheime Schlüssel für Flask-Sessions - `DATABASE_URL`: Die URL zur SQLite-Datenbank -- `STATIC_PASSWORD`: Das Passwort für die Login-Seite +- `LOGIN_PASSWORD`: Das Passwort für die Login-Seite +- `UPLOAD_PASSWORD`: Das Passwort für den CSV-Upload - `ALLOWED_IP_RANGES`: Komma-getrennte Liste von IP-Bereichen, die direkten Zugriff haben - `LOG_LEVEL`: Das Logging-Level (INFO/DEBUG) @@ -107,23 +113,46 @@ curl "http://localhost:5001/search?name=Mustermann&telefon=030" curl "http://localhost:5001/search?fachrichtung=Zahnarzt&ort=Berlin&name=Schmidt" ``` +## Benutzeroberfläche + +### Hauptmenü +- Home: Zurück zur Hauptseite +- CSV-Dateien hochladen: Import neuer Kundendaten +- README: Anzeige der Dokumentation + +### Suchfunktionen +- Allgemeine Suche über alle Felder +- Spezifische Suche nach: + - Name + - Ort + - Kundennummer + - PLZ + - Fachrichtung +- Filterung nach Kundentyp (MEDISOFT/MEDICONSULT) + +### Export +- CSV-Export der Suchergebnisse +- VCF-Export für Kontakte +- Direkte Links zu Kundendetails +- Teilen von Suchergebnissen + ## Version -Aktuelle Version: [v1.2.4](CHANGELOG.md#v124---2024-03-19) +Aktuelle Version: [v1.2.17](CHANGELOG.md#v1217---2024-03-19) ## Code-Statistiken Language|files|blank|comment|code :-------|-------:|-------:|-------:|-------: -HTML|2|56|0|416 -CSS|2|51|1|265 -Markdown|2|66|0|236 -Python|1|51|103|225 -YAML|1|0|0|13 +JavaScript|1|67|28|420 +HTML|4|16|0|382 +CSS|1|63|0|324 +Markdown|2|77|0|295 +YAML|1|0|0|14 Dockerfile|1|8|9|11 -Text|1|0|0|5 +Text|1|0|0|6 --------|--------|--------|--------|-------- -SUM:|10|232|113|1171 +SUM:|12|302|163|1732 ## Lizenz Alle Rechte vorbehalten. © 2025 medisoftware \ No newline at end of file diff --git a/app.py b/app.py index 539c54a..8b2c769 100644 --- a/app.py +++ b/app.py @@ -10,6 +10,7 @@ from functools import wraps from contextlib import contextmanager import time import threading +import markdown2 app = Flask(__name__, static_folder='static') app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev') @@ -394,6 +395,57 @@ def get_orte(): logger.error(f"Fehler beim Abrufen der Orte: {str(e)}") return jsonify([]) +@app.route('/upload', methods=['GET', 'POST']) +def upload(): + if not session.get('logged_in'): + return redirect(url_for('login')) + + if request.method == 'POST': + if request.form.get('password') != os.environ.get('UPLOAD_PASSWORD'): + return render_template('upload.html', error="Falsches Passwort", version=app.config['VERSION']) + + if 'customers_snk' not in request.files or 'customers' not in request.files: + return render_template('upload.html', error="Bitte beide CSV-Dateien auswählen", version=app.config['VERSION']) + + customers_snk = request.files['customers_snk'] + customers = request.files['customers'] + + if customers_snk.filename == '' or customers.filename == '': + return render_template('upload.html', error="Keine Datei ausgewählt", version=app.config['VERSION']) + + if not customers_snk.filename.endswith('.csv') or not customers.filename.endswith('.csv'): + return render_template('upload.html', error="Nur CSV-Dateien sind erlaubt", version=app.config['VERSION']) + + try: + # Speichere die Dateien + customers_snk.save('data/customers_snk.csv') + customers.save('data/customers.csv') + + # Importiere die Daten in die Datenbank + import_csv('data/customers_snk.csv', 'snk') + import_csv('data/customers.csv', 'medisoft') + + return render_template('upload.html', success="Dateien erfolgreich hochgeladen und importiert", version=app.config['VERSION']) + except Exception as e: + logger.error(f"Fehler beim Upload: {str(e)}") + return render_template('upload.html', error=f"Fehler beim Upload: {str(e)}", version=app.config['VERSION']) + + return render_template('upload.html', version=app.config['VERSION']) + +@app.route('/readme') +def readme(): + if not session.get('logged_in'): + return redirect(url_for('login')) + + try: + with open('README.md', 'r', encoding='utf-8') as f: + content = f.read() + html_content = markdown2.markdown(content, extras=['fenced-code-blocks', 'tables']) + return render_template('readme.html', content=html_content, version=app.config['VERSION']) + except Exception as e: + logger.error(f"Fehler beim Lesen der README: {str(e)}") + return render_template('readme.html', error="Fehler beim Lesen der README", version=app.config['VERSION']) + def init_app(app): """Initialisiert die Anwendung mit allen notwendigen Einstellungen.""" with app.app_context(): diff --git a/docker-compose.yml.example b/docker-compose.yml.example index aae2597..d209aad 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -9,5 +9,6 @@ services: - FLASK_APP=app.py - FLASK_ENV=production - LOGIN_PASSWORD=changeme + - UPLOAD_PASSWORD=upload_changeme - ALLOWED_IP_RANGES=213.178.68.218/29,192.168.0.0/24,192.168.177.0/24 command: flask run --host=0.0.0.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 554c259..4bb5e30 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ flask==3.0.2 pandas==2.2.1 numpy==1.26.4 python-dotenv==1.0.1 -requests==2.32.3 \ No newline at end of file +requests==2.32.3 +markdown2==2.4.12 \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 866e7b1..b7cfb99 100644 --- a/templates/index.html +++ b/templates/index.html @@ -15,8 +15,32 @@
-
- medisoftware Logo +

Kundensuche

@@ -111,5 +135,6 @@ + \ No newline at end of file diff --git a/templates/readme.html b/templates/readme.html new file mode 100644 index 0000000..7884aa0 --- /dev/null +++ b/templates/readme.html @@ -0,0 +1,111 @@ + + + + + + medisoftware Kundensuche - README + + + + + + + + +
+
+ + +
+
+

README

+
+
+ {% if error %} + + {% else %} +
+ {{ content | safe }} +
+ {% endif %} +
+
+
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/templates/upload.html b/templates/upload.html new file mode 100644 index 0000000..b316845 --- /dev/null +++ b/templates/upload.html @@ -0,0 +1,87 @@ + + + + + + medisoftware Kundensuche - CSV Upload + + + + +
+
+ medisoftware Logo +
+
+
+
+
+

CSV Upload

+
+
+ {% if error %} + + {% endif %} + {% if success %} + + {% endif %} +
+
+ + +
+
+ + +
+
+ + +
+
+ + Zurück zur Suche +
+
+
+
+
+
+
+ + + \ No newline at end of file