641 lines
23 KiB
Python
641 lines
23 KiB
Python
import sqlite3
|
|
from flask import Flask, render_template, request, redirect, url_for, session, g, flash, jsonify
|
|
from datetime import datetime
|
|
from werkzeug.security import generate_password_hash, check_password_hash
|
|
import smtplib, ssl, secrets
|
|
from datetime import datetime, timedelta
|
|
import json
|
|
|
|
SMTP_SERVER = "smtp.gmail.com"
|
|
SMTP_PORT = 465
|
|
EMAIL_SENDER = "clickcandit@gmail.com"
|
|
EMAIL_PASSWORD = "iuxexntistlwilhl"
|
|
|
|
app = Flask(__name__)
|
|
app.secret_key = "SUPER_SECRET_KEY" # Bitte anpassen
|
|
|
|
DATABASE = 'clickcandit.db'
|
|
|
|
def get_db():
|
|
db = getattr(g, '_database', None)
|
|
if db is None:
|
|
db = g._database = sqlite3.connect(DATABASE)
|
|
db.row_factory = sqlite3.Row
|
|
return db
|
|
|
|
@app.teardown_appcontext
|
|
def close_connection(exception):
|
|
db = getattr(g, '_database', None)
|
|
if db is not None:
|
|
db.close()
|
|
|
|
def init_db():
|
|
with app.app_context():
|
|
db = get_db()
|
|
# Users
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT UNIQUE NOT NULL,
|
|
password TEXT NOT NULL,
|
|
email TEXT,
|
|
is_admin INTEGER DEFAULT 0
|
|
);
|
|
""")
|
|
# Bookmarks
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS bookmarks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
title TEXT NOT NULL,
|
|
url TEXT NOT NULL,
|
|
icon_class TEXT NOT NULL DEFAULT 'fas fa-bookmark',
|
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
""")
|
|
# Notifications
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS notifications (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER, -- NULL = für alle
|
|
message TEXT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
is_read INTEGER DEFAULT 0
|
|
);
|
|
""")
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS reset_tokens (
|
|
user_id INTEGER NOT NULL,
|
|
token TEXT NOT NULL,
|
|
expires_at DATETIME NOT NULL,
|
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
""")
|
|
# Time Tracking
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS time_entries (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
activity TEXT NOT NULL,
|
|
start_time DATETIME NOT NULL,
|
|
end_time DATETIME,
|
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
""")
|
|
# Settings (OPTIONAL, falls du globale User-Einstellungen abspeichern willst)
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS user_settings (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
wallpaper TEXT DEFAULT '1.png',
|
|
city TEXT DEFAULT '',
|
|
show_forecast INTEGER DEFAULT 0,
|
|
bookmarks TEXT DEFAULT '',
|
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
""")
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS settings (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL,
|
|
wallpaper TEXT DEFAULT '19.png',
|
|
city TEXT DEFAULT 'Berlin',
|
|
show_forecast INTEGER DEFAULT 1,
|
|
bookmarks TEXT DEFAULT '[]',
|
|
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
""")
|
|
db.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# HILFSFUNKTIONEN
|
|
# ------------------------------------------------------------
|
|
|
|
def get_user_by_username_or_email(user_input):
|
|
db = get_db()
|
|
return db.execute("""
|
|
SELECT * FROM users
|
|
WHERE username = :val OR email = :val
|
|
""", {"val": user_input}).fetchone()
|
|
|
|
def get_user_by_username(username):
|
|
db = get_db()
|
|
return db.execute("SELECT * FROM users WHERE username = ?", (username,)).fetchone()
|
|
|
|
def get_user_by_id(user_id):
|
|
db = get_db()
|
|
return db.execute("SELECT * FROM users WHERE id = ?", (user_id,)).fetchone()
|
|
|
|
def is_admin():
|
|
return session.get('is_admin', 0) == 1
|
|
|
|
# ------------------------------------------------------------
|
|
# STARTSEITE
|
|
# ------------------------------------------------------------
|
|
@app.route('/')
|
|
def index():
|
|
if 'user_id' in session:
|
|
return redirect(url_for('dashboard'))
|
|
return redirect(url_for('login'))
|
|
|
|
# ------------------------------------------------------------
|
|
# REGISTRIEREN: erster User wird Admin
|
|
# ------------------------------------------------------------
|
|
@app.route('/register', methods=['GET', 'POST'])
|
|
def register():
|
|
if request.method == 'POST':
|
|
username = request.form.get('username')
|
|
email = request.form.get('email')
|
|
password = request.form.get('password')
|
|
|
|
if not username or not email or not password:
|
|
flash('Bitte alle Felder ausfüllen!', 'red')
|
|
return redirect(url_for('register'))
|
|
|
|
db = get_db()
|
|
# Prüfen, ob Benutzer/E-Mail existieren
|
|
existing = db.execute("SELECT * FROM users WHERE username=? OR email=?", (username, email)).fetchone()
|
|
if existing:
|
|
flash('Benutzername oder E-Mail ist bereits vergeben!', 'red')
|
|
return redirect(url_for('register'))
|
|
|
|
# Erster registrierter User wird Admin
|
|
count = db.execute("SELECT COUNT(*) as cnt FROM users").fetchone()['cnt']
|
|
is_admin_val = 1 if count == 0 else 0
|
|
|
|
hashed_pw = generate_password_hash(password)
|
|
db.execute("""
|
|
INSERT INTO users (username, password, email, is_admin)
|
|
VALUES (?, ?, ?, ?)
|
|
""", (username, hashed_pw, email, is_admin_val))
|
|
db.commit()
|
|
|
|
# OPTIONAL: initialer Eintrag in user_settings
|
|
if is_admin_val == 1:
|
|
# Falls du globale Settings pro Benutzer willst
|
|
user_id = db.execute("SELECT id FROM users WHERE username=?",(username,)).fetchone()['id']
|
|
db.execute("""
|
|
INSERT INTO user_settings (user_id, wallpaper, city, show_forecast, bookmarks)
|
|
VALUES (?, '1.png', '', 0, '')
|
|
""", (user_id,))
|
|
db.commit()
|
|
|
|
flash('Registrierung erfolgreich! Bitte melde dich an.', 'green')
|
|
return redirect(url_for('login'))
|
|
|
|
return render_template('register.html')
|
|
|
|
# ------------------------------------------------------------
|
|
# LOGIN / LOGOUT
|
|
# ------------------------------------------------------------
|
|
@app.route('/login', methods=['GET', 'POST'])
|
|
def login():
|
|
if request.method == 'POST':
|
|
username = request.form.get('username')
|
|
password = request.form.get('password')
|
|
user = get_user_by_username(username)
|
|
if user and check_password_hash(user['password'], password):
|
|
session['user_id'] = user['id']
|
|
session['username'] = user['username']
|
|
session['is_admin'] = user['is_admin']
|
|
flash("Login erfolgreich!", "green")
|
|
return redirect(url_for('dashboard'))
|
|
else:
|
|
flash("Benutzername oder Passwort falsch!", "red")
|
|
return render_template('login.html')
|
|
|
|
@app.route('/logout', methods=['POST'])
|
|
def logout():
|
|
session.clear()
|
|
flash("Erfolgreich abgemeldet!", "green")
|
|
return redirect(url_for('login'))
|
|
|
|
# ------------------------------------------------------------
|
|
# PASSWORT VERGESSEN
|
|
# ------------------------------------------------------------
|
|
@app.route('/reset_password/<token>', methods=['GET', 'POST'])
|
|
def reset_password(token):
|
|
db = get_db()
|
|
row = db.execute("""
|
|
SELECT * FROM reset_tokens
|
|
WHERE token = ?
|
|
""", (token,)).fetchone()
|
|
if not row:
|
|
flash("Ungültiges oder bereits benutztes Token!", "red")
|
|
return redirect(url_for('forgot_password'))
|
|
|
|
# Ablaufdatum prüfen
|
|
expires_at = datetime.fromisoformat(row['expires_at'])
|
|
if datetime.now() > expires_at:
|
|
flash("Token abgelaufen! Bitte erneut anfordern.", "red")
|
|
db.execute("DELETE FROM reset_tokens WHERE token=?", (token,))
|
|
db.commit()
|
|
return redirect(url_for('forgot_password'))
|
|
|
|
if request.method == 'POST':
|
|
pw1 = request.form.get('pw1')
|
|
pw2 = request.form.get('pw2')
|
|
if not pw1 or not pw2:
|
|
flash("Bitte beide Felder ausfüllen!", "red")
|
|
return redirect(url_for('reset_password', token=token))
|
|
|
|
if pw1 != pw2:
|
|
flash("Passwörter stimmen nicht überein!", "red")
|
|
return redirect(url_for('reset_password', token=token))
|
|
|
|
hashed_pw = generate_password_hash(pw1)
|
|
# Passwort setzen
|
|
db.execute("UPDATE users SET password=? WHERE id=?", (hashed_pw, row['user_id']))
|
|
# Token direkt löschen
|
|
db.execute("DELETE FROM reset_tokens WHERE token=?", (token,))
|
|
db.commit()
|
|
|
|
flash("Passwort erfolgreich zurückgesetzt! Du kannst dich jetzt einloggen.", "green")
|
|
return redirect(url_for('login'))
|
|
|
|
# GET: Formular
|
|
return render_template('reset_password.html', token=token)
|
|
|
|
@app.route('/forgot_password', methods=['GET', 'POST'])
|
|
def forgot_password():
|
|
if request.method == 'POST':
|
|
user_input = request.form.get('username_or_email')
|
|
if not user_input:
|
|
flash("Bitte Benutzernamen oder E-Mail eingeben!", "red")
|
|
return redirect(url_for('forgot_password'))
|
|
|
|
db = get_db()
|
|
# Schaue nach Username oder Email
|
|
user = db.execute("""
|
|
SELECT * FROM users
|
|
WHERE username=? OR email=?
|
|
""", (user_input, user_input)).fetchone()
|
|
|
|
if user:
|
|
# Token generieren
|
|
token = secrets.token_urlsafe(32)
|
|
expires = datetime.now() + timedelta(hours=1)
|
|
|
|
db.execute("""
|
|
INSERT INTO reset_tokens (user_id, token, expires_at)
|
|
VALUES (?, ?, ?)
|
|
""", (user['id'], token, expires))
|
|
db.commit()
|
|
|
|
reset_link = f"{request.url_root}reset_password/{token}"
|
|
subject = "Passwort zurücksetzen"
|
|
body = f"""Hallo {user['username']},
|
|
|
|
klicke auf folgenden Link, um dein Passwort zurückzusetzen (gültig 1 Stunde):
|
|
{reset_link}
|
|
|
|
Wenn du das nicht angefordert hast, ignoriere diese Nachricht.
|
|
"""
|
|
message = f"Subject: {subject}\n\n{body}"
|
|
context = ssl.create_default_context()
|
|
|
|
try:
|
|
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
|
|
server.login(EMAIL_SENDER, EMAIL_PASSWORD)
|
|
server.sendmail(EMAIL_SENDER, user['email'], message)
|
|
flash("Eine E-Mail zum Zurücksetzen deines Passworts wurde versendet!", "green")
|
|
except Exception as e:
|
|
flash(f"Fehler beim Senden der E-Mail: {e}", "red")
|
|
|
|
return redirect(url_for('login'))
|
|
else:
|
|
flash("Kein Nutzer gefunden!", "red")
|
|
return redirect(url_for('forgot_password'))
|
|
|
|
return render_template('forgot_password.html')
|
|
# ------------------------------------------------------------
|
|
# ADMIN-BEREICH
|
|
# ------------------------------------------------------------
|
|
@app.route('/admin', methods=['GET', 'POST'])
|
|
def admin_panel():
|
|
if not is_admin():
|
|
flash("Zugriff verweigert!", "red")
|
|
return redirect(url_for('dashboard'))
|
|
|
|
db = get_db()
|
|
if request.method == 'POST':
|
|
new_username = request.form.get('new_username')
|
|
new_password = request.form.get('new_password')
|
|
new_is_admin = 1 if request.form.get('new_is_admin') == 'on' else 0
|
|
if new_username and new_password:
|
|
hashed_pw = generate_password_hash(new_password)
|
|
try:
|
|
db.execute("INSERT INTO users (username, password, is_admin) VALUES (?, ?, ?)",
|
|
(new_username, hashed_pw, new_is_admin))
|
|
db.commit()
|
|
flash("Neuer Benutzer erstellt!", "green")
|
|
except sqlite3.IntegrityError:
|
|
flash("Benutzername bereits vorhanden!", "red")
|
|
|
|
users = db.execute("SELECT * FROM users").fetchall()
|
|
return render_template('admin.html', users=users)
|
|
|
|
@app.route('/admin/delete_user/<int:user_id>', methods=['POST'])
|
|
def delete_user(user_id):
|
|
if not is_admin():
|
|
flash("Zugriff verweigert!", "red")
|
|
return redirect(url_for('dashboard'))
|
|
if user_id == session.get('user_id'):
|
|
flash("Du kannst dich nicht selbst löschen!", "red")
|
|
return redirect(url_for('admin_panel'))
|
|
db = get_db()
|
|
db.execute("DELETE FROM users WHERE id=?", (user_id,))
|
|
db.commit()
|
|
flash("Benutzer gelöscht!", "green")
|
|
return redirect(url_for('admin_panel'))
|
|
|
|
# ------------------------------------------------------------
|
|
# BENACHRICHTIGUNGEN
|
|
# ------------------------------------------------------------
|
|
@app.route('/admin/notifications', methods=['POST'])
|
|
def add_notification():
|
|
if not is_admin():
|
|
flash("Zugriff verweigert!", "red")
|
|
return redirect(url_for('dashboard'))
|
|
|
|
message = request.form.get('message')
|
|
user_id = request.form.get('user_id')
|
|
if message:
|
|
db = get_db()
|
|
if user_id == "all":
|
|
db.execute("INSERT INTO notifications (user_id, message) VALUES (NULL, ?)", (message,))
|
|
else:
|
|
db.execute("INSERT INTO notifications (user_id, message) VALUES (?, ?)", (user_id, message))
|
|
db.commit()
|
|
flash("Benachrichtigung erstellt!", "green")
|
|
return redirect(url_for('admin_panel'))
|
|
|
|
# ------------------------------------------------------------
|
|
# BOOKMARKS
|
|
# ------------------------------------------------------------
|
|
@app.route('/admin/bookmarks/<int:user_id>', methods=['GET', 'POST'])
|
|
def manage_bookmarks(user_id):
|
|
if not is_admin():
|
|
flash("Zugriff verweigert!", "red")
|
|
return redirect(url_for('dashboard'))
|
|
db = get_db()
|
|
user = get_user_by_id(user_id)
|
|
if not user:
|
|
flash("Benutzer nicht gefunden!", "red")
|
|
return redirect(url_for('admin_panel'))
|
|
|
|
if request.method == 'POST':
|
|
title = request.form.get('title')
|
|
url_ = request.form.get('url')
|
|
icon = request.form.get('icon_class', 'fas fa-bookmark')
|
|
if title and url_:
|
|
db.execute("INSERT INTO bookmarks (user_id, title, url, icon_class) VALUES (?, ?, ?, ?)",
|
|
(user_id, title, url_, icon))
|
|
db.commit()
|
|
flash("Neues Lesezeichen hinzugefügt!", "green")
|
|
|
|
bookmarks = db.execute("SELECT * FROM bookmarks WHERE user_id=?", (user_id,)).fetchall()
|
|
return render_template('admin.html', single_user=user, bookmarks=bookmarks)
|
|
|
|
@app.route('/admin/delete_bookmark/<int:bookmark_id>/<int:user_id>', methods=['POST'])
|
|
def delete_bookmark(bookmark_id, user_id):
|
|
if not is_admin():
|
|
flash("Zugriff verweigert!", "red")
|
|
return redirect(url_for('dashboard'))
|
|
db = get_db()
|
|
db.execute("DELETE FROM bookmarks WHERE id=?", (bookmark_id,))
|
|
db.commit()
|
|
flash("Lesezeichen gelöscht!", "green")
|
|
return redirect(url_for('manage_bookmarks', user_id=user_id))
|
|
|
|
# ------------------------------------------------------------
|
|
# ZEITERFASSUNG
|
|
# ------------------------------------------------------------
|
|
@app.route('/time_tracking', methods=['POST'])
|
|
def time_tracking():
|
|
if 'user_id' not in session:
|
|
flash("Bitte erst einloggen!", "red")
|
|
return redirect(url_for('login'))
|
|
|
|
action = request.form.get('action')
|
|
activity = request.form.get('activity')
|
|
db = get_db()
|
|
|
|
if action == 'start':
|
|
if activity:
|
|
db.execute("""
|
|
INSERT INTO time_entries (user_id, activity, start_time)
|
|
VALUES (?, ?, ?)
|
|
""", (session['user_id'], activity, datetime.now()))
|
|
db.commit()
|
|
flash("Zeiterfassung gestartet!", "green")
|
|
else:
|
|
flash("Bitte einen Aktivitätsnamen angeben!", "red")
|
|
|
|
elif action == 'stop':
|
|
open_entry = db.execute("""
|
|
SELECT * FROM time_entries
|
|
WHERE user_id = ? AND end_time IS NULL
|
|
ORDER BY start_time DESC
|
|
LIMIT 1
|
|
""", (session['user_id'],)).fetchone()
|
|
if open_entry:
|
|
db.execute("UPDATE time_entries SET end_time=? WHERE id=?", (datetime.now(), open_entry['id']))
|
|
db.commit()
|
|
flash("Zeiterfassung gestoppt!", "green")
|
|
else:
|
|
flash("Keine laufende Zeiterfassung gefunden!", "red")
|
|
|
|
return redirect(url_for('dashboard'))
|
|
|
|
# ------------------------------------------------------------
|
|
# DASHBOARD
|
|
# ------------------------------------------------------------
|
|
@app.route('/dashboard')
|
|
def dashboard():
|
|
if 'user_id' not in session:
|
|
flash("Bitte melde dich an!", "red")
|
|
return redirect(url_for('login'))
|
|
|
|
user_id = session['user_id']
|
|
db = get_db()
|
|
|
|
# User abfragen
|
|
user = db.execute("SELECT * FROM users WHERE id = ?", (user_id,)).fetchone()
|
|
if not user:
|
|
flash("Benutzer nicht gefunden.", "red")
|
|
return redirect(url_for('logout'))
|
|
|
|
# Settings aus user_settings
|
|
settings = db.execute("SELECT * FROM user_settings WHERE user_id = ?", (user_id,)).fetchone()
|
|
|
|
# Standardwerte
|
|
if not settings:
|
|
wallpaper = '19.png'
|
|
city = 'Berlin'
|
|
show_forecast = True
|
|
bookmarks = []
|
|
else:
|
|
wallpaper = settings['wallpaper']
|
|
city = settings['city']
|
|
show_forecast = bool(settings['show_forecast'])
|
|
if settings['bookmarks']:
|
|
bookmarks = settings['bookmarks'].split(",")
|
|
else:
|
|
bookmarks = []
|
|
|
|
# Wetter holen (wenn gewünscht)
|
|
current_temp, weather_icon, forecast = get_weather(city)
|
|
if current_temp is None:
|
|
current_temp = "N/A"
|
|
weather_icon = "fa-question"
|
|
forecast = []
|
|
|
|
# Domain, Logo usw.
|
|
domain = "example.com"
|
|
logo_path = url_for('static', filename='clickcandit.png')
|
|
|
|
# Beispiel-Apps
|
|
user_app_chunks = [
|
|
[
|
|
{
|
|
'name': 'Mail',
|
|
'subdomain': 'mail',
|
|
'appkey': 'mailapp',
|
|
'icon_class': 'fa fa-envelope',
|
|
'bg_color': 'bg-blue-500'
|
|
},
|
|
{
|
|
'name': 'Calendar',
|
|
'subdomain': 'calendar',
|
|
'appkey': 'calendarapp',
|
|
'icon_class': 'fa fa-calendar',
|
|
'bg_color': 'bg-green-500'
|
|
},
|
|
]
|
|
]
|
|
|
|
return render_template(
|
|
'dashboard.html',
|
|
user=user['username'],
|
|
wallpaper=wallpaper,
|
|
city=city,
|
|
show_forecast=show_forecast,
|
|
bookmarks=bookmarks,
|
|
current_temp=current_temp,
|
|
weather_icon=weather_icon,
|
|
forecast=forecast,
|
|
domain=domain,
|
|
logo_path=logo_path,
|
|
user_app_chunks=user_app_chunks
|
|
)
|
|
|
|
# ------------------------------------------------------------
|
|
# SUPPORT & SETTINGS ROUTEN (Aus V1)
|
|
# ------------------------------------------------------------
|
|
|
|
@app.route('/send_support_message', methods=['POST'])
|
|
def send_support_message():
|
|
"""
|
|
Beispiel-Endpunkt, den dein Support-Modal per Fetch aufruft.
|
|
Erwartet JSON-Daten: { "email": ..., "problemType": ..., "message": ... }
|
|
"""
|
|
data = request.get_json()
|
|
email = data.get('email')
|
|
problem_type = data.get('problemType')
|
|
message = data.get('message')
|
|
|
|
if not email or not message:
|
|
return jsonify({"success": False, "error": "Fehlende Felder"}), 400
|
|
|
|
# Hier könntest du z.B. eine E-Mail verschicken oder einen Eintrag in der DB anlegen
|
|
# Demo: wir legen einfach einen Notification-Eintrag an
|
|
db = get_db()
|
|
db.execute("""
|
|
INSERT INTO notifications (user_id, message)
|
|
VALUES (NULL, ?)
|
|
""", (f"Support-Anfrage ({problem_type}) von {email}: {message}",))
|
|
db.commit()
|
|
|
|
return jsonify({"success": True})
|
|
|
|
@app.route('/get_settings', methods=['GET'])
|
|
def get_settings():
|
|
"""
|
|
Liefert das aktuell gespeicherte Setting zurück (V1-Modal).
|
|
Du brauchst user_settings oder ein eigenes Modell, wo du die Bookmarks/Stadt/etc. speicherst
|
|
"""
|
|
if 'user_id' not in session:
|
|
return jsonify({"error": "not logged in"}), 403
|
|
|
|
db = get_db()
|
|
settings_row = db.execute("SELECT * FROM user_settings WHERE user_id=?", (session['user_id'],)).fetchone()
|
|
if settings_row:
|
|
return jsonify({
|
|
"wallpaper": settings_row['wallpaper'],
|
|
"city": settings_row['city'],
|
|
"show_forecast": bool(settings_row['show_forecast']),
|
|
"bookmarks": settings_row['bookmarks'].split(",") if settings_row['bookmarks'] else []
|
|
})
|
|
else:
|
|
# Falls noch kein Datensatz existiert
|
|
return jsonify({
|
|
"wallpaper": "1.png",
|
|
"city": "",
|
|
"show_forecast": False,
|
|
"bookmarks": []
|
|
})
|
|
|
|
@app.route('/save_settings', methods=['POST'])
|
|
def save_settings():
|
|
"""
|
|
Speichert die Einstellungen, die vom Settings-Modal per Fetch geschickt werden
|
|
JSON body: { "wallpaper": ..., "city": ..., "show_forecast": ..., "bookmarks": ... }
|
|
"""
|
|
if 'user_id' not in session:
|
|
return jsonify({"success": False, "error": "not logged in"}), 403
|
|
|
|
data = request.get_json()
|
|
wallpaper = data.get('wallpaper', '1.png')
|
|
city = data.get('city', '')
|
|
show_forecast = data.get('show_forecast', False)
|
|
bookmarks_list = data.get('bookmarks', [])
|
|
|
|
db = get_db()
|
|
# Check if row exists
|
|
existing = db.execute("SELECT id FROM user_settings WHERE user_id=?", (session['user_id'],)).fetchone()
|
|
if existing:
|
|
db.execute("""
|
|
UPDATE user_settings
|
|
SET wallpaper=?, city=?, show_forecast=?, bookmarks=?
|
|
WHERE user_id=?
|
|
""", (wallpaper, city, int(show_forecast), ",".join(bookmarks_list), session['user_id']))
|
|
else:
|
|
db.execute("""
|
|
INSERT INTO user_settings (user_id, wallpaper, city, show_forecast, bookmarks)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
""", (session['user_id'], wallpaper, city, int(show_forecast), ",".join(bookmarks_list)))
|
|
db.commit()
|
|
|
|
return jsonify({"success": True})
|
|
|
|
def get_weather(city):
|
|
"""
|
|
Gibt (current_temp, weather_icon, forecast) zurück
|
|
"""
|
|
# Hier kannst du z. B. eine Wetter-API anfragen
|
|
# oder Dummy-Werte für den Anfang setzen
|
|
|
|
# DUMMY Beispiel:
|
|
current_temp = 24
|
|
weather_icon = "fa-cloud"
|
|
forecast = []
|
|
return (current_temp, weather_icon, forecast)
|
|
|
|
# ------------------------------------------------------------
|
|
# STARTUP
|
|
# ------------------------------------------------------------
|
|
if __name__ == '__main__':
|
|
init_db()
|
|
app.run(debug=True)
|