from flask import Blueprint, request, jsonify, send_file from app.services.auth import require_auth, get_current_user from app.services.nextcloud import NextcloudClient from config import Config from io import BytesIO from PIL import Image bp = Blueprint('webdav', __name__, url_prefix='/api/files') def _get_nc_client(): """Get Nextcloud client for current user.""" user = get_current_user() if not user: return None return NextcloudClient(Config.NEXTCLOUD_URL, user['username'], user['password']) @bp.route('/list', methods=['GET']) @require_auth def list_files(): """List files and directories at the given path.""" path = request.args.get('path', '/') nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 try: result = nc_client.propfind(path, depth=1) return jsonify(result), 200 except Exception as e: return jsonify({'error': f'Failed to list files: {str(e)}'}), 500 @bp.route('/upload', methods=['PUT', 'POST']) @require_auth def upload_file(): """Upload a file to Nextcloud.""" nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 # Get target path from query parameter or form data target_path = request.args.get('path') or request.form.get('path') if not target_path: return jsonify({'error': 'Target path is required'}), 400 # Get file data if 'file' in request.files: # Multipart upload file = request.files['file'] file_data = file.read() filename = file.filename else: # Raw binary upload file_data = request.get_data() filename = request.args.get('filename', 'upload.jpg') if not file_data: return jsonify({'error': 'No file data provided'}), 400 # Construct full path full_path = f"{target_path.rstrip('/')}/{filename}" try: result = nc_client.put_file(full_path, file_data) return jsonify({ 'success': True, 'path': full_path, 'url': result.get('url', '') }), 200 except Exception as e: return jsonify({'error': f'Upload failed: {str(e)}'}), 500 @bp.route('/verify', methods=['HEAD', 'GET']) @require_auth def verify_file(): """Verify that a file exists on Nextcloud.""" path = request.args.get('path') if not path: return jsonify({'error': 'Path is required'}), 400 nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 try: exists = nc_client.head(path) if exists: return jsonify({'exists': True}), 200 else: return jsonify({'exists': False}), 404 except Exception as e: return jsonify({'error': f'Verification failed: {str(e)}'}), 500 @bp.route('/mkdir', methods=['POST']) @require_auth def make_directory(): """Create a new directory on Nextcloud.""" data = request.get_json() if not data or 'path' not in data: return jsonify({'error': 'Path is required'}), 400 path = data['path'] nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 try: nc_client.mkcol(path) return jsonify({'success': True, 'path': path}), 201 except Exception as e: return jsonify({'error': f'Failed to create directory: {str(e)}'}), 500 @bp.route('/rename', methods=['POST']) @require_auth def rename_file(): """Rename or move a file on Nextcloud.""" data = request.get_json() if not data or 'source' not in data or 'destination' not in data: return jsonify({'error': 'Source and destination paths are required'}), 400 source = data['source'] destination = data['destination'] nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 try: nc_client.move(source, destination) return jsonify({ 'success': True, 'source': source, 'destination': destination }), 200 except Exception as e: return jsonify({'error': f'Failed to rename file: {str(e)}'}), 500 @bp.route('/thumbnail', methods=['GET']) @require_auth def get_thumbnail(): """Generate and return a thumbnail of an image file.""" path = request.args.get('path') size = request.args.get('size', '256') if not path: return jsonify({'error': 'Path is required'}), 400 try: size = int(size) if size < 32 or size > 1024: size = 256 except ValueError: size = 256 nc_client = _get_nc_client() if not nc_client: return jsonify({'error': 'Not authenticated'}), 401 try: # Download the file from Nextcloud file_data = nc_client.get_file(path) # Open image and create thumbnail image = Image.open(BytesIO(file_data)) # Convert to RGB if necessary (for PNG with transparency, etc.) if image.mode not in ('RGB', 'L'): image = image.convert('RGB') # Create thumbnail maintaining aspect ratio image.thumbnail((size, size), Image.Resampling.LANCZOS) # Save to BytesIO output = BytesIO() image.save(output, format='JPEG', quality=85) output.seek(0) return send_file( output, mimetype='image/jpeg', as_attachment=False, download_name=f'thumbnail_{size}.jpg' ) except Exception as e: return jsonify({'error': f'Failed to generate thumbnail: {str(e)}'}), 500