|
|
@@ -1,254 +1,307 @@
|
|
|
import os
|
|
|
-import argparse
|
|
|
+import sqlite3
|
|
|
import uuid
|
|
|
-import shutil
|
|
|
+import hashlib
|
|
|
+import threading
|
|
|
+import time
|
|
|
+import secrets
|
|
|
+import string
|
|
|
+import argparse
|
|
|
from datetime import datetime, timedelta
|
|
|
-from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for
|
|
|
from werkzeug.utils import secure_filename
|
|
|
-from dotenv import load_dotenv
|
|
|
-import json
|
|
|
-from database import init_database, save_file, get_file_by_id, get_all_files, delete_file, hard_delete_file, increment_download_count, cleanup_expired_files, get_file_stats
|
|
|
+from flask import Flask, request, jsonify, render_template, send_from_directory, abort
|
|
|
+from werkzeug.security import generate_password_hash
|
|
|
+import re
|
|
|
|
|
|
-# Cargar variables de entorno desde .env
|
|
|
-load_dotenv()
|
|
|
+def generate_secret_key(length=32):
|
|
|
+ """Generate a random secret key with specified length"""
|
|
|
+ alphabet = string.ascii_letters + string.digits + string.punctuation
|
|
|
+ return ''.join(secrets.choice(alphabet) for _ in range(length))
|
|
|
|
|
|
-app = Flask(__name__)
|
|
|
-app.config['MAX_CONTENT_LENGTH'] = int(os.getenv('MAX_FILE_SIZE', 16 * 1024 * 1024)) # 16MB max file size
|
|
|
-app.config['UPLOAD_FOLDER'] = os.getenv('UPLOAD_FOLDER', 'uploads')
|
|
|
-app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'tu_clave_secreta_aqui')
|
|
|
-
|
|
|
-# Manejador de errores para archivos demasiado grandes
|
|
|
-@app.errorhandler(413)
|
|
|
-def too_large(e):
|
|
|
- return jsonify({
|
|
|
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {app.config["MAX_CONTENT_LENGTH"] // (1024*1024)}MB'
|
|
|
- }), 413
|
|
|
-
|
|
|
-# Manejador de errores general
|
|
|
-@app.errorhandler(500)
|
|
|
-def internal_error(e):
|
|
|
- return jsonify({'error': 'Error interno del servidor'}), 500
|
|
|
-
|
|
|
-@app.errorhandler(404)
|
|
|
-def not_found(e):
|
|
|
- return jsonify({'error': 'Página no encontrada'}), 404
|
|
|
-
|
|
|
-# Verificar y crear carpeta de uploads si no existe
|
|
|
-def ensure_upload_folder():
|
|
|
- if not os.path.exists(app.config['UPLOAD_FOLDER']):
|
|
|
- os.makedirs(app.config['UPLOAD_FOLDER'])
|
|
|
- print(f"Carpeta '{app.config['UPLOAD_FOLDER']}' creada automáticamente.")
|
|
|
-
|
|
|
-# Inicializar base de datos
|
|
|
-def init_app():
|
|
|
- ensure_upload_folder()
|
|
|
- init_database()
|
|
|
- print("Base de datos inicializada correctamente.")
|
|
|
-
|
|
|
-# Configurar argumentos de línea de comandos
|
|
|
def parse_arguments():
|
|
|
- parser = argparse.ArgumentParser(description='Servidor de archivos temporales')
|
|
|
- parser.add_argument('--host', default=os.getenv('HOST', '127.0.0.1'), help='Host del servidor (default: 127.0.0.1)')
|
|
|
- parser.add_argument('--port', type=int, default=int(os.getenv('PORT', 5000)), help='Puerto del servidor (default: 5000)')
|
|
|
- parser.add_argument('--https', action='store_true', help='Usar HTTPS')
|
|
|
- parser.add_argument('--debug', action='store_true', default=os.getenv('DEBUG', 'False').lower() == 'true', help='Modo debug')
|
|
|
+ """Parse command line arguments"""
|
|
|
+ parser = argparse.ArgumentParser(description='Flask Temporary File Upload Server')
|
|
|
+ parser.add_argument('--host', default='127.0.0.1', help='Host to bind to (default: 127.0.0.1)')
|
|
|
+ parser.add_argument('--port', type=int, default=5000, help='Port to bind to (default: 5000)')
|
|
|
+ parser.add_argument('--debug', action='store_true', help='Enable debug mode')
|
|
|
+ parser.add_argument('--base-url', default=None, help='Base URL for download links (e.g., https://mysite.com)')
|
|
|
+ parser.add_argument('--network', action='store_true', help='Bind to all network interfaces (0.0.0.0)')
|
|
|
+ parser.add_argument('--max-file-size', type=int, default=16, help='Maximum file size in MB (default: 16)')
|
|
|
return parser.parse_args()
|
|
|
|
|
|
-@app.route('/')
|
|
|
-def index():
|
|
|
- """Página principal para subir archivos"""
|
|
|
- # Pasar configuración al template
|
|
|
- max_file_size = app.config['MAX_CONTENT_LENGTH']
|
|
|
- max_file_size_mb = max_file_size // (1024 * 1024)
|
|
|
+# Parse command line arguments
|
|
|
+args = parse_arguments()
|
|
|
+
|
|
|
+# Set host based on arguments
|
|
|
+if args.network:
|
|
|
+ HOST = '0.0.0.0'
|
|
|
+else:
|
|
|
+ HOST = args.host
|
|
|
+
|
|
|
+# Set base URL for download links
|
|
|
+BASE_URL = args.base_url or os.environ.get('BASE_URL', f'http://{HOST}:{args.port}')
|
|
|
+
|
|
|
+# Validate max file size
|
|
|
+if args.max_file_size <= 0:
|
|
|
+ print("❌ Error: Maximum file size must be a positive integer")
|
|
|
+ exit(1)
|
|
|
+
|
|
|
+app = Flask(__name__)
|
|
|
+app.config['SECRET_KEY'] = generate_secret_key(32)
|
|
|
+app.config['UPLOAD_FOLDER'] = 'uploads'
|
|
|
+app.config['MAX_CONTENT_LENGTH'] = args.max_file_size * 1024 * 1024 # Convert MB to bytes
|
|
|
+app.config['BASE_URL'] = BASE_URL
|
|
|
+
|
|
|
+# Ensure upload directory exists
|
|
|
+os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
|
|
+
|
|
|
+# Database initialization
|
|
|
+def init_db():
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+ cursor.execute('''
|
|
|
+ CREATE TABLE IF NOT EXISTS files (
|
|
|
+ id TEXT PRIMARY KEY,
|
|
|
+ original_filename TEXT NOT NULL,
|
|
|
+ sanitized_filename TEXT NOT NULL,
|
|
|
+ file_path TEXT NOT NULL,
|
|
|
+ user_session TEXT NOT NULL,
|
|
|
+ upload_date TEXT NOT NULL,
|
|
|
+ expiration_date TEXT NOT NULL,
|
|
|
+ duration_hours INTEGER NOT NULL,
|
|
|
+ file_size INTEGER NOT NULL,
|
|
|
+ mime_type TEXT
|
|
|
+ )
|
|
|
+ ''')
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+def sanitize_filename(filename):
|
|
|
+ """Sanitize filename for safe storage"""
|
|
|
+ # Remove special characters and spaces
|
|
|
+ name, ext = os.path.splitext(filename)
|
|
|
+ sanitized = re.sub(r'[^a-zA-Z0-9_-]', '_', name)
|
|
|
+ # Generate unique identifier
|
|
|
+ unique_id = str(uuid.uuid4())[:8]
|
|
|
+ return f"{sanitized}_{unique_id}{ext}"
|
|
|
+
|
|
|
+def cleanup_expired_files():
|
|
|
+ """Remove expired files from database and filesystem"""
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+
|
|
|
+ # Get expired files
|
|
|
+ cursor.execute('''
|
|
|
+ SELECT file_path FROM files
|
|
|
+ WHERE expiration_date < ?
|
|
|
+ ''', (datetime.now().isoformat(),))
|
|
|
|
|
|
- return render_template('index.html',
|
|
|
- max_file_size=max_file_size,
|
|
|
- max_file_size_mb=max_file_size_mb)
|
|
|
+ expired_files = cursor.fetchall()
|
|
|
+
|
|
|
+ # Delete files from filesystem
|
|
|
+ for (file_path,) in expired_files:
|
|
|
+ full_path = os.path.join(app.config['UPLOAD_FOLDER'], file_path)
|
|
|
+ try:
|
|
|
+ if os.path.exists(full_path):
|
|
|
+ os.remove(full_path)
|
|
|
+ print(f"Deleted expired file: {file_path}")
|
|
|
+ except Exception as e:
|
|
|
+ print(f"Error deleting file {file_path}: {e}")
|
|
|
+
|
|
|
+ # Remove from database
|
|
|
+ cursor.execute('DELETE FROM files WHERE expiration_date < ?',
|
|
|
+ (datetime.now().isoformat(),))
|
|
|
+
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
+ print(f"Cleaned up {len(expired_files)} expired files")
|
|
|
+
|
|
|
+def cleanup_worker():
|
|
|
+ """Background worker to cleanup expired files every 10 minutes"""
|
|
|
+ while True:
|
|
|
+ time.sleep(600) # 10 minutes
|
|
|
+ cleanup_expired_files()
|
|
|
|
|
|
-@app.route('/myfiles')
|
|
|
-def myfiles():
|
|
|
- """Página para ver enlaces guardados en localStorage"""
|
|
|
- return render_template('myfiles.html')
|
|
|
+@app.route('/')
|
|
|
+def index():
|
|
|
+ max_file_size = app.config['MAX_CONTENT_LENGTH'] // (1024 * 1024) # Convert bytes to MB
|
|
|
+ return render_template('index.html', max_file_size=max_file_size)
|
|
|
|
|
|
@app.route('/upload', methods=['POST'])
|
|
|
def upload_file():
|
|
|
- """Manejar la subida de archivos"""
|
|
|
- try:
|
|
|
- # Verificar si hay archivo en la request
|
|
|
- if 'file' not in request.files:
|
|
|
- return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
|
|
|
-
|
|
|
- file = request.files['file']
|
|
|
- if file.filename == '':
|
|
|
- return jsonify({'error': 'No se seleccionó ningún archivo'}), 400
|
|
|
-
|
|
|
- # Obtener tiempo de vida del archivo (por defecto 24 horas)
|
|
|
- expires_hours = request.form.get('expires_hours', 24, type=int)
|
|
|
+ if 'file' not in request.files:
|
|
|
+ return jsonify({'error': 'No file provided'}), 400
|
|
|
+
|
|
|
+ file = request.files['file']
|
|
|
+ user_session = request.form.get('user_session')
|
|
|
+ duration_hours = int(request.form.get('duration_hours', 24))
|
|
|
+
|
|
|
+ if file.filename == '':
|
|
|
+ return jsonify({'error': 'No file selected'}), 400
|
|
|
+
|
|
|
+ if not user_session:
|
|
|
+ return jsonify({'error': 'No user session provided'}), 400
|
|
|
+
|
|
|
+ if file:
|
|
|
+ # Generate file info
|
|
|
+ file_id = str(uuid.uuid4())
|
|
|
+ original_filename = file.filename
|
|
|
+ sanitized_filename = sanitize_filename(original_filename)
|
|
|
+ upload_date = datetime.now()
|
|
|
+ expiration_date = upload_date + timedelta(hours=duration_hours)
|
|
|
|
|
|
- # Validar tiempo de vida (entre 1 hora y 7 días)
|
|
|
- if expires_hours < 1 or expires_hours > 168: # 168 horas = 7 días
|
|
|
- expires_hours = 24
|
|
|
+ # Save file
|
|
|
+ file_path = sanitized_filename
|
|
|
+ full_path = os.path.join(app.config['UPLOAD_FOLDER'], file_path)
|
|
|
+ file.save(full_path)
|
|
|
|
|
|
- # Validar tamaño del archivo antes de procesar
|
|
|
- max_size = app.config['MAX_CONTENT_LENGTH']
|
|
|
- max_size_mb = max_size // (1024 * 1024)
|
|
|
+ # Get file info
|
|
|
+ file_size = os.path.getsize(full_path)
|
|
|
+ mime_type = file.content_type
|
|
|
|
|
|
- # Verificar content_length si está disponible
|
|
|
- if request.content_length and request.content_length > max_size:
|
|
|
- return jsonify({
|
|
|
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
|
|
|
- }), 413
|
|
|
+ # Save to database
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+ cursor.execute('''
|
|
|
+ INSERT INTO files (id, original_filename, sanitized_filename, file_path,
|
|
|
+ user_session, upload_date, expiration_date, duration_hours,
|
|
|
+ file_size, mime_type)
|
|
|
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ ''', (file_id, original_filename, sanitized_filename, file_path, user_session,
|
|
|
+ upload_date.isoformat(), expiration_date.isoformat(), duration_hours,
|
|
|
+ file_size, mime_type))
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
|
|
|
- # Verificar el tamaño del archivo después de recibirlo
|
|
|
- if file:
|
|
|
- # Leer el archivo en chunks para verificar el tamaño
|
|
|
- file.seek(0, 2) # Ir al final del archivo
|
|
|
- file_size = file.tell()
|
|
|
- file.seek(0) # Volver al inicio
|
|
|
-
|
|
|
- if file_size > max_size:
|
|
|
- return jsonify({
|
|
|
- 'error': f'El archivo es demasiado grande. Tamaño máximo: {max_size_mb}MB'
|
|
|
- }), 413
|
|
|
-
|
|
|
- # Generar nombre único para el archivo
|
|
|
- original_filename = file.filename
|
|
|
- if not original_filename:
|
|
|
- return jsonify({'error': 'Nombre de archivo no válido'}), 400
|
|
|
-
|
|
|
- filename = secure_filename(original_filename)
|
|
|
- if not filename:
|
|
|
- return jsonify({'error': 'Nombre de archivo no válido'}), 400
|
|
|
-
|
|
|
- file_id = str(uuid.uuid4())
|
|
|
- file_extension = os.path.splitext(filename)[1]
|
|
|
- unique_filename = f"{file_id}{file_extension}"
|
|
|
-
|
|
|
- # Guardar archivo
|
|
|
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
|
|
|
- file.save(file_path)
|
|
|
-
|
|
|
- # Guardar en base de datos con el tiempo de vida especificado
|
|
|
- save_file(file_id, original_filename, unique_filename, file_size, expires_hours)
|
|
|
-
|
|
|
- # Crear enlace temporal con el tiempo de vida especificado
|
|
|
- # Usar el dominio configurado o el host actual
|
|
|
- domain = os.getenv('DOMAIN', request.host)
|
|
|
- protocol = 'https' if args.https else 'http'
|
|
|
- download_url = f"{protocol}://{domain}/download/{file_id}"
|
|
|
-
|
|
|
- return jsonify({
|
|
|
- 'success': True,
|
|
|
- 'download_url': download_url,
|
|
|
- 'file_id': file_id,
|
|
|
- 'original_filename': original_filename,
|
|
|
- 'expires_at': (datetime.now() + timedelta(hours=expires_hours)).isoformat()
|
|
|
- })
|
|
|
- else:
|
|
|
- return jsonify({'error': 'No se pudo procesar el archivo'}), 400
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- print(f"Error en upload: {str(e)}")
|
|
|
- return jsonify({'error': 'Error interno del servidor'}), 500
|
|
|
+ return jsonify({
|
|
|
+ 'success': True,
|
|
|
+ 'file_id': file_id,
|
|
|
+ 'original_filename': original_filename,
|
|
|
+ 'download_url': f'{app.config["BASE_URL"]}/download/{file_id}',
|
|
|
+ 'expiration_date': expiration_date.isoformat(),
|
|
|
+ 'file_size': file_size
|
|
|
+ })
|
|
|
+
|
|
|
+@app.route('/files/<user_session>')
|
|
|
+def get_user_files(user_session):
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+ cursor.execute('''
|
|
|
+ SELECT id, original_filename, upload_date, expiration_date,
|
|
|
+ duration_hours, file_size, mime_type
|
|
|
+ FROM files
|
|
|
+ WHERE user_session = ? AND expiration_date > ?
|
|
|
+ ORDER BY upload_date DESC
|
|
|
+ ''', (user_session, datetime.now().isoformat()))
|
|
|
+
|
|
|
+ files = cursor.fetchall()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+ file_list = []
|
|
|
+ for file_data in files:
|
|
|
+ file_list.append({
|
|
|
+ 'id': file_data[0],
|
|
|
+ 'original_filename': file_data[1],
|
|
|
+ 'upload_date': file_data[2],
|
|
|
+ 'expiration_date': file_data[3],
|
|
|
+ 'duration_hours': file_data[4],
|
|
|
+ 'file_size': file_data[5],
|
|
|
+ 'mime_type': file_data[6],
|
|
|
+ 'download_url': f'{app.config["BASE_URL"]}/download/{file_data[0]}'
|
|
|
+ })
|
|
|
+
|
|
|
+ return jsonify(file_list)
|
|
|
|
|
|
@app.route('/download/<file_id>')
|
|
|
def download_file(file_id):
|
|
|
- """Descargar archivo por ID"""
|
|
|
- # Buscar archivo en la base de datos
|
|
|
- file_info = get_file_by_id(file_id)
|
|
|
- if not file_info:
|
|
|
- return "Archivo no encontrado", 404
|
|
|
-
|
|
|
- # Verificar si el archivo ha expirado
|
|
|
- expires_at = datetime.fromisoformat(file_info['expires_at'])
|
|
|
- if expires_at <= datetime.now():
|
|
|
- return "Archivo expirado", 410
|
|
|
-
|
|
|
- # Verificar si el archivo existe físicamente
|
|
|
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_info['stored_filename'])
|
|
|
- if not os.path.exists(file_path):
|
|
|
- return "Archivo no encontrado", 404
|
|
|
-
|
|
|
- # Incrementar contador de descargas
|
|
|
- increment_download_count(file_id)
|
|
|
-
|
|
|
- # Enviar archivo
|
|
|
- return send_file(file_path, as_attachment=True, download_name=file_info['original_filename'])
|
|
|
-
|
|
|
-@app.route('/api/links')
|
|
|
-def get_links():
|
|
|
- """API para obtener enlaces guardados desde la base de datos"""
|
|
|
- try:
|
|
|
- files = get_all_files()
|
|
|
- links = []
|
|
|
-
|
|
|
- for file_info in files:
|
|
|
- # Crear URL de descarga
|
|
|
- domain = os.getenv('DOMAIN', request.host)
|
|
|
- protocol = 'https' if args.https else 'http'
|
|
|
- download_url = f"{protocol}://{domain}/download/{file_info['id']}"
|
|
|
-
|
|
|
- links.append({
|
|
|
- 'id': file_info['id'],
|
|
|
- 'filename': file_info['original_filename'],
|
|
|
- 'url': download_url,
|
|
|
- 'created_at': file_info['created_at'],
|
|
|
- 'expires_at': file_info['expires_at'],
|
|
|
- 'file_size': file_info['file_size'],
|
|
|
- 'download_count': file_info['download_count']
|
|
|
- })
|
|
|
-
|
|
|
- return jsonify(links)
|
|
|
- except Exception as e:
|
|
|
- print(f"Error obteniendo enlaces: {str(e)}")
|
|
|
- return jsonify({'error': 'Error interno del servidor'}), 500
|
|
|
-
|
|
|
-@app.route('/api/delete/<file_id>', methods=['DELETE'])
|
|
|
-def delete_link(file_id):
|
|
|
- """API para eliminar un enlace permanentemente"""
|
|
|
- try:
|
|
|
- # Obtener información del archivo
|
|
|
- file_info = get_file_by_id(file_id)
|
|
|
- if not file_info:
|
|
|
- return jsonify({'error': 'Archivo no encontrado'}), 404
|
|
|
-
|
|
|
- # Eliminar archivo físico
|
|
|
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_info['stored_filename'])
|
|
|
- if os.path.exists(file_path):
|
|
|
- os.remove(file_path)
|
|
|
-
|
|
|
- # Eliminar permanentemente de la base de datos
|
|
|
- hard_delete_file(file_id)
|
|
|
-
|
|
|
- return jsonify({'success': True, 'message': 'Archivo eliminado permanentemente'})
|
|
|
- except Exception as e:
|
|
|
- print(f"Error eliminando archivo: {str(e)}")
|
|
|
- return jsonify({'error': 'Error interno del servidor'}), 500
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+ cursor.execute('''
|
|
|
+ SELECT original_filename, file_path, expiration_date
|
|
|
+ FROM files
|
|
|
+ WHERE id = ?
|
|
|
+ ''', (file_id,))
|
|
|
+
|
|
|
+ file_data = cursor.fetchone()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+ if not file_data:
|
|
|
+ abort(404)
|
|
|
+
|
|
|
+ original_filename, file_path, expiration_date = file_data
|
|
|
+
|
|
|
+ # Check if file has expired
|
|
|
+ if datetime.fromisoformat(expiration_date) < datetime.now():
|
|
|
+ abort(410) # Gone
|
|
|
+
|
|
|
+ # Check if file exists
|
|
|
+ full_path = os.path.join(app.config['UPLOAD_FOLDER'], file_path)
|
|
|
+ if not os.path.exists(full_path):
|
|
|
+ abort(404)
|
|
|
+
|
|
|
+ return send_from_directory(app.config['UPLOAD_FOLDER'], file_path,
|
|
|
+ as_attachment=True, download_name=original_filename)
|
|
|
|
|
|
-@app.route('/api/stats')
|
|
|
-def get_stats():
|
|
|
- """API para obtener estadísticas"""
|
|
|
+@app.route('/delete/<file_id>', methods=['DELETE'])
|
|
|
+def delete_file(file_id):
|
|
|
+ user_session = request.json.get('user_session')
|
|
|
+
|
|
|
+ if not user_session:
|
|
|
+ return jsonify({'error': 'No user session provided'}), 400
|
|
|
+
|
|
|
+ conn = sqlite3.connect('files.db')
|
|
|
+ cursor = conn.cursor()
|
|
|
+
|
|
|
+ # Get file info and verify ownership
|
|
|
+ cursor.execute('''
|
|
|
+ SELECT file_path FROM files
|
|
|
+ WHERE id = ? AND user_session = ?
|
|
|
+ ''', (file_id, user_session))
|
|
|
+
|
|
|
+ file_data = cursor.fetchone()
|
|
|
+
|
|
|
+ if not file_data:
|
|
|
+ conn.close()
|
|
|
+ return jsonify({'error': 'File not found or unauthorized'}), 404
|
|
|
+
|
|
|
+ file_path = file_data[0]
|
|
|
+
|
|
|
+ # Delete from filesystem
|
|
|
+ full_path = os.path.join(app.config['UPLOAD_FOLDER'], file_path)
|
|
|
try:
|
|
|
- stats = get_file_stats()
|
|
|
- return jsonify(stats)
|
|
|
+ if os.path.exists(full_path):
|
|
|
+ os.remove(full_path)
|
|
|
except Exception as e:
|
|
|
- print(f"Error obteniendo estadísticas: {str(e)}")
|
|
|
- return jsonify({'error': 'Error interno del servidor'}), 500
|
|
|
+ print(f"Error deleting file {file_path}: {e}")
|
|
|
+
|
|
|
+ # Delete from database
|
|
|
+ cursor.execute('DELETE FROM files WHERE id = ? AND user_session = ?',
|
|
|
+ (file_id, user_session))
|
|
|
+
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+ return jsonify({'success': True})
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
- args = parse_arguments()
|
|
|
+ # Print configuration info
|
|
|
+ print(f"🚀 Starting Flask Temporary File Upload Server")
|
|
|
+ print(f"📁 Upload folder: {app.config['UPLOAD_FOLDER']}")
|
|
|
+ print(f"🔑 Secret key: {app.config['SECRET_KEY'][:8]}... (32 chars)")
|
|
|
+ print(f"🌐 Base URL: {app.config['BASE_URL']}")
|
|
|
+ print(f"🖥️ Server: http://{HOST}:{args.port}")
|
|
|
+ print(f"🔒 Max file size: {args.max_file_size}MB")
|
|
|
+ print(f"⏰ Cleanup interval: 10 minutes")
|
|
|
+ print(f"🐛 Debug mode: {'ON' if args.debug else 'OFF'}")
|
|
|
+ print("-" * 50)
|
|
|
|
|
|
- # Inicializar aplicación (carpeta de uploads y base de datos)
|
|
|
- init_app()
|
|
|
+ init_db()
|
|
|
|
|
|
- # Configurar protocolo
|
|
|
- protocol = 'https' if args.https else 'http'
|
|
|
+ # Start cleanup worker in background
|
|
|
+ cleanup_thread = threading.Thread(target=cleanup_worker, daemon=True)
|
|
|
+ cleanup_thread.start()
|
|
|
|
|
|
- print(f"Servidor iniciando en {protocol}://{args.host}:{args.port}")
|
|
|
- print(f"Modo debug: {'Activado' if args.debug else 'Desactivado'}")
|
|
|
+ # Initial cleanup
|
|
|
+ cleanup_expired_files()
|
|
|
|
|
|
- app.run(
|
|
|
- host=args.host,
|
|
|
- port=args.port,
|
|
|
- debug=args.debug
|
|
|
- )
|
|
|
+ app.run(debug=args.debug, host=HOST, port=args.port)
|