EE-downloader-v3/models.py

203 lines
6.0 KiB
Python

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import exc
from settings import *
db = SQLAlchemy()
__all__ = ['db', 'save_row', 'delete_row', 'User', 'Camera', 'Download' ]
#
# helper function to reduce repeated code
#
def commit_or_rollback(db, obj):
try:
db.session.add(obj)
db.session.commit()
except exc.IntegrityError as e:
print(f"caught an exception {e}")
db.session.rollback()
except exc.OperationalError as e:
print(f"caught an exception {e}")
db.session.rollback()
def delete_or_rollback(db, obj):
try:
db.session.delete(obj)
db.session.commit()
except exc.IntegrityError as e:
print(f"caught an exception {e}")
db.session.rollback()
except exc.OperationalError as e:
print(f"caught an exception {e}")
db.session.rollback()
def save_row(obj):
commit_or_rollback(db, obj)
def delete_row(obj):
delete_or_rollback(db, obj)
# trying out making my own BaseModel, follow this blogpost
# https://dev.to/chidioguejiofor/making-sqlalchemy-models-simpler-by-creating-a-basemodel-3m9c
class BaseModel(db.Model):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True)
created = db.Column(db.DateTime, server_default=db.func.now())
updated = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())
def before_save(self, *args, **kwargs):
pass
def after_save(self, *args, **kwargs):
pass
def save(self, commit=True):
self.before_save()
db.session.add(self)
if commit:
try:
db.session.commit()
except Exception as e:
db.session.rollback()
raise e
self.after_save()
def before_update(self, *args, **kwargs):
pass
def after_update(self, *args, **kwargs):
pass
def update(self, *args, **kwargs):
self.before_update(*args, **kwargs)
db.session.commit()
self.after_update(*args, **kwargs)
def delete(self, commit=True):
db.session.delete(self)
if commit:
db.session.commit()
@classmethod
def eager(cls, *args):
cols = [orm.joinedload(arg) for arg in args]
return cls.query.options(*cols)
@classmethod
def before_bulk_create(cls, iterable, *args, **kwargs):
pass
@classmethod
def after_bulk_create(cls, model_objs, *args, **kwargs):
pass
@classmethod
def bulk_create(cls, iterable, *args, **kwargs):
cls.before_bulk_create(iterable, *args, **kwargs)
model_objs = []
for data in iterable:
if not isinstance(data, cls):
data = cls(**data)
model_objs.append(data)
db.session.bulk_save_objects(model_objs)
if kwargs.get('commit', True) is True:
db.session.commit()
cls.after_bulk_create(model_objs, *args, **kwargs)
return model_objs
@classmethod
def bulk_create_or_none(cls, iterable, *args, **kwargs):
try:
return cls.bulk_create(iterable, *args, **kwargs)
except exc.IntegrityError as e:
db.session.rollback()
return None
class User(BaseModel):
'''
The User object stores basic data from EagleEye API along with cameras they have access to, and stores the access/refresh tokens.
'''
account_id = db.Column(db.String(8), nullable=True)
user_id = db.Column(db.String(8), nullable=True)
email = db.Column(db.String(), nullable=True)
timezone = db.Column(db.String(), nullable=True)
access_token = db.Column(db.String(), nullable=True)
refresh_token = db.Column(db.String(), nullable=True)
last_login = db.Column(db.DateTime, nullable=True)
cameras = db.relationship('Camera', backref=db.backref('user', lazy=True))
def __repr__(self):
return f"[User] {email}"
def to_dict(self):
return {
"account_id": self.account_id,
"user_id": self.user_id,
"email": self.email,
"timezone": self.timezone,
"access_token": self.access_token,
"refresh_token": self.refresh_token,
"last_login": self.last_login,
"cameras": self.cameras
}
class Camera(BaseModel):
'''
The Camera object holds the list of recordings (Downloads) and some basics about the device
'''
device_id = db.Column(db.String(8), nullable=True)
timezone = db.Column(db.String(), nullable=True)
name = db.Column(db.String(), nullable=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
downloads = db.relationship('Download', backref=db.backref('camera', lazy=True))
def __repr__(self):
return f"[Camera] {device_id} {name}"
def get_newest_download(self, status=None):
return None
def get_oldest_download(self, status=None):
return None
class Download(BaseModel):
'''
Downloads are the actual recording that should be downloaded.
It keeps its own state/progress/errors so it can be reported on later.
Downloads belong to a camera which by extension belongs to a user
'''
url = db.Column(db.String(), nullable=True)
camera_id = db.Column(db.Integer, db.ForeignKey('camera.id'), nullable=True)
start_timestamp = db.Column(db.DateTime, nullable=True)
end_timestamp = db.Column(db.DateTime, nullable=True)
status = db.Column(db.String(), nullable=True)
error = db.Column(db.String(), nullable=True)
def __repr__(self):
return f"[Download] {id} {camera_id} {status} {error}"