Fix .gitignore, add secure pairing key route, and fix template errors
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,4 +1,11 @@
|
|||||||
|
|
||||||
recticel/
|
recticel/
|
||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
app/__pycache__/
|
app/__pycache__/
|
||||||
|
tray/
|
||||||
|
jdk-11.0.20-full/
|
||||||
|
# Ignore generated or local files
|
||||||
|
py_app/instance/pairing_keys.json
|
||||||
|
py_app/app/forked_tray.py
|
||||||
|
backup/print_module.html
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
import json
|
||||||
|
from flask import Blueprint
|
||||||
|
bp = Blueprint('main', __name__)
|
||||||
|
@bp.route('/get_pairing_keys')
|
||||||
|
def get_pairing_keys():
|
||||||
|
"""Return all pairing keys as JSON for client selection."""
|
||||||
|
keys_path = os.path.join(current_app.instance_path, 'pairing_keys.json')
|
||||||
|
try:
|
||||||
|
with open(keys_path, 'r') as f:
|
||||||
|
keys = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading pairing keys: {e}")
|
||||||
|
return jsonify({'success': False, 'error': str(e), 'pairing_keys': []}), 500
|
||||||
|
return jsonify({'success': True, 'pairing_keys': keys})
|
||||||
import os
|
import os
|
||||||
import mariadb
|
import mariadb
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@@ -932,10 +946,65 @@ def upload_data():
|
|||||||
def print_module():
|
def print_module():
|
||||||
return render_template('print_module.html')
|
return render_template('print_module.html')
|
||||||
|
|
||||||
|
|
||||||
|
import secrets
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
@bp.route('/generate_pairing_key', methods=['POST'])
|
||||||
|
def generate_pairing_key():
|
||||||
|
"""Generate a secure pairing key for a printer and store it."""
|
||||||
|
printer_name = request.form.get('printer_name', '').strip()
|
||||||
|
if not printer_name:
|
||||||
|
flash('Printer name is required.', 'danger')
|
||||||
|
return redirect(url_for('main.download_extension'))
|
||||||
|
|
||||||
|
# Generate a secure random key
|
||||||
|
pairing_key = secrets.token_urlsafe(32)
|
||||||
|
warranty_until = (datetime.utcnow() + timedelta(days=365)).strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
# Load existing keys
|
||||||
|
keys_path = os.path.join(current_app.instance_path, 'pairing_keys.json')
|
||||||
|
try:
|
||||||
|
if os.path.exists(keys_path):
|
||||||
|
with open(keys_path, 'r') as f:
|
||||||
|
keys = json.load(f)
|
||||||
|
else:
|
||||||
|
keys = []
|
||||||
|
except Exception as e:
|
||||||
|
keys = []
|
||||||
|
|
||||||
|
# Add new key
|
||||||
|
keys.append({
|
||||||
|
'printer_name': printer_name,
|
||||||
|
'pairing_key': pairing_key,
|
||||||
|
'warranty_until': warranty_until
|
||||||
|
})
|
||||||
|
|
||||||
|
# Save updated keys
|
||||||
|
with open(keys_path, 'w') as f:
|
||||||
|
json.dump(keys, f, indent=2)
|
||||||
|
|
||||||
|
# Pass new key and all keys to template
|
||||||
|
return render_template('download_extension.html',
|
||||||
|
pairing_key=pairing_key,
|
||||||
|
printer_name=printer_name,
|
||||||
|
warranty_until=warranty_until,
|
||||||
|
pairing_keys=keys)
|
||||||
|
|
||||||
@bp.route('/download_extension')
|
@bp.route('/download_extension')
|
||||||
def download_extension():
|
def download_extension():
|
||||||
"""Route for downloading the Chrome extension"""
|
"""Route for downloading the Chrome extension"""
|
||||||
return render_template('download_extension.html')
|
# Load all pairing keys for display
|
||||||
|
keys_path = os.path.join(current_app.instance_path, 'pairing_keys.json')
|
||||||
|
try:
|
||||||
|
if os.path.exists(keys_path):
|
||||||
|
with open(keys_path, 'r') as f:
|
||||||
|
keys = json.load(f)
|
||||||
|
else:
|
||||||
|
keys = []
|
||||||
|
except Exception as e:
|
||||||
|
keys = []
|
||||||
|
return render_template('download_extension.html', pairing_keys=keys)
|
||||||
|
|
||||||
@bp.route('/extension_files/<path:filename>')
|
@bp.route('/extension_files/<path:filename>')
|
||||||
def extension_files(filename):
|
def extension_files(filename):
|
||||||
|
|||||||
@@ -1,43 +1,44 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}Quality Recticel Print Service Downloads{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div style="max-width: 600px; margin: 40px auto; padding: 32px; background: #fff; border-radius: 12px; box-shadow: 0 2px 12px #0002;">
|
||||||
<!-- Header Section -->
|
<h2>QZ Tray Pairing Key Management</h2>
|
||||||
<div class="row justify-content-center mb-4">
|
<form id="pairing-form" method="POST" action="/generate_pairing_key" style="margin-bottom: 32px;">
|
||||||
<div class="col-md-12">
|
<label for="printer_name">Printer Name:</label>
|
||||||
<div class="text-center">
|
<input type="text" id="printer_name" name="printer_name" required style="margin: 0 8px 0 8px;">
|
||||||
<h1 class="display-4">🖨️ Quality Recticel Print Solutions</h1>
|
<button type="submit">Generate Pairing Key</button>
|
||||||
<p class="lead">Choose Your Printing Method: Chrome Extension or Windows Service</p>
|
</form>
|
||||||
<div class="alert alert-info mx-auto" style="max-width: 800px;">
|
<div id="pairing-result">
|
||||||
<strong>🆕 TWO POWERFUL OPTIONS:</strong> Simple browser-based Chrome extension or enterprise-grade Windows service for advanced printing needs.
|
{% if pairing_key %}
|
||||||
</div>
|
<div style="margin-bottom: 16px;">
|
||||||
</div>
|
<strong>Pairing Key:</strong> <span style="font-family: monospace;">{{ pairing_key }}</span><br>
|
||||||
|
<strong>Printer Name:</strong> {{ printer_name }}<br>
|
||||||
|
<strong>Valid Until:</strong> {{ warranty_until }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Active Pairing Keys</h3>
|
||||||
<!-- Overview Card -->
|
<table style="width:100%; border-collapse:collapse;">
|
||||||
<div class="row justify-content-center mb-4">
|
<thead>
|
||||||
<div class="col-md-10">
|
<tr style="background:#f0f0f0;">
|
||||||
<div class="card border-primary">
|
<th style="padding:8px; border:1px solid #ccc;">Printer Name</th>
|
||||||
<div class="card-header bg-primary text-white">
|
<th style="padding:8px; border:1px solid #ccc;">Pairing Key</th>
|
||||||
<h3 class="mb-0">🚀 Two Printing Solutions Available</h3>
|
<th style="padding:8px; border:1px solid #ccc;">Valid Until</th>
|
||||||
</div>
|
</tr>
|
||||||
<div class="card-body">
|
</thead>
|
||||||
<div class="row">
|
<tbody>
|
||||||
<div class="col-md-6">
|
{% for key in pairing_keys %}
|
||||||
<h5><EFBFBD> Chrome Extension (Recommended)</h5>
|
<tr>
|
||||||
<ul>
|
<td style="padding:8px; border:1px solid #ccc;">{{ key.printer_name }}</td>
|
||||||
<li>✅ <strong>Easy Setup</strong> - 2 minutes to install</li>
|
<td style="padding:8px; border:1px solid #ccc; font-family:monospace;">{{ key.pairing_key }}</td>
|
||||||
<li>✅ <strong>Cross-Platform</strong> - Windows, Mac, Linux</li>
|
<td style="padding:8px; border:1px solid #ccc;">{{ key.warranty_until }}</td>
|
||||||
<li>✅ <strong>User Control</strong> - Print dialog for printer selection</li>
|
</tr>
|
||||||
<li>✅ <strong>Zero Configuration</strong> - Works immediately</li>
|
{% endfor %}
|
||||||
<li>✅ <strong>Secure</strong> - No external services needed</li>
|
</tbody>
|
||||||
</ul>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<script>
|
||||||
<h5>🔧 Windows Service (Enterprise)</h5>
|
// Optionally add AJAX for key generation if you want dynamic updates
|
||||||
|
</script>
|
||||||
<ul>
|
<ul>
|
||||||
<li>⚡ <strong>Silent Printing</strong> - No user interaction needed</li>
|
<li>⚡ <strong>Silent Printing</strong> - No user interaction needed</li>
|
||||||
<li><EFBFBD>️ <strong>Direct Printer Access</strong> - System-level printing</li>
|
<li><EFBFBD>️ <strong>Direct Printer Access</strong> - System-level printing</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user