Files
docupulse/routes/trash.py
2025-05-31 23:08:38 +02:00

181 lines
6.4 KiB
Python

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('/<int:room_id>/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('/<int:room_id>/trash/<int:trash_id>/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('/<int:room_id>/trash/<int:trash_id>', 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('/<int:room_id>/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