暂存-说明文档(部分)

This commit is contained in:
2026-05-16 00:45:51 +08:00
parent 91bedce2d7
commit 9c8de5e664
63 changed files with 2818 additions and 92 deletions

View File

@@ -90,12 +90,40 @@ def settings():
def users():
all_users = User.query.order_by(User.created_at.desc()).all()
user_quotas = {}
# Load defaults
def_guest_stl = SystemConfig.query.filter_by(key="default_guest_stl_quota_mb").first()
def_guest_stl_val = def_guest_stl.value if def_guest_stl else '0'
def_guest_gcode = SystemConfig.query.filter_by(key="default_guest_gcode_quota_mb").first()
def_guest_gcode_val = def_guest_gcode.value if def_guest_gcode else '0'
def_user_stl = SystemConfig.query.filter_by(key="default_user_stl_quota_mb").first()
def_user_stl_val = def_user_stl.value if def_user_stl else '0'
def_user_gcode = SystemConfig.query.filter_by(key="default_user_gcode_quota_mb").first()
def_user_gcode_val = def_user_gcode.value if def_user_gcode else '0'
for u in all_users:
if u.is_admin:
eff_stl = '0'
eff_gcode = '0'
elif u.is_guest:
eff_stl = def_guest_stl_val
eff_gcode = def_guest_gcode_val
else:
eff_stl = def_user_stl_val
eff_gcode = def_user_gcode_val
sq = SystemConfig.query.filter_by(key=f"user_{u.id}_stl_quota_mb").first()
gq = SystemConfig.query.filter_by(key=f"user_{u.id}_gcode_quota_mb").first()
user_stl = sq.value if sq else '0'
user_gcode = gq.value if gq else '0'
user_quotas[u.id] = {
'stl': sq.value if sq else '0',
'gcode': gq.value if gq else '0'
'stl': user_stl,
'gcode': user_gcode,
'eff_stl': eff_stl if user_stl == '0' else user_stl,
'eff_gcode': eff_gcode if user_gcode == '0' else user_gcode,
}
return render_template('admin/users.html', users=all_users, user_quotas=user_quotas)

View File

@@ -35,6 +35,9 @@ def login():
if user and check_password_hash(user.password_hash, password):
# Clear old password check flag
session.pop('pwd_check_done', None)
session.pop('must_change_password', None)
login_user(user, remember=remember)
session_token = str(uuid.uuid4())
# 尝试获取反向代理传递的真实 IP

View File

@@ -21,6 +21,8 @@ main_bp = Blueprint('main', __name__)
def check_user_session():
if current_user.is_authenticated and not current_user.is_guest:
session_token = session.get('user_session_token')
client_ip = request.headers.get('X-Real-IP') or request.remote_addr
if session_token:
user_session = UserSession.query.filter_by(session_token=session_token).first()
if not user_session or not user_session.is_active:
@@ -30,7 +32,36 @@ def check_user_session():
return redirect(url_for('auth.login'))
else:
user_session.last_active = datetime.utcnow()
user_session.ip_address = client_ip
db.session.commit()
else:
# Re-authenticated via remember me, but no session token
new_session_token = str(uuid.uuid4())
user_session = UserSession(
user_id=current_user.id,
session_token=new_session_token,
ip_address=client_ip,
user_agent=request.user_agent.string,
last_active=datetime.utcnow()
)
db.session.add(user_session)
db.session.commit()
session['user_session_token'] = new_session_token
# Check default admin password securely without checking hash on every request
if current_user.is_admin:
if session.get('pwd_check_done') is None:
session['pwd_check_done'] = True
if check_password_hash(current_user.password_hash, 'admin123'):
session['must_change_password'] = True
else:
session.pop('must_change_password', None)
if session.get('must_change_password'):
if request.endpoint and request.endpoint not in ['main.account', 'auth.logout', 'static']:
flash('For security reasons, please change your default admin password.', 'warning')
return redirect(url_for('main.account'))
@@ -317,7 +348,7 @@ def preview_gcode(file_id):
engine_name = SystemConfig.query.filter_by(key='slicer_engine').first()
if engine_name:
engine = get_slicer_engine(str(engine_name.value), current_app.config['PRINT_CONFIG_FOLDER'])
engine = get_slicer_engine(str(engine_name.value), current_app.config['PRINT_CONFIG_FOLDER'], current_app.config['PRUSA_SLICE_BIN'])
w, h, hd = engine.get_bed_dimensions()
configs = {c.key: c.value for c in SystemConfig.query.all()}
offset_x = float(configs.get('offset_x', '0.0'))
@@ -365,7 +396,7 @@ def plater():
engine_name = SystemConfig.query.filter_by(key='slicer_engine').first()
if engine_name:
engine = get_slicer_engine(str(engine_name.value), current_app.config['PRINT_CONFIG_FOLDER'])
engine = get_slicer_engine(str(engine_name.value), current_app.config['PRINT_CONFIG_FOLDER'], current_app.config['PRUSA_SLICE_BIN'])
w, h, hd = engine.get_bed_dimensions()
print(f"Bed dimensions: {w}x{h}x{hd}")
@@ -384,6 +415,27 @@ def plater():
models = [{'id': f.id, 'name': f.original_filename, 'status': f.status, 'url': url_for('main.serve_proxy_file', file_id=f.id), 'transform_matrix': f.transform_matrix} for f in user_files]
return render_template('slice/plater.html', w=w, h=h, hd=hd, last_quality=default_quality, last_material=default_material, models=models, offset_x=offset_x, offset_y=offset_y, default_infill=default_infill, default_support=default_support, default_support_pattern=default_support_pattern, quota_exceeded=quota_exceeded, configs=configs)
import re
import markdown
@main_bp.route('/helper_slice')
def helper_slice():
lang = request.cookies.get('lang', 'en')
filepath = os.path.join(current_app.root_path, 'assets', 'doc', f'slice_helper_{lang}.md')
if not os.path.exists(filepath):
filepath = os.path.join(current_app.root_path, 'assets', 'doc', 'slice_helper_en.md')
content_html = ""
if os.path.exists(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
md_text = f.read()
content_html = markdown.markdown(md_text, extensions=['fenced_code', 'tables'])
# Rewrite relative image links to /assets/doc/
content_html = re.sub(r'src="(?!http|/)([^"]+)"', r'src="/assets/doc/\1"', content_html)
return render_template('slice/helper_slice.html', content_html=content_html)
@main_bp.route('/file/<int:file_id>')
@login_required
def serve_file(file_id):
@@ -579,7 +631,7 @@ def build_plate_model():
@main_bp.route('/api/engine_options/<engine_name>')
@login_required
def engine_options(engine_name):
engine = get_slicer_engine(engine_name, current_app.config['PRINT_CONFIG_FOLDER'])
engine = get_slicer_engine(engine_name, current_app.config['PRINT_CONFIG_FOLDER'], current_app.config['PRUSA_SLICE_BIN'])
presets = engine.get_quality_presets()
patterns = engine.get_support_patterns()
materials = engine.get_materials() if hasattr(engine, 'get_materials') else []
@@ -607,9 +659,13 @@ def account():
flash('New passwords do not match.', 'danger')
elif len(new_pass) < 6:
flash('New password must be at least 6 characters.', 'danger')
elif current_user.is_admin and new_pass == 'admin123':
flash('Your new password cannot be the default "admin123".', 'danger')
else:
current_user.password_hash = generate_password_hash(new_pass)
db.session.commit()
# If they just changed it, clear the must change flag
session.pop('must_change_password', None)
flash('Password updated successfully.', 'success')
elif action == 'terminate_session':

View File

@@ -228,6 +228,26 @@ def control():
error = "OctoPrint is not configured."
return render_template('printer/control.html', webcam_url=webcam_url, error=error)
import re
import markdown
@printer_bp.route('/helper_printer')
def helper_printer():
lang = request.cookies.get('lang', 'en')
filepath = os.path.join(current_app.root_path, 'assets', 'doc', f'printer_helper_{lang}.md')
if not os.path.exists(filepath):
filepath = os.path.join(current_app.root_path, 'assets', 'doc', 'printer_helper_en.md')
content_html = ""
if os.path.exists(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
md_text = f.read()
content_html = markdown.markdown(md_text, extensions=['fenced_code', 'tables'])
# Rewrite relative image links to /assets/doc/
content_html = re.sub(r'src="(?!http|/)([^"]+)"', r'src="/assets/doc/\1"', content_html)
return render_template('printer/helper_printer.html', content_html=content_html)
@printer_bp.route('/api/command', methods=['POST'])
@login_required
def api_command():
@@ -456,7 +476,9 @@ def octo_proxy(path):
class WebSocketResponse(Response):
def __call__(self, *args, **kwargs):
print("WS Response __call__")
if getattr(ws, 'mode', 'werkzeug') == 'werkzeug':
if getattr(ws, 'mode', 'werkzeug') == 'gunicorn':
raise StopIteration()
elif getattr(ws, 'mode', 'werkzeug') == 'werkzeug':
return super().__call__(*args, **kwargs)
return []