296 lines
9.3 KiB
Python
Executable File
296 lines
9.3 KiB
Python
Executable File
#!/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
|
|
from typing import Optional
|
|
|
|
if __name__ != '__main__':
|
|
from . import config, dateutils
|
|
else:
|
|
import config
|
|
import dateutils
|
|
|
|
|
|
def get() -> sqlite3.Connection:
|
|
if 'db' not in g:
|
|
g.db = sqlite3.connect(
|
|
config.DATABASE_PATH,
|
|
detect_types=sqlite3.PARSE_DECLTYPES,
|
|
)
|
|
g.db.row_factory = sqlite3.Row
|
|
cur = g.db.cursor()
|
|
cur.execute('PRAGMA foreign_keys = on')
|
|
|
|
return g.db
|
|
|
|
|
|
def init(db):
|
|
with open('schema.sql', 'r') as f:
|
|
db.executescript(f.read())
|
|
|
|
|
|
def close():
|
|
db = g.pop('db', None)
|
|
|
|
if db is not None:
|
|
db.close()
|
|
|
|
|
|
def init_app(app):
|
|
app.teardown_appcontext(close)
|
|
app.cli.add_command(init)
|
|
|
|
|
|
class CalibrationState(IntEnum):
|
|
Empty = 0
|
|
HasData = 1
|
|
IsComputed = 2
|
|
IsValidated = 3
|
|
|
|
|
|
class Calibration:
|
|
@staticmethod
|
|
def select_args() -> str:
|
|
return 'id, state, validated_date'
|
|
|
|
def __init__(self, calibration_id: int, state: int, validated_date: Optional[int]):
|
|
self.id = calibration_id
|
|
self.state = CalibrationState(state)
|
|
if validated_date is None:
|
|
self.validated_date = None
|
|
else:
|
|
self.validated_date = datetime.fromtimestamp(validated_date)
|
|
|
|
@staticmethod
|
|
def create(db: sqlite3.Connection) -> 'Calibration':
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'INSERT INTO calibration(state, validated_date) VALUES (?, NULL) RETURNING ' + Calibration.select_args() + ';',
|
|
[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: Optional['sqlite3.Row']) -> Optional['Calibration']:
|
|
if row is None:
|
|
return None
|
|
return Calibration(*row)
|
|
|
|
def save(self, db: sqlite3.Connection):
|
|
cur = db.cursor()
|
|
cur.execute(
|
|
'UPDATE calibration SET state = ?, validated_date = ? WHERE id = ?',
|
|
[int(self.state), int(self.validated_date.timestamp()) if self.validated_date is not None else None, self.id]
|
|
)
|
|
|
|
@staticmethod
|
|
def get_from_id(calibration_id: int, db: sqlite3.Connection) -> Optional['Calibration']:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'SELECT ' + Calibration.select_args() + ' FROM calibration WHERE id = ?;',
|
|
[calibration_id]
|
|
)
|
|
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 validated_date DESC LIMIT 1;',
|
|
[]
|
|
)
|
|
return Calibration.from_row(response.fetchone())
|
|
|
|
def validate(self, db: sqlite3.Connection):
|
|
self.state = CalibrationState.IsValidated
|
|
self.validated_date = datetime.now()
|
|
self.save(db)
|
|
|
|
def get_pretty_date(self) -> str:
|
|
return dateutils.format(self.validated_date)
|
|
|
|
def get_pretty_short_date(self) -> str:
|
|
return dateutils.format_short(self.validated_date)
|
|
|
|
|
|
Calibration.Dummy = Calibration(-1, CalibrationState.Empty, None)
|
|
|
|
|
|
class Acquisition:
|
|
@staticmethod
|
|
def select_args() -> str:
|
|
return 'id, calibration_id, object_id, date, validated'
|
|
|
|
def __init__(self, acquisition_id: int, calibration_id: int, object_id: int, date: int, validated: int):
|
|
self.id = acquisition_id
|
|
self.calibration_id = calibration_id
|
|
self.object_id = object_id
|
|
self.date = datetime.fromtimestamp(date)
|
|
self.validated = validated != 0
|
|
|
|
def save(self, db: sqlite3.Connection):
|
|
cur = db.cursor()
|
|
cur.execute(
|
|
'UPDATE acquisition SET calibration_id = ?, object_id = ?, date = ?, validated = ? WHERE id = ?',
|
|
[self.calibration_id, self.object_id, self.date.timestamp(), 1 if self.validated else 0, self.id]
|
|
)
|
|
|
|
@staticmethod
|
|
def from_row(row: Optional[sqlite3.Row]) -> Optional['Acquisition']:
|
|
if row is None:
|
|
return None
|
|
return Acquisition(*row)
|
|
|
|
@staticmethod
|
|
def get_from_id(acquisition_id: int, db: sqlite3.Connection) -> Optional['Acquisition']:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'SELECT ' + Acquisition.select_args() + ' FROM acquisition WHERE id = ?;',
|
|
[acquisition_id]
|
|
)
|
|
return Acquisition.from_row(response.fetchone())
|
|
|
|
def calibration(self, db: sqlite3.Connection) -> Optional[Calibration]:
|
|
if self.calibration_id is None:
|
|
return None
|
|
|
|
return Calibration.get_from_id(self.calibration_id, db)
|
|
|
|
def object(self, db: sqlite3.Connection) -> 'Object':
|
|
return Object.get_from_id(self.object_id, db)
|
|
|
|
def get_pretty_date(self) -> str:
|
|
return dateutils.format(self.date)
|
|
|
|
|
|
class FullObject:
|
|
def __init__(self, object_id: int, name: str, acquisitions: list[Acquisition]):
|
|
self.id = object_id
|
|
self.name = name
|
|
self.acquisitions = acquisitions
|
|
|
|
|
|
class Object:
|
|
@staticmethod
|
|
def select_args() -> str:
|
|
return 'id, name'
|
|
|
|
def __init__(self, object_id: int, name: str):
|
|
self.id = object_id
|
|
self.name = name
|
|
|
|
def save(self, db: sqlite3.Connection):
|
|
cur = db.cursor()
|
|
cur.execute(
|
|
'UPDATE object SET name = ? WHERE id = ?',
|
|
[self.name, self.id]
|
|
)
|
|
|
|
@staticmethod
|
|
def from_row(row: Optional[sqlite3.Row]) -> Optional['Object']:
|
|
if row is None:
|
|
return None
|
|
return Object(*row)
|
|
|
|
@staticmethod
|
|
def create(name: str, db: sqlite3.Connection) -> 'Object':
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'INSERT INTO object(name) VALUES (?) RETURNING ' + Object.select_args() + ';',
|
|
[name]
|
|
)
|
|
object = Object.from_row(response.fetchone())
|
|
os.makedirs(join(config.OBJECT_DIR, str(object.id)))
|
|
return object
|
|
|
|
@staticmethod
|
|
def get_from_id(object_id: int, db: sqlite3.Connection) -> Optional['Object']:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'SELECT ' + Object.select_args() + ' FROM object WHERE id = ?;',
|
|
[object_id]
|
|
)
|
|
return Object.from_row(response.fetchone())
|
|
|
|
@staticmethod
|
|
def all(db: sqlite3.Connection) -> list['Object']:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'SELECT ' + Object.select_args() + ' FROM object;',
|
|
[]
|
|
)
|
|
return list(map(Object.from_row, response.fetchall()))
|
|
|
|
def add_acquisition(self, calibration_id: int, db: sqlite3.Connection) -> Acquisition:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'INSERT INTO acquisition(calibration_id, object_id, date, validated) VALUES (?, ?, ?, ?) RETURNING ' + Acquisition.select_args() + ';',
|
|
[calibration_id, self.id, datetime.now().timestamp(), 0]
|
|
)
|
|
return Acquisition.from_row(response.fetchone())
|
|
|
|
def full(self, db: sqlite3.Connection) -> FullObject:
|
|
cur = db.cursor()
|
|
response = cur.execute(
|
|
'SELECT ' + Acquisition.select_args() + ' FROM acquisition WHERE object_id = ? ORDER BY date DESC;',
|
|
[self.id]
|
|
)
|
|
acquisitions = list(map(lambda x: Acquisition.from_row(x), response.fetchall()))
|
|
return FullObject(self.id, self.name, acquisitions)
|
|
|
|
|
|
def main():
|
|
# 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(
|
|
config.DATABASE_PATH,
|
|
detect_types=sqlite3.PARSE_DECLTYPES,
|
|
)
|
|
db.row_factory = sqlite3.Row
|
|
init(db)
|
|
|
|
# Create a new object
|
|
# with db:
|
|
# Object.create('Mon premier objet', db)
|
|
# # calibration = Calibration.create(db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # calibration = Calibration.create(db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
|
|
# Object.create('Mon deuxième objet', db)
|
|
# # calibration = Calibration.create(db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # calibration = Calibration.create(db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
# # object.add_acquisition(calibration.id, db)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|