diff --git a/.gitignore b/.gitignore index a79263f..2a054fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -db.sqlite .device data -data-keep +data-* +secret.py node_modules static/calibration-visualiser.* diff --git a/app.py b/app.py index f113cad..a2543a8 100755 --- a/app.py +++ b/app.py @@ -9,7 +9,17 @@ import uuid from . import db, config, scanner, calibration app = Flask(__name__) -app.config['SECRET_KEY'] = os.urandom(20).hex() + +# Manage secret key +try: + from . import secret + app.config['SECRET_KEY'] = secret.SECRET_KEY +except ImportError: + # Secret key file does not exist, create it + secret = os.urandom(50).hex() + with open('secret.py', 'w') as f: + f.write(f'SECRET_KEY = "{secret}"') + app.config['SECRET_KEY'] = secret def get_calibration(conn: sqlite3.Connection) -> db.Calibration: @@ -51,19 +61,45 @@ def object(id: int): @app.route('/scan/') def scan(id: int): conn = db.get() + print(session) object = db.Object.get_from_id(id, conn) return render_template('object.html', object=object) @app.route("/calibrate/") def calibrate(): - print(session) conn = db.get() if 'calibration_id' not in session: with conn: calibration = db.Calibration.create(conn) session['calibration_id'] = calibration.id - return render_template('calibrate.html', leds=config.LEDS_UUIDS) + else: + calibration = db.Calibration.get_from_id(session['calibration_id'], conn) + + if calibration.state in [db.CalibrationState.Empty, db.CalibrationState.HasData]: + return render_template('calibrate.html', leds=config.LEDS_UUIDS) + else: + return render_template('calibration.html', calibration=calibration) + + +@app.route("/new-calibration") +def new_calibration(): + conn = db.get() + with conn: + calibration = db.Calibration.create(conn) + session['calibration_id'] = calibration.id + + return redirect('/calibrate') + + +@app.route("/cancel-calibration") +def cancel_calibration(): + conn = db.get() + calibration = db.Calibration.get_from_id(session['calibration_id'], conn) + calibration.state = db.CalibrationState.HasData + with conn: + calibration.save(conn) + return redirect('/calibrate') @app.route("/api/preview/") @@ -102,9 +138,19 @@ def scan_calibration(): return app.response_class(generate(), mimetype='text/plain') -@app.route("/api/calibrate/") -def run_calibration(id: int): +@app.route('/api/use-last-calibration') +def use_last_calibration(): conn = db.get() + calibration = db.Calibration.get_last(conn) + session['calibration_id'] = calibration.id + print(session); + return 'ok' + + +@app.route("/api/calibrate") +def run_calibration(): + conn = db.get() + id = session['calibration_id'] calib = db.Calibration.get_from_id(id, conn) if calib is None: return 'oops', 404 @@ -133,13 +179,6 @@ def validate_calibration(): return redirect('/') -@app.route("/calibration/") -def calibration_page(id: int): - conn = db.get() - calibration = db.Calibration.get_from_id(id, conn) - return render_template('calibration.html', calibration=calibration) - - @app.route('/static/') def send_static(path): return send_from_directory('static', path) diff --git a/calibration.py b/calibration.py index d5a4231..8fc3054 100755 --- a/calibration.py +++ b/calibration.py @@ -20,7 +20,7 @@ def print_error(msg: str): def calibrate(input_dir: str): # Load all images - image_names = sorted(os.listdir(input_dir)) + image_names = list(filter(lambda x: x != 'calibration.json', sorted(os.listdir(input_dir)))) images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names] # Camera parameters diff --git a/config.py b/config.py index 7374ea5..b43f359 100644 --- a/config.py +++ b/config.py @@ -1,9 +1,11 @@ from os.path import join -MODE = 'debug' DATA_DIR = 'data' +BACKUPS_DIR = 'data-backups' CALIBRATION_DIR = join(DATA_DIR, 'calibrations') OBJECT_DIR = join(DATA_DIR, 'objects') +DATABASE_PATH = join(DATA_DIR, 'db.sqlite') +SECRET_KEY = 'tobedefined' LEDS_UUIDS = [ 'ac59350e-3787-46d2-88fa-743c1d34fe86', diff --git a/db.py b/db.py index 29878d4..7c1ae9c 100755 --- a/db.py +++ b/db.py @@ -1,12 +1,12 @@ #!/usr/bin/env python from enum import IntEnum +from datetime import datetime from flask import g import os from os.path import join import shutil import sqlite3 -import sys from typing import Optional if __name__ != '__main__': @@ -18,7 +18,7 @@ else: def get() -> sqlite3.Connection: if 'db' not in g: g.db = sqlite3.connect( - os.environ.get('DATABASE_PATH', 'db.sqlite'), + config.DATABASE_PATH, detect_types=sqlite3.PARSE_DECLTYPES, ) g.db.row_factory = sqlite3.Row @@ -69,11 +69,15 @@ class Calibration: [int(CalibrationState.Empty)] ) calibration = Calibration.from_row(response.fetchone()) + if calibration is None: + return None os.makedirs(join(config.CALIBRATION_DIR, str(calibration.id))) return calibration @staticmethod - def from_row(row: sqlite3.Row) -> 'Calibration': + def from_row(row: Optional['sqlite3.Row']) -> Optional['Calibration']: + if row is None: + return None return Calibration(*row) def save(self, db: sqlite3.Connection): @@ -92,6 +96,15 @@ class Calibration: ) return Calibration.from_row(response.fetchone()) + @staticmethod + def get_last(db: sqlite3.Connection) -> Optional['Calibration']: + cur = db.cursor() + response = cur.execute( + 'SELECT ' + Calibration.select_args() + ' FROM calibration WHERE state = 3 ORDER BY id DESC LIMIT 1;', + [] + ) + return Calibration.from_row(response.fetchone()) + Calibration.Dummy = Calibration(-1, CalibrationState.Empty) @@ -114,7 +127,9 @@ class Acquisition: ) @staticmethod - def from_row(row: sqlite3.Row) -> 'Acquisition': + def from_row(row: Optional[sqlite3.Row]) -> Optional['Acquisition']: + if row is None: + return None return Acquisition(*row) @staticmethod @@ -150,7 +165,9 @@ class Object: ) @staticmethod - def from_row(row: sqlite3.Row) -> 'Object': + def from_row(row: Optional[sqlite3.Row]) -> Optional['Object']: + if row is None: + return None return Object(*row) @staticmethod @@ -192,20 +209,25 @@ class Object: def main(): - if config.MODE != 'debug': - print('Can only reset db in debug mode') - sys.exit(1) + # Move current data to backup dir + if os.path.isdir(config.DATA_DIR): + # Ensure backup dir exists + os.makedirs(config.BACKUPS_DIR, exist_ok=True) + + now = datetime.now() + dest = join(config.BACKUPS_DIR, f'{now.year}-{now.month:02}-{now.day:02}--{now.hour:02}-{now.minute:02}-{now.second:02}') + shutil.move(config.DATA_DIR, dest) + + # Create new empty data dir + os.makedirs(config.DATA_DIR, exist_ok=True) db = sqlite3.connect( - os.environ.get('DATABASE_PATH', 'db.sqlite'), + config.DATABASE_PATH, detect_types=sqlite3.PARSE_DECLTYPES, ) db.row_factory = sqlite3.Row init(db) - if os.path.isdir(config.DATA_DIR): - shutil.rmtree(config.DATA_DIR) - # Create a new object with db: Object.create('Mon premier objet', db) @@ -230,5 +252,4 @@ def main(): if __name__ == '__main__': - if len(sys.argv) > 1 and sys.argv[1] == 'reset': - main() + main() diff --git a/templates/base.html b/templates/base.html index 1604ba3..b5c7cd9 100644 --- a/templates/base.html +++ b/templates/base.html @@ -22,30 +22,30 @@ diff --git a/templates/calibrate.html b/templates/calibrate.html index cffeb68..b3d3ca6 100644 --- a/templates/calibrate.html +++ b/templates/calibrate.html @@ -131,8 +131,8 @@ calibrateButton.addEventListener('click', async () => { calibrateButton.classList.add('is-loading'); - await fetch('/api/calibrate/{{ calibration.id }}'); - window.location.href = '/calibration/{{ calibration.id }}'; + await fetch('/api/calibrate'); + window.location.reload(); }); diff --git a/templates/calibration.html b/templates/calibration.html index 776a7b0..0ec13da 100644 --- a/templates/calibration.html +++ b/templates/calibration.html @@ -18,7 +18,7 @@

