120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
"""
|
|
routes/user_dashboard.py — Regular user: shift check dashboard.
|
|
"""
|
|
|
|
import logging
|
|
import time
|
|
import requests as _http_req
|
|
from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify
|
|
from models import (
|
|
get_today_checks, mark_website_checked, unmark_website_checked,
|
|
update_check_note, get_user_active_shifts, get_website_credentials,
|
|
get_website_url, log_action,
|
|
)
|
|
from utils.decorators import login_required
|
|
|
|
logger = logging.getLogger("routes.user_dashboard")
|
|
user_dashboard_bp = Blueprint("user_dashboard", __name__, url_prefix="/dashboard")
|
|
|
|
|
|
@user_dashboard_bp.route("/")
|
|
@login_required
|
|
def my_shifts():
|
|
user_id = session["user"]["id"]
|
|
try:
|
|
sites = get_today_checks(user_id)
|
|
shifts = get_user_active_shifts(user_id)
|
|
except Exception as e:
|
|
logger.error(f"my_shifts error: {e}")
|
|
sites, shifts = [], []
|
|
|
|
checked = sum(1 for s in sites if s.get("check_id"))
|
|
total = len(sites)
|
|
pct = round(checked * 100 / total) if total else 0
|
|
|
|
return render_template("user/dashboard.html",
|
|
sites=sites, shifts=shifts,
|
|
checked=checked, total=total, pct=pct)
|
|
|
|
|
|
@user_dashboard_bp.route("/check/<int:website_id>", methods=["POST"])
|
|
@login_required
|
|
def check_site(website_id):
|
|
user_id = session["user"]["id"]
|
|
user_note = request.form.get("user_note", "").strip()
|
|
try:
|
|
mark_website_checked(user_id, website_id, user_note)
|
|
flash("Site marked as checked.", "success")
|
|
logger.info(f"User {user_id} checked website {website_id}.")
|
|
except Exception as e:
|
|
logger.error(f"check_site error: {e}")
|
|
flash(f"Error: {e}", "danger")
|
|
return redirect(url_for("user_dashboard.my_shifts"))
|
|
|
|
|
|
@user_dashboard_bp.route("/uncheck/<int:website_id>", methods=["POST"])
|
|
@login_required
|
|
def uncheck_site(website_id):
|
|
user_id = session["user"]["id"]
|
|
try:
|
|
unmark_website_checked(user_id, website_id)
|
|
flash("Check removed.", "info")
|
|
logger.info(f"User {user_id} unchecked website {website_id}.")
|
|
except Exception as e:
|
|
logger.error(f"uncheck_site error: {e}")
|
|
flash(f"Error: {e}", "danger")
|
|
return redirect(url_for("user_dashboard.my_shifts"))
|
|
|
|
|
|
@user_dashboard_bp.route("/note/<int:website_id>", methods=["POST"])
|
|
@login_required
|
|
def update_note(website_id):
|
|
user_id = session["user"]["id"]
|
|
user_note = request.form.get("user_note", "").strip()
|
|
try:
|
|
update_check_note(user_id, website_id, user_note)
|
|
flash("Note updated.", "success")
|
|
except Exception as e:
|
|
logger.error(f"update_note error: {e}")
|
|
flash(f"Error: {e}", "danger")
|
|
return redirect(url_for("user_dashboard.my_shifts"))
|
|
|
|
|
|
@user_dashboard_bp.route("/credentials/<int:website_id>")
|
|
@login_required
|
|
def view_credentials(website_id):
|
|
"""JSON endpoint: return decrypted credentials for a site."""
|
|
try:
|
|
creds = get_website_credentials(website_id)
|
|
user_id = session["user"]["id"]
|
|
log_action(user_id, "VIEW_CREDENTIALS", "websites", website_id,
|
|
f"User viewed credentials for website {website_id}.")
|
|
return jsonify([{
|
|
"label": c.get("label", ""),
|
|
"username": c.get("username", ""),
|
|
"password": c.get("password", ""),
|
|
} for c in creds])
|
|
except Exception as e:
|
|
logger.error(f"view_credentials error: {e}")
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@user_dashboard_bp.route("/health/<int:website_id>")
|
|
@login_required
|
|
def health_check(website_id):
|
|
"""Server-side HEAD probe for a website's reachability."""
|
|
url = get_website_url(website_id)
|
|
if not url:
|
|
return jsonify({"status": "not_found"}), 404
|
|
try:
|
|
t0 = time.time()
|
|
resp = _http_req.head(url, timeout=6, allow_redirects=True,
|
|
headers={"User-Agent": "WebsiteChecker/1.0 (health-check)"})
|
|
ms = int((time.time() - t0) * 1000)
|
|
ok = resp.status_code < 400
|
|
return jsonify({"status": "ok" if ok else "error", "ms": ms})
|
|
except _http_req.exceptions.Timeout:
|
|
return jsonify({"status": "timeout", "ms": 6000})
|
|
except Exception:
|
|
return jsonify({"status": "unreachable", "ms": None})
|