280 lines
11 KiB
Python
280 lines
11 KiB
Python
import json
|
|
from datetime import datetime, timedelta
|
|
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, abort
|
|
from flask_login import current_user, login_required
|
|
from sqlalchemy import and_, or_
|
|
|
|
from models import Job, Printer, User, UserPermission, get_cached_session
|
|
from utils.logging_config import get_logger
|
|
|
|
calendar_blueprint = Blueprint('calendar', __name__)
|
|
logger = get_logger("calendar")
|
|
|
|
def can_edit_events(user):
|
|
"""Prüft, ob ein Benutzer Kalendereinträge bearbeiten darf."""
|
|
if user.is_admin:
|
|
return True
|
|
|
|
with get_cached_session() as db_session:
|
|
permission = db_session.query(UserPermission).filter_by(user_id=user.id).first()
|
|
if not permission:
|
|
return False
|
|
return permission.can_approve_jobs
|
|
|
|
@calendar_blueprint.route('/calendar', methods=['GET'])
|
|
@login_required
|
|
def calendar_view():
|
|
"""Kalender-Ansicht anzeigen."""
|
|
can_edit = can_edit_events(current_user)
|
|
|
|
with get_cached_session() as db_session:
|
|
printers = db_session.query(Printer).filter_by(active=True).all()
|
|
|
|
return render_template('calendar.html',
|
|
printers=printers,
|
|
can_edit=can_edit)
|
|
|
|
@calendar_blueprint.route('/api/calendar', methods=['GET'])
|
|
@login_required
|
|
def api_get_calendar_events():
|
|
"""Kalendereinträge als JSON für FullCalendar zurückgeben."""
|
|
try:
|
|
# Datumsbereich aus Anfrage
|
|
start_str = request.args.get('from')
|
|
end_str = request.args.get('to')
|
|
|
|
if not start_str or not end_str:
|
|
# Standardmäßig eine Woche anzeigen
|
|
start_date = datetime.now()
|
|
end_date = start_date + timedelta(days=7)
|
|
else:
|
|
try:
|
|
start_date = datetime.fromisoformat(start_str)
|
|
end_date = datetime.fromisoformat(end_str)
|
|
except ValueError:
|
|
return jsonify({"error": "Ungültiges Datumsformat"}), 400
|
|
|
|
# Optional: Filter nach Druckern
|
|
printer_id = request.args.get('printer_id')
|
|
|
|
with get_cached_session() as db_session:
|
|
# Jobs im angegebenen Zeitraum abfragen
|
|
query = db_session.query(Job).filter(
|
|
or_(
|
|
# Jobs, die im Zeitraum beginnen
|
|
and_(Job.start_at >= start_date, Job.start_at <= end_date),
|
|
# Jobs, die im Zeitraum enden
|
|
and_(Job.end_at >= start_date, Job.end_at <= end_date),
|
|
# Jobs, die den Zeitraum komplett umfassen
|
|
and_(Job.start_at <= start_date, Job.end_at >= end_date)
|
|
)
|
|
)
|
|
|
|
if printer_id:
|
|
query = query.filter(Job.printer_id == printer_id)
|
|
|
|
jobs = query.all()
|
|
|
|
# Jobs in FullCalendar-Event-Format umwandeln
|
|
events = []
|
|
for job in jobs:
|
|
# Farbe basierend auf Status bestimmen
|
|
color = "#6B7280" # Grau für pending
|
|
if job.status == "running":
|
|
color = "#3B82F6" # Blau für running
|
|
elif job.status == "finished":
|
|
color = "#10B981" # Grün für finished
|
|
elif job.status == "scheduled":
|
|
color = "#10B981" # Grün für approved
|
|
elif job.status == "cancelled" or job.status == "failed":
|
|
color = "#EF4444" # Rot für abgebrochen/fehlgeschlagen
|
|
|
|
# Benutzerinformationen laden
|
|
user = db_session.query(User).filter_by(id=job.user_id).first()
|
|
user_name = user.name if user else "Unbekannt"
|
|
|
|
# Druckerinformationen laden
|
|
printer = db_session.query(Printer).filter_by(id=job.printer_id).first()
|
|
printer_name = printer.name if printer else "Unbekannt"
|
|
|
|
event = {
|
|
"id": job.id,
|
|
"title": job.name,
|
|
"start": job.start_at.isoformat(),
|
|
"end": job.end_at.isoformat(),
|
|
"color": color,
|
|
"extendedProps": {
|
|
"status": job.status,
|
|
"description": job.description,
|
|
"userName": user_name,
|
|
"printerId": job.printer_id,
|
|
"printerName": printer_name
|
|
}
|
|
}
|
|
|
|
events.append(event)
|
|
|
|
return jsonify(events)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Abrufen der Kalendereinträge: {str(e)}")
|
|
return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500
|
|
|
|
@calendar_blueprint.route('/api/calendar/event', methods=['POST'])
|
|
@login_required
|
|
def api_create_calendar_event():
|
|
"""Neuen Kalendereintrag (Job) erstellen."""
|
|
# Nur Admins und Benutzer mit can_approve_jobs dürfen Einträge erstellen
|
|
if not can_edit_events(current_user):
|
|
return jsonify({"error": "Keine Berechtigung zum Erstellen von Kalendereinträgen"}), 403
|
|
|
|
try:
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({"error": "Keine Daten erhalten"}), 400
|
|
|
|
# Pflichtfelder prüfen
|
|
title = data.get('title')
|
|
start = data.get('start')
|
|
end = data.get('end')
|
|
printer_id = data.get('printerId')
|
|
|
|
if not all([title, start, end, printer_id]):
|
|
return jsonify({"error": "Titel, Start, Ende und Drucker sind erforderlich"}), 400
|
|
|
|
# Datumsfelder konvertieren
|
|
try:
|
|
start_date = datetime.fromisoformat(start)
|
|
end_date = datetime.fromisoformat(end)
|
|
except ValueError:
|
|
return jsonify({"error": "Ungültiges Datumsformat"}), 400
|
|
|
|
# Dauer in Minuten berechnen
|
|
duration_minutes = int((end_date - start_date).total_seconds() / 60)
|
|
|
|
with get_cached_session() as db_session:
|
|
# Drucker prüfen
|
|
printer = db_session.query(Printer).filter_by(id=printer_id).first()
|
|
if not printer:
|
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
|
|
|
# Neuen Job erstellen
|
|
job = Job(
|
|
name=title,
|
|
description=data.get('description', ''),
|
|
user_id=current_user.id,
|
|
printer_id=printer_id,
|
|
start_at=start_date,
|
|
end_at=end_date,
|
|
status="scheduled",
|
|
duration_minutes=duration_minutes,
|
|
owner_id=current_user.id
|
|
)
|
|
|
|
db_session.add(job)
|
|
db_session.commit()
|
|
|
|
logger.info(f"Neuer Kalendereintrag erstellt: ID {job.id}, Name: {title}")
|
|
|
|
return jsonify({
|
|
"success": True,
|
|
"id": job.id,
|
|
"title": job.name,
|
|
"start": job.start_at.isoformat(),
|
|
"end": job.end_at.isoformat(),
|
|
"status": job.status
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Erstellen des Kalendereintrags: {str(e)}")
|
|
return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500
|
|
|
|
@calendar_blueprint.route('/api/calendar/event/<int:event_id>', methods=['PUT'])
|
|
@login_required
|
|
def api_update_calendar_event(event_id):
|
|
"""Kalendereintrag (Job) aktualisieren."""
|
|
# Nur Admins und Benutzer mit can_approve_jobs dürfen Einträge bearbeiten
|
|
if not can_edit_events(current_user):
|
|
return jsonify({"error": "Keine Berechtigung zum Bearbeiten von Kalendereinträgen"}), 403
|
|
|
|
try:
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({"error": "Keine Daten erhalten"}), 400
|
|
|
|
with get_cached_session() as db_session:
|
|
job = db_session.query(Job).filter_by(id=event_id).first()
|
|
if not job:
|
|
return jsonify({"error": "Kalendereintrag nicht gefunden"}), 404
|
|
|
|
# Felder aktualisieren, die im Request enthalten sind
|
|
if 'title' in data:
|
|
job.name = data['title']
|
|
|
|
if 'description' in data:
|
|
job.description = data['description']
|
|
|
|
if 'start' in data and 'end' in data:
|
|
try:
|
|
start_date = datetime.fromisoformat(data['start'])
|
|
end_date = datetime.fromisoformat(data['end'])
|
|
|
|
job.start_at = start_date
|
|
job.end_at = end_date
|
|
job.duration_minutes = int((end_date - start_date).total_seconds() / 60)
|
|
except ValueError:
|
|
return jsonify({"error": "Ungültiges Datumsformat"}), 400
|
|
|
|
if 'printerId' in data:
|
|
printer = db_session.query(Printer).filter_by(id=data['printerId']).first()
|
|
if not printer:
|
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
|
job.printer_id = data['printerId']
|
|
|
|
if 'status' in data:
|
|
# Status nur ändern, wenn er gültig ist
|
|
valid_statuses = ["scheduled", "running", "finished", "cancelled"]
|
|
if data['status'] in valid_statuses:
|
|
job.status = data['status']
|
|
|
|
db_session.commit()
|
|
|
|
logger.info(f"Kalendereintrag aktualisiert: ID {job.id}")
|
|
|
|
return jsonify({
|
|
"success": True,
|
|
"id": job.id,
|
|
"title": job.name,
|
|
"start": job.start_at.isoformat(),
|
|
"end": job.end_at.isoformat(),
|
|
"status": job.status
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Aktualisieren des Kalendereintrags: {str(e)}")
|
|
return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500
|
|
|
|
@calendar_blueprint.route('/api/calendar/event/<int:event_id>', methods=['DELETE'])
|
|
@login_required
|
|
def api_delete_calendar_event(event_id):
|
|
"""Kalendereintrag (Job) löschen."""
|
|
# Nur Admins und Benutzer mit can_approve_jobs dürfen Einträge löschen
|
|
if not can_edit_events(current_user):
|
|
return jsonify({"error": "Keine Berechtigung zum Löschen von Kalendereinträgen"}), 403
|
|
|
|
try:
|
|
with get_cached_session() as db_session:
|
|
job = db_session.query(Job).filter_by(id=event_id).first()
|
|
if not job:
|
|
return jsonify({"error": "Kalendereintrag nicht gefunden"}), 404
|
|
|
|
db_session.delete(job)
|
|
db_session.commit()
|
|
|
|
logger.info(f"Kalendereintrag gelöscht: ID {event_id}")
|
|
|
|
return jsonify({"success": True})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Löschen des Kalendereintrags: {str(e)}")
|
|
return jsonify({"error": "Fehler beim Verarbeiten der Anfrage"}), 500 |