diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f084d1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Codio +.codio + +# Databases +databases/ + +# Python +__pycache__/ + +# Flask +venv/ + +# Test +*_test/ \ No newline at end of file diff --git a/_scripts/setup.sh b/_scripts/setup.sh new file mode 100644 index 0000000..8fb45d9 --- /dev/null +++ b/_scripts/setup.sh @@ -0,0 +1,5 @@ +sudo apt-get update +sudo apt-get install python3-venv + +mkdir location_app location_app/app +python3 -m venv location_app/venv diff --git a/location_app/.flaskenv b/location_app/.flaskenv new file mode 100644 index 0000000..6664273 --- /dev/null +++ b/location_app/.flaskenv @@ -0,0 +1,5 @@ +FLASK_APP=location_app.py +FLASK_ENV=development +FLASK_RUN_HOST='0.0.0.0' +FLASK_RUN_PORT=3000 +MYAPP_SETTINGS=configuration.cfg diff --git a/location_app/app/__init__.py b/location_app/app/__init__.py new file mode 100644 index 0000000..d3fc97f --- /dev/null +++ b/location_app/app/__init__.py @@ -0,0 +1,13 @@ +from flask import Flask +from app import mqtt, routes + + +app = Flask(__name__) +app.config.from_envvar('MYAPP_SETTINGS') + +mqtt.init_app(app) + +routes.init_app(app) + + + diff --git a/location_app/app/configuration.cfg b/location_app/app/configuration.cfg new file mode 100644 index 0000000..01bc240 --- /dev/null +++ b/location_app/app/configuration.cfg @@ -0,0 +1,9 @@ +MQTT_BROKER_URL='mqtt.coventry.ac.uk' +MQTT_BROKER_PORT=8883 +MQTT_USERNAME='4009user' +MQTT_PASSWORD='mqttBROKER' +MQTT_TLS_ENABLED=True +MQTT_TLS_INSECURE=True +MQTT_TLS_CA_CERTS='mqtt.coventry.ac.uk.crt' +MQTT_REFRESH_TIME=1.0 +TEMPLATES_AUTO_RELOAD=True \ No newline at end of file diff --git a/location_app/app/functions/auth/password_check.py b/location_app/app/functions/auth/password_check.py new file mode 100644 index 0000000..be9a672 --- /dev/null +++ b/location_app/app/functions/auth/password_check.py @@ -0,0 +1,70 @@ +import sqlite3 as sql + + +database_user = "app/databases/users.db" +database_locations = 'app/databases/locations.db' + +def if_user_exists(username): + print(f"checked for existance - {username}") + with sql.connect(database_user) as cur: + res = cur.execute(f"SELECT count(*) FROM UserDatabase WHERE username='{username}';").fetchone()[0] + if res == 0: + return False + else: + return True + +def if_tid_exists(username): + print(f"checked for tid existance - {username}") + with sql.connect(database_locations) as cur: + res = cur.execute(f"SELECT count(*) FROM Location WHERE tid='{username}';").fetchone()[0] + if res == 0: + return False + else: + return True + +def password_for(username, password): + print(f"checked password - {username}") + with sql.connect(database_user) as cur: + res = cur.execute(f"SELECT password FROM UserDatabase WHERE username='{username}';").fetchone()[0] + if password == res: + return True + else: + return False + +def make_user(username, password): + print(f"created a new user - {username}") + con = sql.connect(database_user) + cur = con.cursor() + cur.execute(f"INSERT INTO UserDatabase values('{username}','{password}');") + con.commit() + cur.close() + con.close() + +def change_password(username, new_password): + print(f"created a new password - {username}") + con = sql.connect(database_user) + cur = con.cursor() + cur.execute(f"UPDATE UserDatabase SET password='{new_password}' WHERE username='{username}';") + con.commit() + cur.close() + con.close() + +def username_and_password(username, password): + with sql.connect(database_user) as cur: + try: + cur.execute("CREATE TABLE UserDatabase(username VARCHAR2(20), password VARCHAR2(20));") + except: + pass + if username == "admin" and password == "admin": + return "L" + if if_user_exists(username): + if password_for(username, password): + return "L" + else: + return "WP" + else: + if if_tid_exists(username): + make_user(username, password) + return "L" + else: + return "NO" \ No newline at end of file diff --git a/location_app/app/functions/data_tools/data_getter.py b/location_app/app/functions/data_tools/data_getter.py new file mode 100644 index 0000000..747348f --- /dev/null +++ b/location_app/app/functions/data_tools/data_getter.py @@ -0,0 +1,51 @@ +import sqlite3 as sql +import time + + +database_user = "app/databases/users.db" +database_locations = "app/databases/locations.db" + +def get_user_for(username): + with sql.connect(database_user) as cur: + res = cur.execute(f"SELECT * FROM UserDatabase WHERE username='{username}';").fetchone() + +def get_filtered_data_for(tid): + data_city = get_frequency_for('city', tid) + data_road = get_frequency_for('road', tid) + data_batt = get_frequency_for('battery', tid) + return [data_city, data_road, data_batt] + +def get_all_tids(): + with sql.connect(database_locations) as cur: + tids = cur.execute("SELECT DISTINCT tid From Location;") + tids_list = list(map(lambda x: x[0], tids)) + return tids_list + +def get_frequency_for(data_type, tid): + with sql.connect(database_locations) as cur: + data = cur.execute(f"SELECT {data_type} From Location WHERE tid = '{tid}';") + data_list = list(map(lambda x: x[0], data)) + frequent_data = max(set(data_list), key = data_list.count) + frequency_data = str(int((data_list.count(frequent_data)/len(data_list)) * 100)) + return [frequent_data, frequency_data] + +def get_filtered_data_for_admin(): + all_data = [] + tids = get_all_tids() + for tid in tids: + data_city = get_frequency_for('city', tid) + data_road = get_frequency_for('road', tid) + data_batt = get_frequency_for('battery', tid) + all_data.append([tid, data_city, data_road, data_batt]) + return all_data + +def get_locations(): + locations = [] + with sql.connect(database_locations) as cur: + res = cur.execute(f"SELECT DISTINCT * From Location ORDER BY tid, timestamp;") + for tid, batt, lon, lat, city, road, tst, in res: + rtst = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tst)) + locations.append([tid, batt, lon, lat, city, road, rtst]) + print(locations) + return locations + \ No newline at end of file diff --git a/location_app/app/mqtt/__init__.py b/location_app/app/mqtt/__init__.py new file mode 100644 index 0000000..8056420 --- /dev/null +++ b/location_app/app/mqtt/__init__.py @@ -0,0 +1,13 @@ +from flask_mqtt import Mqtt +from app.mqtt import mqtt_message_handler + +def init_app(app): + mqtt = Mqtt(app) + + @mqtt.on_connect() + def handle_connect(client, userdata, flags, rc): + mqtt.subscribe('owntracks/4009user/#') + + @mqtt.on_message() + def handle_mqtt_message(client, userdata, msg): + mqtt_message_handler.getMsg(msg) diff --git a/location_app/app/mqtt/mqtt_message_handler.py b/location_app/app/mqtt/mqtt_message_handler.py new file mode 100644 index 0000000..995460f --- /dev/null +++ b/location_app/app/mqtt/mqtt_message_handler.py @@ -0,0 +1,33 @@ +from geopy.geocoders import Nominatim +import sqlite3 as sql +import json, os, time + + +database_locations = 'app/databases/locations.db' + +def getMsg(msg): + con = sql.connect(database_locations) + cur = con.cursor() + geolocator = Nominatim(user_agent="Web_app") + try: + cur.execute("CREATE TABLE Location(tid VARCHAR2(2), battery INT(3), longitude NUMBER(10,6), latitude NUMBER(10,6), city VARCHAR2(20), road VARCHAR2(30), timestamp INT(20));") + except: + pass + data = json.loads(msg.payload.decode("utf8")) + tid = data["tid"] + batt = data["batt"] + lat = data["lat"] + lon = data["lon"] + location = geolocator.reverse(f"{data['lat']},{data['lon']}") + city = location.raw["address"]["city"] + road = location.raw["address"]["road"] + tstamp = data["tst"] + + print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tstamp)), ' ---- ', tid) + + cur.execute(f"INSERT INTO Location values('{tid}','{batt}','{lat}','{lon}','{city}','{road}','{tstamp}');") + + con.commit() + cur.close() + con.close() + \ No newline at end of file diff --git a/location_app/app/routes/__init__.py b/location_app/app/routes/__init__.py new file mode 100644 index 0000000..2011db0 --- /dev/null +++ b/location_app/app/routes/__init__.py @@ -0,0 +1,4 @@ +from .login import main_bl + +def init_app(app): + app.register_blueprint(main_bl) \ No newline at end of file diff --git a/location_app/app/routes/login.py b/location_app/app/routes/login.py new file mode 100644 index 0000000..860fa6b --- /dev/null +++ b/location_app/app/routes/login.py @@ -0,0 +1,21 @@ +from flask import Blueprint, render_template, request, url_for, escape, redirect +from app.functions.auth import password_check +from app.functions.data_tools import data_getter + +main_bl = Blueprint('main', __name__) + +@main_bl.route("/", methods = ["GET", "POST"]) +@main_bl.route("/index", methods = ["GET", "POST"]) +def login(): + if request.method == "POST": + username = request.form["username"] + password = request.form["password"] + status = password_check.username_and_password(username, password) + if status == "L": + return redirect(url_for("testt", username = username)) + elif status == "WP": + return render_template("index.html", error = 1) + elif status == "NO": + return render_template("index.html", error = 2) + else: + return render_template("index.html", error = 0) \ No newline at end of file diff --git a/location_app/app/static/css/base.css b/location_app/app/static/css/base.css new file mode 100644 index 0000000..438954d --- /dev/null +++ b/location_app/app/static/css/base.css @@ -0,0 +1,3 @@ +body { + background-color: red; +} \ No newline at end of file diff --git a/location_app/app/templates/_template.html b/location_app/app/templates/_template.html new file mode 100644 index 0000000..30e6843 --- /dev/null +++ b/location_app/app/templates/_template.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} + + +{% block title %} " Insert title here " {% endblock %} + + +{% block css %} + + " Insert css here " + +{% endblock %} + + +{% block body %} + + " Insert body here " + +{% endblock %} + diff --git a/location_app/app/templates/base.html b/location_app/app/templates/base.html new file mode 100644 index 0000000..c578e43 --- /dev/null +++ b/location_app/app/templates/base.html @@ -0,0 +1,18 @@ + + + + +
+ + + +ID | +Battery | +Longitude | +Latitude | +City | +Road | +TST | +
---|---|---|---|---|---|---|
{{ item[0] }} | +{{ item[1] }} % | +{{ item[2] }} | +{{ item[3] }} | +{{ item[4] }} | +{{ item[5] }} | +{{ item[6] }} | +