diff --git a/docs/.gitignore b/docs/.gitignore
deleted file mode 100644
index 45c1505..0000000
--- a/docs/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-_site
-.sass-cache
-.jekyll-metadata
diff --git a/docs/404.html b/docs/404.html
deleted file mode 100644
index c472b4e..0000000
--- a/docs/404.html
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: default
----
-
-
-
-
-
404
-
-
Page not found :(
-
The requested page could not be found.
-
diff --git a/docs/Gemfile b/docs/Gemfile
deleted file mode 100644
index 9a776ce..0000000
--- a/docs/Gemfile
+++ /dev/null
@@ -1,27 +0,0 @@
-source "https://rubygems.org"
-
-# Hello! This is where you manage which Jekyll version is used to run.
-# When you want to use a different version, change it below, save the
-# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
-#
-# bundle exec jekyll serve
-#
-# This will help ensure the proper Jekyll version is running.
-# Happy Jekylling!
-# gem "jekyll", "3.5.2"
-
-# This is the default theme for new Jekyll sites. You may change this to anything you like.
-gem "minima", "~> 2.0"
-
-# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
-# uncomment the line below. To upgrade, run `bundle update github-pages`.
-gem "github-pages", group: :jekyll_plugins
-
-# If you have any plugins, put them here!
-group :jekyll_plugins do
- gem "jekyll-feed", "~> 0.6"
-end
-
-# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
-gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
deleted file mode 100644
index e88fbb4..0000000
--- a/docs/Gemfile.lock
+++ /dev/null
@@ -1,221 +0,0 @@
-GEM
- remote: https://rubygems.org/
- specs:
- activesupport (4.2.8)
- i18n (~> 0.7)
- minitest (~> 5.1)
- thread_safe (~> 0.3, >= 0.3.4)
- tzinfo (~> 1.1)
- addressable (2.5.2)
- public_suffix (>= 2.0.2, < 4.0)
- coffee-script (2.4.1)
- coffee-script-source
- execjs
- coffee-script-source (1.11.1)
- colorator (1.1.0)
- ethon (0.10.1)
- ffi (>= 1.3.0)
- execjs (2.7.0)
- faraday (0.13.1)
- multipart-post (>= 1.2, < 3)
- ffi (1.9.18)
- forwardable-extended (2.6.0)
- gemoji (3.0.0)
- github-pages (160)
- activesupport (= 4.2.8)
- github-pages-health-check (= 1.3.5)
- jekyll (= 3.5.2)
- jekyll-avatar (= 0.5.0)
- jekyll-coffeescript (= 1.0.2)
- jekyll-default-layout (= 0.1.4)
- jekyll-feed (= 0.9.2)
- jekyll-gist (= 1.4.1)
- jekyll-github-metadata (= 2.9.3)
- jekyll-mentions (= 1.2.0)
- jekyll-optional-front-matter (= 0.2.0)
- jekyll-paginate (= 1.1.0)
- jekyll-readme-index (= 0.1.0)
- jekyll-redirect-from (= 0.12.1)
- jekyll-relative-links (= 0.4.1)
- jekyll-sass-converter (= 1.5.0)
- jekyll-seo-tag (= 2.3.0)
- jekyll-sitemap (= 1.1.1)
- jekyll-swiss (= 0.4.0)
- jekyll-theme-architect (= 0.1.0)
- jekyll-theme-cayman (= 0.1.0)
- jekyll-theme-dinky (= 0.1.0)
- jekyll-theme-hacker (= 0.1.0)
- jekyll-theme-leap-day (= 0.1.0)
- jekyll-theme-merlot (= 0.1.0)
- jekyll-theme-midnight (= 0.1.0)
- jekyll-theme-minimal (= 0.1.0)
- jekyll-theme-modernist (= 0.1.0)
- jekyll-theme-primer (= 0.5.2)
- jekyll-theme-slate (= 0.1.0)
- jekyll-theme-tactile (= 0.1.0)
- jekyll-theme-time-machine (= 0.1.0)
- jekyll-titles-from-headings (= 0.4.0)
- jemoji (= 0.8.0)
- kramdown (= 1.13.2)
- liquid (= 4.0.0)
- listen (= 3.0.6)
- mercenary (~> 0.3)
- minima (= 2.1.1)
- rouge (= 1.11.1)
- terminal-table (~> 1.4)
- github-pages-health-check (1.3.5)
- addressable (~> 2.3)
- net-dns (~> 0.8)
- octokit (~> 4.0)
- public_suffix (~> 2.0)
- typhoeus (~> 0.7)
- html-pipeline (2.7.0)
- activesupport (>= 2)
- nokogiri (>= 1.4)
- i18n (0.8.6)
- jekyll (3.5.2)
- addressable (~> 2.4)
- colorator (~> 1.0)
- jekyll-sass-converter (~> 1.0)
- jekyll-watch (~> 1.1)
- kramdown (~> 1.3)
- liquid (~> 4.0)
- mercenary (~> 0.3.3)
- pathutil (~> 0.9)
- rouge (~> 1.7)
- safe_yaml (~> 1.0)
- jekyll-avatar (0.5.0)
- jekyll (~> 3.0)
- jekyll-coffeescript (1.0.2)
- coffee-script (~> 2.2)
- coffee-script-source (~> 1.11.1)
- jekyll-default-layout (0.1.4)
- jekyll (~> 3.0)
- jekyll-feed (0.9.2)
- jekyll (~> 3.3)
- jekyll-gist (1.4.1)
- octokit (~> 4.2)
- jekyll-github-metadata (2.9.3)
- jekyll (~> 3.1)
- octokit (~> 4.0, != 4.4.0)
- jekyll-mentions (1.2.0)
- activesupport (~> 4.0)
- html-pipeline (~> 2.3)
- jekyll (~> 3.0)
- jekyll-optional-front-matter (0.2.0)
- jekyll (~> 3.0)
- jekyll-paginate (1.1.0)
- jekyll-readme-index (0.1.0)
- jekyll (~> 3.0)
- jekyll-redirect-from (0.12.1)
- jekyll (~> 3.3)
- jekyll-relative-links (0.4.1)
- jekyll (~> 3.3)
- jekyll-sass-converter (1.5.0)
- sass (~> 3.4)
- jekyll-seo-tag (2.3.0)
- jekyll (~> 3.3)
- jekyll-sitemap (1.1.1)
- jekyll (~> 3.3)
- jekyll-swiss (0.4.0)
- jekyll-theme-architect (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-cayman (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-dinky (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-hacker (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-leap-day (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-merlot (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-midnight (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-minimal (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-modernist (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-primer (0.5.2)
- jekyll (~> 3.5)
- jekyll-github-metadata (~> 2.9)
- jekyll-seo-tag (~> 2.2)
- jekyll-theme-slate (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-tactile (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-theme-time-machine (0.1.0)
- jekyll (~> 3.5)
- jekyll-seo-tag (~> 2.0)
- jekyll-titles-from-headings (0.4.0)
- jekyll (~> 3.3)
- jekyll-watch (1.5.0)
- listen (~> 3.0, < 3.1)
- jemoji (0.8.0)
- activesupport (~> 4.0)
- gemoji (~> 3.0)
- html-pipeline (~> 2.2)
- jekyll (>= 3.0)
- kramdown (1.13.2)
- liquid (4.0.0)
- listen (3.0.6)
- rb-fsevent (>= 0.9.3)
- rb-inotify (>= 0.9.7)
- mercenary (0.3.6)
- mini_portile2 (2.2.0)
- minima (2.1.1)
- jekyll (~> 3.3)
- minitest (5.10.3)
- multipart-post (2.0.0)
- net-dns (0.8.0)
- nokogiri (1.8.0)
- mini_portile2 (~> 2.2.0)
- octokit (4.7.0)
- sawyer (~> 0.8.0, >= 0.5.3)
- pathutil (0.14.0)
- forwardable-extended (~> 2.6)
- public_suffix (2.0.5)
- rb-fsevent (0.10.2)
- rb-inotify (0.9.10)
- ffi (>= 0.5.0, < 2)
- rouge (1.11.1)
- safe_yaml (1.0.4)
- sass (3.5.1)
- sass-listen (~> 4.0.0)
- sass-listen (4.0.0)
- rb-fsevent (~> 0.9, >= 0.9.4)
- rb-inotify (~> 0.9, >= 0.9.7)
- sawyer (0.8.1)
- addressable (>= 2.3.5, < 2.6)
- faraday (~> 0.8, < 1.0)
- terminal-table (1.8.0)
- unicode-display_width (~> 1.1, >= 1.1.1)
- thread_safe (0.3.6)
- typhoeus (0.8.0)
- ethon (>= 0.8.0)
- tzinfo (1.2.3)
- thread_safe (~> 0.1)
- unicode-display_width (1.3.0)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- github-pages
- jekyll-feed (~> 0.6)
- minima (~> 2.0)
- tzinfo-data
-
-BUNDLED WITH
- 1.16.0.pre.2
diff --git a/docs/_config.yml b/docs/_config.yml
deleted file mode 100644
index 4f8fd28..0000000
--- a/docs/_config.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-# Welcome to Jekyll!
-#
-# This config file is meant for settings that affect your whole blog, values
-# which you are expected to set up once and rarely edit after that. If you find
-# yourself editing this file very often, consider using Jekyll's data files
-# feature for the data you need to update frequently.
-#
-# For technical reasons, this file is *NOT* reloaded automatically when you use
-# 'bundle exec jekyll serve'. If you change this file, please restart the server process.
-
-# Site settings
-# These are used to personalize your new site. If you look in the HTML files,
-# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
-# You can create any custom variable you would like, and they will be accessible
-# in the templates via {{ site.myvariable }}.
-title: HealthTools.KE-api documentation
-email: your-email@example.com
-description: > # this means to ignore newlines until "baseurl:"
- Write an awesome description for your new site here. You can edit this
- line in _config.yml. It will appear in your document head meta (for
- Google search results) and in your feed.xml site description.
-baseurl: "" # the subpath of your site, e.g. /blog
-url: "" # the base hostname & protocol for your site, e.g. http://example.com
-twitter_username: jekyllrb
-github_username: jekyll
-
-# Build settings
-markdown: kramdown
-theme: minima
-plugins:
- - jekyll-feed
-
-# Exclude from processing.
-# The following items will not be processed, by default. Create a custom list
-# to override the default setting.
-# exclude:
-# - Gemfile
-# - Gemfile.lock
-# - node_modules
-# - vendor/bundle/
-# - vendor/cache/
-# - vendor/gems/
-# - vendor/ruby/
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 82e5944..0000000
--- a/docs/index.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-# You don't need to edit this file, it's empty on purpose.
-# Edit theme's home layout instead if you wanna make some changes
-# See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults
-layout: home
----
-# 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:
-
-- Doctors: http://medicalboard.co.ke/online-services/retention/
-- Foreign doctors: http://medicalboard.co.ke/online-services/foreign-doctors-license-register
-- Clinical officers: http://clinicalofficerscouncil.org/online-services/retention/
-
-### Specifications
-Specification for the API is shown below. It is an open api and requires no authentication to access.
-
-
-| EndPoint | Allowed Methods | Functionality | Parameters |
-|-------------------------------------|------------------|----------------------------------------------------------|------------|
-| `/doctors/search.json` | GET | Search a doctor by the name | q=[name] |
-| `/nurses/search.json` | GET | Search a nurse by the name | q=[name] |
-| `/clinical-officers/search.json` | GET | Search a clinical officer by the name | q=[name] |
-
-
-### Installation
-Clone the repo from github `$ git clone git@github.com:RyanSept/HealthTools.KE-api.git`
-
-Change directory into package `$ cd HealthTools.KE-api`
-
-Install the dependencies by running `$ pip install -r requirements.txt`
-
-Install Memcached
- * If on linux follow this [link](https://github.com/memcached/memcached/wiki/Install)
- * On mac use `brew install memcached`
-
-You can set the required environment variables like so
-```<>
-$ export APP_DEBUG= # True or False
-$ export MEMCACHED_URL= # defaults to 127.0.0.1:8000
-$ export GA_TRACKING_ID=
-$ export SMS_USER=
-$ export SMS_PASS=
-$ export SMS_SHORTCODE=
-$ export SMS_SEND_URL=
-$ export AWS_ACCESS_KEY=
-$ export AWS_SECRET_KEY=
-$ export ES_HOST= (DO NOT SET THIS IF YOU WOULD LIKE TO USE ELASTIC SEARCH LOCALLY ON YOUR MACHINE)
-$ export ES_PORT=
-$ export ES_INDEX=
-```
-**If you want to use elasticsearch locally on your machine use the following instructions to set it up**
-
-For linux and windows users, follow instructions from this [link](https://www.elastic.co/guide/en/elasticsearch/reference/current/setup.html)
-
-For mac users run `brew install elasticsearch` on your terminal
-
-Run memcached on your terminal `$ memcached -p (default: 8000)`
-
-If you set up elasticsearch locally run it `$ elasticsearch`
-
-You can now run the server `$ python manage.py` or `gunicorn manage:app` for production.
-
-
-
-## Running the tests
-
-Run memcached on your terminal `$ memcached -p (default: 8000)`
-
-_**make sure if you use elasticsearch locally, it's running**_
-
-Use nosetests to run tests (with stdout) like this:
-```$ nosetests --nocapture```
diff --git a/healthtools/analytics.py b/healthtools/analytics.py
deleted file mode 100644
index e700b82..0000000
--- a/healthtools/analytics.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import requests
-
-
-def track_event(tracking_id, category, action, cid, label=None, value=0):
- '''
- Posts Tracking in info to Google Analytics using measurement protocol.
- Args:
- tracking_id: The tracking ID of the Google Analytics account in which these data is associated with.
- category: The name assigned to the group of similar events to track.
- action: The Specific action being tracked.
- cid: Anonymous Client Identifier. Ideally, this should be a UUID that is associated with particular user, device
- label: Label of the event.
- value: Value of event in this case number of results obtained
- Returns:
- No return value # If the request fails, it will raise a
- RequestException. .
- '''
- data = {
- 'v': '1',
- 'tid': tracking_id,
- 'cid': cid,
- 't': 'event',
- 'ec': category,
- 'ea': action,
- 'el': label,
- 'ev': value,
- }
- response = requests.post(
- 'http://www.google-analytics.com/collect', data=data)
- response.raise_for_status()
diff --git a/healthtools/build_query.py b/healthtools/build_query.py
deleted file mode 100644
index d980d84..0000000
--- a/healthtools/build_query.py
+++ /dev/null
@@ -1,258 +0,0 @@
-import getpass
-import json
-import requests
-import re
-
-from datetime import datetime
-from flask import Blueprint, request, current_app
-
-from healthtools_ke_api.analytics 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()
-
-
-class BuildQuery(object):
- def __init__(self):
- self.SMS_RESULT_COUNT = 4 # Number of results to be send via sms
- self.DOC_KEYWORDS = ['doc', 'daktari', 'doctor', 'oncologist', 'dr']
- self.CO_KEYWORDS = ['CO', 'clinical officer',
- 'clinic officer', 'clinical', 'clinical oficer', ]
- self.NO_KEYWORDS = ['nurse', 'no', 'nursing officer',
- 'mhuguzi', 'muuguzi', 'RN', 'Registered Nurse']
- self.NHIF_KEYWORDS = ['nhif', 'bima', 'insurance',
- 'insurance fund', 'health insurance', 'hospital fund']
- self.HF_KEYWORDS = ['hf', 'hospital', 'dispensary', 'clinic',
- 'hospitali', 'sanatorium', 'health centre']
-
- def find_keyword_in_query(self, query, keywords):
- regex = re.compile(r'\b(?:%s)\b' % '|'.join(keywords), re.IGNORECASE)
- return re.search(regex, query)
-
- def build_query_response(self, query):
- query = self.clean_query(query)
- # Start by looking for doctors keywords
- if self.find_keyword_in_query(query, self.DOC_KEYWORDS):
- search_terms = self.find_keyword_in_query(query, self.DOC_KEYWORDS)
- query = query[:search_terms.start()] + query[search_terms.end():]
- print query
- doctors = es.get_from_elasticsearch('doctors', query)
- msg = self.construct_docs_response(doctors[:self.SMS_RESULT_COUNT])
- self.check_message(msg)
- 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])
- self.check_message(msg)
- return [msg]
- # Looking for clinical officers Keywords
- elif self.find_keyword_in_query(query, self.CO_KEYWORDS):
- search_terms = self.find_keyword_in_query(query, self.CO_KEYWORDS)
- query = query[:search_terms.start()] + query[search_terms.end():]
- print query
- clinical_officers = es.get_from_elasticsearch(
- 'clinical-officers', query)
- msg = self.construct_co_response(
- clinical_officers[:self.SMS_RESULT_COUNT])
- self.check_message(msg)
- return [msg]
- # Looking for nhif hospitals
- elif self.find_keyword_in_query(query, self.NHIF_KEYWORDS):
- search_terms = self.find_keyword_in_query(
- query, self.NHIF_KEYWORDS)
- query = query[:search_terms.start()] + query[search_terms.end():]
-
- if re.search("inpatient", query):
- query = re.sub("\s*inpatient\s*", "",
- query, flags=re.IGNORECASE)
- doc_type = "nhif-inpatient"
- else:
- query = re.sub("\s*outpatient\s*", "",
- query, flags=re.IGNORECASE)
-
- # Default: ES doc_type = nhif-outpatient-cs
- doc_type = ["nhif-outpatient", "nhif-outpatient-cs"]
-
- nhif_hospitals = es.get_from_elasticsearch(
- doc_type, query)
-
- msg = self.construct_nhif_response(nhif_hospitals)
- print msg
- return [msg]
- # Looking for health facilities
- elif self.find_keyword_in_query(query, self.HF_KEYWORDS):
- search_terms = self.find_keyword_in_query(query, self.HF_KEYWORDS)
- query = query[:search_terms.start()] + query[search_terms.end():]
- health_facilities = es.get_from_elasticsearch(
- 'health-facilities', query)
- msg = self.construct_hf_response(
- health_facilities[:self.SMS_RESULT_COUNT])
- print msg
- return [msg]
- # If we miss the keywords then reply with the preferred query formats
- else:
- self.print_error(query)
- 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)
- return [msg, {'error': " ".join(msg_items)}]
-
- def construct_co_response(self, co_list):
- # Just incase we found ourselves here with an empty list
- if len(co_list) < 1:
- return "Could not find a clinical officer with that name."
- count = 1
- msg_items = []
- for co in co_list:
- # co = co["fields"]
- co = co["_source"]
- status = " ".join(
- [str(count) + ".", "".join(co['name'].title()), "-", "".join(co['qualifications'].upper())])
- msg_items.append(status)
- count = count + 1
- if len(co_list) > 1:
- msg_items.append(
- "\nFind the full list at http://health.the-star.co.ke")
- print "\n".join(msg_items)
- return "\n".join(msg_items)
-
- def construct_docs_response(self, docs_list):
- # Just incase we found ourselves here with an empty list
- if len(docs_list) < 1:
- return "Could not find a doctor with that name"
- count = 1
- msg_items = []
-
- for doc in docs_list:
- doc = doc["_source"]
- status = " ".join([str(count) + ".", "".join(doc['name'].title()), "-",
- "".join(doc['reg_no'].title()), "-", "".join(doc['qualifications'].upper())])
-
- msg_items.append(status)
- count = count + 1
- if len(docs_list) > 1:
- msg_items.append(
- "\nFind the full list at http://health.the-star.co.ke")
-
- return "\n".join(msg_items)
-
- def construct_nurse_response(self, nurse_list):
- # Just incase we found ourselves here with an empty list
- if len(nurse_list) < 1:
- return "Could not find a nurse with that name"
- count = 1
- msg_items = []
- for nurse in nurse_list:
- status = " ".join([str(count) + ".", nurse['name'].title() +
- ",", "Valid to", nurse['valid_till'].title()])
- msg_items.append(status)
- count = count + 1
- if len(nurse_list) > 1:
- msg_items.append(
- "\nFind the full list at http://health.the-star.co.ke")
-
- return "\n".join(msg_items)
-
- def construct_nhif_response(self, nhif_list):
- # Just incase we found ourselves here with an empty list
- if len(nhif_list) < 1:
- return "We could not find an NHIF accredited hospital with the name or in the location you provided."
- count = 1
- msg_items = []
- nhif_hospitals = []
-
- for nhif in nhif_list:
- nhif = nhif['_source']
- hospital = nhif['hospital']
- nhif_hospitals.append(hospital)
-
- nhif_hospitals = list(set(nhif_hospitals))
-
- for hospital in nhif_hospitals:
- status = " ".join([str(count) + ".", hospital.title()])
- msg_items.append(status)
- count = count + 1
-
- if len(nhif_list) > 1:
- msg_items.append(
- "\nFind the full list at http://health.the-star.co.ke")
-
- return "\n".join(msg_items)
-
- def construct_hf_response(self, hf_list):
- # Just incase we found ourselves here with an empty list
- if len(hf_list) < 1:
- return "We could not find a health facility with the name or in the location you provided."
- count = 1
- msg_items = []
- for hf in hf_list:
- hf = hf['_source']
- status = " ".join([str(count) + ".", hf['name'].title() +
- " -", hf['keph_level_name'].title()])
- msg_items.append(status)
- count = count + 1
- if len(hf_list) > 1:
- msg_items.append(
- "\nFind the full list at http://health.the-star.co.ke")
-
- return "\n".join(msg_items)
-
- def clean_query(self, query):
- query = query.lower().strip().replace(".", "")
- return query
-
- def parse_elastic_search_results(self, response):
- result_to_send_count = self.SMS_RESULT_COUNT
- data_dict = response.json()
- fields_dict = (data_dict['hits'])
- hits = fields_dict['hit']
- result_list = []
- search_results_count = len(hits)
- print "FOUND {} RESULTS".format(search_results_count)
- for item in hits:
- result = item['fields']
- if len(result_list) < result_to_send_count:
- result_list.append(result)
- else:
- break
- 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:
- self.print_error(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(datetime.now().strftime(
- "%Y-%m-%d %H:%M:%S")) + message)
- response = None
- if SLACK["url"]:
- response = requests.post(
- SLACK["url"],
- data=json.dumps({
- "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
diff --git a/healthtools/core.py b/healthtools/core.py
index 557e94f..0f9e1a5 100644
--- a/healthtools/core.py
+++ b/healthtools/core.py
@@ -1,6 +1,56 @@
-from flask import Flask
+from werkzeug.local import LocalProxy
+from flask import Flask, current_app
+from elasticsearch import Elasticsearch, RequestsHttpConnection
+from requests_aws4auth import AWS4Auth
+from healthtools import settings
-def create_app():
+
+def create_app(config={}):
app = Flask('healthtools')
+ app.config.from_object(settings)
+ app.config.update(config)
return app
+
+
+def get_es():
+ app = current_app._get_current_object()
+ if not hasattr(app, '_es_instance'):
+ if 'aws' in app.config.get('ELASTICSEARCH_HOST'):
+ host = app.config.get('ELASTICSEARCH_HOST')
+ awsauth = AWS4AuthNotUnicode(app.config.get('AWS_ACCESS_KEY'),
+ app.config.get('AWS_SECRET_KEY'),
+ app.config.get('AWS_REGION'),
+ 'es')
+ app._es_instance = Elasticsearch(
+ hosts=[{'host': host, 'port': 443}],
+ http_auth=awsauth,
+ use_ssl=True,
+ verify_certs=True,
+ connection_class=RequestsHttpConnection,
+ timeout=120
+ )
+ else:
+ app._es_instance = Elasticsearch(
+ app.config.get('ELASTICSEARCH_HOST'),
+ timeout=120
+ )
+ return app._es_instance
+
+
+def get_es_index():
+ app = current_app._get_current_object()
+ return app.config.get('ELASTICSEARCH_INDEX')
+
+
+es = LocalProxy(get_es)
+es_index = LocalProxy(get_es_index)
+
+
+# Work-around: https://github.com/sam-washington/requests-aws4auth/issues/24
+
+class AWS4AuthNotUnicode(AWS4Auth):
+ def __call__(self, req):
+ req = super(AWS4AuthNotUnicode, self).__call__(req)
+ req.headers = {str(name): value for name, value in req.headers.items()}
+ return req
diff --git a/healthtools/elastic_search.py b/healthtools/elastic_search.py
deleted file mode 100644
index dca29e9..0000000
--- a/healthtools/elastic_search.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from elasticsearch import Elasticsearch, RequestsHttpConnection
-from requests_aws4auth import AWS4Auth
-
-from healthtools_ke_api.settings import AWS, ES
-from healthtools_ke_api.views.serializer import JSONSerializerPython2
-import re
-
-
-class Elastic(object):
- """
- Common class for elastic search client and methods
- """
-
- def __init__(self):
- # client host for aws elastic search service
- if "aws" in ES["host"]:
- # set up authentication credentials
- awsauth = AWS4Auth(AWS["access_key"],
- AWS["secret_key"], AWS["region"], 'es')
- self.es_client = Elasticsearch(
- hosts=ES["host"],
- port=int(ES["port"]),
- http_auth=awsauth,
- use_ssl=True,
- verify_certs=True,
- connection_class=RequestsHttpConnection,
- serializer=JSONSerializerPython2()
- )
- else:
- self.es_client = Elasticsearch(
- "{}:{}".format(ES["host"], ES["port"]))
-
- @staticmethod
- def remove_keyword(query):
- """
- Remove keyword from search term
- """
- query_formatted = query.strip().lower()
- keywords = ['dr', 'dr.', 'doctor', 'nurse',
- 'co', 'c.o.', 'c.o', 'clinical officer']
- for word in keywords:
- regex = r'(? 0)
-
- def test_cos_endpoint_with_bad_query(self):
- response = self.client.get("/clinical-officers/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_cos_endpoint_gets_doctors(self):
- response = self.client.get("/clinical-officers/search.json?q=Ann")
- self.assertIn("success", response.data)
diff --git a/healthtools/tests/doctors_api.py b/healthtools/tests/doctors_api.py
deleted file mode 100644
index ddd489a..0000000
--- a/healthtools/tests/doctors_api.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.elastic_search import Elastic
-
-
-class TestDoctorsAPI(TestCase):
- def setUp(self):
- self.client = app.test_client()
- self.es = Elastic()
-
- def test_gets_doctors_from_elasticsearch(self):
- doctors = self.es.get_from_elasticsearch("doctors", "BHATT")
- self.assertTrue(len(doctors) > 0)
-
- def test_doctors_endpoint_with_bad_query(self):
- response = self.client.get("/doctors/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_doctors_endpoint_gets_doctors(self):
- response = self.client.get("/doctors/search.json?q=Marie")
- self.assertIn("success", response.data)
diff --git a/healthtools/tests/nhif_inpatient.py b/healthtools/tests/nhif_inpatient.py
deleted file mode 100644
index b657d63..0000000
--- a/healthtools/tests/nhif_inpatient.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.search import Elastic
-
-class TestNhifInpatientAPI(TestCase):
- def setUp(self):
- self.client = app.test_client()
- self.es = Elastic()
- def test_gets_nhifin_from_elasticsearch(self):
- nhif_inpatient = self.es.get_from_elasticsearch("nhif-inpatient", "ABRAR HEALTH SERVICES LTD")
- self.assertTrue(len(nhif_inpatient) > 0)
-
- def test_nhifin_endpoint_with_bad_query(self):
- response = self.client.get("/nhif-inpatient/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_nhifin_endpoint_gets_nhif_inpatient(self):
- response = self.client.get("/nhif-inpatient/search.json?q=Kenyatta Hsopital")
- self.assertIn("success", response.data)
\ No newline at end of file
diff --git a/healthtools/tests/nhif_outpatient.py b/healthtools/tests/nhif_outpatient.py
deleted file mode 100644
index a1c6fa1..0000000
--- a/healthtools/tests/nhif_outpatient.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.search import Elastic
-
-class TestNhifOutpatientAPI(TestCase):
- def setUp(self):
- self.client = app.test_client()
- self.es = Elastic()
- def test_gets_nhifop_from_elasticsearch(self):
- nhif_outpatient = self.es.get_from_elasticsearch("nhif-outpatient", "Jacob")
- self.assertTrue(len(nhif_outpatient) > 0)
-
- def test_nhifop_endpoint_with_bad_query(self):
- response = self.client.get("/nhif-outpatient/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_nhifop_endpoint_gets_nhif_outpatient(self):
- response = self.client.get("/nhif-outpatient/search.json?q=Kenyatta")
- self.assertIn("success", response.data)
\ No newline at end of file
diff --git a/healthtools/tests/nhif_outpatient_cs.py b/healthtools/tests/nhif_outpatient_cs.py
deleted file mode 100644
index 01c9086..0000000
--- a/healthtools/tests/nhif_outpatient_cs.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.search import Elastic
-
-
-class TestNhifOutpatientCSAPI(TestCase):
- def setUp(self):
- self.client = app.test_client()
- self.es = Elastic()
- def test_gets_nhifopcs_from_elasticsearch(self):
- nhif_outpatient_cs = self.es.get_from_elasticsearch("nhif-outpatient-cs", "Kenyatta hospital")
- self.assertTrue(len(nhif_outpatient_cs) > 0)
-
- def test_nhifopcs_endpoint_with_bad_query(self):
- response = self.client.get("/nhif-outpatient-cs/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_nhifopcs_endpoint_gets_nhif_outpatient_cs(self):
- response = self.client.get("/nhif-outpatient-cs/search.json?q=Kenyatta")
- self.assertIn("success", response.data)
\ No newline at end of file
diff --git a/healthtools/tests/nurses_api.py b/healthtools/tests/nurses_api.py
deleted file mode 100644
index 968f984..0000000
--- a/healthtools/tests/nurses_api.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.nurses import get_nurses_from_nc_registry
-
-
-class TestNursesAPI(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_gets_nurses_from_nc_registry(self):
- nurses = get_nurses_from_nc_registry("Marie")
- self.assertTrue(len(nurses) > 0)
-
- def test_gets_nurses_from_nc_registry_handle_inexistent_nurse(self):
- nurses = get_nurses_from_nc_registry("ihoafiho39023u8")
- self.assertEqual(len(nurses), 0)
-
- def test_nurses_endpoint_handles_bad_query(self):
- response = self.client.get("/nurses/search.json?q=")
- self.assertIn("A query is required.", response.data)
-
- def test_nurses_endpoint_gets_nurses(self):
- response = self.client.get("/nurses/search.json?q=Marie")
- self.assertIn("success", response.data)
-
- def test_nurses_endpoint_can_retrieve_cached_result(self):
- # call once
- self.client.get("/nurses/search.json?q=Marie")
- # second time should retrieve cached result
- response = self.client.get("/nurses/search.json?q=Marie")
- self.assertIn("X-Retrieved-From-Cache", response.headers.keys())
diff --git a/healthtools/tests/sms_api.py b/healthtools/tests/sms_api.py
deleted file mode 100644
index 6070557..0000000
--- a/healthtools/tests/sms_api.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import send_sms
-from healthtools_ke_api.build_query import BuildQuery
-
-bq = BuildQuery()
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = bq.build_query_response('nurse mary')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- 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]})
- self.assertEqual(
- 'Could not find a doctor with that name', response.data)
diff --git a/healthtools/tests/sms_api_clinical_officers.py b/healthtools/tests/sms_api_clinical_officers.py
deleted file mode 100644
index f0db58b..0000000
--- a/healthtools/tests/sms_api_clinical_officers.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = build_query_response('clinical officer John')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": 'CO KEBAGENDI'})
- self.assertEqual(200, response.status_code)
-
- def test_queries_not_understood_post_to_slack(self):
- message = build_query_response('Test SMS error posts to slack')
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": message[0]})
- self.assertEqual('Could not find a Clinical Officer with that name', response.data)
\ No newline at end of file
diff --git a/healthtools/tests/sms_api_doctors.py b/healthtools/tests/sms_api_doctors.py
deleted file mode 100644
index 51f3e7d..0000000
--- a/healthtools/tests/sms_api_doctors.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = build_query_response('daktari John')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": 'oncologist KEBAGENDI'})
- self.assertEqual(200, response.status_code)
-
- def test_queries_not_understood_post_to_slack(self):
- message = build_query_response('Test SMS error posts to slack')
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": message[0]})
- self.assertEqual('Could not find a Doctor with that name', response.data)
\ No newline at end of file
diff --git a/healthtools/tests/sms_api_healthfacilities.py b/healthtools/tests/sms_api_healthfacilities.py
deleted file mode 100644
index 03e2cfc..0000000
--- a/healthtools/tests/sms_api_healthfacilities.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
-
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = build_query_response('sanatorium Kituni')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": 'hf Emayian'})
- self.assertEqual(200, response.status_code)
-
- def test_queries_not_understood_post_to_slack(self):
- message = build_query_response('Test SMS error posts to slack')
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": message[0]})
- self.assertEqual('Could not find a health facility with that name', response.data)
\ No newline at end of file
diff --git a/healthtools/tests/sms_api_nhif_accredited_hospitals.py b/healthtools/tests/sms_api_nhif_accredited_hospitals.py
deleted file mode 100644
index b0cf0d0..0000000
--- a/healthtools/tests/sms_api_nhif_accredited_hospitals.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = build_query_response('nhif EDELVALE')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": 'hospital fund alif'})
- self.assertEqual(200, response.status_code)
-
- def test_queries_not_understood_post_to_slack(self):
- message = build_query_response('Test SMS error posts to slack')
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": message[0]})
- self.assertEqual('Could not find a NHIF accredited hospital with that name', response.data)
diff --git a/healthtools/tests/sms_api_nurse.py b/healthtools/tests/sms_api_nurse.py
deleted file mode 100644
index e874292..0000000
--- a/healthtools/tests/sms_api_nurse.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from unittest import TestCase
-from healthtools_ke_api import app
-from healthtools_ke_api.views.sms_handler import build_query_response, send_sms
-
-
-class TestSmsApi(TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_sms_requires_message_and_number(self):
- response = self.client.get("/sms")
- message = "The url parameters 'message' and 'phoneNumber' are required."
- self.assertEqual(message, response.data)
-
- def test_query_response(self):
- response = build_query_response('nurse mary')
- self.assertTrue(len(response[0]) > 0)
-
- def test_send_sms(self):
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": 'nurse mary'})
- self.assertEqual(200, response.status_code)
-
- def test_queries_not_understood_post_to_slack(self):
- message = build_query_response('Test SMS error posts to slack')
- response = self.client.get("/sms", query_string={"phoneNumber": "09", "message": message[0]})
- self.assertEqual('Could not find a doctor with that name', response.data)
diff --git a/healthtools/tests/test_telegram_bot.py b/healthtools/tests/test_telegram_bot.py
deleted file mode 100644
index e3c3ce4..0000000
--- a/healthtools/tests/test_telegram_bot.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import re
-import unittest
-
-from healthtools_ke_api import app
-from healthtools_ke_api.views.telegram_bot import telegram_bot as tg
-
-from healthtools_ke_api.settings import DEBUG, TGBOT
-
-DEBUG = False
-
-
-class TestTelegramBot(unittest.TestCase):
- def setUp(self):
- self.client = app.test_client()
-
- def test_https_webhook(self):
- """
- Test a https url is provided
- """
- url = re.search("https", TGBOT["BOT_WEBHOOK_URL"])
- self.assertTrue(url)
-
- def test_invalid_get(self):
- response = self.client.get('/' + TGBOT["BOT_TOKEN"])
- self.assertEqual(response.status_code, 405)
diff --git a/healthtools/views/base_api.py b/healthtools/views/base_api.py
index bd012bc..da9473a 100644
--- a/healthtools/views/base_api.py
+++ b/healthtools/views/base_api.py
@@ -1,4 +1,4 @@
-from flask import Blueprint, request, jsonify
+from flask import Blueprint, redirect
blueprint = Blueprint('base_api', __name__)
@@ -6,4 +6,5 @@
@blueprint.route('/')
def index():
- return jsonify({'results': [], 'status': 'OK'})
+ # TODO: Redirect to HealthTools docs instead
+ return redirect('https://github.com/CodeForAfricaLabs/HealthTools.API')
diff --git a/healthtools/views/clinical_officers.py b/healthtools/views/clinical_officers.py
deleted file mode 100644
index f84163f..0000000
--- a/healthtools/views/clinical_officers.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from flask import Blueprint, request, jsonify, current_app
-
-from healthtools_ke_api.elastic_search import Elastic
-from healthtools_ke_api.analytics import track_event
-
-clinical_officers_api = Blueprint('clinical_officers_api', __name__)
-
-
-@clinical_officers_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "API to Kenyan Clinical Officers registry",
- "authentication": [],
- "endpoints": {
- "/": {
- "methods": ["GET"]
- },
- "/clinical-officers/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-
-@clinical_officers_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"clinical_officers": []}
- })
-
- # get clinical_officers by that name from aws
- response = {}
- es = Elastic()
- clinical_officers = es.get_from_elasticsearch('clinical-officers', query)
-
- if not clinical_officers:
- response["message"] = "No clinical officer by that name found."
-
- track_event(current_app.config.get('GA_TRACKING_ID'),
- 'Clinical-Officers', 'search', request.remote_addr,
- label=query, value=len(clinical_officers))
- response["data"] = {"clinical_officers": clinical_officers}
- response["status"] = "success"
-
- results = jsonify(response)
- return results
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"clinical_officers": []}
- })
diff --git a/healthtools/views/doctors.py b/healthtools/views/doctors.py
deleted file mode 100644
index 5ba8153..0000000
--- a/healthtools/views/doctors.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from flask import Blueprint, request, jsonify, current_app
-
-from healthtools_ke_api.analytics import track_event
-from healthtools_ke_api.elastic_search import Elastic
-
-doctors_api = Blueprint('doctors_api', __name__)
-
-
-@doctors_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "API to the Kenyan doctors registry",
- "authentication": [],
- "endpoints": {
- "/": {"methods": ["GET"]},
- "/doctors/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-
-@doctors_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"doctors": []}
- })
-
- # get doctors by that name from aws
- response = {}
- es = Elastic()
- doctors = es.get_from_elasticsearch('doctors', query)
-
- if not doctors:
- response["message"] = "No doctor by that name found."
-
- track_event(current_app.config.get('GA_TRACKING_ID'), 'Doctor', 'search',
- request.remote_addr, label=query, value=len(doctors))
- response["data"] = {"doctors": doctors}
- response["status"] = "success"
-
- results = jsonify(response)
- return results
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"doctors": []}
- })
diff --git a/healthtools/views/json_serializer.py b/healthtools/views/json_serializer.py
deleted file mode 100644
index a4196d6..0000000
--- a/healthtools/views/json_serializer.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import json
-from elasticsearch import serializer, compat, exceptions
-
-
-class JSONSerializerPython2(serializer.JSONSerializer):
- """Override elasticsearch library serializer to ensure it encodes utf characters during json dump.
- See original at: https://github.com/elastic/elasticsearch-py/blob/master/elasticsearch/serializer.py#L42
- A description of how ensure_ascii encodes unicode characters to ensure they can be sent across the wire
- as ascii can be found here: https://docs.python.org/2/library/json.html#basic-usage
- """
- def dumps(self, data):
- # don't serialize strings
- if isinstance(data, compat.string_types):
- return data
- try:
- return json.dumps(data, default=self.default, ensure_ascii=True)
- except (ValueError, TypeError) as e:
- raise exceptions.SerializationError(data, e)
diff --git a/healthtools/views/nhif_inpatient.py b/healthtools/views/nhif_inpatient.py
deleted file mode 100644
index 13079ce..0000000
--- a/healthtools/views/nhif_inpatient.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from flask import Blueprint, request, jsonify, make_response, json, current_app
-from bs4 import BeautifulSoup
-from elastic_search import Elastic
-
-from healthtools_ke_api.analytics import track_event
-
-import requests
-
-nhif_inpatient_api = Blueprint('nhif_inpatient_api', __name__)
-
-@nhif_inpatient_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "API to the NHIF inpatient registry",
- "authentication": [],
- "endpoints": {
- "/": {"methods": ["GET"]},
- "/nhif-inpatient/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-@nhif_inpatient_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"nhif_inpatient": []}
- })
-
- response = {}
- es = Elastic()
- nhif_inpatient = es.get_from_elasticsearch('nhif-inpatient', query)
-
- if not nhif_inpatient:
- response["message"] = "No NHIF inpatient facility by that name found."
-
- track_event(current_app.config.get('GA_TRACKING_ID'), 'Nhif-Inpatient', 'search',
- request.remote_addr, label=query, value=len(nhif_inpatient))
-
- response["data"] = {"nhif_inpatient": nhif_inpatient}
- response["status"] = "success"
-
- results = jsonify(response)
- return results
-
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"nhif_inpatient": []}
- })
\ No newline at end of file
diff --git a/healthtools/views/nhif_outpatient.py b/healthtools/views/nhif_outpatient.py
deleted file mode 100644
index b178434..0000000
--- a/healthtools/views/nhif_outpatient.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from flask import Blueprint, request, jsonify, make_response, json, current_app
-from bs4 import BeautifulSoup
-from elastic_search import Elastic
-
-from healthtools_ke_api.analytics import track_event
-
-import requests
-
-nhif_outpatient_api = Blueprint('nhif_outpatient_api', __name__)
-
-@nhif_outpatient_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "API to the NHIF inpatient registry",
- "authentication": [],
- "endpoints": {
- "/": {"methods": ["GET"]},
- "/nhif-outpatient/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-@nhif_outpatient_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"nhif_outpatient": []}
- })
-
- response = {}
- es = Elastic()
- nhif_outpatient = es.get_from_elasticsearch('nhif-outpatient', query)
-
- if not nhif_outpatient:
- response["message"] = "No NHIF Outpatient facility by that name found."
-
- track_event(current_app.config.get('GA_TRACKING_ID'), 'Nhif-Outpatient', 'search',
- request.remote_addr, label=query, value=len(nhif_outpatient))
-
- response["data"] = {"nhif_outpatient": nhif_outpatient}
- response["status"] = "success"
-
- results = jsonify(response)
- return results
-
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"nhif_outpatient": []}
- })
\ No newline at end of file
diff --git a/healthtools/views/nhif_outpatient_cs.py b/healthtools/views/nhif_outpatient_cs.py
deleted file mode 100644
index 063199b..0000000
--- a/healthtools/views/nhif_outpatient_cs.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from flask import Blueprint, request, jsonify, make_response, json, current_app
-from bs4 import BeautifulSoup
-from elastic_search import Elastic
-
-from healthtools_ke_api.analytics import track_event
-
-import requests
-
-nhif_outpatient_cs_api = Blueprint('nhif_outpatient_cs_api', __name__)
-
-@nhif_outpatient_cs_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "API to the NHIF Outpatient CS registry",
- "authentication": [],
- "endpoints": {
- "/": {"methods": ["GET"]},
- "/nhif-outpatientcs/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-@nhif_outpatient_cs_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"nhif-outpatient-cs": []}
- })
-
- response = {}
- es = Elastic()
- nhif_outpatientcs = es.get_from_elasticsearch('nhif-outpatient-cs', query)
-
- if not nhif_outpatientcs:
- response["message"] = "No NHIF Outpatient CS facility by that name found."
-
- track_event(current_app.config.get('GA_TRACKING_ID'), 'Nhif-OutpatientCS', 'search',
- request.remote_addr, label=query, value=len(nhif_outpatientcs))
-
- response["data"] = {"nhif_outpatientcs": nhif_outpatientcs}
- response["status"] = "success"
-
- results = jsonify(response)
- return results
-
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"nhif_outpatientcs": []}
- })
\ No newline at end of file
diff --git a/healthtools/views/nurses.py b/healthtools/views/nurses.py
deleted file mode 100644
index acc8062..0000000
--- a/healthtools/views/nurses.py
+++ /dev/null
@@ -1,112 +0,0 @@
-from bs4 import BeautifulSoup
-from flask import Blueprint, request, jsonify, make_response, json, current_app
-
-from healthtools_ke_api.analytics import track_event
-from healthtools_ke_api.settings import MEMCACHED_URL
-
-import requests
-import memcache
-
-nurses_api = Blueprint('nurses_api', __name__)
-cache = memcache.Client([MEMCACHED_URL], debug=True) # cache server
-
-nurse_fields = ["name", "licence_no", "valid_till"]
-NURSING_COUNCIL_URL = "http://nckenya.com/services/search.php?p=1&s={}"
-
-
-@nurses_api.route('/', methods=['GET'])
-def index():
- '''
- Landing endpoint
- '''
- msg = {
- "name": "Nursing Council of Kenya API",
- "authentication": [],
- "endpoints": {
- "/": {"methods": ["GET"]},
- "/nurses/search.json": {
- "methods": ["GET"],
- "args": {
- "q": {"required": True}
- }
- },
- }
- }
- return jsonify(msg)
-
-
-@nurses_api.route('/search.json', methods=['GET'])
-def search():
- try:
- query = request.args.get('q')
- if not query or len(query) < 1:
- return jsonify({
- "error": "A query is required.",
- "results": "",
- "data": {"nurses": []}
- })
-
- # try to get queried result first
- cached_result = cache.get(query.replace(" ", ""))
- if cached_result:
- num_cached_results = len(json.loads(
- cached_result.data)["data"]["nurses"])
- track_event(current_app.config.get('GA_TRACKING_ID'), 'Nurse', 'search',
- request.remote_addr, label=query, value=num_cached_results)
- response = make_response(cached_result)
- response.headers["X-Retrieved-From-Cache"] = True
- return response
-
- # get nurses by that name from nursing council site
- response = {}
- nurses = get_nurses_from_nc_registry(query)
- if not nurses:
- response["message"] = "No nurse by that name found."
-
- # send action to google analytics
- track_event(current_app.config.get('GA_TRACKING_ID'),
- 'Nurse', 'search',
- request.remote_addr, label=query, value=len(nurses))
-
- response["data"] = {"nurses": nurses}
- response["status"] = "success"
-
- results = jsonify(response)
- cache.set(query.replace(" ", ""), results,
- time=345600) # expire after 4 days
- return results
-
- except Exception as err:
- return jsonify({
- "status": "error",
- "message": str(err),
- "data": {"nurses": []}
- })
-
-
-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 = []
-
- if "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")
-
- # parse table for the nurses data
- for row in rows:
- # only the columns we want
- columns = row.find_all("td")[:len(nurse_fields)]
- columns = [text.text.strip() for text in columns]
-
- entry = dict(zip(nurse_fields, columns))
- nurses.append(entry)
-
- return nurses
diff --git a/healthtools/views/search_api.py b/healthtools/views/search_api.py
index 3de9a50..5263469 100644
--- a/healthtools/views/search_api.py
+++ b/healthtools/views/search_api.py
@@ -6,18 +6,20 @@
blueprint = Blueprint('search_api', __name__)
-@blueprint.route('/search', methods=['GET'])
-@blueprint.route('/search/', methods=['GET'])
+@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')
- results = run_query(query, doc_type)
+ result = run_query(query, doc_type) # TODO: Return run_query message here
# Error with run_query (run_query returns false)
- if(not results):
+ if(not result):
return jsonify({
- 'results': [],
+ 'result': {'hits': [], 'total': 0},
'status': 'FAILED',
- 'msg': '' # TODO: Pass run_query msg here.
+ 'msg': '' # TODO: Pass run_query message here.
})
- return jsonify({'results': results, 'status': 'OK'})
+ # TODO: Log event here (send to Google Analytics)
+
+ return jsonify({'result': result, 'status': 'OK'})
diff --git a/healthtools/views/sms_handler.py b/healthtools/views/sms_handler.py
deleted file mode 100644
index 3a64b99..0000000
--- a/healthtools/views/sms_handler.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import getpass
-import json
-import re
-import requests
-
-from datetime import datetime
-from flask import Blueprint, request, current_app
-
-from healthtools_ke_api.analytics import track_event
-from healthtools_ke_api.settings import SLACK
-
-from healthtools_ke_api.views.nurses import get_nurses_from_nc_registry
-from healthtools_ke_api.elastic_search import Elastic
-from healthtools_ke_api.build_query import BuildQuery
-
-
-SMS_SEND_URL = 'http://ke.mtechcomm.com/remote'
-SMS_RESULT_COUNT = 4 # Number of results to be send via sms
-DOC_KEYWORDS = ['doc', 'daktari', 'doctor', 'oncologist', 'dr']
-CO_KEYWORDS = ['CO', 'clinical officer',
- 'clinic officer', 'clinical', 'clinical oficer', ]
-NO_KEYWORDS = ['nurse', 'no', 'nursing officer',
- 'mhuguzi', 'muuguzi', 'RN', 'Registered Nurse']
-NHIF_KEYWORDS = ['nhif', 'bima', 'insurance',
- 'insurance fund', 'health insurance', 'hospital fund']
-HF_KEYWORDS = ['hf', 'hospital', 'dispensary', 'clinic',
- 'hospitali', 'sanatorium', 'health centre']
-es = Elastic()
-bq = BuildQuery()
-
-sms_handler = Blueprint("sms_handler", __name__)
-
-
-@sms_handler.route("/sms", methods=['GET'])
-def sms():
- name = request.args.get("message")
- phone_number = request.args.get("phoneNumber")
- if not name or not phone_number:
- return "The url parameters 'message' and 'phoneNumber' are required."
- # Track Event SMS RECEIVED
- track_event(current_app.config.get('GA_TRACKING_ID'), 'smsquery', 'receive',
- encode_cid(phone_number), label='lambda', value=2)
- msg = bq.build_query_response(name)
- resp = send_sms(phone_number, msg[0])
- # Track Event SMS SENT
- track_event(current_app.config.get('GA_TRACKING_ID'), 'smsquery', 'send',
- encode_cid(phone_number), label='lambda', value=2)
-
- return msg[0]
-
-
-def send_sms(phone_number, msg):
- params = {
- 'user': current_app.config.get('SMS_USER'),
- 'pass': current_app.config.get('SMS_PASS'),
- 'messageID': 0,
- 'shortCode': current_app.config.get('SMS_SHORTCODE'),
- 'MSISDN': phone_number,
- 'MESSAGE': msg
- }
- resp = requests.get(SMS_SEND_URL, params=params)
- return resp
-
-
-def encode_cid(phone_number):
- # TODO: Generate a hash instead of using phone number
- return phone_number
diff --git a/healthtools/views/telegram_bot/__init__.py b/healthtools/views/telegram_bot/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/healthtools/views/telegram_bot/telegram_bot.py b/healthtools/views/telegram_bot/telegram_bot.py
deleted file mode 100644
index 56f3578..0000000
--- a/healthtools/views/telegram_bot/telegram_bot.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import json
-import requests
-
-from flask import Blueprint, request, jsonify
-from telegram import Update
-
-from healthtools_ke_api.views.telegram_bot import telegram_manager as manager
-
-
-telegram_bot = Blueprint('telegram_bot', __name__)
-
-# Initialize the Telegram Bot handler
-manager.setup()
-
-
-@telegram_bot.route('/' + manager.TOKEN, methods=['POST'])
-def webhook():
- if request.method == "POST":
- if not manager.DEBUG:
- # retrieve the message in JSON and then transform it to Telegram
- # object
- update = Update.de_json(request.get_json(force=True), manager.bot)
-
- # Start conversation
- manager.update_queue.put(update)
-
- return jsonify({
- "Success": "Telegram Bot is up and running on Webhooks",
- "status": 200})
- else:
- return jsonify({
- "Success": "Telegram Bot is up and running on polling",
- "status": 200})
- else:
- return jsonify({"Error": "Method not allowed", "status": 405})
diff --git a/healthtools/views/telegram_bot/telegram_manager.py b/healthtools/views/telegram_bot/telegram_manager.py
deleted file mode 100644
index 2c88513..0000000
--- a/healthtools/views/telegram_bot/telegram_manager.py
+++ /dev/null
@@ -1,299 +0,0 @@
-import json
-import logging
-import os
-import re
-import requests
-import string
-import time
-
-from flask import Flask, Blueprint, request, jsonify
-
-from queue import Queue
-from threading import Thread
-
-from emoji import emojize
-from telegram import (Bot, Update, ReplyKeyboardMarkup, ParseMode,
- ReplyKeyboardRemove)
-from telegram.ext import (Dispatcher, Updater, CommandHandler,
- ConversationHandler, Filters, MessageHandler, RegexHandler)
-
-from healthtools_ke_api.build_query import BuildQuery
-from healthtools_ke_api.settings import DEBUG, TGBOT
-
-TOKEN = TGBOT["BOT_TOKEN"]
-SERVER_IP = TGBOT["SERVER_IP"]
-PORT = TGBOT["TELEGRAM_PORT"]
-CERT_FILE = TGBOT["CERT_FILE"]
-KEY_FILE = TGBOT["KEY_FILE"]
-
-WEBHOOK_URL = TGBOT["BOT_WEBHOOK_URL"]
-WEBHOOK_URL = WEBHOOK_URL + "/" + TOKEN
-
-CONTEXT = (CERT_FILE, KEY_FILE)
-
-# States
-CHOOSING, TYPING_REPLY = range(2)
-
-bot = Bot(TOKEN)
-build_query = BuildQuery()
-build_query.SMS_RESULT_COUNT = 5
-
-# Enable logging
-if DEBUG:
- logging.basicConfig(
- level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-else:
- logging.basicConfig(
- level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-
-
-logger = logging.getLogger("telegram.bot.Manager")
-
-
-if DEBUG:
- updater = Updater(bot=bot)
- dp = updater.dispatcher
-else:
- update_queue = Queue()
- dp = Dispatcher(bot, update_queue)
-
-
-# Custom keyboard with reply options
-reply_keyboard = [["Clinical Officer", "Doctor", "Nurse"],
- ["NHIF Accredited Hospital: Inpatient",
- "NHIF Accredited Hospital: Outpatient"],
- ["Health Facility"]]
-
-markup = ReplyKeyboardMarkup(
- reply_keyboard, one_time_keyboard=True)
-
-
-def start_polling():
- """
- Activates schedulers of all setups, and starts polling updates from Telegram.
- """
-
- logger.info('Start polling')
-
- # getUpdate does not work if webhook is set. So we delete any webhook
- updater.bot.set_webhook()
-
- updater.start_polling(poll_interval=1.0, timeout=20)
- updater.idle()
-
-
-def set_webhook(webhook_url, cert, key):
- """
- Activates schedulers of all setups, setups webhook, and
- starts small http server to listen for updates via this webhook.
- """
- logger.info('Start webhook')
-
- # Delete any webhook to avoid Conflict: terminated by other setWebhook
- bot.setWebhook()
- time.sleep(5) # to avoid error 4RetryAfter: Flood control exceeded
-
- # Using nginx + bot
- bot.setWebhook(url=webhook_url
- # certificate=open(CERT_FILE, 'rb')
- )
-
- print ("\nWebhook set: %s \n", bot.getWebhookInfo().url)
-
- thread = Thread(target=dp.start, name='dp')
- thread.start()
-
- return (update_queue, dp)
-
-
-def facts_to_str(user_data):
- facts = list()
-
- for key, value in user_data.items():
- facts.append("%s - %s" % (key, value))
-
- return "\n".join(facts).join(["\n", "\n"])
-
-
-def start(bot, update):
-
- chat_id = update.message.chat_id
- user = update.message.from_user.first_name
-
- wave = emojize(':wave:', use_aliases=True)
- welcome_msg = (
- u"*Hello* {0} {1} \n"
- "My name is `Healthtools Bot`.\n\n"
- "*Here's what I can do for you:*\n"
- "1. Check to see if your doctor, nurse, or clinical officer is registered\n"
- "2. Find out which facilities your NHIF card will cover in your county\n"
- "3. Find the nearest doctor or health facility\n"
- "\nSend /cancel to stop talking to me.\n".format(user, wave)
- ).encode('utf-8')
-
- bot.send_message(
- chat_id=chat_id,
- text=welcome_msg,
- parse_mode=ParseMode.MARKDOWN,
- reply_markup=markup,
- )
-
- # Call the next function
- return CHOOSING
-
-# TODO: Handle edited_message in these too
-
-
-def regular_choice(bot, update, user_data):
- """
- Show summary of user choice and input
- """
- chat_id = update.message.chat_id
-
- text = update.message.text
- user_data['choice'] = text
-
- msg = "Please enter the name of a `%s` you want to find" % text.title()
-
- bot.send_message(
- chat_id=chat_id,
- text=msg,
- parse_mode=ParseMode.MARKDOWN,
- )
-
- # Call next function: received_information
- # return TYPING_REPLY
- return TYPING_REPLY
-
-
-def received_information(bot, update, user_data):
- """
- Show summary of user choice and input
- """
- chat_id = update.message.chat_id
-
- text = update.message.text
- choice = user_data['choice']
- user_data[choice] = text
- del user_data['choice']
-
- update.message.reply_text("Here's what you have asked me to search"
- "%s"
- % facts_to_str(user_data))
-
- bot.sendChatAction(chat_id=chat_id, action="typing")
-
- # Now we fetch the data
- results = fetch_data(user_data)
-
- print("\n")
- print(results)
-
- # Remove multiple whitespaces
- results = re.sub(" +", " ", str(results[0]))
- search_msg = (
- "*Search Results*\n"
- "%s" % results
- )
-
- bot.send_message(
- chat_id=chat_id,
- text=search_msg,
- parse_mode=ParseMode.MARKDOWN,
- reply_markup=markup,
- )
-
- # Empty the user_data dictionary
- user_data.clear()
-
- # Call functi0n regular_choice
- # return CHOOSING
- return CHOOSING
-
-
-def fetch_data(user_data):
- """
- Fetch the data requested by the user
- """
- query = user_data.keys()[-1]
-
- if query:
- keyword = str(query).encode("utf-8")
- search_term = user_data[keyword]
-
- if re.search("NHIF Accredited Hospital", keyword):
- keyword = re.sub("accredited hospital: ", "",
- keyword, flags=re.IGNORECASE)
-
- if keyword == "Health Facility":
- keyword = "hf"
-
- keyword = keyword.lower()
- query = keyword + " " + search_term
-
- else:
- return "Keyword not valid"
-
- search_results = build_query.build_query_response(query)
- return search_results
-
-
-def cancel(bot, update):
- user = update.message.from_user
- update.message.reply_text("Catch you later %s! Hope to talk to you soon." % user.first_name,
- reply_markup=ReplyKeyboardRemove())
-
- return ConversationHandler.END
-
-
-def unknown(bot, update):
- bot.sendMessage(
- chat_id=update.message.chat_id,
- text="Sorry, I didn't understand that command.")
-
-
-def error(bot, update, error):
- logger.warning("Update % s caused error % s" % (update, error))
-
-
-def setup():
- dp.add_handler(CommandHandler('help', start))
-
- # Add conversation handler with the states
- dp.add_handler(ConversationHandler(
- # Handler object to trigger the start of the conversation
- entry_points=[CommandHandler('start', start)],
-
- # Conversation states
- states={
- CHOOSING: [RegexHandler('^(Clinical Officer|Doctor|Nurse|Health Facility|NHIF Accredited Hospital)',
- regular_choice,
- pass_user_data=True,
- edited_updates=True),
- ],
-
- TYPING_REPLY: [MessageHandler(Filters.text,
- received_information,
- pass_user_data=True,
- edited_updates=True),
- ],
-
- },
-
- fallbacks=[CommandHandler('cancel', cancel)],
-
- # Allow user to restart a conversation with an entry point
- allow_reentry=True
- ))
-
- dp.add_handler(MessageHandler(Filters.command, unknown))
- dp.add_error_handler(error)
-
- if DEBUG:
- # Use webhook
- return start_polling()
- else:
- # Start Webhook
- set_webhook(webhook_url=WEBHOOK_URL,
- cert=CERT_FILE,
- key=KEY_FILE)
diff --git a/setup.py b/setup.py
index b979596..a001d02 100644
--- a/setup.py
+++ b/setup.py
@@ -13,6 +13,8 @@
install_requires=[
'flask',
'requests',
- 'bs4'
+ 'bs4',
+ 'elasticsearch',
+ 'requests_aws4auth'
],
)