feature 7919 - Subscription API for OSS/BSS management systems

Delete_extra used to remove mapped_subscription
Moved code to use db.create_list function
Addressed review comments.

Change-Id: I84bd39e9a9c942d15762d4715843c7c539842767
Signed-off-by: preethika.p <preethika.p@tataelxsi.co.in>
diff --git a/osm_nbi/subscription_topics.py b/osm_nbi/subscription_topics.py
new file mode 100644
index 0000000..a5c9c44
--- /dev/null
+++ b/osm_nbi/subscription_topics.py
@@ -0,0 +1,144 @@
+# Copyright 2020 Preethika P(Tata Elxsi)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+__author__ = "Preethika P,preethika.p@tataelxsi.co.in"
+
+
+import requests
+from osm_nbi.base_topic import BaseTopic, EngineException
+from osm_nbi.validation import subscription
+
+
+class CommonSubscriptions(BaseTopic):
+    topic = "subscriptions"
+    topic_msg = None
+    
+    def format_on_new(self, content, project_id=None, make_public=False):
+        super().format_on_new(content, project_id=project_id, make_public=make_public)
+        
+        # TODO check how to release Engine.write_lock during the check
+        def _check_endpoint(url, auth):
+            """
+            Checks if the notification endpoint is valid
+            :param url: the notification end
+            :param auth: contains the aunthentication details with type basic
+            """
+            try:
+                if auth is None:
+                    response = requests.get(url, timeout=5)
+                    if response.status_code != 204:
+                        raise EngineException("Cannot access to the notification URL '{}',received {}: {}"
+                                              .format(url, response.status_code, response.content))
+                elif auth["authType"] == "basic":
+                    username = auth["paramsBasic"].get("userName")
+                    password = auth["paramsBasic"].get("password")
+                    response = requests.get(url, auth=(username, password), timeout=5)
+                    if response.status_code != 204:
+                        raise EngineException("Cannot access to the notification URL '{}',received {}: {}"
+                                              .format(url, response.status_code, response.content))
+            except requests.exceptions.RequestException as e:
+                error_text = type(e).__name__ + ": " + str(e)
+                raise EngineException("Cannot access to the notification URL '{}': {}".format(url, error_text))
+        url = content["CallbackUri"]
+        auth = content.get("authentication")
+        _check_endpoint(url, auth)
+        content["schema_version"] = schema_version = "1.1"
+        if auth is not None and auth["authType"] == "basic":
+            if content["authentication"]["paramsBasic"].get("password"):
+                content["authentication"]["paramsBasic"]["password"] = \
+                    self.db.encrypt(content["authentication"]["paramsBasic"]["password"], 
+                                    schema_version=schema_version, salt=content["_id"])
+        return None
+
+    def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+        """
+        Uses BaseTopic.new to create entry into db
+        Once entry is made into subscriptions,mapper function is invoked
+        """
+        _id, op_id = BaseTopic.new(self, rollback, session, indata=indata, kwargs=kwargs, headers=headers)
+        rollback.append({"topic": "mapped_subscriptions", "operation": "del_list", "filter": {"reference": _id}})
+        self._subscription_mapper(_id, indata, table="mapped_subscriptions")
+        return _id, op_id
+
+    def delete_extra(self, session, _id, db_content, not_send_msg=None):
+        """
+        Deletes the mapped_subscription entry for this particular subscriber
+        :param _id: subscription_id deleted
+        """
+        super().delete_extra(session, _id, db_content, not_send_msg)
+        filter_q = {}
+        filter_q["reference"] = _id
+        self.db.del_list("mapped_subscriptions", filter_q)
+
+
+class NslcmSubscriptionsTopic(CommonSubscriptions):
+    schema_new = subscription
+
+    def _subscription_mapper(self, _id, data, table):
+        """
+        Performs data transformation on subscription request
+        :param data: data to be trasformed
+        :param table: table in which transformed data are inserted
+        """
+        formatted_data = []
+        formed_data = {"reference": data.get("_id"),
+                       "CallbackUri": data.get("CallbackUri")}
+        if data.get("authentication"):
+            formed_data.update({"authentication": data.get("authentication")})
+        if data.get("filter"):
+            if data["filter"].get("nsInstanceSubscriptionFilter"):
+                key = list(data["filter"]["nsInstanceSubscriptionFilter"].keys())[0]
+                identifier = data["filter"]["nsInstanceSubscriptionFilter"][key]
+                formed_data.update({"identifier": identifier})
+            if data["filter"].get("notificationTypes"):
+                for elem in data["filter"].get("notificationTypes"):
+                    update_dict = formed_data.copy()
+                    update_dict["notificationType"] = elem
+                    if elem == "NsIdentifierCreationNotification":
+                        update_dict["operationTypes"] = "INSTANTIATE"
+                        update_dict["operationStates"] = "ANY"
+                        formatted_data.append(update_dict)
+                    elif elem == "NsIdentifierDeletionNotification":
+                        update_dict["operationTypes"] = "TERMINATE"
+                        update_dict["operationStates"] = "ANY"
+                        formatted_data.append(update_dict)
+                    elif elem == "NsLcmOperationOccurrenceNotification":
+                        if "operationTypes" in data["filter"].keys():
+                            update_dict["operationTypes"] = data["filter"]["operationTypes"]
+                        else:
+                            update_dict["operationTypes"] = "ANY"
+                        if "operationStates" in data["filter"].keys():
+                            update_dict["operationStates"] = data["filter"]["operationStates"]
+                        else:
+                            update_dict["operationStates"] = "ANY"
+                        formatted_data.append(update_dict)
+                    elif elem == "NsChangeNotification":
+                        if "nsComponentTypes" in data["filter"].keys():
+                            update_dict["nsComponentTypes"] = data["filter"]["nsComponentTypes"]
+                        else:
+                            update_dict["nsComponentTypes"] = "ANY"
+                        if "lcmOpNameImpactingNsComponent" in data["filter"].keys():
+                            update_dict["lcmOpNameImpactingNsComponent"] = \
+                                data["filter"]["lcmOpNameImpactingNsComponent"]
+                        else:
+                            update_dict["lcmOpNameImpactingNsComponent"] = "ANY"
+                        if "lcmOpOccStatusImpactingNsComponent" in data["filter"].keys():
+                            update_dict["lcmOpOccStatusImpactingNsComponent"] = \
+                                data["filter"]["lcmOpOccStatusImpactingNsComponent"]
+                        else:
+                            update_dict["lcmOpOccStatusImpactingNsComponent"] = "ANY"
+                        formatted_data.append(update_dict)
+        self.db.create_list(table, formatted_data)
+        return None