4 Commits

Author SHA1 Message Date
c4a65bba48 Version 2025-08-02 18:39:30 +02:00
e4b37d9261 Fehler in der API behoben 2025-08-02 18:37:17 +02:00
45cc02b4b0 Fehler in API behoben 2025-08-02 18:30:16 +02:00
05766d9a97 Version auf 1.4.7 erhöht - Dashboard mit Toggle-Funktionalität 2025-08-02 14:28:22 +02:00
4 changed files with 20 additions and 25 deletions

View File

@@ -334,6 +334,7 @@ curl -X POST http://localhost:5000/api/plusminus \
```
**Hinweis:**
- `"einheit"`: `"tage"`, `"wochen"` oder `"monate"`
- `"richtung"`: `"add"` (plus) oder `"sub"` (minus)
- `"werktage"`: `true` für Werktage, sonst `false` (nur bei `"tage"` unterstützt)

31
app.py
View File

@@ -20,7 +20,7 @@ app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations'
babel = Babel()
# Version der App
APP_VERSION = "1.4.6"
APP_VERSION = "1.4.8"
# HTML-Template wird jetzt aus templates/index.html geladen
@@ -415,34 +415,22 @@ def api_plusminus():
if is_werktage:
result = np.busday_offset(d.date(), anzahl_int, roll='forward')
result_dt = datetime.strptime(str(result), '%Y-%m-%d')
if locale == 'en':
plusminus_result = f"Date {d.strftime('%m/%d/%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} workdays: {result_dt.strftime('%m/%d/%Y')}"
else:
plusminus_result = f"Datum {d.strftime('%d.%m.%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} Werktage: {result_dt.strftime('%d.%m.%Y')}"
return jsonify({'result': result_dt.strftime('%Y-%m-%d')})
else:
result = d + timedelta(days=anzahl_int)
if locale == 'en':
plusminus_result = f"Date {d.strftime('%m/%d/%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} days: {result.strftime('%m/%d/%Y')}"
else:
plusminus_result = f"Datum {d.strftime('%d.%m.%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} Tage: {result.strftime('%d.%m.%Y')}"
return jsonify({'result': result.strftime('%Y-%m-%d')})
elif einheit == 'wochen':
if is_werktage:
return jsonify({'error': 'Nicht unterstützt: Werktage + Wochen.'}), 400
else:
result = d + timedelta(weeks=anzahl_int)
if locale == 'en':
plusminus_result = f"Date {d.strftime('%m/%d/%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} weeks: {result.strftime('%m/%d/%Y')}"
else:
plusminus_result = f"Datum {d.strftime('%d.%m.%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} Wochen: {result.strftime('%d.%m.%Y')}"
return jsonify({'result': result.strftime('%Y-%m-%d')})
elif einheit == 'monate':
if is_werktage:
return jsonify({'error': 'Nicht unterstützt: Werktage + Monate.'}), 400
else:
result = d + relativedelta(months=anzahl_int)
if locale == 'en':
plusminus_result = f"Date {d.strftime('%m/%d/%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} months: {result.strftime('%m/%d/%Y')}"
else:
plusminus_result = f"Datum {d.strftime('%d.%m.%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} Monate: {result.strftime('%d.%m.%Y')}"
return jsonify({'result': result.strftime('%Y-%m-%d')})
else:
return jsonify({'error': 'Ungültige Einheit'}), 400
except Exception as e:
@@ -451,8 +439,13 @@ def api_plusminus():
@app.route('/api/stats', methods=['GET'])
def api_stats():
log_path = os.path.join('log', 'pageviews.log')
pageviews, func_counts, impressions_per_day, api_counts = parse_log_stats(log_path)
return render_template('stats_dashboard.html', pageviews=pageviews, func_counts=func_counts, impressions_per_day=impressions_per_day, api_counts=api_counts)
pageviews, func_counts, func_counts_hourly, impressions_per_day, impressions_per_hour, api_counts, api_counts_hourly = parse_log_stats(log_path)
return jsonify({
"pageviews": pageviews,
"func_counts": func_counts,
"impressions_per_day": impressions_per_day,
"api_counts": api_counts
})
@app.route('/api/monitor', methods=['GET'])
def api_monitor():

View File

@@ -1081,9 +1081,9 @@ footer br + a {
</div>
<footer style="text-align:center; margin-top:2em; color:#475569; font-size:0.98em; padding-bottom:1.5em;">
Dies ist ein werbe- und trackingfreier <a href="https://codeberg.org/elpatron/datecalc/src/branch/main/README.md" target="_blank" style="color:#1e40af; text-decoration:underline;">Open Source Datumsrechner</a><br>
Dies ist ein werbe- und trackingfreier <a href="https://codeberg.org/elpatron/datecalc/src/branch/main/README.md" target="_blank" style="color:#1e40af; text-decoration:underline;">Open Source</a> Datumsrechner<br>
<a href="/api-docs" target="_blank" style="color:#1e40af; text-decoration:underline;">REST API Dokumentation (Swagger)</a><br>
© 2025 <a href="mailto:elpatron@mailbox.org?subject=Datumsrechner" style="color:#1e40af; text-decoration:underline;">M. Busche</a>
© 2025 <a href="mailto:elpatron@mailbox.org?subject=Datumsrechner" style="color:#1e40af; text-decoration:underline;">Markus Busche</a>
<div style="margin-top:0.5em; font-size:0.85em; color:#64748b;">v{{ app_version }}</div>
</footer>
<script>

View File

@@ -221,10 +221,11 @@ def test_api_plusminus(client):
def test_api_stats(client):
resp = client.get('/api/stats')
assert resp.status_code == 200
# Die Route gibt HTML zurück, nicht JSON
html = resp.data.decode('utf-8')
# Prüfe auf typische HTML-Elemente des Dashboards
assert 'Statistik-Dashboard' in html or 'Dashboard' in html
data = resp.get_json()
assert "pageviews" in data
assert "func_counts" in data
assert "impressions_per_day" in data
assert "api_counts" in data
def test_api_monitor(client):
resp = client.get('/api/monitor')