Vue de la LED selectionnée

- +
@@ -41,13 +41,24 @@
-
- - +
+ {% if calibration.state == CalibrationState.IsValidated %} +
+ +
+ + {% else %} + + + {% endif %}
@@ -77,5 +88,6 @@ {% endblock extracss %} {% block extrajs %} + {% endblock extrajs %} diff --git a/templates/object.html b/templates/object.html index 8806557..c98ef90 100644 --- a/templates/object.html +++ b/templates/object.html @@ -18,7 +18,7 @@ Étalonner le scanner
- Réutiliser le dernier étalonnage +
@@ -41,5 +41,10 @@ modal.classList.remove('is-active'); }); }); + document.getElementById('use-last-calibration-button').addEventListener('click', async () => { + let resp = await fetch('/api/use-last-calibration'); + await resp.text(); + window.location.href = '/scan/{{ object.id }}'; + }); {% endif %}{% endblock %} diff --git a/ts/Engine.ts b/ts/Engine.ts index d181884..54a5fcc 100644 --- a/ts/Engine.ts +++ b/ts/Engine.ts @@ -39,6 +39,13 @@ function getImageElementById(id: string): HTMLImageElement { return element; } +declare global { + interface Window { + /** This global variable must be set before including this script in the HTML page. */ + CALIBRATION_ID: number; + } +} + /** * The class that manages the interface for the calibration visualisation. */ @@ -105,7 +112,7 @@ export class Engine { /** Initialises the engine. */ static async create(domId: string) { - let calibrationId = parseInt(window.location.pathname.split('/')[2], 10); + let calibrationId = window.CALIBRATION_ID; let domElement = getElementById(domId); let engine = new Engine();