132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
"""
|
|
routes/admin_shifts.py — Shift management CRUD routes.
|
|
"""
|
|
|
|
import logging
|
|
from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify
|
|
from models import (
|
|
get_all_shifts, get_shift_by_id, get_shift_assigned_users,
|
|
get_shift_assigned_websites, create_shift, update_shift, delete_shift,
|
|
get_all_users, get_all_websites,
|
|
)
|
|
from utils.decorators import admin_required
|
|
|
|
logger = logging.getLogger("routes.admin_shifts")
|
|
admin_shifts_bp = Blueprint("admin_shifts", __name__, url_prefix="/admin/shifts")
|
|
|
|
# MySQL DAYOFWEEK: 1=Sun 2=Mon … 7=Sat
|
|
DAY_MAP = [
|
|
("Mon", "2"), ("Tue", "3"), ("Wed", "4"),
|
|
("Thu", "5"), ("Fri", "6"), ("Sat", "7"), ("Sun", "1"),
|
|
]
|
|
|
|
|
|
@admin_shifts_bp.route("/")
|
|
@admin_required
|
|
def shifts_list():
|
|
shifts = get_all_shifts()
|
|
all_users = get_all_users()
|
|
all_sites = get_all_websites()
|
|
return render_template("admin/shifts.html",
|
|
shifts=shifts, all_users=all_users,
|
|
all_sites=all_sites, day_map=DAY_MAP)
|
|
|
|
|
|
@admin_shifts_bp.route("/<int:shift_id>/detail")
|
|
@admin_required
|
|
def detail(shift_id):
|
|
shift = get_shift_by_id(shift_id)
|
|
users = get_shift_assigned_users(shift_id)
|
|
websites = get_shift_assigned_websites(shift_id)
|
|
if not shift:
|
|
return jsonify({"error": "Not found"}), 404
|
|
|
|
# Convert time objects to HH:MM strings for form inputs
|
|
def _fmt(t):
|
|
if t is None:
|
|
return ""
|
|
if hasattr(t, "seconds"): # timedelta from MySQL
|
|
h, rem = divmod(int(t.total_seconds()), 3600)
|
|
return f"{h:02d}:{rem // 60:02d}"
|
|
return str(t)[:5]
|
|
|
|
return jsonify({
|
|
"id": shift["id"],
|
|
"name": shift["name"],
|
|
"days_of_week": shift["days_of_week"],
|
|
"start_time": _fmt(shift["start_time"]),
|
|
"end_time": _fmt(shift["end_time"]),
|
|
"note": shift["note"] or "",
|
|
"is_active": shift["is_active"],
|
|
"user_ids": [u["id"] for u in users],
|
|
"website_ids": [w["id"] for w in websites],
|
|
})
|
|
|
|
|
|
@admin_shifts_bp.route("/create", methods=["POST"])
|
|
@admin_required
|
|
def create():
|
|
admin_id = session["user"]["id"]
|
|
name = request.form.get("name", "").strip()
|
|
days_of_week = "".join(request.form.getlist("days_of_week[]"))
|
|
start_time = request.form.get("start_time", "08:00")
|
|
end_time = request.form.get("end_time", "17:00")
|
|
note = request.form.get("note", "").strip()
|
|
user_ids = [int(x) for x in request.form.getlist("user_ids[]") if x]
|
|
website_ids = [int(x) for x in request.form.getlist("website_ids[]") if x]
|
|
|
|
if not name:
|
|
flash("Shift name is required.", "danger")
|
|
return redirect(url_for("admin_shifts.shifts_list"))
|
|
|
|
try:
|
|
create_shift(admin_id, name, days_of_week, start_time, end_time,
|
|
note, user_ids, website_ids)
|
|
flash(f"Shift '{name}' created successfully.", "success")
|
|
logger.info(f"Shift '{name}' created by admin_id={admin_id}.")
|
|
except Exception as e:
|
|
logger.error(f"create_shift error: {e}")
|
|
flash(f"Error creating shift: {e}", "danger")
|
|
|
|
return redirect(url_for("admin_shifts.shifts_list"))
|
|
|
|
|
|
@admin_shifts_bp.route("/<int:shift_id>/edit", methods=["POST"])
|
|
@admin_required
|
|
def edit(shift_id):
|
|
admin_id = session["user"]["id"]
|
|
name = request.form.get("name", "").strip()
|
|
days_of_week = "".join(request.form.getlist("days_of_week[]"))
|
|
start_time = request.form.get("start_time", "08:00")
|
|
end_time = request.form.get("end_time", "17:00")
|
|
note = request.form.get("note", "").strip()
|
|
is_active = int(request.form.get("is_active", 1))
|
|
user_ids = [int(x) for x in request.form.getlist("user_ids[]") if x]
|
|
website_ids = [int(x) for x in request.form.getlist("website_ids[]") if x]
|
|
|
|
try:
|
|
update_shift(admin_id, shift_id, name, days_of_week, start_time, end_time,
|
|
note, is_active, user_ids, website_ids)
|
|
flash(f"Shift '{name}' updated successfully.", "success")
|
|
logger.info(f"Shift id={shift_id} updated by admin_id={admin_id}.")
|
|
except Exception as e:
|
|
logger.error(f"update_shift error: {e}")
|
|
flash(f"Error updating shift: {e}", "danger")
|
|
|
|
return redirect(url_for("admin_shifts.shifts_list"))
|
|
|
|
|
|
@admin_shifts_bp.route("/<int:shift_id>/delete", methods=["POST"])
|
|
@admin_required
|
|
def delete(shift_id):
|
|
admin_id = session["user"]["id"]
|
|
try:
|
|
delete_shift(admin_id, shift_id)
|
|
flash("Shift deactivated successfully.", "success")
|
|
logger.info(f"Shift id={shift_id} soft-deleted by admin_id={admin_id}.")
|
|
except Exception as e:
|
|
logger.error(f"delete_shift error: {e}")
|
|
flash(f"Error deleting shift: {e}", "danger")
|
|
|
|
return redirect(url_for("admin_shifts.shifts_list"))
|