from flask import Blueprint, jsonify from flask_login import login_required, current_user from models import db, Room, RoomFile, User import os from datetime import datetime admin = Blueprint('admin', __name__) @admin.route('/api/admin/sync-files', methods=['POST']) @login_required def sync_files(): if not current_user.is_admin: return jsonify({'error': 'Unauthorized'}), 403 try: DATA_ROOT = '/data/rooms' admin_user = User.query.filter_by(is_admin=True).first() if not admin_user: return jsonify({'error': 'No admin user found'}), 500 rooms = Room.query.all() for room in rooms: room_dir = os.path.join(DATA_ROOT, str(room.id)) if not os.path.exists(room_dir): continue for root, dirs, files in os.walk(room_dir): rel_root = os.path.relpath(root, room_dir) rel_path = '' if rel_root == '.' else rel_root.replace('\\', '/') # Folders for d in dirs: exists = RoomFile.query.filter_by(room_id=room.id, name=d, path=rel_path, type='folder').first() folder_path = os.path.join(root, d) stat = os.stat(folder_path) if not exists: rf = RoomFile( room_id=room.id, name=d, path=rel_path, type='folder', size=None, modified=stat.st_mtime, uploaded_by=admin_user.id, uploaded_at=datetime.utcfromtimestamp(stat.st_mtime) ) db.session.add(rf) # Files for f in files: exists = RoomFile.query.filter_by(room_id=room.id, name=f, path=rel_path, type='file').first() file_path = os.path.join(root, f) stat = os.stat(file_path) if not exists: rf = RoomFile( room_id=room.id, name=f, path=rel_path, type='file', size=stat.st_size, modified=stat.st_mtime, uploaded_by=admin_user.id, uploaded_at=datetime.utcfromtimestamp(stat.st_mtime) ) db.session.add(rf) db.session.commit() return jsonify({'success': True, 'message': 'File system synchronized successfully'}) except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @admin.route('/api/admin/verify-db-state', methods=['GET']) @login_required def verify_db_state(): if not current_user.is_admin: return jsonify({'error': 'Unauthorized'}), 403 try: DATA_ROOT = '/data/rooms' verification_results = { 'rooms_checked': 0, 'files_in_db_not_fs': [], 'files_in_fs_not_db': [], 'permission_mismatches': [], 'size_mismatches': [], 'modified_time_mismatches': [], 'total_files_checked': 0, 'total_folders_checked': 0 } rooms = Room.query.all() for room in rooms: verification_results['rooms_checked'] += 1 room_dir = os.path.join(DATA_ROOT, str(room.id)) # Get all files and folders from database for this room db_files = RoomFile.query.filter_by(room_id=room.id, deleted=False).all() db_paths = {(f.path, f.name): f for f in db_files} # Check filesystem if directory exists if os.path.exists(room_dir): for root, dirs, files in os.walk(room_dir): rel_root = os.path.relpath(root, room_dir) rel_path = '' if rel_root == '.' else rel_root.replace('\\', '/') # Check folders for d in dirs: verification_results['total_folders_checked'] += 1 folder_path = os.path.join(root, d) stat = os.stat(folder_path) # Check if folder exists in database db_file = db_paths.get((rel_path, d)) if not db_file: verification_results['files_in_fs_not_db'].append({ 'room_id': room.id, 'room_name': room.name, 'path': rel_path, 'name': d, 'type': 'folder' }) else: # Verify folder metadata if abs(stat.st_mtime - db_file.modified) > 1: # Allow 1 second difference verification_results['modified_time_mismatches'].append({ 'room_id': room.id, 'room_name': room.name, 'path': rel_path, 'name': d, 'type': 'folder', 'fs_modified': stat.st_mtime, 'db_modified': db_file.modified }) # Remove from db_paths as we've checked it db_paths.pop((rel_path, d), None) # Check files for f in files: verification_results['total_files_checked'] += 1 file_path = os.path.join(root, f) stat = os.stat(file_path) # Check if file exists in database db_file = db_paths.get((rel_path, f)) if not db_file: verification_results['files_in_fs_not_db'].append({ 'room_id': room.id, 'room_name': room.name, 'path': rel_path, 'name': f, 'type': 'file' }) else: # Verify file metadata if abs(stat.st_mtime - db_file.modified) > 1: # Allow 1 second difference verification_results['modified_time_mismatches'].append({ 'room_id': room.id, 'room_name': room.name, 'path': rel_path, 'name': f, 'type': 'file', 'fs_modified': stat.st_mtime, 'db_modified': db_file.modified }) if stat.st_size != db_file.size: verification_results['size_mismatches'].append({ 'room_id': room.id, 'room_name': room.name, 'path': rel_path, 'name': f, 'type': 'file', 'fs_size': stat.st_size, 'db_size': db_file.size }) # Remove from db_paths as we've checked it db_paths.pop((rel_path, f), None) # Any remaining items in db_paths are in DB but not in filesystem for (path, name), db_file in db_paths.items(): verification_results['files_in_db_not_fs'].append({ 'room_id': room.id, 'room_name': room.name, 'path': path, 'name': name, 'type': db_file.type }) # Calculate total issues total_issues = ( len(verification_results['files_in_db_not_fs']) + len(verification_results['files_in_fs_not_db']) + len(verification_results['permission_mismatches']) + len(verification_results['size_mismatches']) + len(verification_results['modified_time_mismatches']) ) # Add summary statistics verification_results['summary'] = { 'total_issues': total_issues, 'status': 'healthy' if total_issues == 0 else 'issues_found' } return jsonify(verification_results) except Exception as e: return jsonify({'error': str(e)}), 500 @admin.route('/api/admin/cleanup-orphaned-records', methods=['POST']) @login_required def cleanup_orphaned_records(): if not current_user.is_admin: return jsonify({'error': 'Unauthorized'}), 403 try: DATA_ROOT = '/data/rooms' rooms = Room.query.all() cleaned_records = [] for room in rooms: room_dir = os.path.join(DATA_ROOT, str(room.id)) # Get all files and folders from database for this room db_files = RoomFile.query.filter_by(room_id=room.id, deleted=False).all() for db_file in db_files: file_path = os.path.join(room_dir, db_file.path, db_file.name) if db_file.path else os.path.join(room_dir, db_file.name) # If file doesn't exist in filesystem, mark it as deleted in database if not os.path.exists(file_path): db_file.deleted = True cleaned_records.append({ 'room_id': room.id, 'room_name': room.name, 'path': db_file.path, 'name': db_file.name, 'type': db_file.type }) db.session.commit() return jsonify({ 'success': True, 'message': f'Cleaned up {len(cleaned_records)} orphaned records', 'cleaned_records': cleaned_records }) except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500