From 22224547a5aeaa4e45eba78d1e5cdaf69adceb57 Mon Sep 17 00:00:00 2001
From: "saket.agrahari" <saket.agrahari@geant.org>
Date: Wed, 27 Mar 2024 10:07:44 +0000
Subject: [PATCH] [DBOARD3-676]: creating new api for mic third party data

---
 inventory_provider/routes/mic.py   | 84 +++++++++++++++++++++++++++
 inventory_provider/tasks/worker.py | 92 +++++++++++++++++++++++++++++-
 2 files changed, 173 insertions(+), 3 deletions(-)

diff --git a/inventory_provider/routes/mic.py b/inventory_provider/routes/mic.py
index 8ee62dee..13e9fd21 100644
--- a/inventory_provider/routes/mic.py
+++ b/inventory_provider/routes/mic.py
@@ -68,6 +68,76 @@ ALL_DATA_SCHEMA = {
     "additionalProperties": False
 }
 
+THIRD_PARTY_RESPONSE_SCHEMA ={
+    "schema": "http://json-schema.org/draft-07/schema#",
+    "type": "object",
+    "properties": {
+        "circuit_hierarchy": {
+            "type": "array",
+            "items": {
+                "type": "object",
+                "properties": {
+                    "id": {"type": "integer"},
+                    "status": {"type": "string"},
+                    "name": {"type": "string"},
+                    "service_type": {"type": "string"},
+                    "contacts": {
+                        "type": "array",
+                        "items": {"type": "string"}
+                    },
+                    "planned_work_contacts": {
+                        "type": "array",
+                        "items": {"type": "string"}
+                    },
+                    "third_party_id": {"type": "string"}
+                },
+                "required": ["id", "status", "name", "service_type", "contacts", "planned_work_contacts", "third_party_id"],
+                "additionalProperties": False
+            }
+        },
+        "interface_services": {
+            "type": "object",
+            "patternProperties": {
+                "^.*$": {
+                    "type": "object",
+                    "patternProperties": {
+                        "^.*$": {
+                            "type": "object",
+                            "patternProperties": {
+                                "^.*$": {
+                                    "type": "array",
+                                    "items": {
+                                        "type": "object",
+                                        "properties": {
+                                            "id": {"type": "integer"},
+                                            "sid": {"type": "string"},
+                                            "status": {"type": "string"},
+                                            "name": {"type": "string"},
+                                            "service_type": {"type": "string"},
+                                            "contacts": {
+                                                "type": "array",
+                                                "items": {"type": "string"}
+                                            },
+                                            "planned_work_contacts": {
+                                                "type": "array",
+                                                "items": {"type": "string"}
+                                            },
+                                            "third_party_id": {"type": "string"}
+                                        },
+                                        "required": ["id", "sid", "status", "name", "service_type", "contacts", "planned_work_contacts", "third_party_id"],
+                                        "additionalProperties": False
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "required": ["circuit_hierarchy", "interface_services"],
+    "additionalProperties": False
+}
 
 @routes.route("/all-data")
 def get_everything():
@@ -81,3 +151,17 @@ def get_everything():
             status=404,
             mimetype="text/html")
     return Response(result, mimetype='application/json')
+
+
+@routes.route("/third-party-data")
+def get_third_party_data():
+    cache_key = "mic:impact:third-party-data"
+    logger.debug(cache_key)
+    r = common.get_current_redis()
+    result = _ignore_cache_or_retrieve(request, cache_key, r)
+    if not result:
+        return Response(
+            response='no data found',
+            status=404,
+            mimetype="text/html")
+    return Response(result, mimetype='application/json')
diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py
index 4c77d0d7..1cf01456 100644
--- a/inventory_provider/tasks/worker.py
+++ b/inventory_provider/tasks/worker.py
@@ -1226,6 +1226,9 @@ def transform_ims_data(data):
         d['contacts'] = sorted(list(c))
         d['planned_work_contacts'] = sorted(list(ttc))
 
+        if d['id'] in circuit_ids_and_third_party_ids:
+            d['third_party_id'] = circuit_ids_and_third_party_ids[d['id']]
+
         # add flexils data to port_id_details and port_id_services
         all_ils_details = flexils_data.get(d['id'])
         if all_ils_details:
@@ -1321,9 +1324,6 @@ def transform_ims_data(data):
                 if c['id'] in circuit_ids_and_sids:
                     rs[c['id']]['sid'] = circuit_ids_and_sids[c['id']]
 
-                if c['id'] in circuit_ids_and_third_party_ids:
-                    rs[c['id']]['third_party_id'] = circuit_ids_and_third_party_ids[c['id']]
-
             if c['sub-circuits']:
                 for sub in c['sub-circuits']:
                     temp_parents = \
@@ -1578,6 +1578,7 @@ def persist_ims_data(data, use_current=False):
 
     populate_poller_cache(interface_services, r)
     populate_mic_cache(interface_services, r)
+    populate_mic_with_third_party_data(interface_services, hierarchy, r)
 
     for service_type, services in services_by_type.items():
         for v in services.values():
@@ -1612,6 +1613,91 @@ def persist_ims_data(data, use_current=False):
     rp.execute()
 
 
+def populate_mic_with_third_party_data(interface_services, hierarchy, r):
+    cache_key = "mic:impact:third-party-data"
+    third_party_data = defaultdict(lambda: defaultdict(dict))
+    third_party_interface_data = defaultdict(lambda: defaultdict(dict))
+
+    def _get_formatted_third_party_data(_circuit_data):
+        if _circuit_data['status'] == 'operational' and _circuit_data.get('third_party_id'):
+            return {
+                'id': _circuit_data['id'],
+                'status': _circuit_data['status'],
+                'name': _circuit_data['name'],
+                'service_type': 'circuit_hierarchy',
+                'contacts': _circuit_data['contacts'],
+                'planned_work_contacts': _circuit_data['planned_work_contacts'],
+                'third_party_id': _circuit_data['third_party_id'],
+            }
+
+    def _get_formatted_related_service(_d):
+        for rs in _d['related-services']:
+            if rs['status'] == 'operational' and rs.get('third_party_id'):
+                yield {
+                    'id': rs['id'],
+                    'sid': rs.get('sid', ''),
+                    'status': rs['status'],
+                    'name': rs['name'],
+                    'service_type': rs['service_type'],
+                    'contacts': rs['contacts'],
+                    'planned_work_contacts': rs['planned_work_contacts'],
+                    'third_party_id': rs.get('third_party_id', '')
+                }
+
+    def _get_formatted_interface_service(_is):
+        if _is['status'] == 'operational' and _is.get('third_party_id'):
+            return {
+                'id': _is['id'],
+                'sid': _is.get('sid', ''),
+                'status': _is['status'],
+                'name': _is['name'],
+                'service_type': 'circuit_type',
+                'contacts': _is['contacts'],
+                'planned_work_contacts': _is['planned_work_contacts'],
+                'third_party_id': _is.get('third_party_id', '')
+            }
+
+    # get circuit hierarchy items that have third party id
+    third_party_circuit = {
+        k: v for k, v in hierarchy.items() if 'third_party_id' in v
+    }
+
+    # iterate over each third_party_circuit items to format and add operational once only
+    third_party_circuit_data = [_get_formatted_third_party_data(v)
+                                for k, v in third_party_circuit.items()
+                                if v and _get_formatted_third_party_data(v)]
+
+    # add third_party_circuit_data to the third_party_data map and add the map to cache
+    third_party_data['circuit_hierarchy'] = third_party_circuit_data
+
+    for services in interface_services.values():
+        if services:
+            current_interface_services = []
+            seen_ids = set()
+            for d in services:
+                if d.get('related-services'):
+                    for rs in _get_formatted_related_service(d):
+                        if rs['id'] not in seen_ids:
+                            current_interface_services.append(rs)
+                            seen_ids.add(rs['id'])
+                    if (str(d.get('id')) + 'circuit') not in seen_ids:
+                        _is = _get_formatted_interface_service(d)
+                        if _is:
+                            current_interface_services.append(_is)
+                        seen_ids.add(str(d.get('id')) + 'circuit')
+
+            if current_interface_services:
+                site = f'{services[0]["pop_name"]} ' \
+                       f'({services[0]["pop_abbreviation"]})'
+                eq_name = services[0]['equipment']
+                if_name = services[0]['port']
+                third_party_interface_data[site][eq_name][if_name] = current_interface_services
+    third_party_data['interface_services'] = third_party_interface_data
+
+    result = json.dumps(third_party_data)
+    r.set(cache_key, result.encode('utf-8'))
+
+
 def populate_mic_cache(interface_services, r):
     cache_key = "mic:impact:all-data"
     all_data = defaultdict(lambda: defaultdict(dict))
-- 
GitLab