import os
import shutil
from flask import Blueprint, request, render_template_string, send_from_directory, redirect, url_for, flash, session
from werkzeug.utils import secure_filename
def create_filemanager_blueprint(base_dir, url_prefix='/files', auth_password=None):
"""
Creates a Flask blueprint providing a simple file manager with a clipboard-style
move operation (cut/paste) for the given base directory.
"""
base_dir = os.path.abspath(base_dir)
os.makedirs(base_dir, exist_ok=True)
filemanager = Blueprint('filemanager', __name__, url_prefix=url_prefix)
def secure_path(path):
"""Ensure that the provided relative path stays within the base_dir."""
safe_path = os.path.abspath(os.path.join(base_dir, path))
if not safe_path.startswith(base_dir):
raise Exception("Invalid path")
return safe_path
@filemanager.before_request
def require_login():
if auth_password is not None:
# Allow access to login and logout pages without being authenticated.
if request.endpoint in ['filemanager.login', 'filemanager.logout']:
return None
if not session.get('filemanager_authenticated'):
return redirect(url_for('filemanager.login', next=request.url))
return None
@filemanager.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
password = request.form.get('password', '')
if password == auth_password:
session['filemanager_authenticated'] = True
flash("Logged in successfully")
next_url = request.args.get('next') or url_for('filemanager.index')
return redirect(next_url)
else:
flash("Incorrect password")
return render_template_string('''
Login
Login
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
''')
@filemanager.route('/logout', methods=['POST'])
def logout():
session.pop('filemanager_authenticated', None)
flash("Logged out")
return redirect(url_for('filemanager.login'))
@filemanager.route('/')
def index():
# Determine current directory from query parameter; defaults to the base.
rel_path = request.args.get('path', '')
try:
abs_path = secure_path(rel_path)
except Exception:
return "Invalid path", 400
if not os.path.isdir(abs_path):
return "Not a directory", 400
# Build a list of items (files and folders) in the current directory.
items = []
for entry in os.listdir(abs_path):
entry_path = os.path.join(abs_path, entry)
rel_entry_path = os.path.join(rel_path, entry) if rel_path else entry
items.append({
'name': entry,
'is_dir': os.path.isdir(entry_path),
'path': rel_entry_path
})
items.sort(key=lambda x: (not x['is_dir'], x['name'].lower()))
parent = os.path.dirname(rel_path) if rel_path else ''
# Minimal HTML template that displays the file tree along with a clipboard if active.
template = """
File Manager