Skip to content
Browse files

Resolving merge conflicts

  • Loading branch information...
TinaMurimi committed Aug 25, 2017
1 parent a1e6b61 commit fe4ec309413e3c2ef4e9f54b4e287dd4756a55e5
@@ -1,12 +1,19 @@
# HealthTools.KE-api
HealthTools Kenya API to retrieve, structure and return data being used by the health tools. It provides
data on the following medical officer registries:
# HealthTools.API

The HealthTools API. Providing actionable health information.

Our data sources include:

- Doctors:
- Foreign doctors:
- Clinical officers:

### Specifications
The scrapers for this data can be found here:

- ?

## Usage

Specification for the API is shown below. It is an open api and requires no authentication to access.

@@ -17,7 +24,8 @@ Specification for the API is shown below. It is an open api and requires no auth
| `/clinical-officers/search.json` | GET | Search a clinical officer by the name | q=[name] |

### Installation
## Installation

Clone the repo from github `$ git clone`

Change directory into package `$ cd HealthTools.KE-api`
@@ -42,6 +50,18 @@ $ export AWS_SECRET_KEY=<aws-secret-key>
$ export ES_PORT=<elasticsearch_port>
$ export ES_INDEX=<elasticsearch_index>
# Telegram Bot required environment variables
export BOT_TOKEN=<telegram-bot-token-assigned-by-BotFather>
# Note: Telegram Bot only works with HTTPS
export BOT_WEBHOOK_URL=<https-forwarding-address-from-ngrok>
export SERVER_IP="localhost"
export TELEGRAM_PORT=5000
# openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 3650 -out cert.pem
export CERT_FILE=</path/to/cert/file>
export KEY_FILE=</path/to/keu/file>
**If you want to use elasticsearch locally on your machine use the following instructions to set it up**

@@ -55,13 +75,64 @@ If you set up elasticsearch locally run it `$ elasticsearch`

You can now run the server `$ python` or `gunicorn manage:app` for production.

# Setting up Telegram Bot on HealthTools.KE-api
The Telegram Bot does the followinng:
1. Check to see if your doctor, nurse, or clinical officer is registered
2. Find out which facilities your NHIF card will cover in your county
3. Find the nearest doctor or health facility

## Running the tests
### Installation
Make sure you have installed in your environment: `python-telegram-bot`

# Create a new telegram bot
- After you create your bot, save the token assigned.

# ngrok Configuration
- ngrok allows you to expose a web server running on your local machine to the interne
- Install Ngrok:
- Follow the instructions on:
Note: The listening port you use, is the same one your app should listen on. E.g.
```$ ngrok http 5000```
if __name__ == '__main__':
host="localhost", # Since ngrok is running locally
port=5000, # the app listens on the same port as ngrok
- Configuration
See the nginx.config.template
# Nginx Configuration
- Install Nginx
for mac users:
- Configuration
Ensure you add `proxy_set_header X-Forwarded-Proto https;` in location since Telegram bot webhooks works *only* with HTTPS URLs
### Tests
Run memcached on your terminal `$ memcached -p <port you set MEMCACHED_URL to run on>(default: 8000)`
_**make sure if you use elasticsearch locally, it's running**_
Use nosetests to run tests (with stdout) like this:
```$ nosetests --nocapture```
## Contributing
## License
@@ -9,7 +9,6 @@
from healthtools_ke_api.views.doctors import doctors_api
from healthtools_ke_api.views.nurses import nurses_api
from healthtools_ke_api.views.clinical_officers import clinical_officers_api
from healthtools_ke_api.views.health_facilities import health_facilities_api

from healthtools_ke_api.views.sms_handler import sms_handler
from healthtools_ke_api.views.telegram_bot import telegram_bot as tg
@@ -20,10 +19,10 @@
app.register_blueprint(doctors_api, url_prefix='/doctors')
app.register_blueprint(nurses_api, url_prefix='/nurses')
app.register_blueprint(clinical_officers_api, url_prefix='/clinical-officers')
app.register_blueprint(health_facilities_api, url_prefix='/health-facilities')

def index():
@@ -37,7 +36,6 @@ def index():
"/nurses": {"methods": ["GET"]},
"/doctors": {"methods": ["GET"]},
"/clinical-officers": {"methods": ["GET"]},
"/health-facilities": {"methods": ["GET"]},
return jsonify(msg)
@@ -1,14 +1,15 @@
import re
import getpass
import json
import requests
import string
import re

from datetime import datetime
from flask import Blueprint, request, current_app

from import track_event
from healthtools_ke_api.views.nurses import get_nurses_from_nc_registry
from healthtools_ke_api.elastic_search import Elastic

es = Elastic()

