# deck_endpoints.py from flask import Blueprint, request, jsonify import sqlite3 import os import shutil import logging deck_bp = Blueprint('deck_bp', __name__) DATABASE = 'mydatabase.db' # Logger konfigurieren (angenommen, ocr_server3.py konfiguriert das Logging) logger = logging.getLogger(__name__) def get_db_connection(): conn = sqlite3.connect(DATABASE) conn.row_factory = sqlite3.Row return conn # Erstellen der Tabellen, falls sie nicht existieren def init_db(): conn = get_db_connection() cursor = conn.cursor() # Tabelle Deck erstellen cursor.execute(''' CREATE TABLE IF NOT EXISTS Deck ( id INTEGER PRIMARY KEY AUTOINCREMENT, deckname TEXT UNIQUE NOT NULL ) ''') # Tabelle Image erstellen cursor.execute(''' CREATE TABLE IF NOT EXISTS Image ( id INTEGER PRIMARY KEY AUTOINCREMENT, deckid INTEGER, bildname TEXT, iconindex INTEGER, x1 REAL, x2 REAL, y1 REAL, y2 REAL, FOREIGN KEY(deckid) REFERENCES Deck(id) ) ''') conn.commit() conn.close() def clean_debug_directories(): """ Löscht alle Verzeichnisse unter 'debug_images', die keinen Eintrag in der Image-Tabelle haben. """ debug_base_dir = 'debug_images' if not os.path.exists(debug_base_dir): logger.info(f"Debug-Verzeichnis '{debug_base_dir}' existiert nicht. Nichts zu bereinigen.") return try: conn = get_db_connection() cursor = conn.cursor() cursor.execute('SELECT DISTINCT bildname FROM Image') bildnames = {row['bildname'] for row in cursor.fetchall()} conn.close() except sqlite3.Error as e: logger.error(f"Fehler beim Abrufen der bildname aus der Datenbank: {e}") return # Durchlaufe alle Verzeichnisse unter 'debug_images' for dir_name in os.listdir(debug_base_dir): dir_path = os.path.join(debug_base_dir, dir_name) if os.path.isdir(dir_path): if dir_name not in bildnames: try: shutil.rmtree(dir_path) logger.info(f"Nicht verwendetes Debug-Verzeichnis gelöscht: {dir_path}") except Exception as e: logger.error(f"Fehler beim Löschen des Verzeichnisses '{dir_path}': {e}") else: logger.debug(f"Debug-Verzeichnis behalten: {dir_path}") logger.info("Bereinigung der Debug-Verzeichnisse abgeschlossen.") # ------ # Endpoints # ------ # ------ # Deck - POST, GET, DELETE # ------ @deck_bp.route('/api/decks', methods=['POST']) def create_deck(): data = request.get_json() if not data or 'deckname' not in data: return jsonify({'error': 'No deckname provided'}), 400 deckname = data['deckname'] conn = get_db_connection() cursor = conn.cursor() try: cursor.execute('INSERT INTO Deck (deckname) VALUES (?)', (deckname,)) conn.commit() deck_id = cursor.lastrowid conn.close() return jsonify({'status': 'success', 'deck_id': deck_id}), 201 except sqlite3.IntegrityError: conn.close() return jsonify({'error': 'Deckname already exists'}), 400 @deck_bp.route('/api/decks', methods=['GET']) def get_decks(): conn = get_db_connection() cursor = conn.cursor() decks = cursor.execute('SELECT * FROM Deck').fetchall() deck_list = [] for deck in decks: deck_id = deck['id'] deck_name = deck['deckname'] # Alle Images für dieses Deck abrufen images = cursor.execute(''' SELECT bildname AS name, iconindex, x1, x2, y1, y2 FROM Image WHERE deckid = ? ''', (deck_id,)).fetchall() images_list = [dict(image) for image in images] # Deck mit Namen und zugehörigen Images hinzufügen deck_dict = { 'name': deck_name, 'images': images_list } deck_list.append(deck_dict) conn.close() return jsonify(deck_list) @deck_bp.route('/api/decks/', methods=['DELETE']) def delete_deck(deckname): conn = get_db_connection() cursor = conn.cursor() # Zuerst die Images löschen, die zu diesem Deck gehören cursor.execute('SELECT id FROM Deck WHERE deckname = ?', (deckname,)) deck = cursor.fetchone() if deck: deck_id = deck['id'] cursor.execute('DELETE FROM Image WHERE deckid = ?', (deck_id,)) # Dann das Deck löschen cursor.execute('DELETE FROM Deck WHERE id = ?', (deck_id,)) conn.commit() conn.close() return jsonify({'status': 'success'}), 200 else: conn.close() return jsonify({'error': 'Deck not found'}), 404 # ------ # Image - POST, GET, DELETE # ------ @deck_bp.route('/api/decks/image', methods=['POST']) def update_image(): data = request.get_json() if not data: return jsonify({'error': 'No data provided'}), 400 # Überprüfen, ob die erforderlichen Felder vorhanden sind required_fields = ['deckname', 'image', 'boxes'] if not all(field in data for field in required_fields): return jsonify({'error': 'Missing fields in data'}), 400 deckname = data['deckname'] bildname = data['image'] boxes = data['boxes'] # Überprüfen, ob 'boxes' eine Liste ist und mindestens ein Box-Element enthält if not isinstance(boxes, list) or len(boxes) == 0: return jsonify({'error': "'boxes' must be a non-empty list"}), 400 # Verbindung zur Datenbank herstellen conn = get_db_connection() cursor = conn.cursor() try: # Deck-ID anhand des Decknamens abrufen cursor.execute('SELECT id FROM Deck WHERE deckname = ?', (deckname,)) deck = cursor.fetchone() if not deck: return jsonify({'error': 'Deck not found'}), 404 deck_id = deck['id'] inserted_image_ids = [] # Durch jede Box iterieren und einen Eintrag in der Image-Tabelle erstellen for index, box in enumerate(boxes): # Überprüfen, ob alle erforderlichen Koordinaten vorhanden sind box_fields = ['x1', 'x2', 'y1', 'y2'] if not all(field in box for field in box_fields): return jsonify({'error': 'Missing fields in one of the boxes'}), 400 x1 = box['x1'] x2 = box['x2'] y1 = box['y1'] y2 = box['y2'] # Setzen des iconindex auf den aktuellen Index der Box iconindex = index cursor.execute(''' INSERT INTO Image (deckid, bildname, iconindex, x1, x2, y1, y2) VALUES (?, ?, ?, ?, ?, ?, ?) ''', (deck_id, bildname, iconindex, x1, x2, y1, y2)) inserted_image_ids.append(cursor.lastrowid) conn.commit() return jsonify({'status': 'success', 'inserted_image_ids': inserted_image_ids}), 201 except sqlite3.Error as e: conn.rollback() return jsonify({'error': 'Database error', 'details': str(e)}), 500 finally: conn.close() @deck_bp.route('/api/decks/image/', methods=['GET']) def get_images_by_bildname(bildname): conn = get_db_connection() images = conn.execute('SELECT * FROM Image WHERE bildname = ?', (bildname,)).fetchall() conn.close() image_list = [dict(image) for image in images] return jsonify(image_list) @deck_bp.route('/api/decks/image/', methods=['DELETE']) def delete_images_by_bildname(bildname): """ Löscht alle Einträge in der Image-Tabelle für den gegebenen bildname. Optional: Löscht das zugehörige Debug-Verzeichnis, wenn keine weiteren Einträge bestehen. """ try: # Sicherheitsmaßnahme: Nur erlaubte Zeichen im bildname if not all(c.isalnum() or c in ('_', '-') for c in bildname): logger.warning(f"Ungültiger bildname angefordert: {bildname}") return jsonify({'error': 'Invalid image name'}), 400 conn = get_db_connection() cursor = conn.cursor() # Überprüfen, ob es Einträge mit dem bildname gibt cursor.execute('SELECT COUNT(*) as count FROM Image WHERE bildname = ?', (bildname,)) result = cursor.fetchone() count = result['count'] if result else 0 if count == 0: conn.close() return jsonify({'error': 'No entries found for the given image name'}), 404 # Löschen der Einträge cursor.execute('DELETE FROM Image WHERE bildname = ?', (bildname,)) conn.commit() conn.close() # Optional: Löschen des Debug-Verzeichnisses, wenn keine weiteren Einträge bestehen # Überprüfen, ob das Verzeichnis existiert debug_dir = os.path.join('debug_images', bildname) if os.path.exists(debug_dir): try: shutil.rmtree(debug_dir) logger.info(f"Debug-Verzeichnis gelöscht: {debug_dir}") except Exception as e: logger.error(f"Fehler beim Löschen des Debug-Verzeichnisses '{debug_dir}': {e}") # Sie können entscheiden, ob Sie einen Fehler zurückgeben oder nicht # Hier geben wir eine Warnung zurück, aber setzen die Anfrage als erfolgreich fort return jsonify({ 'status': 'success', 'message': 'Database entries deleted, but failed to delete debug directory.', 'details': str(e) }), 200 return jsonify({'status': 'success', 'message': f'All entries for image "{bildname}" have been deleted.'}), 200 except sqlite3.Error as e: logger.error(f"Fehler beim Löschen der Image-Einträge für '{bildname}': {e}") return jsonify({'error': 'Database error', 'details': str(e)}), 500 except Exception as e: logger.error(f"Unerwarteter Fehler beim Löschen der Image-Einträge für '{bildname}': {e}") return jsonify({'error': 'Failed to delete image entries', 'details': str(e)}), 500 # Sicherstellen, dass die Datenbank existiert if not os.path.exists(DATABASE): init_db() clean_debug_directories()