WIP, most basic version is writing data to database
parent
b6c35e015e
commit
baf32f857d
|
@ -10,5 +10,5 @@ my_settings.py
|
|||
flask_session/
|
||||
git-version.txt
|
||||
settings.py
|
||||
|
||||
*.db
|
||||
|
||||
|
|
70
app.py
70
app.py
|
@ -9,7 +9,7 @@ from matplotlib.figure import Figure
|
|||
import matplotlib.dates as mdates
|
||||
import base64
|
||||
from tqdm import tqdm
|
||||
|
||||
import datetime
|
||||
from io import BytesIO
|
||||
|
||||
import logging
|
||||
|
@ -58,6 +58,21 @@ app.config.from_object(__name__)
|
|||
Session(app)
|
||||
|
||||
|
||||
|
||||
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from models import *
|
||||
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
|
||||
db.init_app(app)
|
||||
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# $ flask routes -s rule
|
||||
# INFO:root:Using EagleEyev3 version 0.0.17
|
||||
# Endpoint Methods Rule
|
||||
|
@ -186,8 +201,29 @@ def login_callback():
|
|||
logging.debug(oauth_object)
|
||||
|
||||
|
||||
|
||||
|
||||
# let's try resaving this to see if it fixs the missing access_token on first request after login
|
||||
session['een'] = een
|
||||
|
||||
een.get_current_user()
|
||||
|
||||
try:
|
||||
user = User.query.filter(User.email == een.current_user['email']).first()
|
||||
if user is None:
|
||||
user = User(account_id=een.current_user['accountId'],\
|
||||
user_id=een.current_user['id'],\
|
||||
email=een.current_user['email'],\
|
||||
timezone=een.current_user['timeZone']['timeZone'],\
|
||||
access_token=een.access_token,\
|
||||
refresh_token=een.refresh_token,\
|
||||
last_login=None)
|
||||
user.save()
|
||||
except Exception as e:
|
||||
logging.warn(e)
|
||||
|
||||
|
||||
|
||||
return redirect(url_for('index'))
|
||||
|
||||
|
||||
|
@ -213,6 +249,17 @@ def cameras():
|
|||
|
||||
logging.debug(een.get_list_of_cameras())
|
||||
|
||||
for c in een.cameras:
|
||||
try:
|
||||
check_camera = Camera.query.filter(Camera.device_id == c.id).first()
|
||||
if check_camera is None:
|
||||
new_camera = Camera(device_id=c.id,\
|
||||
timezone=None, \
|
||||
name=c.name)
|
||||
new_camera.save()
|
||||
except Exception as e:
|
||||
logging.warn(e)
|
||||
|
||||
values = {
|
||||
"current_user": een.current_user,
|
||||
"cameras": een.cameras,
|
||||
|
@ -329,6 +376,25 @@ def camera_list_of_videos(esn=None):
|
|||
camera = een.get_camera_by_id(esn)
|
||||
logging.debug(camera.get_list_of_videos(start_timestamp=een.time_before(hours=24), end_timestamp=een.time_now()))
|
||||
|
||||
db_camera = Camera.query.filter(Camera.device_id == esn).first()
|
||||
if db_camera:
|
||||
|
||||
for v in camera.videos:
|
||||
try:
|
||||
check_video = Download.query.filter(Download.camera_id == db_camera.id)\
|
||||
.filter(Download.url == v['mp4Url'])\
|
||||
.first()
|
||||
if check_video is None:
|
||||
new_video = Download(url=v['mp4Url'],\
|
||||
camera_id=db_camera.id,\
|
||||
start_timestamp=datetime.fromisoformat(v['startTimestamp']),\
|
||||
end_timestamp=datetime.fromisoformat(v['endTimestamp']),\
|
||||
status='new',
|
||||
error=None)
|
||||
new_video.save()
|
||||
except Exception as e:
|
||||
logging.warn(f"saving videos to db: {e}")
|
||||
|
||||
values = {
|
||||
"current_user": een.current_user,
|
||||
"camera": { 'id': camera.id, 'name': camera.name },
|
||||
|
@ -348,4 +414,4 @@ def camera_list_of_videos(esn=None):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host=config.server_host, port=config.server_port)
|
||||
app.run(host=config['server_host'], port=config['server_port'])
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
|
||||
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}"
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue