|
|
@@ -1,15 +1,29 @@ |
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
""" |
|
|
|
|
|
enpoints for logging |
|
|
|
|
|
""" |
|
|
import csv |
|
|
import csv |
|
|
import datetime |
|
|
import datetime |
|
|
import os |
|
|
import os |
|
|
from flask import Blueprint, request, send_from_directory, json |
|
|
|
|
|
|
|
|
import re |
|
|
|
|
|
|
|
|
|
|
|
from flask import send_from_directory, json |
|
|
from flask_classy import FlaskView, route |
|
|
from flask_classy import FlaskView, route |
|
|
from modules import cbpi |
|
|
from modules import cbpi |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LogView(FlaskView): |
|
|
class LogView(FlaskView): |
|
|
|
|
|
""" |
|
|
|
|
|
View for logging |
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
@route('/', methods=['GET']) |
|
|
@route('/', methods=['GET']) |
|
|
def get_all_logfiles(self): |
|
|
|
|
|
|
|
|
def get_all_logfiles(self): # pylint: disable=no-self-use |
|
|
|
|
|
""" |
|
|
|
|
|
get all log files |
|
|
|
|
|
|
|
|
|
|
|
:return: json for all logs |
|
|
|
|
|
""" |
|
|
result = [] |
|
|
result = [] |
|
|
for filename in os.listdir("./logs"): |
|
|
for filename in os.listdir("./logs"): |
|
|
if filename.endswith(".log"): |
|
|
if filename.endswith(".log"): |
|
|
@@ -17,90 +31,150 @@ class LogView(FlaskView): |
|
|
return json.dumps(result) |
|
|
return json.dumps(result) |
|
|
|
|
|
|
|
|
@route('/actions') |
|
|
@route('/actions') |
|
|
def actions(self): |
|
|
|
|
|
|
|
|
def actions(self): # pylint: disable=no-self-use |
|
|
|
|
|
""" |
|
|
|
|
|
get actions log |
|
|
|
|
|
|
|
|
|
|
|
:return: json for actions log |
|
|
|
|
|
""" |
|
|
filename = "./logs/action.log" |
|
|
filename = "./logs/action.log" |
|
|
if os.path.isfile(filename) == False: |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
if not os.path.isfile(filename): |
|
|
|
|
|
return ('File not found', 404) |
|
|
array = [] |
|
|
array = [] |
|
|
with open(filename, 'rb', encoding='utf-8') as f: |
|
|
|
|
|
reader = csv.reader(f) |
|
|
|
|
|
|
|
|
with open(filename, 'rb', encoding='utf-8') as csv_file: |
|
|
|
|
|
reader = csv.reader(csv_file) |
|
|
for row in reader: |
|
|
for row in reader: |
|
|
try: |
|
|
try: |
|
|
array.append([int((datetime.datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S") - datetime.datetime(1970, 1, 1)).total_seconds()) * 1000, row[1]]) |
|
|
|
|
|
except: |
|
|
|
|
|
|
|
|
array.append([ |
|
|
|
|
|
int((datetime.datetime.strptime( |
|
|
|
|
|
row[0], "%Y-%m-%d %H:%M:%S") - |
|
|
|
|
|
datetime.datetime(1970, 1, 1)).total_seconds()) * |
|
|
|
|
|
1000, row[1] |
|
|
|
|
|
]) |
|
|
|
|
|
except IndexError: |
|
|
pass |
|
|
pass |
|
|
return json.dumps(array) |
|
|
return json.dumps(array) |
|
|
|
|
|
|
|
|
@route('/<file>', methods=["DELETE"]) |
|
|
@route('/<file>', methods=["DELETE"]) |
|
|
def clearlog(self, file): |
|
|
def clearlog(self, file): |
|
|
""" |
|
|
""" |
|
|
Overload delete method to shutdown sensor before delete |
|
|
|
|
|
:param id: sensor id |
|
|
|
|
|
|
|
|
log delete |
|
|
|
|
|
:param file: log file name |
|
|
:return: HTTP 204 |
|
|
:return: HTTP 204 |
|
|
""" |
|
|
""" |
|
|
if not self.check_filename(file): |
|
|
if not self.check_filename(file): |
|
|
return ('File Not Found', 404) |
|
|
return ('File Not Found', 404) |
|
|
|
|
|
|
|
|
filename = "./logs/%s" % file |
|
|
filename = "./logs/%s" % file |
|
|
if os.path.isfile(filename) == True: |
|
|
|
|
|
|
|
|
if os.path.isfile(filename): |
|
|
os.remove(filename) |
|
|
os.remove(filename) |
|
|
cbpi.notify("log deleted succesfully", "") |
|
|
cbpi.notify("log deleted succesfully", "") |
|
|
else: |
|
|
else: |
|
|
cbpi.notify("Failed to delete log", "", type="danger") |
|
|
cbpi.notify("Failed to delete log", "", type="danger") |
|
|
return ('', 204) |
|
|
return ('', 204) |
|
|
|
|
|
|
|
|
def read_log_as_json(self, type, id): |
|
|
|
|
|
filename = "./logs/%s_%s.log" % (type, id) |
|
|
|
|
|
if os.path.isfile(filename) == False: |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
def read_log_as_json(self, log_type, log_id): # pylint: disable=no-self-use |
|
|
|
|
|
""" |
|
|
|
|
|
:param log_type: log type |
|
|
|
|
|
:param log_id: log id |
|
|
|
|
|
|
|
|
|
|
|
:return: log as array |
|
|
|
|
|
""" |
|
|
|
|
|
filename = "./logs/%s_%s.log" % (log_type, log_id) |
|
|
|
|
|
if not os.path.isfile(filename): |
|
|
|
|
|
return ('File not found', 404) |
|
|
|
|
|
|
|
|
import csv |
|
|
|
|
|
array = [] |
|
|
array = [] |
|
|
with open(filename, 'rb', encoding='utf-8') as f: |
|
|
|
|
|
reader = csv.reader(f) |
|
|
|
|
|
|
|
|
with open(filename, 'rb', encoding='utf-8') as csv_file: |
|
|
|
|
|
reader = csv.reader(csv_file) |
|
|
for row in reader: |
|
|
for row in reader: |
|
|
try: |
|
|
try: |
|
|
array.append([int((datetime.datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S") - datetime.datetime(1970, 1, 1)).total_seconds()) * 1000, float(row[1])]) |
|
|
|
|
|
except: |
|
|
|
|
|
|
|
|
array.append([ |
|
|
|
|
|
int((datetime.datetime.strptime( |
|
|
|
|
|
row[0], "%Y-%m-%d %H:%M:%S") - |
|
|
|
|
|
datetime.datetime(1970, 1, 1)).total_seconds()) * |
|
|
|
|
|
1000, |
|
|
|
|
|
float(row[1]) |
|
|
|
|
|
]) |
|
|
|
|
|
except IndexError: |
|
|
pass |
|
|
pass |
|
|
return array |
|
|
return array |
|
|
|
|
|
|
|
|
def convert_chart_data_to_json(self, chart_data): |
|
|
def convert_chart_data_to_json(self, chart_data): |
|
|
return {"name": chart_data["name"], "data": self.read_log_as_json(chart_data["data_type"], chart_data["data_id"])} |
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
:param chart_data: data for a chart |
|
|
|
|
|
|
|
|
@route('/<t>/<int:id>', methods=["POST"]) |
|
|
|
|
|
def get_logs_as_json(self, t, id): |
|
|
|
|
|
data = request.json |
|
|
|
|
|
result = [] |
|
|
|
|
|
if t == "s": |
|
|
|
|
|
name = cbpi.cache.get("sensors").get(id).name |
|
|
|
|
|
result.append({"name": name, "data": self.read_log_as_json("sensor", id)}) |
|
|
|
|
|
|
|
|
:return: json for chart data |
|
|
|
|
|
""" |
|
|
|
|
|
return { |
|
|
|
|
|
"name": |
|
|
|
|
|
chart_data["name"], |
|
|
|
|
|
"data": |
|
|
|
|
|
self.read_log_as_json(chart_data["data_type"], |
|
|
|
|
|
chart_data["data_id"]) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if t == "k": |
|
|
|
|
|
kettle = cbpi.cache.get("kettle").get(id) |
|
|
|
|
|
result = list(map(self.convert_chart_data_to_json, cbpi.get_controller(kettle.logic).get("class").chart(kettle))) |
|
|
|
|
|
|
|
|
@route('/<t>/<int:id>', methods=["POST"]) |
|
|
|
|
|
def get_logs_as_json(self, log_type, log_id): |
|
|
|
|
|
""" |
|
|
|
|
|
:param log_type: log type |
|
|
|
|
|
:param log_id: log id |
|
|
|
|
|
|
|
|
if t == "f": |
|
|
|
|
|
fermenter = cbpi.cache.get("fermenter").get(id) |
|
|
|
|
|
result = list(map(self.convert_chart_data_to_json, cbpi.get_fermentation_controller(fermenter.logic).get("class").chart(fermenter))) |
|
|
|
|
|
|
|
|
:return: log as array |
|
|
|
|
|
""" |
|
|
|
|
|
result = [] |
|
|
|
|
|
if log_type == "s": |
|
|
|
|
|
name = cbpi.cache.get("sensors").get(log_id).name |
|
|
|
|
|
result.append({ |
|
|
|
|
|
"name": name, |
|
|
|
|
|
"data": self.read_log_as_json("sensor", log_id) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
if log_type == "k": |
|
|
|
|
|
kettle = cbpi.cache.get("kettle").get(log_id) |
|
|
|
|
|
result = list( |
|
|
|
|
|
map( |
|
|
|
|
|
self.convert_chart_data_to_json, |
|
|
|
|
|
cbpi.get_controller( |
|
|
|
|
|
kettle.logic).get("class").chart(kettle))) |
|
|
|
|
|
|
|
|
|
|
|
if log_type == "f": |
|
|
|
|
|
fermenter = cbpi.cache.get("fermenter").get(log_id) |
|
|
|
|
|
result = list( |
|
|
|
|
|
map( |
|
|
|
|
|
self.convert_chart_data_to_json, |
|
|
|
|
|
cbpi.get_fermentation_controller( |
|
|
|
|
|
fermenter.logic).get("class").chart(fermenter))) |
|
|
|
|
|
|
|
|
return json.dumps(result) |
|
|
return json.dumps(result) |
|
|
|
|
|
|
|
|
@route('/download/<file>') |
|
|
@route('/download/<file>') |
|
|
@cbpi.nocache |
|
|
@cbpi.nocache |
|
|
def download(self, file): |
|
|
def download(self, file): |
|
|
|
|
|
""" |
|
|
|
|
|
:param file: log file name |
|
|
|
|
|
|
|
|
|
|
|
:return: log data |
|
|
|
|
|
""" |
|
|
if not self.check_filename(file): |
|
|
if not self.check_filename(file): |
|
|
return ('File Not Found', 404) |
|
|
return ('File Not Found', 404) |
|
|
return send_from_directory('../logs', file, as_attachment=True, attachment_filename=file) |
|
|
|
|
|
|
|
|
return send_from_directory('../logs', |
|
|
|
|
|
file, |
|
|
|
|
|
as_attachment=True, |
|
|
|
|
|
attachment_filename=file) |
|
|
|
|
|
|
|
|
def check_filename(self, name): |
|
|
|
|
|
import re |
|
|
|
|
|
|
|
|
def check_filename(self, name): # pylint: disable=no-self-use |
|
|
|
|
|
""" |
|
|
|
|
|
:param name: log file name |
|
|
|
|
|
:return: bool |
|
|
|
|
|
""" |
|
|
pattern = re.compile('^([A-Za-z0-9-_])+.log$') |
|
|
pattern = re.compile('^([A-Za-z0-9-_])+.log$') |
|
|
|
|
|
|
|
|
return True if pattern.match(name) else False |
|
|
|
|
|
|
|
|
return bool(pattern.match(name)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@cbpi.initalizer() |
|
|
@cbpi.initalizer() |
|
|
def init(app): |
|
|
|
|
|
|
|
|
def init(app): # pylint: disable=unused-argument |
|
|
""" |
|
|
""" |
|
|
Initializer for the message module |
|
|
Initializer for the message module |
|
|
:param app: the flask app |
|
|
:param app: the flask app |
|
|
|