基础的切片和质量控制
This commit is contained in:
229
app/routes.py
Normal file
229
app/routes.py
Normal file
@@ -0,0 +1,229 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, session, make_response, send_file, abort, jsonify
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from werkzeug.utils import secure_filename
|
||||
from .models import db, User, PrintFile, SystemConfig
|
||||
import os
|
||||
import uuid
|
||||
import configparser
|
||||
from datetime import datetime
|
||||
from .tasks import slice_stl_task
|
||||
|
||||
main_bp = Blueprint('main', __name__)
|
||||
|
||||
def get_quality_presets():
|
||||
preset_dir = os.path.join(current_app.root_path, '..', 'print_config', 'presets', 'creality', 'base')
|
||||
presets = []
|
||||
if os.path.exists(preset_dir):
|
||||
for f in os.listdir(preset_dir):
|
||||
if f.startswith('base_global_') and f.endswith('.inst.cfg'):
|
||||
config = configparser.ConfigParser()
|
||||
try:
|
||||
config.read(os.path.join(preset_dir, f))
|
||||
name = config.get('general', 'name', fallback=f)
|
||||
presets.append((f, name))
|
||||
except Exception as e:
|
||||
pass
|
||||
# Custom sort order or alphanumeric
|
||||
return sorted(presets, key=lambda x: x[1])
|
||||
|
||||
auth_bp = Blueprint('auth', __name__, url_prefix='/auth')
|
||||
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
|
||||
|
||||
# Guest User Middleware
|
||||
@main_bp.before_app_request
|
||||
def assign_guest_cookie():
|
||||
if not current_user.is_authenticated:
|
||||
guest_id = request.cookies.get('guest_id')
|
||||
if not guest_id:
|
||||
guest_id = str(uuid.uuid4())
|
||||
user = User(username=f'guest_{guest_id[:8]}', is_guest=True, guest_cookie_id=guest_id)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
login_user(user)
|
||||
# We will set the cookie in the response after request, see below
|
||||
request.guest_id_to_set = guest_id
|
||||
else:
|
||||
user = User.query.filter_by(guest_cookie_id=guest_id).first()
|
||||
if user:
|
||||
login_user(user)
|
||||
|
||||
@main_bp.after_app_request
|
||||
def set_guest_cookie(response):
|
||||
if hasattr(request, 'guest_id_to_set'):
|
||||
response.set_cookie('guest_id', request.guest_id_to_set, max_age=60*60*24*365) # 1 year
|
||||
return response
|
||||
|
||||
# --- Main Routes ---
|
||||
|
||||
@main_bp.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@main_bp.route('/set_language/<lang>')
|
||||
def set_language(lang):
|
||||
from app import i18n_dict
|
||||
if lang not in i18n_dict:
|
||||
lang = 'en'
|
||||
# return to previous page
|
||||
response = make_response(redirect(request.referrer or url_for('main.index')))
|
||||
response.set_cookie('lang', lang, max_age=60*60*24*365)
|
||||
return response
|
||||
|
||||
@main_bp.route('/slice', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def slice_page():
|
||||
if request.method == 'POST':
|
||||
if 'file' not in request.files:
|
||||
flash('No file part', 'danger')
|
||||
return redirect(request.url)
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
flash('No selected file', 'danger')
|
||||
return redirect(request.url)
|
||||
if file and file.filename.lower().endswith('.stl'):
|
||||
original_filename = file.filename # Do not use secure_filename to keep Chinese characters
|
||||
ext = os.path.splitext(original_filename)[1].lower()
|
||||
if not ext:
|
||||
ext = '.stl'
|
||||
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
|
||||
unique_filename = f"{timestamp}_{uuid.uuid4().hex}{ext}"
|
||||
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], unique_filename)
|
||||
file.save(filepath)
|
||||
|
||||
print_file = PrintFile(
|
||||
filename=unique_filename,
|
||||
original_filename=original_filename,
|
||||
file_type='stl',
|
||||
user_id=current_user.id,
|
||||
status='waiting'
|
||||
)
|
||||
db.session.add(print_file)
|
||||
db.session.commit()
|
||||
|
||||
# Start slicing task
|
||||
quality_preset = request.form.get('quality', 'base_global_standard.inst.cfg')
|
||||
slice_stl_task(print_file.id, filepath, quality_preset)
|
||||
flash('File uploaded and slicing started!', 'success')
|
||||
response = make_response(redirect(url_for('main.files')))
|
||||
response.set_cookie('last_quality_preset', quality_preset, max_age=60*60*24*365)
|
||||
return response
|
||||
|
||||
presets = get_quality_presets()
|
||||
last_quality = request.cookies.get('last_quality_preset', 'base_global_standard.inst.cfg')
|
||||
return render_template('slice.html', presets=presets, last_quality=last_quality)
|
||||
|
||||
@main_bp.route('/files')
|
||||
@login_required
|
||||
def files():
|
||||
# Order by newest first
|
||||
user_files = PrintFile.query.filter_by(user_id=current_user.id).order_by(PrintFile.created_at.desc()).all()
|
||||
return render_template('files.html', files=user_files)
|
||||
|
||||
@main_bp.route('/api/files_status')
|
||||
@login_required
|
||||
def files_status():
|
||||
files = PrintFile.query.filter_by(user_id=current_user.id).all()
|
||||
return jsonify({str(f.id): f.status for f in files})
|
||||
|
||||
@main_bp.route('/download/<int:file_id>')
|
||||
@login_required
|
||||
def download_gcode(file_id):
|
||||
print_file = PrintFile.query.get_or_404(file_id)
|
||||
if print_file.user_id != current_user.id and not current_user.is_admin:
|
||||
abort(403)
|
||||
if print_file.status != 'sliced':
|
||||
flash('File is not ready yet.', 'warning')
|
||||
return redirect(url_for('main.files'))
|
||||
|
||||
gcode_filename = print_file.filename.rsplit('.', 1)[0] + '.gcode'
|
||||
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], gcode_filename)
|
||||
|
||||
if os.path.exists(filepath):
|
||||
safe_name = print_file.original_filename.rsplit('.', 1)[0] + '.gcode'
|
||||
return send_file(filepath, as_attachment=True, download_name=safe_name)
|
||||
flash('GCode file not found. It might have been deleted.', 'danger')
|
||||
return redirect(url_for('main.files'))
|
||||
|
||||
@main_bp.route('/preview_gcode/<int:file_id>')
|
||||
@login_required
|
||||
def preview_gcode(file_id):
|
||||
print_file = PrintFile.query.get_or_404(file_id)
|
||||
if print_file.user_id != current_user.id and not current_user.is_admin:
|
||||
abort(403)
|
||||
|
||||
gcode_filename = print_file.filename.rsplit('.', 1)[0] + '.gcode'
|
||||
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], gcode_filename)
|
||||
|
||||
content = "File not found or not ready."
|
||||
line_count = 0
|
||||
if os.path.exists(filepath):
|
||||
with open(filepath, 'r') as f:
|
||||
lines = f.readlines()
|
||||
line_count = len(lines)
|
||||
content = "".join(lines[:500]) # Preview first 500 lines
|
||||
if line_count > 500:
|
||||
content += f"\n... \n[Preview truncated. Total lines: {line_count}. Please download to view full file.]"
|
||||
|
||||
return render_template('gcode_preview.html', file=print_file, content=content, line_count=line_count)
|
||||
|
||||
@main_bp.route('/delete_file/<int:file_id>', methods=['POST'])
|
||||
@login_required
|
||||
def delete_file(file_id):
|
||||
print_file = PrintFile.query.get_or_404(file_id)
|
||||
if print_file.user_id != current_user.id and not current_user.is_admin:
|
||||
abort(403)
|
||||
|
||||
stl_path = os.path.join(current_app.config['UPLOAD_FOLDER'], print_file.filename)
|
||||
gcode_filename = print_file.filename.rsplit('.', 1)[0] + '.gcode'
|
||||
gcode_path = os.path.join(current_app.config['UPLOAD_FOLDER'], gcode_filename)
|
||||
|
||||
if os.path.exists(stl_path):
|
||||
os.remove(stl_path)
|
||||
if os.path.exists(gcode_path):
|
||||
os.remove(gcode_path)
|
||||
|
||||
db.session.delete(print_file)
|
||||
db.session.commit()
|
||||
flash(f"Deleted {print_file.original_filename} successfully.", 'success')
|
||||
return redirect(url_for('main.files'))
|
||||
|
||||
# --- Auth Routes ---
|
||||
|
||||
@auth_bp.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
username = request.form.get('username')
|
||||
password = request.form.get('password')
|
||||
user = User.query.filter_by(username=username, is_guest=False).first()
|
||||
if user and check_password_hash(user.password_hash, password):
|
||||
login_user(user)
|
||||
return redirect(url_for('main.index'))
|
||||
flash('Invalid username or password', 'danger')
|
||||
return render_template('login.html')
|
||||
|
||||
@auth_bp.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
response = make_response(redirect(url_for('main.index')))
|
||||
response.delete_cookie('guest_id') # Optionally clear guest cookie
|
||||
return response
|
||||
|
||||
# --- Admin Routes ---
|
||||
|
||||
@admin_bp.before_request
|
||||
def require_admin():
|
||||
if not current_user.is_authenticated or not current_user.is_admin:
|
||||
flash('Admin access required', 'danger')
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
@admin_bp.route('/settings')
|
||||
def settings():
|
||||
configs = SystemConfig.query.all()
|
||||
return render_template('admin_settings.html', configs=configs)
|
||||
|
||||
@admin_bp.route('/users')
|
||||
def users():
|
||||
all_users = User.query.order_by(User.created_at.desc()).all()
|
||||
return render_template('admin_users.html', users=all_users)
|
||||
Reference in New Issue
Block a user