203 lines
6.0 KiB
Python
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}"
|
|
|
|
|
|
|
|
|
|
|