@@ -191,3 +191,34 @@ def delete_user(user_id):
|
||||
|
||||
|
||||
|
||||
|
||||
@admin_bp.route('/api_keys')
|
||||
def api_keys():
|
||||
from app.models import ApiKey
|
||||
keys = ApiKey.query.order_by(ApiKey.created_at.desc()).all()
|
||||
return render_template('admin/api_keys.html', keys=keys)
|
||||
|
||||
@admin_bp.route('/api_key/add', methods=['POST'])
|
||||
def add_api_key():
|
||||
from app.models import ApiKey
|
||||
import secrets
|
||||
name = request.form.get('name')
|
||||
if not name:
|
||||
flash("Name is required", "danger")
|
||||
return redirect(url_for('admin.api_keys'))
|
||||
|
||||
key_value = secrets.token_urlsafe(32)
|
||||
new_key = ApiKey(name=name, key=key_value)
|
||||
db.session.add(new_key)
|
||||
db.session.commit()
|
||||
flash(f"API Key '{name}' created.", "success")
|
||||
return redirect(url_for('admin.api_keys'))
|
||||
|
||||
@admin_bp.route('/api_key/<int:key_id>/delete', methods=['POST'])
|
||||
def delete_api_key(key_id):
|
||||
from app.models import ApiKey
|
||||
key = ApiKey.query.get_or_404(key_id)
|
||||
db.session.delete(key)
|
||||
db.session.commit()
|
||||
flash(f'API Key {key.name} deleted.', 'success')
|
||||
return redirect(url_for('admin.api_keys'))
|
||||
|
||||
@@ -298,7 +298,18 @@ def preview_gcode(file_id):
|
||||
|
||||
content = "File not found or not ready."
|
||||
line_count = 0
|
||||
|
||||
time_info = "-"
|
||||
layer1_time = "-"
|
||||
filament_used = "-"
|
||||
|
||||
if os.path.exists(filepath):
|
||||
from app.utils.gcode_parser import get_gcode_metadata
|
||||
metadata = get_gcode_metadata(filepath)
|
||||
time_info = metadata.get('print_time', '-')
|
||||
layer1_time = metadata.get('first_layer_time', '-')
|
||||
filament_used = metadata.get('filament_used', '-')
|
||||
|
||||
with open(filepath, 'r') as f:
|
||||
lines = f.readlines()
|
||||
line_count = len(lines)
|
||||
@@ -313,7 +324,8 @@ def preview_gcode(file_id):
|
||||
configs = {c.key: c.value for c in SystemConfig.query.all()}
|
||||
offset_x = float(configs.get('offset_x', '0.0'))
|
||||
offset_y = float(configs.get('offset_y', '0.0'))
|
||||
return render_template('slice/gcode_preview.html', file=print_file, content=content, line_count=line_count, machine_width=w, machine_depth=h, machine_height=hd, offset_x=offset_x, offset_y=offset_y)
|
||||
return render_template('slice/gcode_preview.html', file=print_file, content=content, line_count=line_count, machine_width=w, machine_depth=h, machine_height=hd, offset_x=offset_x, offset_y=offset_y,
|
||||
time_info=time_info, layer1_time=layer1_time, filament_used=filament_used)
|
||||
|
||||
@main_bp.route('/delete_file/<int:file_id>', methods=['POST'])
|
||||
@login_required
|
||||
|
||||
@@ -23,9 +23,15 @@ def _enrich_job_data(job_data):
|
||||
if job_data and job_data.get('job', {}).get('file', {}).get('name'):
|
||||
from app.models import PrintFile
|
||||
internal_name = job_data['job']['file']['name']
|
||||
print_file = PrintFile.query.filter_by(filename=internal_name).first()
|
||||
if print_file and print_file.original_filename:
|
||||
job_data['job']['file']['display_name'] = print_file.original_filename
|
||||
internal_stl_name = str(internal_name)[:-5]+"stl"
|
||||
user_files = {}
|
||||
print_file = None
|
||||
for f in PrintFile.query.filter_by(user_id=current_user.id, status='sliced').all():
|
||||
user_files[f.filename] = f.original_filename
|
||||
if internal_stl_name in user_files.keys():
|
||||
print_file = user_files[str(internal_name)[:-5]+"stl"]
|
||||
if print_file:
|
||||
job_data['job']['file']['display_name'] = print_file
|
||||
else:
|
||||
job_data['job']['file']['display_name'] = internal_name
|
||||
return job_data
|
||||
@@ -40,9 +46,13 @@ def status():
|
||||
if client:
|
||||
try:
|
||||
status_data = client.get_printer_status()
|
||||
print(status_data)
|
||||
print(client.get_job_info())
|
||||
job_data = _enrich_job_data(client.get_job_info())
|
||||
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
print(error)
|
||||
else:
|
||||
error = "OctoPrint is not configured."
|
||||
|
||||
@@ -73,6 +83,7 @@ def get_gcode_dir():
|
||||
def prepare():
|
||||
from app.models import PrintFile
|
||||
import os
|
||||
from app.utils.gcode_parser import get_gcode_metadata
|
||||
|
||||
# Query only the sliced GCode files belonging to the current user
|
||||
user_files = PrintFile.query.filter_by(user_id=current_user.id, status='sliced').order_by(PrintFile.created_at.desc()).all()
|
||||
@@ -95,8 +106,16 @@ def prepare():
|
||||
gcode_path = os.path.join(gcode_dir, gcode_filename)
|
||||
|
||||
size = 0
|
||||
f.meta_print_time = '-'
|
||||
f.meta_first_layer_time = '-'
|
||||
f.meta_filament_used = '-'
|
||||
|
||||
if os.path.exists(gcode_path):
|
||||
size = os.path.getsize(gcode_path)
|
||||
metadata = get_gcode_metadata(gcode_path)
|
||||
f.meta_print_time = metadata.get('print_time', '-')
|
||||
f.meta_first_layer_time = metadata.get('first_layer_time', '-')
|
||||
f.meta_filament_used = metadata.get('filament_used', '-')
|
||||
|
||||
# Upload to OctoPrint if not found but exists locally
|
||||
if client and gcode_filename not in octo_files_dict and size > 0:
|
||||
@@ -118,7 +137,10 @@ def prepare():
|
||||
'size': size,
|
||||
'origin': 'local',
|
||||
'path': gcode_filename,
|
||||
'gcodeAnalysis': analysis
|
||||
'gcodeAnalysis': analysis,
|
||||
'meta_print_time': f.meta_print_time,
|
||||
'meta_first_layer_time': f.meta_first_layer_time,
|
||||
'meta_filament_used': f.meta_filament_used
|
||||
})
|
||||
|
||||
error = None
|
||||
@@ -220,6 +242,8 @@ def api_command():
|
||||
try:
|
||||
if cmd == 'home':
|
||||
client.home_axes()
|
||||
elif cmd == 'auto_level':
|
||||
client.auto_leveling()
|
||||
elif cmd == 'pause':
|
||||
client.pause_print()
|
||||
elif cmd == 'cancel':
|
||||
|
||||
Reference in New Issue
Block a user