diff --git a/myems-api/core/equipment.py b/myems-api/core/equipment.py index 84edc4d5..ae938394 100644 --- a/myems-api/core/equipment.py +++ b/myems-api/core/equipment.py @@ -3,18 +3,22 @@ import simplejson as json import mysql.connector import config import uuid +from log import decorator_record_action_log class EquipmentCollection: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp): cnx = mysql.connector.connect(**config.myems_system_db) cursor = cnx.cursor(dictionary=True) @@ -57,6 +61,7 @@ class EquipmentCollection: resp.body = json.dumps(result) @staticmethod + @decorator_record_action_log def on_post(req, resp): """Handles POST requests""" try: @@ -144,14 +149,17 @@ class EquipmentCollection: class EquipmentItem: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -198,6 +206,7 @@ class EquipmentItem: resp.body = json.dumps(meta_result) @staticmethod + @decorator_record_action_log def on_delete(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -284,6 +293,7 @@ class EquipmentItem: resp.status = falcon.HTTP_204 @staticmethod + @decorator_record_action_log def on_put(req, resp, id_): """Handles PUT requests""" if not id_.isdigit() or int(id_) <= 0: @@ -380,6 +390,7 @@ class EquipmentItem: # Clone an Equipment @staticmethod + @decorator_record_action_log def on_post(req, resp, id_): """Handles PUT requests""" if not id_.isdigit() or int(id_) <= 0: @@ -525,14 +536,17 @@ class EquipmentItem: class EquipmentParameterCollection: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -655,6 +669,7 @@ class EquipmentParameterCollection: resp.body = json.dumps(result) @staticmethod + @decorator_record_action_log def on_post(req, resp, id_): """Handles POST requests""" if not id_.isdigit() or int(id_) <= 0: @@ -838,14 +853,17 @@ class EquipmentParameterCollection: class EquipmentParameterItem: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_, pid): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_, pid): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -962,6 +980,7 @@ class EquipmentParameterItem: resp.body = json.dumps(meta_result) @staticmethod + @decorator_record_action_log def on_delete(req, resp, id_, pid): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1008,6 +1027,7 @@ class EquipmentParameterItem: resp.status = falcon.HTTP_204 @staticmethod + @decorator_record_action_log def on_put(req, resp, id_, pid): """Handles POST requests""" if not id_.isdigit() or int(id_) <= 0: @@ -1209,14 +1229,17 @@ class EquipmentParameterItem: class EquipmentMeterCollection: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1265,6 +1288,7 @@ class EquipmentMeterCollection: resp.body = json.dumps(result) @staticmethod + @decorator_record_action_log def on_post(req, resp, id_): """Handles POST requests""" try: @@ -1336,14 +1360,17 @@ class EquipmentMeterCollection: class EquipmentMeterItem: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_, mid): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_delete(req, resp, id_, mid): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1394,14 +1421,17 @@ class EquipmentMeterItem: class EquipmentOfflineMeterCollection: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1450,6 +1480,7 @@ class EquipmentOfflineMeterCollection: resp.body = json.dumps(result) @staticmethod + @decorator_record_action_log def on_post(req, resp, id_): """Handles POST requests""" try: @@ -1521,14 +1552,17 @@ class EquipmentOfflineMeterCollection: class EquipmentOfflineMeterItem: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_, mid): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_delete(req, resp, id_, mid): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1580,14 +1614,17 @@ class EquipmentOfflineMeterItem: class EquipmentVirtualMeterCollection: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_get(req, resp, id_): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', @@ -1636,6 +1673,7 @@ class EquipmentVirtualMeterCollection: resp.body = json.dumps(result) @staticmethod + @decorator_record_action_log def on_post(req, resp, id_): """Handles POST requests""" try: @@ -1707,14 +1745,17 @@ class EquipmentVirtualMeterCollection: class EquipmentVirtualMeterItem: @staticmethod + @decorator_record_action_log def __init__(): pass @staticmethod + @decorator_record_action_log def on_options(req, resp, id_, mid): resp.status = falcon.HTTP_200 @staticmethod + @decorator_record_action_log def on_delete(req, resp, id_, mid): if not id_.isdigit() or int(id_) <= 0: raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', diff --git a/myems-api/log.py b/myems-api/log.py new file mode 100644 index 00000000..383db162 --- /dev/null +++ b/myems-api/log.py @@ -0,0 +1,140 @@ +import os +from functools import wraps +import config +import mysql.connector +from datetime import datetime, timezone +import uuid +from gunicorn.http.body import Body + + +def write_log(user_uuid, action, _class, record_id, record_text): + """ + :param user_uuid: user_uuid + :param action: create, update, delete and others: login, logout, reset password, change password + :param _class: class_name + :param record_id: int + :param record_text: str + """ + now = datetime.now() + cnx = None + cursor = None + try: + cnx = mysql.connector.connect(**config.myems_user_db) + cursor = cnx.cursor() + cursor.execute(" SELECT display_name " + " FROM tbl_users " + " WHERE uuid = %s ", + (user_uuid,)) + row = cursor.fetchone() + user = dict() + if row is not None and len(row) > 0: + user["name"] = row[0] + else: + user["name"] = "visitor" + + cnx = mysql.connector.connect(**config.myems_user_db) + cursor = cnx.cursor() + add_row = (" INSERT INTO tbl_action_logs " + " (user_name, date_time, action, class, record_id, record_text) " + " VALUES (%s, %s, %s, %s, %s , %s) ") + cursor.execute(add_row, (user['name'], + now, + action, + _class, + record_id if record_id else None, + record_text if record_text else None, + )) + cnx.commit() + except Exception as e: + print(str(e)) + if cnx: + cnx.disconnect() + if cursor: + cursor.close() + finally: + if cnx: + cnx.disconnect() + if cursor: + cursor.close() + + +def decorator_record_action_log(func): + @wraps(func) + def log_fun(*args, **kwargs): + type_dict = { + "on_post": "create", + "on_put": "update", + "on_delete": "delete", + } + + func_names = func.__qualname__ + class_name = func_names.split(".")[0] + fun_name = func_names.split(".")[1] + if fun_name not in type_dict.keys(): + return func(*args, **kwargs) + + if len(args) > 1: + req, resp = args + cookies = req.cookies + if cookies is not None and 'user_uuid' in cookies.keys(): + user_uuid = cookies['user_uuid'] + else: + user_uuid = None + else: + return func(*args, **kwargs) + + action = type_dict.get(fun_name) + + if class_name == "UserLogin": + action = "login" + elif class_name == "UserLogout": + action = "logout" + elif class_name == "ResetPassword": + action = "reset password" + elif class_name == "ChangePassword": + action = "change password" + else: + pass + + if fun_name == "on_post": + file_name = str(uuid.uuid4()) + with open(file_name, "wb") as fw: + reads = req.stream.read() + fw.write(reads) + raw_json = reads.decode('utf-8') + + with open(file_name, "rb") as fr: + req.stream = Body(fr) + write_log(user_uuid=user_uuid, action=action, _class=class_name, + record_id=None, record_text=raw_json) + func(*args, **kwargs) + os.remove(file_name) + return + + elif fun_name == "on_put": + id_ = kwargs.get('id_') + file_name = str(uuid.uuid4()) + with open(file_name, "wb") as fw: + reads = req.stream.read() + fw.write(reads) + raw_json = reads.decode('utf-8') + + with open(file_name, "rb") as fr: + req.stream = Body(fr) + write_log(user_uuid=user_uuid, action=action, _class=class_name, + record_id=id_, record_text=raw_json) + func(*args, **kwargs) + os.remove(file_name) + return + + elif fun_name == "on_delete": + id_ = kwargs.get('id_') + write_log(user_uuid=user_uuid, action=action, _class=class_name, + record_id=id_, record_text=None) + func(*args, **kwargs) + return + else: + func(*args, **kwargs) + return + + return log_fun