from flask import Blueprint, jsonify, request, abort, render_template, redirect, url_for, flash from flask_login import login_required, current_user from models import db, Room, RoomFile, TrashedFile, UserStarredFile, Notif from routes.auth import require_password_change from utils import user_has_permission, clean_path, log_event, create_notification, get_unread_count import os from datetime import datetime trash_bp = Blueprint('trash', __name__, url_prefix='/trash') @trash_bp.context_processor def inject_unread_notifications(): if current_user.is_authenticated: unread_count = get_unread_count(current_user.id) return {'unread_notifications': unread_count} return {'unread_notifications': 0} @trash_bp.route('//trash', methods=['GET']) @login_required def list_trashed_files(room_id): room = Room.query.get_or_404(room_id) if not user_has_permission(room, 'can_view'): abort(403) # Get all trashed files in the room files = TrashedFile.query.filter_by(room_id=room_id).order_by(TrashedFile.deleted_at.desc()).all() result = [] for f in files: uploader_full_name = None uploader_profile_pic = None if f.uploader: uploader_full_name = f.uploader.username if getattr(f.uploader, 'last_name', None): uploader_full_name += ' ' + f.uploader.last_name uploader_profile_pic = f.uploader.profile_picture if getattr(f.uploader, 'profile_picture', None) else None deleter_full_name = None if f.deleter: deleter_full_name = f.deleter.username if getattr(f.deleter, 'last_name', None): deleter_full_name += ' ' + f.deleter.last_name result.append({ 'id': f.id, 'name': f.name, 'type': f.type, 'size': f.size if f.type == 'file' else '-', 'modified': f.modified, 'uploaded_by': uploader_full_name, 'uploader_profile_pic': uploader_profile_pic, 'uploaded_at': f.uploaded_at.isoformat() if f.uploaded_at else None, 'original_path': f.original_path, 'deleted_by': deleter_full_name, 'deleted_at': f.deleted_at.isoformat() }) return jsonify(result) @trash_bp.route('//trash//restore', methods=['POST']) @login_required def restore_file(room_id, trash_id): room = Room.query.get_or_404(room_id) if not user_has_permission(room, 'can_upload'): abort(403) trashed_file = TrashedFile.query.get_or_404(trash_id) if trashed_file.room_id != room_id: abort(404) # Create new RoomFile entry rf = RoomFile( room_id=room_id, name=trashed_file.name, path=trashed_file.original_path, type=trashed_file.type, size=trashed_file.size, modified=trashed_file.modified, uploaded_by=trashed_file.uploaded_by, uploaded_at=trashed_file.uploaded_at ) db.session.add(rf) # Delete the trashed file entry db.session.delete(trashed_file) db.session.commit() log_event( event_type='file_restore', details={ 'filename': trashed_file.name, 'room_id': room_id, 'room_name': room.name, 'original_path': trashed_file.original_path, 'restored_by': f"{current_user.username} {current_user.last_name}", 'file_type': trashed_file.type, 'file_size': trashed_file.size if trashed_file.type == 'file' else None }, user_id=current_user.id ) return jsonify({'success': True}) @trash_bp.route('//trash/', methods=['DELETE']) @login_required def permanently_delete_file(room_id, trash_id): room = Room.query.get_or_404(room_id) if not user_has_permission(room, 'can_delete'): abort(403) trashed_file = TrashedFile.query.get_or_404(trash_id) if trashed_file.room_id != room_id: abort(404) # Delete the trashed file entry db.session.delete(trashed_file) db.session.commit() log_event( event_type='file_delete_permanent', details={ 'filename': trashed_file.name, 'room_id': room_id, 'room_name': room.name, 'original_path': trashed_file.original_path, 'deleted_by': f"{current_user.username} {current_user.last_name}", 'file_type': trashed_file.type, 'file_size': trashed_file.size if trashed_file.type == 'file' else None, 'was_in_trash': True }, user_id=current_user.id ) return jsonify({'success': True}) @trash_bp.route('//trash/empty', methods=['POST']) @login_required def empty_trash(room_id): """Empty the trash for a specific room.""" try: room = Room.query.get_or_404(room_id) # Get all trashed files trashed_files = TrashedFile.query.filter_by(room_id=room_id).all() # Delete physical files first for file in trashed_files: try: file_path = os.path.join(current_app.config['UPLOAD_FOLDER'], str(room_id), file.name) if os.path.exists(file_path): os.remove(file_path) except Exception as e: print(f"Error deleting physical file {file.name}: {str(e)}") continue # Delete all starred file references for the trashed files room_files = RoomFile.query.filter_by(room_id=room_id, deleted=True).all() for file in room_files: UserStarredFile.query.filter_by(file_id=file.id).delete() # Delete all trashed files from both tables TrashedFile.query.filter_by(room_id=room_id).delete() RoomFile.query.filter_by(room_id=room_id, deleted=True).delete() db.session.commit() log_event( event_type='trash_empty', details={ 'room_id': room_id, 'room_name': room.name, 'emptied_by': f"{current_user.username} {current_user.last_name}", 'files_deleted_count': len(trashed_files) }, user_id=current_user.id ) return jsonify({'success': True}) except Exception as e: db.session.rollback() print(f"Error emptying trash: {str(e)}") return jsonify({'success': False, 'error': str(e)}), 500