diff --git a/backend/SC4SNMP_UI_backend/common/conversions.py b/backend/SC4SNMP_UI_backend/common/conversions.py index d5e3e30..b5e2c48 100644 --- a/backend/SC4SNMP_UI_backend/common/conversions.py +++ b/backend/SC4SNMP_UI_backend/common/conversions.py @@ -1,35 +1,65 @@ from abc import abstractmethod -class Conversion: +def camel_case2snake_case(txt): + return ''.join(['_' + i.lower() if i.isupper() + else i for i in txt]).lstrip('_') + + +def snake_case2camel_case(txt): + result = [] + to_upper = False + for i in range(len(txt)): + if txt[i] != "_": + result.append(txt[i].upper()) if to_upper else result.append(txt[i]) + to_upper = False + elif txt[i] == "_" and i < len(txt) - 1: + to_upper = True + continue + + return ''.join(result) + + +def get_group_name_from_backend(document: dict): + group_name = None + for key in document.keys(): + if key != "_id": + group_name = key + if group_name is None: + raise ValueError("No group name detected") + else: + return group_name + + +class Conversion: @abstractmethod - def _ui2backend_map(self, document: dict): + def _ui2backend_map(self, document: dict, **kwargs): pass @abstractmethod - def _backend2ui_map(self, document: dict): + def _backend2ui_map(self, document: dict, **kwargs): pass - def backend2ui(self, document: dict): - return self._backend2ui_map(document) + def backend2ui(self, document: dict, **kwargs): + return self._backend2ui_map(document, **kwargs) - def ui2backend(self, document: dict): - return self._ui2backend_map(document) + def ui2backend(self, document: dict, **kwargs): + return self._ui2backend_map(document, **kwargs) class ProfileConversion(Conversion): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - def _backend2ui_map(self, profile: dict): + def _backend2ui_map(self, document: dict, **kwargs): profile_name = None - for key in profile.keys(): + for key in document.keys(): if key != "_id": profile_name = key if profile_name is None: raise ValueError("No profile name detected") else: - backend_var_binds = profile[profile_name]["varBinds"] + backend_var_binds = document[profile_name]["varBinds"] var_binds = [] for vb in backend_var_binds: new_vb = { @@ -39,8 +69,8 @@ def _backend2ui_map(self, profile: dict): } var_binds.append(new_vb) - if "condition" in profile[profile_name]: - backend_condition = profile[profile_name]["condition"] + if "conditions" in document[profile_name]: + backend_condition = document[profile_name]["conditions"] condition_type = backend_condition["type"] field = backend_condition["field"] if condition_type == "field" else "" patterns = [{"pattern": p} for p in backend_condition["patterns"]] if condition_type == "field" else None @@ -55,30 +85,30 @@ def _backend2ui_map(self, profile: dict): "field": "", "patterns": None } - converted = { - "_id": profile["_id"], + result = { + "_id": document["_id"], "profileName": profile_name, - "frequency": profile[profile_name]["frequency"], + "frequency": document[profile_name]["frequency"], "conditions": conditions, "varBinds": var_binds } - return converted + return result - def _ui2backend_map(self, profile: dict): - if profile['conditions']['condition'] == "field": + def _ui2backend_map(self, document: dict, **kwargs): + if document['conditions']['condition'] == "field": conditions = { 'type': 'field', - 'field': profile['conditions']['field'], - 'patterns': [el['pattern'] for el in profile['conditions']['patterns']] + 'field': document['conditions']['field'], + 'patterns': [el['pattern'] for el in document['conditions']['patterns']] } - elif profile['conditions']['condition'] == "None": + elif document['conditions']['condition'] == "None": conditions = None else: conditions = { - 'type': profile['conditions']['condition'] + 'type': document['conditions']['condition'] } var_binds = [] - for var_b in profile['varBinds']: + for var_b in document['varBinds']: single_var_bind = [var_b['family']] if len(var_b['category']) > 0: single_var_bind.append(var_b['category']) @@ -86,30 +116,72 @@ def _ui2backend_map(self, profile: dict): single_var_bind.append(int(var_b['index'])) var_binds.append(single_var_bind) - if conditions is None: - item = { - profile['profileName']: { - 'frequency': int(profile['frequency']), - 'varBinds': var_binds - } - } - else: - item = { - profile['profileName']: { - 'frequency': int(profile['frequency']), - 'condition': conditions, - 'varBinds': var_binds - } + item = { + document['profileName']: { + 'frequency': int(document['frequency']), + 'varBinds': var_binds } + } + if conditions is not None: + item[document['profileName']].update({'conditions': conditions}) return item -class InventoryConversion(Conversion): - def __init__(self, mongo): - super().__init__(mongo, "inventory") +class GroupConversion(Conversion): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _backend2ui_map(self, document: dict, **kwargs): + try: + group_name = get_group_name_from_backend(document) + result = { + "_id": document["_id"], + "groupName": group_name + } + return result + except ValueError as e: + raise e + + def _ui2backend_map(self, document: dict, **kwargs): + result = { + document["groupName"]: [] + } + return result + + +class GroupDeviceConversion(Conversion): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.optional_fields = ["port", "version", "community", "secret", "security_engine"] + def _backend2ui_map(self, document: dict, **kwargs): + if "group_id" in kwargs.keys() and "device_id" in kwargs.keys(): + group_id = kwargs["group_id"] + device_id = kwargs["device_id"] + result = { + "_id": f"{group_id}-{device_id}", + "groupId": str(group_id), + "address": document['address'] + } + for backend_key in self.optional_fields: + ui_key = snake_case2camel_case(backend_key) + if backend_key in document.keys(): + result.update({f'{ui_key}': str(document[backend_key])}) + else: + result.update({f'{ui_key}': ""}) + print(result) + return result + else: + raise ValueError("No group_id or device_id provided") -if __name__ == '__main__': - from SC4SNMP_UI_backend import mongo_client - prof_converter = ProfileConversion(mongo_client) - prof_converter.ui2backend() + def _ui2backend_map(self, document: dict, **kwargs): + result = { + "address": document["address"] + } + for backend_key in self.optional_fields: + ui_key = snake_case2camel_case(backend_key) + if len(document[ui_key]) > 0: + result.update({f"{backend_key}": str(document[ui_key])}) + if len(document['port']) > 0: + result.update({"port": int(document['port'])}) + return result diff --git a/backend/SC4SNMP_UI_backend/ui_handling/routes.py b/backend/SC4SNMP_UI_backend/ui_handling/routes.py index 5944016..84ba8c0 100644 --- a/backend/SC4SNMP_UI_backend/ui_handling/routes.py +++ b/backend/SC4SNMP_UI_backend/ui_handling/routes.py @@ -2,16 +2,21 @@ from flask import Flask, request, Blueprint from flask_cors import cross_origin from SC4SNMP_UI_backend import db -from SC4SNMP_UI_backend.common.conversions import ProfileConversion +from SC4SNMP_UI_backend.common.conversions import ProfileConversion, GroupConversion, GroupDeviceConversion, \ + get_group_name_from_backend +from copy import copy ui = Blueprint('ui', __name__) profile_conversion = ProfileConversion() +group_conversion = GroupConversion() +group_device_conversion = GroupDeviceConversion() + @ui.route('/profiles/names') @cross_origin() def get_profile_names(): - profiles = db.profiles_ui.find() + profiles = db.profiles.find() profiles_list = [] for pr in list(profiles): profiles_list.append(profile_conversion.backend2ui(pr)) @@ -53,56 +58,14 @@ def update_profile_record(profile_id): db.profiles.update_one({'_id': ObjectId(profile_id)}, new_values) return "success" -# @cross_origin(origins='*', headers=['access-control-allow-origin', 'Content-Type']) -@ui.route('/inventory//') -@cross_origin() -def get_inventory_list(page_num, dev_per_page): - page_num = int(page_num) - dev_per_page = int(dev_per_page) - skips = dev_per_page * (page_num - 1) - inventory = db.inventory_ui.find().skip(skips).limit(dev_per_page) - inventory_list = list(inventory) - return json_util.dumps(inventory_list) - - -@ui.route('/inventory/count') -@cross_origin() -def get_inventory_count(): - total_count = db.inventory_ui.count_documents({}) - return json_util.dumps(total_count) - - -@ui.route('/inventory/add', methods=['POST']) -@cross_origin() -def add_inventory_record(): - inventory_obj = request.json - print(inventory_obj) - db.inventory_ui.insert_one(inventory_obj) - return "success" - - -@ui.route('/inventory/delete/', methods=['POST']) -@cross_origin() -def delete_inventory_record(inventory_id): - db.inventory_ui.delete_one({'_id': ObjectId(inventory_id)}) - return "success" - - -@ui.route('/inventory/update/', methods=['POST']) -@cross_origin() -def update_inventory_record(inventory_id): - inventory_obj = request.json - print(f"{inventory_obj}") - new_values = {"$set": inventory_obj} - db.inventory_ui.update_one({'_id': ObjectId(inventory_id)}, new_values) - return "success" - @ui.route('/groups') @cross_origin() def get_groups_list(): - groups = db.groups_ui.find() - groups_list = list(groups) + groups = db.groups.find() + groups_list = [] + for gr in list(groups): + groups_list.append(group_conversion.backend2ui(gr)) return json_util.dumps(groups_list) @@ -110,8 +73,8 @@ def get_groups_list(): @cross_origin() def add_group_record(): group_obj = request.json - print(group_obj) - db.groups_ui.insert_one(group_obj) + group_obj = group_conversion.ui2backend(group_obj) + db.groups.insert_one(group_obj) return "success" @@ -119,60 +82,152 @@ def add_group_record(): @cross_origin() def update_group(group_id): group_obj = request.json - print(f"{group_obj}") - new_values = {"$set": group_obj} - db.groups_ui.update_one({'_id': ObjectId(group_id)}, new_values) - return "success" + old_group = db.groups.find({'_id': ObjectId(group_id)}) + old_group = list(old_group)[0] + try: + old_group_name = get_group_name_from_backend(old_group) + db.groups.update_one({'_id': old_group['_id']}, {"$rename": {f"{old_group_name}": f"{group_obj['groupName']}"}}) + return "success" + except ValueError as e: + raise e @ui.route('/groups/delete/', methods=['POST']) @cross_origin() def delete_group_and_devices(group_id): - db.groups_ui.delete_one({'_id': ObjectId(group_id)}) - db.devices_ui.delete_many({"groupId": group_id}) + db.groups.delete_one({'_id': ObjectId(group_id)}) return "success" @ui.route('/group//devices/count') @cross_origin() def get_devices_count_for_group(group_id): - total_count = db.devices_ui.count_documents({"groupId": group_id}) - return json_util.dumps(total_count) + group = db.groups.find({"_id": ObjectId(group_id)}) + group = list(group)[0] + try: + old_group_name = get_group_name_from_backend(group) + total_count = len(group[old_group_name]) + return json_util.dumps(total_count) + except ValueError as e: + raise e @ui.route('/group//devices//') @cross_origin() -def get_devices_of_groups_list(group_id, page_num, dev_per_page): +def get_devices_of_group(group_id, page_num, dev_per_page): page_num = int(page_num) dev_per_page = int(dev_per_page) skips = dev_per_page * (page_num - 1) - devices = db.devices_ui.find({"groupId": group_id}).skip(skips).limit(dev_per_page) - devices_list = list(devices) - return json_util.dumps(devices_list) + group = db.groups.find({"_id": ObjectId(group_id)}) + group = list(group)[0] + try: + group_name = get_group_name_from_backend(group) + devices_list = [] + i = 0 + for device in group[group_name]: + devices_list.append(group_device_conversion.backend2ui(device, group_id=group_id, device_id=copy(i))) + i += 1 + devices_list = devices_list[skips:skips+dev_per_page] + return json_util.dumps(devices_list) + except ValueError as e: + raise e @ui.route('/devices/add', methods=['POST']) @cross_origin() -def add_device_to_group_record(): +def add_device_to_group(): device_obj = request.json - print(device_obj) - db.devices_ui.insert_one(device_obj) - return "success" + group_id = device_obj["groupId"] + group = db.groups.find({'_id': ObjectId(group_id)}, {"_id": 0}) + group = list(group)[0] + device_obj = group_device_conversion.ui2backend(device_obj) + try: + group_name = get_group_name_from_backend(group) + group[group_name].append(device_obj) + new_values = {"$set": group} + print(group_id, new_values) + db.groups.update_one({"_id": ObjectId(group_id)}, new_values) + return "success" + except ValueError as e: + raise e @ui.route('/devices/update/', methods=['POST']) @cross_origin() def update_device_from_group(device_id): device_obj = request.json - print(f"{device_obj}") - new_values = {"$set": device_obj} - db.devices_ui.update_one({'_id': ObjectId(device_id)}, new_values) - return "success" + group_id = device_id.split("-")[0] + device_id = device_id.split("-")[1] + group = db.groups.find({'_id': ObjectId(group_id)}, {"_id": 0}) + group = list(group)[0] + device_obj = group_device_conversion.ui2backend(device_obj) + try: + group_name = get_group_name_from_backend(group) + group[group_name][int(device_id)] = device_obj + new_values = {"$set": group} + db.groups.update_one({"_id": ObjectId(group_id)}, new_values) + return "success" + except ValueError as e: + raise e @ui.route('/devices/delete/', methods=['POST']) @cross_origin() -def delete_device_from_group_record(device_id): - db.devices_ui.delete_one({'_id': ObjectId(device_id)}) +def delete_device_from_group_record(device_id: str): + group_id = device_id.split("-")[0] + device_id = device_id.split("-")[1] + group = db.groups.find({'_id': ObjectId(group_id)}, {"_id": 0}) + group = list(group)[0] + try: + group_name = get_group_name_from_backend(group) + group[group_name].pop(int(device_id)) + new_values = {"$set": group} + db.groups.update_one({"_id": ObjectId(group_id)}, new_values) + return "success" + except ValueError as e: + raise e + + +# @cross_origin(origins='*', headers=['access-control-allow-origin', 'Content-Type']) +@ui.route('/inventory//') +@cross_origin() +def get_inventory_list(page_num, dev_per_page): + page_num = int(page_num) + dev_per_page = int(dev_per_page) + skips = dev_per_page * (page_num - 1) + inventory = db.inventory_ui.find().skip(skips).limit(dev_per_page) + inventory_list = list(inventory) + return json_util.dumps(inventory_list) + + +@ui.route('/inventory/count') +@cross_origin() +def get_inventory_count(): + total_count = db.inventory_ui.count_documents({}) + return json_util.dumps(total_count) + + +@ui.route('/inventory/add', methods=['POST']) +@cross_origin() +def add_inventory_record(): + inventory_obj = request.json + print(inventory_obj) + db.inventory_ui.insert_one(inventory_obj) return "success" + +@ui.route('/inventory/delete/', methods=['POST']) +@cross_origin() +def delete_inventory_record(inventory_id): + db.inventory_ui.delete_one({'_id': ObjectId(inventory_id)}) + return "success" + + +@ui.route('/inventory/update/', methods=['POST']) +@cross_origin() +def update_inventory_record(inventory_id): + inventory_obj = request.json + print(f"{inventory_obj}") + new_values = {"$set": inventory_obj} + db.inventory_ui.update_one({'_id': ObjectId(inventory_id)}, new_values) + return "success"