@@ -38,13 +39,15 @@ def build_query_response(self, query):
print query
doctors = es.get_from_elasticsearch('doctors', query)
msg = self.construct_docs_response(doctors[:self.SMS_RESULT_COUNT])
return [msg]
# Looking for Nurses keywords
elif self.find_keyword_in_query(query, self.NO_KEYWORDS):
search_terms = self.find_keyword_in_query(query, self.NO_KEYWORDS)
query = query[:search_terms.start()] + query[search_terms.end():]
nurses = get_nurses_from_nc_registry(query)
msg = self.construct_nurse_response(nurses[:self.SMS_RESULT_COUNT])
return [msg]
# Looking for clinical officers Keywords
elif self.find_keyword_in_query(query, self.CO_KEYWORDS):
@@ -55,6 +58,7 @@ def build_query_response(self, query):
'clinical-officers', query)
msg = self.construct_co_response(
return [msg]
# Looking for nhif hospitals
elif self.find_keyword_in_query(query, self.NHIF_KEYWORDS):
@@ -91,15 +95,15 @@ def build_query_response(self, query):
return [msg]
# If we miss the keywords then reply with the preferred query formats
msg_items = []
msg_items = list()
msg_items.append("We could not understand your query. Try these:")
msg_items.append("1. Doctors: DR. SAMUEL AMAI")
msg_items.append("2. Clinical Officers: CO SAMUEL AMAI")
msg_items.append("3. Nurses: NURSE SAMUEL AMAI")
msg_items.append("4. NHIF accredited hospital: NHIF KITALE")
msg_items.append("5. Health Facility: HF KITALE")
msg = " ".join(msg_items)
print msg
return [msg, {'error': " ".join(msg_items)}]

def construct_co_response(self, co_list):
@@ -221,3 +225,34 @@ def parse_elastic_search_results(self, response):
return result_list

def check_message(self, msg):
# check the message and if query wasn't understood, post error
if 'could not find' in msg:

def print_error(self, message):
print error messages in the terminal
if slack webhook is set up, post the errors to slack
print("[{0}] - ".format(
"%Y-%m-%d %H:%M:%S")) + message)
response = None
if SLACK["url"]:
response =
"attachments": [{
"author_name": "HealthTools API",
"color": "warning",
"pretext": "[SMS] Could not find a result for this SMS.",
"fields": [{
"title": "Message",
"value": message,
"short": False
headers={"Content-Type": "application/json"})
return response
@@ -31,8 +31,10 @@
"BOT_TOKEN": os.getenv('BOT_TOKEN'),
"SERVER_IP": os.getenv("SERVER_IP"),
"TELEGRAM_PORT": os.getenv("TELEGRAM_PORT", 8443),
"TELEGRAM_PORT": os.getenv("TELEGRAM_PORT", 5000),
"CERT_FILE": os.getenv("CERT_FILE"),
"KEY_FILE": os.getenv("KEY_FILE"),

SLACK = {"url": os.getenv("WEBHOOK_URL")}
@@ -9,13 +9,14 @@ def setUp(self): = Elastic()

def test_gets_cos_from_elasticsearch(self):
clinical_officers ="clinical-officers", "Jacob")
clinical_officers =
"clinical-officers", "Jacob")
self.assertTrue(len(clinical_officers) > 0)

def test_cos_endpoint_with_bad_query(self):
response = self.client.get("/clinical-officers/search.json?q=")
self.assertIn("A query is required.",

def test_cos_endpoint_gets_doctors(self):
response = self.client.get("/clinical-officers/search.json?q=Marie")
response = self.client.get("/clinical-officers/search.json?q=Ann")
@@ -1,6 +1,9 @@
from unittest import TestCase
from healthtools_ke_api import app
from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
from healthtools_ke_api.views.sms_handler import send_sms
from healthtools_ke_api.build_query import BuildQuery

bq = BuildQuery()

class TestSmsApi(TestCase):
@@ -13,10 +16,19 @@ def test_sms_requires_message_and_number(self):

def test_query_response(self):
response = build_query_response('nurse mary')
response = bq.build_query_response('nurse mary')
self.assertTrue(len(response[0]) > 0)

def test_send_sms(self):
message = build_query_response('nurse mary')
response = self.client.get("/sms", query_string={"phoneNumber": "+254726075080", "message": message[0]})
response = self.client.get(
"/sms", query_string={"phoneNumber": "+254726075080",
"message": 'nurse mary'})
self.assertEqual(200, response.status_code)

def test_queries_not_understood_post_to_slack(self):
message = bq.build_query_response('Test SMS error posts to slack')
response = self.client.get(
"/sms", query_string={"phoneNumber": "+254726075080",
"message": message[0]})
'Could not find a doctor with that name',
@@ -13,42 +13,6 @@ class TestTelegramBot(unittest.TestCase):
def setUp(self):
self.client = app.test_client()

msg = {
"update_id": 865272811,
"message": {
"message_id": 83,
"from": {
"id": 346670031,
"is_bot": "false",
"first_name": "Tina",
"language_code": "en-KE"
"chat": {
"id": 346670031,
"first_name": "Tina",
"type": "private"
"date": 1503566582,
"text": "/start",
"entities": [
"offset": 0,
"length": 6,
"type": "bot_command"

# TGBOT = {
# "BOT_TOKEN": os.getenv('BOT_TOKEN'),
# "SERVER_IP": os.getenv("SERVER_IP"),
# "TELEGRAM_PORT": os.getenv("TELEGRAM_PORT", 8443),
# "CERT_FILE": os.getenv("CERT_FILE"),
# "KEY_FILE": os.getenv("KEY_FILE"),
# }

def test_https_webhook(self):
Test a https url is provided

0 comments on commit fe4ec30

Please sign in to comment.
You can’t perform that action at this time.