暂存-说明文档(部分)
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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 []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user