From 2388c3731f278188ec211ca71390f1a6faa5cb5a Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Wed, 23 Sep 2020 18:13:50 +0200 Subject: [PATCH] Fixed #1, #2 - added post route and save to database --- .gitignore | 1 + settings-example.json | 3 ++ src/blueprints/Routes.py | 48 ++++++++++++++++++++- src/logic/Database.py | 79 +++++++++++++++++++++++++++++++++++ src/logic/RequestValidator.py | 29 +++++++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/logic/Database.py create mode 100644 src/logic/RequestValidator.py diff --git a/.gitignore b/.gitignore index 2a71b46..6e87e73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /Pipfile.lock /settings.json +/src/storageLeaf.db diff --git a/settings-example.json b/settings-example.json index 5324240..d8ae21d 100644 --- a/settings-example.json +++ b/settings-example.json @@ -6,5 +6,8 @@ "useSSL": false, "keyfile": "", "certfile": "" + }, + "database": { + "databasePath": "storageLeaf.db" } } \ No newline at end of file diff --git a/src/blueprints/Routes.py b/src/blueprints/Routes.py index da3d6d8..81dc5d8 100644 --- a/src/blueprints/Routes.py +++ b/src/blueprints/Routes.py @@ -1,4 +1,27 @@ -from flask import Blueprint, render_template +from enum import Enum + +from flask import Blueprint, request, jsonify + +from logic.Database import Database +from logic.RequestValidator import ValidationError, RequestValidator + + +class DeviceParameters(Enum): + SENSORS = 'sensors' + + @staticmethod + def get_values(): + return [m.value for m in DeviceParameters] + + +class SensorParameters(Enum): + NAME = 'name' + TYPE = 'type' + VALUE = 'value' + + @staticmethod + def get_values(): + return [m.value for m in SensorParameters] def construct_blueprint(settings): @@ -8,4 +31,27 @@ def construct_blueprint(settings): def index(): return "Hello World!" + @routes.route('/device/<deviceName>', methods=['POST']) + def postSensorData(deviceName): + try: + parameters = RequestValidator.validate(request, DeviceParameters.get_values()) + sensors = parameters[DeviceParameters.SENSORS.value] + for sensor in sensors: + sensorParams = RequestValidator.validate_parameters(sensor, + SensorParameters.get_values(), + f'sensor "{sensor}"') + database = Database(settings['database']['databasePath']) + database.add_device_if_not_exists(deviceName) + device = database.get_device(deviceName) + database.add_or_update_sensor(device, + sensorParams['name'], + sensorParams['type'], + sensorParams['value']) + return jsonify(database.get_device("0182")) + + except ValidationError as e: + return e.response, 400 + + return "" + return routes diff --git a/src/logic/Database.py b/src/logic/Database.py new file mode 100644 index 0000000..6774059 --- /dev/null +++ b/src/logic/Database.py @@ -0,0 +1,79 @@ +import sqlite3 +from typing import Tuple + +from TheCodeLabs_BaseUtils import DefaultLogger + +from logic import Constants + +LOGGER = DefaultLogger().create_logger_if_not_exists(Constants.APP_NAME) + + +class Database: + TABLE_DEVICE = 'device' + TABLE_SENSOR = 'sensor' + + def __init__(self, databasePath): + self._databasePath = databasePath + self.__create_database() + + def __create_database(self): + LOGGER.debug('Creating database tables...') + with self.__get_connection() as connection: + connection.execute(f'''CREATE TABLE IF NOT EXISTS {self.TABLE_DEVICE} ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL)''') + connection.execute(f'''CREATE TABLE IF NOT EXISTS sensor ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + device_id INTEGER, + name TEXT NOT NULL, + type TEXT NOT NULL, + value TEXT NOT NULL)''') + + def __get_connection(self): + return sqlite3.connect(self._databasePath) + + def get_all_devices(self): + with self.__get_connection() as connection: + cursor = connection.execute(f'SELECT * FROM {self.TABLE_DEVICE} ORDER BY name') + return cursor.fetchall() + + def get_device(self, deviceName: str): + with self.__get_connection() as connection: + cursor = connection.execute(f'SELECT * FROM {self.TABLE_DEVICE} WHERE name = "{deviceName}"') + return cursor.fetchone() + + def add_device_if_not_exists(self, deviceName: str): + if self.get_device(deviceName): + LOGGER.debug(f'Device "{deviceName}" already exists') + return + + with self.__get_connection() as connection: + LOGGER.debug(f'Inserting new device "{deviceName}"') + connection.execute(f'INSERT INTO {self.TABLE_DEVICE}(name) VALUES(?)', (deviceName,)) + + def get_all_sensors(self): + with self.__get_connection() as connection: + cursor = connection.execute(f'SELECT * FROM {self.TABLE_SENSOR} ORDER BY device_id, name') + return cursor.fetchall() + + def get_sensor(self, deviceName: str, name: str): + device = self.get_device(deviceName) + if not device: + return None + + with self.__get_connection() as connection: + cursor = connection.execute(f'SELECT * FROM {self.TABLE_SENSOR} WHERE device_id = ? AND name = ?', + (device[0], name)) + return cursor.fetchone() + + def add_or_update_sensor(self, device: Tuple[int, str], name: str, sensorType: str, value: str): + sensor = self.get_sensor(device[1], name) + with self.__get_connection() as connection: + if sensor: + LOGGER.debug(f'Updating sensor "{name}" for device "{device[1]}" (type: "{sensorType}", value: "{value}")') + connection.execute(f'UPDATE {self.TABLE_SENSOR} SET value = ? WHERE device_id = ? AND name = ?', + (value, device[0], name)) + else: + LOGGER.debug(f'Inserting new sensor "{name}" for device "{device[1]}" (type: "{sensorType}", value: "{value}")') + connection.execute(f'INSERT INTO {self.TABLE_SENSOR}(name, device_id, type, value) VALUES(?, ?, ?, ?)', + (name, device[0], sensorType, value)) diff --git a/src/logic/RequestValidator.py b/src/logic/RequestValidator.py new file mode 100644 index 0000000..5303324 --- /dev/null +++ b/src/logic/RequestValidator.py @@ -0,0 +1,29 @@ +from typing import Dict, List + +from flask import jsonify + + +class ValidationError(Exception): + def __init__(self, message): + super().__init__(message) + self.response = jsonify({'success': False, + 'msg': message}) + + +class RequestValidator: + @staticmethod + def validate(request, parameters: List[str]) -> Dict: + if not request.is_json: + raise ValidationError('Missing JSON in request') + + return RequestValidator.validate_parameters(request.json, parameters, 'request') + + @staticmethod + def validate_parameters(data: Dict, parameters: List[str], itemName: str) -> Dict: + result = {} + for param in parameters: + value = data.get(param, None) + if value is None: + raise ValidationError(f'Missing parameter "{param}" for {itemName}') + result[param] = value + return result -- GitLab