Skip to content

Commit 62d0a58

Browse files
authored
V0.6 cleanup (#78)
* cleanup structure * More logging and Error Catching add `/` to self.snap and self.clip and replace `//api` with `/api` to make sure the fetch url is correct. Add more logging to the Fetch functions Standardize Log Output Stnadardize returns to a dict with values of error, msg, exception Change camera and frigate instance name to a input/text box instead of hidden. Change show to a checkbox instead of actually printing True or False in a textbox * Frigate Setup Fixed errors while editing frigate instances.
1 parent 15efeda commit 62d0a58

35 files changed

+507
-577
lines changed

-d

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Netscape HTTP Cookie File
2+
# https://curl.se/docs/http-cookies.html
3+
# This file was generated by libcurl! Edit at your own risk.
4+
5+
#HttpOnly_localhost FALSE / FALSE 1657536008 fEVR_Session eyJfcGVybWFuZW50Ijp0cnVlfQ.Ysv3AA.nb-2fPLFOwCK9MyzB-wiSRfX5Eo

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.cache
2+
.env
3+
.git
4+
.gitattributes
5+
.gitignore
6+
.github
7+
docs
8+
docker-compose.yml
9+
install.sh
10+
README.md
11+
template.env
12+
test
13+
venv

.drone.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ image_pull_secrets:
44
- docker-auth-beardedtek.com
55
trigger:
66
branch:
7-
- main
7+
- v0.6-cleanup
88
event:
99
- push
1010
steps:
@@ -19,7 +19,7 @@ steps:
1919
from_secret: docker_password
2020
repo: docker.beardedtek.com/beardedtek/fevr
2121
registry: docker.beardedtek.com
22-
tags: latest,${DRONE_REPO_BRANCH},0.6
22+
tags: dev,${DRONE_REPO_BRANCH}
2323
experimental: true
2424
compress: true
2525
squash: true

app/__init__.py

Lines changed: 20 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,57 +16,58 @@
1616
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1717

1818
# External Imports
19-
from flask import Flask, session, jsonify
20-
from flask_sqlalchemy import SQLAlchemy, inspect
21-
from sqlalchemy import desc
19+
from flask import Flask, session
20+
from flask_sqlalchemy import SQLAlchemy
2221
import json
2322
from flask_login import LoginManager
2423
from datetime import timedelta
25-
from datetime import datetime
26-
from dateutil import tz
2724
import pytz
28-
from os import environ,path,access,R_OK
25+
26+
# Config File
27+
configFile = "data/config"
2928

3029
# Flask app Setup
3130
app = Flask(__name__)
3231
app.config.from_file('config.json',load=json.load)
3332

34-
login_mgr = LoginManager(app)
35-
login_mgr.login_view = 'login'
36-
login_mgr.refresh_view = 'relogin'
37-
login_mgr.needs_refresh_message = (u"Session timedout, please re-login")
38-
login_mgr.needs_refresh_message_category = "info"
33+
34+
35+
# Setup Session Timeout
3936
@app.before_request
4037
def before_request():
4138
session.permanent = True
4239
app.permanent_session_lifetime = timedelta(minutes=30)
4340

4441
# Database Setup
45-
4642
db = SQLAlchemy(app)
4743
app.SQLALCHEMY_TRACK_MODIFICATIONS=False
4844

45+
from app.models.user import User
46+
47+
# Flask Login Setup
4948
login_manager = LoginManager()
5049
login_manager.login_view = 'auth.login'
5150
login_manager.init_app(app)
5251

53-
from .models.models import User, mqtt
54-
5552
@login_manager.user_loader
5653
def load_user(user_id):
5754
return User.query.get(int(user_id))
58-
from .api import api as api_blueprint
55+
56+
# Import Blueprints
57+
from app.blueprints.api import api as api_blueprint
5958
app.register_blueprint(api_blueprint)
6059

61-
from .main import main as main_blueprint
60+
from app.blueprints.main import main as main_blueprint
6261
app.register_blueprint(main_blueprint)
6362

64-
from .auth import auth as auth_blueprint
63+
from app.blueprints.auth import auth as auth_blueprint
6564
app.register_blueprint(auth_blueprint)
6665

67-
from .setup import setup as setup_blueprint
66+
from app.blueprints.setup import setup as setup_blueprint
6867
app.register_blueprint(setup_blueprint)
6968

69+
70+
# Define Templates
7071
@app.template_filter('timezone')
7172
def convertTZ(time,clockFmt=12,Timezone="America/Anchorage"):
7273
dt_utc = time
@@ -77,41 +78,4 @@ def convertTZ(time,clockFmt=12,Timezone="America/Anchorage"):
7778
else:
7879
outformat = "%-m/%-d/%y %H:%M:%S"
7980
outTime = dt.strftime(outformat).lower()
80-
return outTime
81-
82-
# Setup mqtt_client
83-
# Gather environment variables in a dict
84-
# NOTE: Environment Variables are only used if app/data/config.json does not exist.
85-
86-
def writeConfigFile(file,ev):
87-
config = {}
88-
config["fevr_url"] = f"{ev['FEVR_URL']}:{ev['FEVR_PORT']}"
89-
if ev["MQTT_TRANSPORT"] == "https" or ev["MQTT_TRANSPORT"] == "https://":
90-
config["fevr_transport"] = "https://"
91-
else:
92-
config["fevr_transport"] = "http://"
93-
config["fevr_apikey"] = ev["MQTT_APIAUTH_KEY"]
94-
config["mqtt_broker"] = ev["MQTT_BROKER"]
95-
config["mqtt_port"] = ev["MQTT_BROKER_PORT"]
96-
config["mqtt_user"] = ev["MQTT_BROKER_USER"]
97-
config["mqtt_password"] = ev["MQTT_BROKER_PASSWORD"]
98-
config["mqtt_topics"] = ev["MQTT_TOPICS"]
99-
config["verbose"] = ev["MQTT_VERBOSE_LOGGING"]
100-
with open('/fevr/app/data/config.json', "w") as configFile:
101-
json.dump(config,configFile,sort_keys=True,indent=0)
102-
103-
ev = {}
104-
ev["MQTT_BROKER_PORT"] = environ.get("MQTT_BROKER_PORT")
105-
ev["MQTT_TOPICS"] = environ.get("MQTT_TOPICS")
106-
ev["MQTT_BROKER_USER"] = environ.get("MQTT_BROKER_USER")
107-
ev["MQTT_BROKER_PASSWORD"] = environ.get("MQTT_BROKER_PASSWORD")
108-
ev["MQTT_TRANSPORT"] = environ.get("MQTT_TRANSPORT")
109-
ev["MQTT_BROKER"] = environ.get("MQTT_BROKER")
110-
ev["MQTT_APIAUTH_KEY"] = environ.get("MQTT_APIAUTH_KEY")
111-
ev["FEVR_URL"] = environ.get('FEVR_URL')
112-
ev["FEVR_PORT"] = environ.get('FEVR_PORT')
113-
ev["MQTT_VERBOSE_LOGGING"] = environ.get("MQTT_VERBOSE_LOGGING")
114-
115-
config="/fevr/app/data/config.json"
116-
if not path.isfile(config) or not access(config, R_OK):
117-
writeConfigFile(config,ev)
81+
return outTime

app/api.py renamed to app/blueprints/api.py

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@
2424
import os
2525
import shutil
2626

27-
from .models.models import events,frigate,cameras
28-
from . import db
29-
from .fetch import Fetch
30-
from .helpers.cookies import cookies
31-
from .helpers.iterateQuery import iterateQuery
27+
from app.models.frigate import frigate
28+
from app.models.events import events
29+
from app.models.frigate import frigate
30+
from app.models.cameras import cameras
31+
from app import db
32+
from app.helpers.fetch import Fetch
33+
from app.helpers.cookies import cookies
34+
from app.helpers.iterateQuery import iterateQuery
35+
from app.helpers.logit import logit
3236

3337
# API Routes
3438
api = Blueprint('api',__name__)
@@ -75,6 +79,7 @@ def apiFrigate():
7579
@api.route('/api/events/add/<eventid>/<camera>/<object>/<score>')
7680
@login_required
7781
def apiAddEvent(eventid,camera,score,object):
82+
source = "fEVR | EVENT ADD"
7883
time = datetime.fromtimestamp(int(eventid.split('.')[0]))
7984
# Define default JSON return value
8085
rVal = {'error':0,
@@ -86,36 +91,40 @@ def apiAddEvent(eventid,camera,score,object):
8691
'score':score}
8792
db.create_all()
8893
Cameras = cameras.query.filter_by(camera=camera).first()
89-
if not Cameras:
90-
rVal["msg"] = "Camera Not Defined"
94+
if Cameras:
95+
show = True if Cameras.show else False
96+
# Check if eventid already exists
97+
if events.query.filter_by(eventid=eventid).first():
98+
rVal["msg"] = 'Event Already Exists'
99+
rVal["error"] = 2
100+
else:
101+
try:
102+
fetchPath = f"{os.getcwd()}/app/static/events/{eventid}/"
103+
logit.execute(f"Fetching event into {fetchPath}",src=source)
104+
frigateConfig = apiFrigate()
105+
fetched = False
106+
for frigate in frigateConfig:
107+
logit.execute(f"Trying to fetch from {frigateConfig[frigate]['url']}",src=source)
108+
frigateURL = frigateConfig[frigate]["url"]
109+
Fetched = Fetch(fetchPath,eventid,frigateURL)
110+
logit.execute(f"Fetched {Fetched.event}", src=source)
111+
fetched = True
112+
if not fetched:
113+
rVal["msg"] = "Cannot Fetch"
114+
rVal["error"] = 3
115+
except Exception as e:
116+
rVal["error"] = 4
117+
rVal["msg"] = str(e).replace('"','')
118+
try:
119+
event = events(eventid=eventid,camera=camera,object=object,score=int(score),ack='',time=time,show=show)
120+
db.session.add(event)
121+
db.session.commit()
122+
except Exception as e:
123+
rVal["error"] = 5
124+
rVal["msg"] = str(e).replace('"','')
125+
else:
126+
rVal["msg"] = f"Camera '{camera}' Not Defined"
91127
rVal["error"] = 1
92-
show = True if Cameras.show else False
93-
# Check if eventid already exists
94-
if events.query.filter_by(eventid=eventid).first():
95-
rVal["msg"] = 'Event Already Exists'
96-
rVal["error"] = 2
97-
else:
98-
try:
99-
fetchPath = f"{os.getcwd()}/app/static/events/{eventid}/"
100-
frigateConfig = apiFrigate()
101-
fetched = False
102-
for frigate in frigateConfig:
103-
frigateURL = frigateConfig[frigate]["url"]
104-
print(Fetch(fetchPath,eventid,frigateURL))
105-
fetched = True
106-
if not fetched:
107-
rVal["msg"] = "Cannot Fetch"
108-
rVal["error"] = 3
109-
except Exception as e:
110-
rVal["error"] = 4
111-
rVal["msg"] = str(e).replace('"','')
112-
try:
113-
event = events(eventid=eventid,camera=camera,object=object,score=int(score),ack='',time=time,show=show)
114-
db.session.add(event)
115-
db.session.commit()
116-
except Exception as e:
117-
rVal["error"] = 5
118-
rVal["msg"] = str(e).replace('"','')
119128
return jsonify(rVal)
120129

121130
@api.route('/api/events/ack/<eventid>')
@@ -152,7 +161,7 @@ def apiDelEvent(eventid):
152161
if os.path.exists(eventPath):
153162
shutil.rmtree(eventPath)
154163
db.session.commit()
155-
return redirect(url_for('main.index'))
164+
return redirect(cookiejar['page'])
156165

157166
@api.route('/api/events/latest')
158167
@login_required

app/auth.py renamed to app/blueprints/auth.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,19 @@
1515
# You should have received a copy of the GNU AfferoGeneral Public License
1616
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1717

18-
import ipaddress
1918
from flask import Blueprint, render_template, redirect, url_for, request, flash, jsonify, make_response
2019
from werkzeug.security import generate_password_hash, check_password_hash
2120
from flask_login import login_user, logout_user, login_required, current_user
2221
from IPy import IP
22+
import sqlite3
2323

24-
from .models.models import User, apiAuth, cameras
25-
from . import db
26-
from .rndpwd import randpwd
27-
from .helpers.cookies import cookies
24+
from app.models.user import User
25+
from app.models.apiauth import apiAuth
26+
from app.models.cameras import cameras
27+
from app import db
28+
from app.helpers.rndpwd import randpwd
29+
from app.helpers.cookies import cookies
30+
from app.helpers.logit import logit
2831

2932
auth = Blueprint('auth', __name__)
3033

@@ -79,6 +82,7 @@ def validIP(ip):
7982

8083
@auth.route('/apiAuth',methods=['POST'])
8184
def apiAuthenticate():
85+
source = "fEVR | AUTH"
8286
ip = request.remote_addr
8387
auth = {"auth":False,"name":None,"authIP":ip,"changed":False,"remember":False}
8488
requestData = request.get_json()
@@ -113,6 +117,9 @@ def apiAuthenticate():
113117
# If we changed they key limit or set it to expired, commit it to the database.
114118
if auth['changed']:
115119
db.session.commit()
120+
success = "successful" if auth['auth'] else "failed"
121+
keyname = f"{auth['name']} " if auth['name'] else ""
122+
logit.execute(f"Authentication {success} by key {keyname}from {auth['authIP']}",src=source)
116123
return jsonify(auth)
117124

118125
@auth.route('/login',methods=['GET'])
@@ -133,7 +140,7 @@ def login():
133140

134141
@auth.route('/login', methods=['POST'])
135142
def loginProcessForm():
136-
143+
source="fEVR | LOGIN"
137144
# login code goes here
138145
email = request.form.get('email')
139146
password = request.form.get('password')
@@ -142,16 +149,20 @@ def loginProcessForm():
142149
fwd = request.form.get('fwd')
143150
else:
144151
fwd = "/"
145-
146-
user = User.query.filter_by(email=email).first()
147-
148-
# check if the user actually exists
149-
# take the user-supplied password, hash it, and compare it to the hashed password in the database
150-
if not user or not check_password_hash(user.password, password):
151-
flash('Please check your login details and try again.')
152-
return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
153-
# if the above check passes, then we know the user has the right credentials
154-
login_user(user, remember=remember)
152+
try:
153+
user = User.query.filter_by(email=email).first()
154+
# check if the user actually exists
155+
# take the user-supplied password, hash it, and compare it to the hashed password in the database
156+
if not user or not check_password_hash(user.password, password):
157+
flash('Please check your login details and try again.')
158+
return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
159+
# if the above check passes, then we know the user has the right credentials
160+
login_user(user, remember=remember)
161+
except Exception as e:
162+
if "no such table" in str(e):
163+
logit.execute("Database is missing. Please visit `/setup` to complete setup.",src=source)
164+
else:
165+
logit.execute(e,src=source)
155166
return redirect(fwd)
156167

157168
@auth.route('/signup')

0 commit comments

Comments
 (0)