From e628f5c8ce7f36118b236ccd0dfdb2a45b8d58e9 Mon Sep 17 00:00:00 2001 From: Mayowa Makinde Date: Wed, 15 Nov 2017 11:13:22 +0100 Subject: [PATCH 1/4] add africastalking adapter --- healthtools/search/nurses.py | 4 ++-- healthtools/settings.py | 4 ++++ healthtools/sms/__init__.py | 12 ++++++++++-- healthtools/sms/africastalking.py | 21 +++++++++++++++++++++ healthtools/views/sms.py | 9 ++++++++- requirements.txt | 6 ++++++ runtime.txt | 2 +- src/healthtools | 1 + 8 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 healthtools/sms/africastalking.py create mode 160000 src/healthtools diff --git a/healthtools/search/nurses.py b/healthtools/search/nurses.py index 9cc02f9..b79b628 100644 --- a/healthtools/search/nurses.py +++ b/healthtools/search/nurses.py @@ -19,7 +19,7 @@ def get_nurses_from_nc_registry(query): response = requests.get(url) nurses = {'hits': [], 'total': 0} - if 'No results' in response.content: + if b'No results' in response.content: return nurses # make soup for parsing out of response and get the table @@ -37,5 +37,5 @@ def get_nurses_from_nc_registry(query): nurses['hits'].append(entry) nurses['total'] = len(nurses['hits']) - + return nurses diff --git a/healthtools/settings.py b/healthtools/settings.py index acd2638..d646eb5 100644 --- a/healthtools/settings.py +++ b/healthtools/settings.py @@ -44,6 +44,10 @@ SMS_MTECH_PASS = os.getenv('HTOOLS_SMS_MTECH_PASS') SMS_MTECH_SHORTCODE = os.getenv('HTOOLS_SMS_MTECH_SHORTCODE', '22495') +AFRICASTALKING = { + "SMS_AFRICASTALKING_USER": os.getenv("SMS_AFRICASTALKING_USER", "healthtoolsAPI"), + "SMS_AFRICASTALKING_KEY": os.getenv("SMS_AFRICASTALKING_KEY", '2875c45d0b660118cacb640f0efb1541c80f2fc1b5fcba4ee2cbf1f943ae6cf9'), +} # TGBOT: TElegram Bot TGBOT = { diff --git a/healthtools/sms/__init__.py b/healthtools/sms/__init__.py index e5e20b5..1c695d3 100644 --- a/healthtools/sms/__init__.py +++ b/healthtools/sms/__init__.py @@ -1,6 +1,6 @@ import logging -from healthtools.sms import twilio, mtech +from healthtools.sms import twilio, mtech, africastalking from healthtools.search import run_query log = logging.getLogger(__name__) @@ -18,7 +18,7 @@ def process_sms(args, adapter='mtech'): # TODO: Track event SMS RECEIVED here result, doc_type = run_query(msg) - + sms_to_send = create_sms(result, doc_type) try: @@ -39,6 +39,7 @@ def create_sms(result, doc_type): ''' response = '' + result_count = 1 if (not result or not doc_type): log.info('No result') @@ -51,6 +52,13 @@ def create_sms(result, doc_type): '5. Health Facility: HF KITALE' return response + if (doc_type == 'nurses'): + response += 'We found ' + str(result['total']) + ' matches:' + for hit in result['hits'][:3]: + response += '\n' + "{}. {}".format(str(result_count), hit['name']) + result_count += 1 + return response + # TODO: Figure out singular vs plural response += 'We found ' + str(result['total']) + ' matches:' for hit in result['hits'][:3]: diff --git a/healthtools/sms/africastalking.py b/healthtools/sms/africastalking.py new file mode 100644 index 0000000..fb8431c --- /dev/null +++ b/healthtools/sms/africastalking.py @@ -0,0 +1,21 @@ +import logging +from africastalking.AfricasTalkingGateway import (AfricasTalkingGateway, AfricasTalkingGatewayException) +from flask import current_app +from settings import AFRICASTALKING + +log = logging.getLogger(__name__) + +def send_sms(msg, phone_no): + username = AFRICASTALKING['SMS_AFRICASTALKING_USER'] + apikey = AFRICASTALKING['SMS_AFRICASTALKING_KEY'] + to = phone_no + message = msg + + results = '' + gateway = AfricasTalkingGateway(username, apikey) + + try: + results = gateway.sendMessage(to, message) + except AfricasTalkingGatewayException as e: + log.error('Encountered an error while sending: %s' ,str(e)) + return results \ No newline at end of file diff --git a/healthtools/views/sms.py b/healthtools/views/sms.py index 0aab20e..368fcbd 100644 --- a/healthtools/views/sms.py +++ b/healthtools/views/sms.py @@ -10,7 +10,14 @@ @blueprint.route('/sms', methods=['GET', 'POST']) @blueprint.route('/sms/', methods=['GET', 'POST']) def index(adapter='mtech'): - result = process_sms(request.args, adapter) + arguments = request.args + if adapter == "africastalking": + arguments = { + 'phoneNumber': request.values.get('from'), + 'message': request.values.get('text') + } + + result = process_sms(arguments, adapter) # Error with process_sms (process_sms returns false result) if(not result): diff --git a/requirements.txt b/requirements.txt index d9a2ee9..84f2dd7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +AfricastalkingGateway==1.9 beautifulsoup4==4.6.0 bs4==0.0.1 certifi==2017.7.27.1 @@ -10,11 +11,16 @@ idna==2.6 itsdangerous==0.24 Jinja2==2.9.6 MarkupSafe==1.0 +nested-lookup==0.1.3 +prompt-toolkit==1.0.15 PyJWT==1.5.3 +PySocks==1.6.7 pytz==2017.2 requests==2.18.4 requests-aws4auth==0.9 six==1.11.0 twilio==6.6.3 urllib3==1.22 +wcwidth==0.1.7 Werkzeug==0.12.2 +wit==4.3.0 diff --git a/runtime.txt b/runtime.txt index ba85ab9..fc81e75 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -python-2.7.13 \ No newline at end of file +python-3.6.2 \ No newline at end of file diff --git a/src/healthtools b/src/healthtools new file mode 160000 index 0000000..a6aeeb9 --- /dev/null +++ b/src/healthtools @@ -0,0 +1 @@ +Subproject commit a6aeeb94d90168eea3faf54599f2f4b1aee0f202 From b08a62e0af5df1e5c2d147f6f611a2d5b28e6ade Mon Sep 17 00:00:00 2001 From: Mayowa Makinde Date: Wed, 15 Nov 2017 15:24:35 +0100 Subject: [PATCH 2/4] hide api key --- healthtools/__init__.py | 4 +++- healthtools/search/elastic.py | 20 ++++++++++------ healthtools/search/nurses.py | 38 +++++++++++++++++-------------- healthtools/search/query.py | 5 ++-- healthtools/settings.py | 4 ++-- healthtools/sms/africastalking.py | 2 +- healthtools/views/search_api.py | 19 +++++++++++----- 7 files changed, 56 insertions(+), 36 deletions(-) diff --git a/healthtools/__init__.py b/healthtools/__init__.py index 1781b68..a30c974 100644 --- a/healthtools/__init__.py +++ b/healthtools/__init__.py @@ -1,4 +1,6 @@ import logging # loggers. -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.INFO, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt="%Y-%m-%d %H:%M:%S") diff --git a/healthtools/search/elastic.py b/healthtools/search/elastic.py index 53351f2..29c5d25 100644 --- a/healthtools/search/elastic.py +++ b/healthtools/search/elastic.py @@ -1,14 +1,20 @@ +import logging from healthtools.core import es, es_index +log = logging.getLogger(__name__) def search(query, doc_type): - result = es.search( - index=es_index, - body={'query': match_all_text(query)}, - doc_type=doc_type - ) - hits = result.get('hits', {}) - return hits + try: + result = es.search( + index=es_index, + body={'query': match_all_text(query)}, + doc_type=doc_type + ) + + hits = result.get('hits', {}) + return hits + except Exception as err: + log.error("Error fetching data from elastic search \n" + str(err)) def match_all(): diff --git a/healthtools/search/nurses.py b/healthtools/search/nurses.py index b79b628..6ee9358 100644 --- a/healthtools/search/nurses.py +++ b/healthtools/search/nurses.py @@ -1,10 +1,12 @@ import requests +import logging from bs4 import BeautifulSoup NURSING_COUNCIL_URL = 'http://nckenya.com/services/search.php?p=1&s={}' NURSES_FIELDS = ['name', 'licence_no', 'valid_till'] +log = logging.getLogger(__name__) def search(query): results = get_nurses_from_nc_registry(query) @@ -16,26 +18,28 @@ def get_nurses_from_nc_registry(query): Get nurses from the nursing council of Kenya registry ''' url = NURSING_COUNCIL_URL.format(query) - response = requests.get(url) nurses = {'hits': [], 'total': 0} + try: + response = requests.get(url) + if b'No results' in response.content: + return nurses - if b'No results' in response.content: - return nurses + # make soup for parsing out of response and get the table + soup = BeautifulSoup(response.content, 'html.parser') + table = soup.find('table', {'class': 'zebra'}).find('tbody') + rows = table.find_all("tr") - # make soup for parsing out of response and get the table - soup = BeautifulSoup(response.content, 'html.parser') - table = soup.find('table', {'class': 'zebra'}).find('tbody') - rows = table.find_all("tr") + # parse table for the nurses data + for row in rows: + # only the columns we want + columns = row.find_all('td')[:len(NURSES_FIELDS)] + columns = [text.text.strip() for text in columns] - # parse table for the nurses data - for row in rows: - # only the columns we want - columns = row.find_all('td')[:len(NURSES_FIELDS)] - columns = [text.text.strip() for text in columns] + entry = dict(zip(NURSES_FIELDS, columns)) + nurses['hits'].append(entry) - entry = dict(zip(NURSES_FIELDS, columns)) - nurses['hits'].append(entry) + nurses['total'] = len(nurses['hits']) - nurses['total'] = len(nurses['hits']) - - return nurses + return nurses + except Exception as err: + log.error("Error getting nurses from the nursing council url \n" + str(err)) diff --git a/healthtools/search/query.py b/healthtools/search/query.py index 46c2848..abbe49c 100644 --- a/healthtools/search/query.py +++ b/healthtools/search/query.py @@ -1,11 +1,12 @@ +import logging from wit import Wit from nested_lookup import nested_lookup from healthtools.settings import WIT_ACCESS_TOKEN from healthtools.documents import DOCUMENTS, doc_exists - from healthtools.search import elastic, nurses +log = logging.getLogger(__name__) def run_query(query, doc_type=None): @@ -18,7 +19,6 @@ def run_query(query, doc_type=None): else: search_type = 'nurses' return doc_type, search_type - doc_type, search_type = determine_doc_type(query, doc_type) if not doc_type: @@ -55,6 +55,7 @@ def determine_doc_type(query, doc_type=None): for keyword in DOCUMENTS[doc]['keywords']: if query.startswith(keyword + ' '): return doc, DOCUMENTS[doc]['search_type'] + log.error("doc_type could not be determined from query\n Query: " + query) return False, False diff --git a/healthtools/settings.py b/healthtools/settings.py index d646eb5..bdbf529 100644 --- a/healthtools/settings.py +++ b/healthtools/settings.py @@ -45,8 +45,8 @@ SMS_MTECH_SHORTCODE = os.getenv('HTOOLS_SMS_MTECH_SHORTCODE', '22495') AFRICASTALKING = { - "SMS_AFRICASTALKING_USER": os.getenv("SMS_AFRICASTALKING_USER", "healthtoolsAPI"), - "SMS_AFRICASTALKING_KEY": os.getenv("SMS_AFRICASTALKING_KEY", '2875c45d0b660118cacb640f0efb1541c80f2fc1b5fcba4ee2cbf1f943ae6cf9'), + "SMS_AFRICASTALKING_USER": os.getenv("SMS_AFRICASTALKING_USER"), + "SMS_AFRICASTALKING_KEY": os.getenv("SMS_AFRICASTALKING_KEY"), } # TGBOT: TElegram Bot diff --git a/healthtools/sms/africastalking.py b/healthtools/sms/africastalking.py index fb8431c..8f173a0 100644 --- a/healthtools/sms/africastalking.py +++ b/healthtools/sms/africastalking.py @@ -18,4 +18,4 @@ def send_sms(msg, phone_no): results = gateway.sendMessage(to, message) except AfricasTalkingGatewayException as e: log.error('Encountered an error while sending: %s' ,str(e)) - return results \ No newline at end of file + return results diff --git a/healthtools/views/search_api.py b/healthtools/views/search_api.py index 8fe6623..d26ce8b 100644 --- a/healthtools/views/search_api.py +++ b/healthtools/views/search_api.py @@ -1,25 +1,32 @@ +import logging from flask import Blueprint, request, jsonify from healthtools.search import run_query blueprint = Blueprint('search_api', __name__) +log = logging.getLogger(__name__) @blueprint.route('/search', methods=['GET'], strict_slashes=False) @blueprint.route('/search/', methods=['GET'], strict_slashes=False) def index(doc_type=None): query = request.args.get('q') - result, doc_type = run_query(query, doc_type) + try: + result, doc_type = run_query(query, doc_type) + response = jsonify({ + 'result': result, + 'doc_type': doc_type, + 'status': 'OK' + }) - # Error with run_query (run_query returns false) - if not result: - return jsonify({ + except Exception as err: + response = jsonify({ 'result': {'hits': [], 'total': 0}, 'doc_type': doc_type, 'status': 'FAILED', 'msg': '' # TODO: Pass run_query message here. }) + log.error('Search failed \n' + str(err)) # TODO: Log event here (send to Google Analytics) - - return jsonify({'result': result, 'doc_type': doc_type, 'status': 'OK'}) + return response From eade496c19423d1cd0060568fee1db031f37ee1c Mon Sep 17 00:00:00 2001 From: Mayowa Makinde Date: Thu, 16 Nov 2017 15:12:07 +0100 Subject: [PATCH 3/4] rewrite exports and implement feedback --- healthtools/settings.py | 6 ++---- healthtools/sms/__init__.py | 10 +++++++--- healthtools/sms/africastalking.py | 5 ++--- healthtools/views/sms.py | 9 +-------- src/healthtools | 1 - 5 files changed, 12 insertions(+), 19 deletions(-) delete mode 160000 src/healthtools diff --git a/healthtools/settings.py b/healthtools/settings.py index bdbf529..c9f8d91 100644 --- a/healthtools/settings.py +++ b/healthtools/settings.py @@ -44,10 +44,8 @@ SMS_MTECH_PASS = os.getenv('HTOOLS_SMS_MTECH_PASS') SMS_MTECH_SHORTCODE = os.getenv('HTOOLS_SMS_MTECH_SHORTCODE', '22495') -AFRICASTALKING = { - "SMS_AFRICASTALKING_USER": os.getenv("SMS_AFRICASTALKING_USER"), - "SMS_AFRICASTALKING_KEY": os.getenv("SMS_AFRICASTALKING_KEY"), -} +SMS_AFRICASTALKING_USER = os.getenv('HTOOLS_SMS_AFRICASTALKING_USER') +SMS_AFRICASTALKING_KEY = os.getenv('HTOOLS_SMS_AFRICASTALKING_KEY') # TGBOT: TElegram Bot TGBOT = { diff --git a/healthtools/sms/__init__.py b/healthtools/sms/__init__.py index 1c695d3..ab859d5 100644 --- a/healthtools/sms/__init__.py +++ b/healthtools/sms/__init__.py @@ -6,8 +6,13 @@ log = logging.getLogger(__name__) -def process_sms(args, adapter='mtech'): - +def process_sms(request, adapter='mtech'): + args = request.args + if adapter == "africastalking": + args = { + 'phoneNumber': request.values.get('from'), + 'message': request.values.get('text') + } msg = args.get('message') phone_no = args.get('phoneNumber') @@ -20,7 +25,6 @@ def process_sms(args, adapter='mtech'): result, doc_type = run_query(msg) sms_to_send = create_sms(result, doc_type) - try: response = eval(adapter+'.send_sms(sms_to_send, phone_no)') except Exception as e: diff --git a/healthtools/sms/africastalking.py b/healthtools/sms/africastalking.py index 8f173a0..3fc251a 100644 --- a/healthtools/sms/africastalking.py +++ b/healthtools/sms/africastalking.py @@ -1,13 +1,12 @@ import logging from africastalking.AfricasTalkingGateway import (AfricasTalkingGateway, AfricasTalkingGatewayException) from flask import current_app -from settings import AFRICASTALKING log = logging.getLogger(__name__) def send_sms(msg, phone_no): - username = AFRICASTALKING['SMS_AFRICASTALKING_USER'] - apikey = AFRICASTALKING['SMS_AFRICASTALKING_KEY'] + username = current_app.config.get('SMS_AFRICASTALKING_USER') + apikey = current_app.config.get('SMS_AFRICASTALKING_KEY') to = phone_no message = msg diff --git a/healthtools/views/sms.py b/healthtools/views/sms.py index 368fcbd..293fa95 100644 --- a/healthtools/views/sms.py +++ b/healthtools/views/sms.py @@ -10,14 +10,7 @@ @blueprint.route('/sms', methods=['GET', 'POST']) @blueprint.route('/sms/', methods=['GET', 'POST']) def index(adapter='mtech'): - arguments = request.args - if adapter == "africastalking": - arguments = { - 'phoneNumber': request.values.get('from'), - 'message': request.values.get('text') - } - - result = process_sms(arguments, adapter) + result = process_sms(request, adapter) # Error with process_sms (process_sms returns false result) if(not result): diff --git a/src/healthtools b/src/healthtools deleted file mode 160000 index a6aeeb9..0000000 --- a/src/healthtools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a6aeeb94d90168eea3faf54599f2f4b1aee0f202 From 15e019720eb2d873f93fe82f7403153a69050aa2 Mon Sep 17 00:00:00 2001 From: Mayowa Makinde Date: Thu, 16 Nov 2017 15:17:13 +0100 Subject: [PATCH 4/4] fix style issues --- healthtools/sms/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/healthtools/sms/__init__.py b/healthtools/sms/__init__.py index ab859d5..5a21797 100644 --- a/healthtools/sms/__init__.py +++ b/healthtools/sms/__init__.py @@ -23,8 +23,9 @@ def process_sms(request, adapter='mtech'): # TODO: Track event SMS RECEIVED here result, doc_type = run_query(msg) - + sms_to_send = create_sms(result, doc_type) + try: response = eval(adapter+'.send_sms(sms_to_send, phone_no)') except Exception as e: