From 8b523a1853db70d06761692ab585a197174118c7 Mon Sep 17 00:00:00 2001 From: Heather Schovanec <hschovanec@usgs.gov> Date: Tue, 8 Aug 2017 07:51:56 -0600 Subject: [PATCH] Change parse to return WebServiceQuery object Also, made changes based on PR revision requests. --- geomagio/WebService.py | 168 +++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 64 deletions(-) diff --git a/geomagio/WebService.py b/geomagio/WebService.py index 7b472f0e..c634fd47 100644 --- a/geomagio/WebService.py +++ b/geomagio/WebService.py @@ -11,6 +11,19 @@ from geomagio.iaga2002 import IAGA2002Writer from obspy.core import UTCDateTime +DEFAULT_ELEMENTS = ('X', 'Y', 'Z', 'F') +DEFAULT_PERIOD = '60' +DEFAULT_TYPE = 'variation' +VALID_TYPES = [ + 'variation', + 'adjusted', + 'quasi-definitive', + 'definitive' +] +VALID_PERIODS = ['1', '60'] +VALID_FORMATS = ['iaga2002'] + + class WebService(object): def __init__(self, factory): self.factory = factory @@ -18,19 +31,18 @@ class WebService(object): def __call__(self, environ, start_response): """Implement WSGI interface""" # parse params - query = {} query = WebServiceQuery.parse(environ['QUERY_STRING']) # fetch data data = self.fetch(query) # format data data_string = self.format(query, data) + if isinstance(data_string, str): + data_string = data_string.encode('utf8') # send response start_response('200 OK', [ ("Content-Type", "text/plain") ]) - if isinstance(data_string, str): - data_string = data_string.encode('utf8') return [data_string] def fetch(self, query): @@ -46,12 +58,12 @@ class WebService(object): timeseries object with requested data. """ data = self.factory.get_timeseries( - observatory=query['id'], - channels=query['elements'], - starttime=query['starttime'], - endtime=query['endtime'], - type=query['type'], - interval=query['sampling_period']) + observatory=query.id, + channels=query.elements, + starttime=query.starttime, + endtime=query.endtime, + type=query.type, + interval=query.sampling_period) return data def format(self, query, data): @@ -69,7 +81,7 @@ class WebService(object): IMFJSON or IAGA2002 formatted string. """ # TODO: Add option for json format - data_string = IAGA2002Writer.format(data, query['elements']) + data_string = IAGA2002Writer.format(data, query.elements) return data_string @@ -126,88 +138,116 @@ class WebServiceQuery(object): """ # Create dictionary of lists dict = parse_qs(params) - # Return values - id = dict.get('id', [''])[0] - starttime = dict.get('starttime', [''])[0] - endtime = dict.get('endtime', [''])[0] - elements = dict.get('elements', [''])[0] - sampling_period = dict.get('sampling_period', [''])[0] - type = dict.get('type', [''])[0] - format = dict.get('format', [''])[0] + # Get values + if len(dict.get('id', [])) <= 1: + id = dict.get('id', [''])[0] + else: + raise WebServiceException( + '"id" accepts only one value') + if len(dict.get('starttime', [])) <= 1: + starttime = dict.get('starttime', [''])[0] + else: + raise WebServiceException( + '"starttime" accepts only one value') + if len(dict.get('endtime', [])) <= 1: + endtime = dict.get('endtime', [''])[0] + else: + raise WebServiceException( + '"endtime" accepts only one value') + if len(dict.get('elements', [])) <= 1: + elements = dict.get('elements', [''])[0] + else: + raise WebServiceException( + '"elements" accepts only one set of values') + if len(dict.get('sampling_period', [])) <= 1: + sampling_period = dict.get('sampling_period', [''])[0] + else: + raise WebServiceException( + '"sampling_period" accepts only one value') + if len(dict.get('type', [])) <= 1: + type = dict.get('type', [''])[0] + else: + raise WebServiceException( + '"type" accepts only one value') + if len(dict.get('format', [])) <= 1: + format = dict.get('format', [''])[0] + else: + raise WebServiceException( + '"format" accepts only one value') # Escape to avoid script injection id = escape(id) starttime = escape(starttime) endtime = escape(endtime) elements = escape(elements) sampling_period = escape(sampling_period) - type = escape(type) + type = escape(type).lower() format = escape(format) # Check for parameters and set defaults if not id: raise WebServiceException( - 'Missing observatory id.') + '"id" is a required parameter') now = datetime.now() - if starttime and endtime: - starttime = UTCDateTime(starttime) - endtime = UTCDateTime(endtime) - if not starttime and not endtime: + if starttime: + try: + starttime = UTCDateTime(starttime) + except: + raise WebServiceException( + 'Invalid starttime "%s"' % starttime) + else: starttime = UTCDateTime( - year=now.year, - month=now.month, - day=now.day, - hour=0) - endtime = starttime + (24 * 60 * 60 - 1) - if starttime and not endtime: - starttime = UTCDateTime(starttime) - endtime = starttime + (24 * 60 * 60 - 1) - if not starttime and endtime: + year=now.year, + month=now.month, + day=now.day, + hour=0) + if endtime: + try: + endtime = UTCDateTime(endtime) + except: + raise WebServiceException( + 'Invalid endtime "%s"' % endtime) + else: + endtime = starttime + (24 * 60 * 60 - 1) + if starttime > endtime: raise WebServiceException( - 'Missing start time.') + 'Starttime before endtime "%s" "%s"' + % (starttime, endtime)) if elements: elements = [el.strip().upper() for el in elements.split(',')] - if not elements: - elements = ('X', 'Y', 'Z', 'F') - valid_periods = ['1', '60'] + else: + elements = DEFAULT_ELEMENTS if not sampling_period: - sampling_period = '60' - if sampling_period not in valid_periods: + sampling_period = DEFAULT_PERIOD + if sampling_period not in VALID_PERIODS: raise WebServiceException( - 'Invalid sampling period.'\ - ' Valid sampling periods: %s' % valid_periods) + 'Invalid sampling period.' + ' Valid sampling periods: %s' % VALID_PERIODS) # TODO: Add hourly option if sampling_period == '1': sampling_period = 'second' if sampling_period == '60': sampling_period = 'minute' - valid_types = [ - 'variation', - 'adjusted', - 'quasi-definitive', - 'definitive' - ] if not type: - type = 'variation' - if type not in valid_types: + type = DEFAULT_TYPE + if type not in VALID_TYPES: raise WebServiceException( - 'Invalid data type.'\ - ' Valid data types: %s' % valid_types) + 'Invalid data type.' + ' Valid data types: %s' % VALID_TYPES) # TODO: Add json to valid formats - valid_formats = ['iaga2002'] if not format: format = 'iaga2002' - if format not in valid_formats: + if format not in VALID_FORMATS: raise WebServiceException( - 'Invalid format.'\ - ' Valid formats: %s' % valid_formats) - # Fill dictionary with parameters and return - query = {} - query['id'] = id - query['starttime'] = starttime - query['endtime'] = endtime - query['elements'] = elements - query['sampling_period'] = sampling_period - query['type'] = type - query['format'] = format + 'Invalid format.' + ' Valid formats: %s' % VALID_FORMATS) + # Create WebServiceQuery object and set properties + query = WebServiceQuery + query.id = id + query.starttime = starttime + query.endtime = endtime + query.elements = elements + query.sampling_period = sampling_period + query.type = type + query.format = format return query -- GitLab