Files
infoscreen/server/routes/eventmedia.py
RobbStarkAustria 7b38b49598 rename benutzer to users
add role management to media page
2025-10-16 17:57:06 +00:00

307 lines
12 KiB
Python

from re import A
from flask import Blueprint, request, jsonify, send_from_directory
from server.permissions import editor_or_higher
from server.database import Session
from models.models import EventMedia, MediaType, Conversion, ConversionStatus
from server.task_queue import get_queue
from server.worker import convert_event_media_to_pdf
import hashlib
import os
eventmedia_bp = Blueprint('eventmedia', __name__, url_prefix='/api/eventmedia')
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
def get_param(key, default=None):
# Reihenfolge: form > json > args
if request.form and key in request.form:
return request.form.get(key, default)
if request.is_json and request.json and key in request.json:
return request.json.get(key, default)
return request.args.get(key, default)
# --- FileManager: List, Create Folder, Rename, Delete, Move ---
@eventmedia_bp.route('/filemanager/operations', methods=['GET', 'POST'])
@editor_or_higher
def filemanager_operations():
action = get_param('action')
path = get_param('path', '/')
name = get_param('name')
new_name = get_param('newName')
target_path = get_param('targetPath')
full_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))
print(action, path, name, new_name, target_path, full_path) # Debug-Ausgabe
# Superadmin-only protection for the converted folder
from flask import session as flask_session
user_role = flask_session.get('role')
is_superadmin = user_role == 'superadmin'
# Normalize path for checks
norm_path = os.path.normpath('/' + path.lstrip('/'))
under_converted = norm_path == '/converted' or norm_path.startswith('/converted/')
if action == 'read':
# Block listing inside converted for non-superadmins
if under_converted and not is_superadmin:
return jsonify({'files': [], 'cwd': {'name': os.path.basename(full_path), 'path': path}})
# List files and folders
items = []
session = Session()
for entry in os.scandir(full_path):
item = {
'name': entry.name,
'isFile': entry.is_file(),
'size': entry.stat().st_size,
'type': os.path.splitext(entry.name)[1][1:] if entry.is_file() else '',
'hasChild': entry.is_dir()
}
# Wenn Datei, versuche Upload-Datum aus DB zu holen
if entry.is_file():
media = session.query(EventMedia).filter_by(
url=entry.name).first()
if media and media.uploaded_at:
# FileManager erwartet UNIX-Timestamp (Sekunden)
item['dateModified'] = int(media.uploaded_at.timestamp())
else:
item['dateModified'] = entry.stat().st_mtime
else:
item['dateModified'] = entry.stat().st_mtime
# Hide the converted folder at root for non-superadmins
if not (not is_superadmin and not entry.is_file() and entry.name == 'converted' and (norm_path == '/' or norm_path == '')):
items.append(item)
session.close()
return jsonify({'files': items, 'cwd': {'name': os.path.basename(full_path), 'path': path}})
elif action == 'details':
# Details für eine oder mehrere Dateien zurückgeben
names = request.form.getlist('names[]') or (request.json.get(
'names') if request.is_json and request.json else [])
path = get_param('path', '/')
details = []
session = Session()
for name in names:
file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'), name)
media = session.query(EventMedia).filter_by(url=name).first()
if os.path.isfile(file_path):
detail = {
'name': name,
'size': os.path.getsize(file_path),
'dateModified': int(media.uploaded_at.timestamp()) if media and media.uploaded_at else int(os.path.getmtime(file_path)),
'type': os.path.splitext(name)[1][1:],
'hasChild': False,
'isFile': True,
'description': media.message_content if media else '',
# weitere Felder nach Bedarf
}
details.append(detail)
session.close()
return jsonify({'details': details})
elif action == 'delete':
if under_converted and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
for item in request.form.getlist('names[]'):
item_path = os.path.join(full_path, item)
if os.path.isdir(item_path):
os.rmdir(item_path)
else:
os.remove(item_path)
return jsonify({'success': True})
elif action == 'rename':
if under_converted and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
src = os.path.join(full_path, name)
dst = os.path.join(full_path, new_name)
os.rename(src, dst)
return jsonify({'success': True})
elif action == 'move':
# Prevent moving into converted if not superadmin
if (target_path and target_path.strip('/').split('/')[0] == 'converted') and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
src = os.path.join(full_path, name)
dst = os.path.join(MEDIA_ROOT, target_path.lstrip('/'), name)
os.rename(src, dst)
return jsonify({'success': True})
elif action == 'create':
if under_converted and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
os.makedirs(os.path.join(full_path, name), exist_ok=True)
return jsonify({'success': True})
else:
return jsonify({'error': 'Unknown action'}), 400
# --- FileManager: Upload ---
@eventmedia_bp.route('/filemanager/upload', methods=['POST'])
@editor_or_higher
def filemanager_upload():
session = Session()
# Korrigiert: Erst aus request.form, dann aus request.args lesen
path = request.form.get('path') or request.args.get('path', '/')
from flask import session as flask_session
user_role = flask_session.get('role')
is_superadmin = user_role == 'superadmin'
norm_path = os.path.normpath('/' + path.lstrip('/'))
if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
upload_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))
os.makedirs(upload_path, exist_ok=True)
for file in request.files.getlist('uploadFiles'):
file_path = os.path.join(upload_path, file.filename)
file.save(file_path)
ext = os.path.splitext(file.filename)[1][1:].lower()
try:
media_type = MediaType(ext)
except ValueError:
media_type = MediaType.other
from datetime import datetime, timezone
media = EventMedia(
media_type=media_type,
url=file.filename,
file_path=os.path.relpath(file_path, MEDIA_ROOT),
uploaded_at=datetime.now(timezone.utc)
)
session.add(media)
session.commit()
# Enqueue conversion for office presentation types
if media_type in {MediaType.ppt, MediaType.pptx, MediaType.odp}:
# compute file hash
h = hashlib.sha256()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
file_hash = h.hexdigest()
# upsert Conversion row
conv = (
session.query(Conversion)
.filter_by(
source_event_media_id=media.id,
target_format='pdf',
file_hash=file_hash,
)
.one_or_none()
)
if not conv:
conv = Conversion(
source_event_media_id=media.id,
target_format='pdf',
status=ConversionStatus.pending,
file_hash=file_hash,
)
session.add(conv)
session.commit()
if conv.status in {ConversionStatus.pending, ConversionStatus.failed}:
q = get_queue()
q.enqueue(convert_event_media_to_pdf, conv.id)
session.commit()
return jsonify({'success': True})
# --- FileManager: Download ---
@eventmedia_bp.route('/filemanager/download', methods=['GET'])
def filemanager_download():
path = request.args.get('path', '/')
from flask import session as flask_session
user_role = flask_session.get('role')
is_superadmin = user_role == 'superadmin'
norm_path = os.path.normpath('/' + path.lstrip('/'))
names = request.args.getlist('names[]')
# Nur Einzel-Download für Beispiel
if names:
# Block access to converted for non-superadmins
if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'), names[0])
return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
return jsonify({'error': 'No file specified'}), 400
# --- FileManager: Get Image (optional, für Thumbnails) ---
@eventmedia_bp.route('/filemanager/get-image', methods=['GET'])
def filemanager_get_image():
path = request.args.get('path', '/')
from flask import session as flask_session
user_role = flask_session.get('role')
is_superadmin = user_role == 'superadmin'
norm_path = os.path.normpath('/' + path.lstrip('/'))
if (norm_path == '/converted' or norm_path.startswith('/converted/')) and not is_superadmin:
return jsonify({'error': 'Insufficient permissions'}), 403
file_path = os.path.join(MEDIA_ROOT, path.lstrip('/'))
return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path))
# --- EventMedia-API: Metadaten-Liste (wie gehabt) ---
@eventmedia_bp.route('', methods=['GET'])
def list_media():
session = Session()
media = session.query(EventMedia).all()
return jsonify([m.to_dict() for m in media])
# --- EventMedia-API: Metadaten-Update ---
@eventmedia_bp.route('/<int:media_id>', methods=['PUT'])
@editor_or_higher
def update_media(media_id):
session = Session()
media = session.query(EventMedia).get(media_id)
if not media:
return jsonify({'error': 'Not found'}), 404
data = request.json
media.url = data.get('title', media.url)
media.message_content = data.get('description', media.message_content)
# Event-Zuordnung ggf. ergänzen
session.commit()
return jsonify(media.to_dict())
@eventmedia_bp.route('/find_by_filename', methods=['GET'])
def find_by_filename():
filename = request.args.get('filename')
if not filename:
return jsonify({'error': 'Missing filename'}), 400
session = Session()
# Suche nach exaktem Dateinamen in url oder file_path
media = session.query(EventMedia).filter(
(EventMedia.url == filename) | (
EventMedia.file_path.like(f"%{filename}"))
).first()
if not media:
return jsonify({'error': 'Not found'}), 404
return jsonify({
'id': media.id,
'file_path': media.file_path,
'url': media.url
})
@eventmedia_bp.route('/<int:media_id>', methods=['GET'])
def get_media_by_id(media_id):
session = Session()
media = session.query(EventMedia).get(media_id)
if not media:
session.close()
return jsonify({'error': 'Not found'}), 404
result = {
'id': media.id,
'file_path': media.file_path,
'url': media.url,
'name': media.url, # oder ein anderes Feld für den Namen
'media_type': media.media_type.name if media.media_type else None
}
session.close()
return jsonify(result)