update coverage command
[modeling/etsicatalog.git] / genericparser / packages / biz / nsdm_subscription.py
1 # Copyright (C) 2019 Verizon. All Rights Reserved
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import ast
16 import json
17 import logging
18 import requests
19 import uuid
20
21 from collections import Counter
22
23 from rest_framework import status
24
25 from genericparser.packages import const
26 from genericparser.pub.database.models import NsdmSubscriptionModel
27 from genericparser.pub.exceptions import GenericparserException, \
28     ResourceNotFoundException, \
29     NsdmBadRequestException, NsdmDuplicateSubscriptionException
30 from genericparser.pub.utils.values import ignore_case_get
31
32 logger = logging.getLogger(__name__)
33
34 PARAMSBASICKEYS = ["userName", "password"]
35
36 PARAMSOAUTH2CLIENTCREDENTIALSKEYS = ["clientId", "clientPassword",
37                                      "tokenEndpoint"]
38
39
40 def is_filter_type_equal(new_filter, existing_filter):
41     return Counter(list(set(new_filter))) == Counter(existing_filter)
42
43
44 class NsdmSubscription:
45
46     def __init__(self):
47         pass
48
49     def query_single_subscription(self, subscription_id):
50         logger.debug("Start Query Subscription... ")
51         subscription = \
52             NsdmSubscriptionModel.objects.filter(
53                 subscriptionid=subscription_id)
54         if not subscription.exists():
55             raise ResourceNotFoundException(
56                 "Subscription(%s) doesn't exists" % subscription_id)
57         logger.debug("Subscription found... ")
58         return self.fill_resp_data(subscription[0])
59
60     def delete_single_subscription(self, subscription_id):
61         logger.debug("Start Delete Subscription... ")
62         subscription = \
63             NsdmSubscriptionModel.objects.filter(
64                 subscriptionid=subscription_id)
65         if not subscription.exists():
66             raise ResourceNotFoundException(
67                 "Subscription(%s) doesn't exists" % subscription_id)
68         subscription.delete()
69         logger.debug("Deleted Subscription... ")
70
71     def query_multi_subscriptions(self, query_params):
72         self.params = query_params
73         query_data = {}
74         logger.debug("Start QueryMultiSubscriptions get --> "
75                      "Check for filters in query params" % self.params)
76         for query, value in self.params.iteritems():
77             if query in const.NSDM_NOTIFICATION_FILTERS and value:
78                 query_data[query + '__icontains'] = json.dumps(list(set(value)))
79         # Query the database with filters if the request
80         # has fields in request params, else fetch all records
81         if query_data:
82             subscriptions = NsdmSubscriptionModel.objects.filter(**query_data)
83         else:
84             subscriptions = NsdmSubscriptionModel.objects.all()
85         if not subscriptions.exists():
86             raise ResourceNotFoundException("Subscriptions doesn't exist")
87         return [self.fill_resp_data(subscription)
88                 for subscription in subscriptions]
89
90     def check_callbackuri_connection(self):
91         logger.debug("Create Subscription --> Test Callback URI --"
92                      "Sending GET request to %s" % self.callback_uri)
93         try:
94             response = requests.get(self.callback_uri, timeout=2)
95             if response.status_code != status.HTTP_204_NO_CONTENT:
96                 raise GenericparserException("callbackUri %s returns %s status "
97                                              "code." % (self.callback_uri,
98                                                         response.status_code))
99         except Exception:
100             raise GenericparserException("callbackUri %s didn't return 204 status"
101                                          "code." % self.callback_uri)
102
103     def fill_resp_data(self, subscription):
104         subscription_filter = dict()
105         for filter_type in const.NSDM_NOTIFICATION_FILTERS:
106             subscription_filter[filter_type] = \
107                 ast.literal_eval(subscription.__dict__[filter_type])
108         resp_data = {
109             'id': subscription.subscriptionid,
110             'callbackUri': subscription.callback_uri,
111             'filter': subscription_filter,
112             '_links': json.loads(subscription.links)
113         }
114         return resp_data
115
116     def create(self, data):
117         logger.debug("Start Create Subscription... ")
118         self.filter = ignore_case_get(data, "filter", {})
119         self.callback_uri = ignore_case_get(data, "callbackUri")
120         self.authentication = ignore_case_get(data, "authentication", {})
121         self.subscription_id = str(uuid.uuid4())
122         self.check_callbackuri_connection()
123         self.check_valid_auth_info()
124         self.check_filter_types()
125         self.check_valid()
126         self.save_db()
127         subscription = \
128             NsdmSubscriptionModel.objects.get(
129                 subscriptionid=self.subscription_id)
130         return self.fill_resp_data(subscription)
131
132     def check_filter_types(self):
133         # Check if both nsdId and nsdInfoId
134         # or pnfdId and pnfdInfoId are present
135         logger.debug("Create Subscription --> Validating Filters... ")
136         if self.filter and \
137                 self.filter.get("nsdId", "") and \
138                 self.filter.get("nsdInfoId", ""):
139             raise NsdmBadRequestException("Notification Filter should contain"
140                                           " either nsdId or nsdInfoId")
141         if self.filter and \
142                 self.filter.get("pnfdId", "") and \
143                 self.filter.get("pnfdInfoIds", ""):
144             raise NsdmBadRequestException("Notification Filter should contain"
145                                           " either pnfdId or pnfdInfoIds")
146
147     def check_valid_auth_info(self):
148         logger.debug("Create Subscription --> Validating Auth "
149                      "details if provided... ")
150         if self.authentication.get("paramsBasic", {}) and \
151                 const.BASIC not in self.authentication.get("authType", ''):
152             raise NsdmBadRequestException('Auth type should be ' + const.BASIC)
153         if self.authentication.get("paramsOauth2ClientCredentials", {}) and \
154                 const.OAUTH2_CLIENT_CREDENTIALS not in \
155                 self.authentication.get("authType", ''):
156             raise NsdmBadRequestException('Auth type should '
157                                           'be ' + const.OAUTH2_CLIENT_CREDENTIALS)
158         if const.BASIC in self.authentication.get("authType", '') and \
159                 "paramsBasic" in self.authentication.keys() and \
160                 not is_filter_type_equal(PARAMSBASICKEYS,
161                                          self.authentication.get("paramsBasic").keys()):
162             raise NsdmBadRequestException('userName and password needed '
163                                           'for ' + const.BASIC)
164         if const.OAUTH2_CLIENT_CREDENTIALS in \
165                 self.authentication.get("authType", '') and \
166                 "paramsOauth2ClientCredentials" in \
167                 self.authentication.keys() and \
168                 not is_filter_type_equal(PARAMSOAUTH2CLIENTCREDENTIALSKEYS,
169                                          self.authentication.get("paramsOauth2ClientCredentials").keys()):
170             raise NsdmBadRequestException('clientId, clientPassword and '
171                                           'tokenEndpoint required '
172                                           'for ' + const.OAUTH2_CLIENT_CREDENTIALS)
173
174     def check_filter_exists(self, subscription):
175         for filter_type in const.NSDM_NOTIFICATION_FILTERS:
176             if not is_filter_type_equal(self.filter.get(filter_type, []),
177                                         ast.literal_eval(
178                                             getattr(subscription,
179                                                     filter_type))):
180                 return False
181         return True
182
183     def check_valid(self):
184         logger.debug("Create Subscription --> Checking DB if "
185                      "same subscription exists already exists... ")
186         subscriptions = \
187             NsdmSubscriptionModel.objects.filter(
188                 callback_uri=self.callback_uri)
189         if not subscriptions.exists():
190             return
191         for subscription in subscriptions:
192             if self.check_filter_exists(subscription):
193                 raise NsdmDuplicateSubscriptionException(
194                     "Already Subscription exists with the "
195                     "same callbackUri and filter")
196
197     def save_db(self):
198         logger.debug("Create Subscription --> Saving the subscription "
199                      "%s to the database" % self.subscription_id)
200         links = {
201             "self": {
202                 "href":
203                     const.NSDM_SUBSCRIPTION_ROOT_URI + self.subscription_id
204             }
205         }
206         subscription_save_db = {
207             "subscriptionid": self.subscription_id,
208             "callback_uri": self.callback_uri,
209             "auth_info": self.authentication,
210             "links": json.dumps(links)
211         }
212         for filter_type in const.NSDM_NOTIFICATION_FILTERS:
213             subscription_save_db[filter_type] = json.dumps(
214                 list(set(self.filter.get(filter_type, []))))
215         NsdmSubscriptionModel.objects.create(**subscription_save_db)
216         logger.debug('Create Subscription[%s] success', self.subscription_id)