def country_report(country_code): """ """ country_code = country_code.upper() if not available_countries.get(country_code): raise ApiException(400, "Reports are not available for the country that you specified.") if g.user is None or not g.user.is_active(): raise ApiException(401, "You need to be logged-in in order to access this resource.") country = Country.query.filter_by(code=country_code).one() report_json = cache.retrieve('country_overview_' + country.code) if report_json: logger.debug('loading country overview from cache') else: report = {} procurement_list = [] procurements = Procurement.query.filter_by(country=country).filter_by(approved=True).order_by(Procurement.start_date.desc(), Procurement.end_date.desc()).all() for procurement in procurements: procurement_list.append(procurement.to_dict(include_related=True)) report['country'] = country.to_dict() report['medicines'] = calculate_country_overview(country) report['procurements'] = procurement_list report_json = json.dumps(report, cls=serializers.CustomEncoder) cache.store('country_overview_' + country.code, report_json) return send_api_response(report_json)
def get_source_choices(): source_choices = [] sources = models.Source.query.all() for source in sources: source_choices.append((source.source_id, str(source))) logger.debug(source_choices) return source_choices
def autocomplete(query): """ Return the name and medicine_id of each medicine that matches the given query. """ out = [] medicine_list_json = cache.retrieve('medicine_list') if medicine_list_json: logger.debug('calculating autocomplete from cache') medicine_list = json.loads(medicine_list_json) else: medicine_list = calculate_autocomplete() cache.store('medicine_list', json.dumps(medicine_list, cls=serializers.CustomEncoder)) for medicine in medicine_list: tmp = {} query_index = medicine['name'].lower().find(query.lower()) if query_index > -1: tmp['medicine_id'] = medicine['medicine_id'] tmp['name'] = medicine['name'] tmp['index'] = query_index out.append(tmp) if len(out) > 20: break out = sorted(out, key=itemgetter('index')) if len(out) > 10: out = out[0:10] return send_api_response(json.dumps(out))
def calculate_autocomplete(): """ Retrieve all medicine records and serialize them for use by the autocomplete endpoint. THIS IS slightly COMPUTATIONALLY EXPENSIVE """ cutoff = datetime.datetime.today() - datetime.timedelta(days=MAX_AGE) logger.debug("Calculating autocomplete") # medicines = Medicine.query.order_by(Medicine.name).all() procurements = Procurement.query.join(Product).filter( or_( Procurement.start_date > cutoff, Procurement.end_date > cutoff ) ).filter( Procurement.approved != False ).all() medicines = [] for procurement in procurements: if not procurement.product.medicine in medicines: medicines.append(procurement.product.medicine) out = [] for medicine in medicines: tmp_dict = { 'name': medicine.name, 'medicine_id': medicine.medicine_id, } out.append(tmp_dict) return out
def revoke_token(access_token): h = Http(disable_ssl_certificate_validation=True) logger.debug('revoking %s' % access_token) resp, cont = h.request( 'https://accounts.google.com/o/oauth2/revoke?token=%s' % access_token, headers={ 'Host': 'www.googleapis.com', 'Authorization': 'Bearer %s' % access_token }) return resp
def country_ranking(): """ """ ranking_json = cache.retrieve('country_ranking') if ranking_json: logger.debug('loading country ranking from cache') else: ranking = calculate_country_rankings() ranking_json = json.dumps(ranking) cache.store('country_ranking', ranking_json) return send_api_response(ranking_json)
def overview(): """ Give a broad overview of the size of -, and recent activity related to, the database. """ tmp = cache.retrieve('db_overview') if tmp: logger.debug("DB overview served from cache") return send_api_response(tmp) else: tmp = calculate_db_overview() cache.store('db_overview', json.dumps(tmp, cls=serializers.CustomEncoder)) return send_api_response(json.dumps(tmp))
def calculate_country_rankings(): """ THIS IS COMPUTATIONALLY EXPENSIVE """ logger.debug("Calculating country rankings") ranking = {} for country_code in available_countries.keys(): ranking[country_code] = { 'score': 0, 'overall_spend': 0, 'potential_savings': 0, } # iterate through all medicines in the db medicines = Medicine.query.order_by(Medicine.name).all() for medicine in medicines: # serialize medicine, so that procurements may be ordered medicine_dict = medicine.to_dict(include_related=True) procurements = medicine_dict['procurements'] if not procurements: continue # calculate the total spend and potential savings for each transaction best_price = procurements[0]['unit_price_usd'] benchmarks = medicine_dict['benchmarks'] for benchmark in benchmarks: if benchmark['price'] < best_price: best_price = benchmark['price'] for procurement in procurements: if ranking.get(procurement['country']['code']): total = procurement['quantity'] * procurement['pack_price_usd'] tmp_diff = procurement['unit_price_usd'] - best_price potential_saving = procurement['quantity'] * procurement['pack_size'] * tmp_diff ranking[procurement['country']['code']]['overall_spend'] += total ranking[procurement['country']['code']]['potential_savings'] += potential_saving # score countries by how close their spend is to the theoretical best ranked_list = [] for country_code, entry in ranking.iteritems(): if entry['overall_spend']: entry['score'] = 1 - (entry['potential_savings']/float(entry['overall_spend'])) entry['country'] = Country.query.filter_by(code=country_code).one().to_dict() ranked_list.append(entry) ranked_list = sorted(ranked_list, key=itemgetter("score")) ranked_list.reverse() out = {'count': len(ranked_list), 'countries': ranked_list} return out
def calculate_country_overview(country): """ THIS IS COMPUTATIONALLY EXPENSIVE """ logger.debug("Calculating country overview") # iterate through all medicines in the db medicines = Medicine.query.order_by(Medicine.name).all() medicines_out = [] for medicine in medicines: tmp = { 'score': 0, 'overall_spend': 0, 'potential_savings': 0, } # serialize medicine, so that procurements may be ordered medicine_dict = medicine.to_dict(include_related=True) procurements = medicine_dict['procurements'] if not procurements: continue # calculate the total spend and potential savings for each transaction best_price = procurements[0]['unit_price_usd'] benchmarks = medicine_dict['benchmarks'] for benchmark in benchmarks: if benchmark['price'] < best_price: best_price = benchmark['price'] for procurement in procurements: if procurement['country']['code']==country.code: total = procurement['quantity'] * procurement['pack_price_usd'] tmp_diff = procurement['unit_price_usd'] - best_price potential_saving = procurement['quantity'] * procurement['pack_size'] * tmp_diff tmp['overall_spend'] += total tmp['potential_savings'] += potential_saving if tmp['overall_spend'] and tmp['overall_spend'] > 1000: tmp['name'] = medicine.name tmp['medicine_id'] = medicine.medicine_id tmp['score'] = 1 - (tmp['potential_savings']/float(tmp['overall_spend'])) medicines_out.append(tmp) # score medicines by how close their spend is to the theoretical best medicines_out = sorted(medicines_out, key=itemgetter("potential_savings")) medicines_out.reverse() return medicines_out
def get(self, user): """Search stack by query param. Query is passed by 'q' URL param..""" query = { "sort": [{ "last_activity": { "order": "desc" } }], "query": { "query_string": { "query": request.args.get('q') } } } logger.debug('query %s' % query) return repository.search_data_by_query(index=index, doc_type=doc_type, query=query)
def calculate_db_overview(): """ Run a set of queries to get an overview of the database. THIS IS COMPUTATIONALLY EXPENSIVE """ logger.debug("Calculating DB overview") overview = {} # number of recent products & medicines count_procurements, count_products, count_medicines = Procurement.query.join(Product).filter( Procurement.approved != False ).with_entities( func.count(Procurement.procurement_id), func.count(distinct(Procurement.product_id)), func.count(distinct(Product.medicine_id)) ).first() overview['count_procurements'] = count_procurements overview['count_products'] = count_products overview['count_medicines'] = count_medicines # number of recent procurements logged per country top_sources = [] sources = db.session.query(Procurement.country_id, func.count(Procurement.procurement_id)) \ .filter( Procurement.approved != False ).group_by(Procurement.country_id) \ .order_by(func.count(Procurement.procurement_id).desc()).all() for country_id, count in sources[0:5]: print 'Country ID %d: %d' % (country_id, count) country = Country.query.get(country_id) top_sources.append( { 'country': country.to_dict(), 'procurement_count': count } ) overview['top_sources'] = top_sources return overview
def try_dispach_whti_refresh_token(fn, *args, **kwargs): json_web_token = parse_token_no_validade(request) logger.debug('=== Trying to refresh access_token') if 'refresh_token' in json_web_token['user']: refresh_token = json_web_token['user']['refresh_token'] logger.debug('=== Refresh access_token using %s' % refresh_token) new_token = refresh_access_token(refresh_token) logger.debug('=== Getting user by access_token') user = validate_token(new_token['access_token']) if user is not None: return fn(user=user, *args, **kwargs) else: logger.debug('=== Refresh access_token not work')
def refresh_access_token(refresh_token): """"Refresh access_token""" payload = dict(grant_type='refresh_token', client_id=app.config['GOOGLE_CLIENT_ID'], client_secret=app.config['GOOGLE_CLIENT_SECRET'], refresh_token=refresh_token) # h = Http(disable_ssl_certificate_validation=True) # resp, cont = h.request( # "https://www.googleapis.com/oauth2/v3/userinfo", # method='POST', # body=json.dumps(payload), # ) logger.debug(payload) headers = {'Content-Type': 'application/x-www-form-urlencoded'} r = requests.post("https://accounts.google.com/o/oauth2/token", data=payload, headers=headers) logger.debug('=====> %s' % r.status_code) if not r.status_code == 200: return None logger.debug(r.text) return json.loads(r.text)
def post(self): """Autenticate google user account. Expect a request json with clientId, redirectUri and code attributes. Samples: { 'clientId': your-google-client-id, 'code': '4/xHYKb3CD9gbiXBiL2XPaj_ILlMjXTJbVmBTFCVGBjKo', 'accessType': 'offline', 'redirectUri': u'http://localhost:8080' } """ access_token_url = 'https://www.googleapis.com/oauth2/v4/token' people_api_url = 'https://www.googleapis.com/oauth2/v3/userinfo' tokeninfo_url = 'https://www.googleapis.com/oauth2/v3/tokeninfo' logger.debug('google request =>') logger.debug(request.json) payload = dict(client_id=request.json['clientId'], redirect_uri=request.json['redirectUri'], client_secret=app.config['GOOGLE_CLIENT_SECRET'], code=request.json['code'], grant_type='authorization_code') logger.debug('Google Payload =>') logger.debug(payload) # Step 2. Exchange authorization code for access token. r = requests.post(access_token_url, data=payload) token = json.loads(r.text) logger.debug('Access Token =>') logger.debug(token) # Step 2. Retrieve information about the current user. headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])} r = requests.get(people_api_url, headers=headers) profile = json.loads(r.text) logger.info('Login as => %s' % profile['email']) logger.debug(profile) if security.is_valid_email(profile['email']): # Step 4. Create a new account or return an existing one. r = requests.get('%s?access_token=%s' % (tokeninfo_url, token['access_token'])) token_info = json.loads(r.text) logger.debug('Tokeninfo =>') logger.debug(token_info) # Step 5. Sign-up a user process account = {} try: account = repository.get_document( index=index, doc_type=doc_type, id=profile['sub']) # update refresh_token if it was informed (after revoke token) logger.debug('Account found for %s' % profile['email']) if 'refresh_token' in token: logger.debug('A new refresh_token was defined. It will be updated') repository.update( index=index, doc_type=doc_type, id=profile['sub'], body={"doc": {"refresh_token": token['refresh_token']}} ) # if extits, profile will be the accound founded # profile['refresh_token'] = account["_source"]['refresh_token'] except NotFoundError as e: # create a new user if not exists one account logger.warning('First logging for %s' % profile['email']) account = profile.copy() account['created_at'] = datetime.utcnow() if 'refresh_token' in token: account['refresh_token'] = token['refresh_token'] repository.insert(index=index, doc_type=doc_type, login=account['sub'], document=account) # Step 6. Build and return a json web token. jwt_payload = { 'sub': profile['sub'], 'iat': datetime.utcnow(), 'exp': datetime.utcnow() + timedelta(days=5), 'access_token':token['access_token'], 'user': profile } jwt = security.create_token(jwt_payload) return jsonify(token=jwt) # return jsonify(token=token['access_token']) else: return security.response_not_authorized( 403, 'Invalid email domain. Please sign with ciandt.com acccount' )
def decorated_function(*args, **kwargs): logger.debug('=== Authorization check ===') if 'Authorization' in request.headers: logger.debug('=== Check Authorization token') access_token = request.headers.get('Authorization').split()[1] user = validate_token(access_token) if user is not None: return fn(user=user, *args, **kwargs) response = jsonify(message='Check access token failed') response.status_code = 403 return response # try parser json web token if 'jwt-authorization' in request.headers: logger.debug('=== Check JWT Authorization') try: json_web_token = parse_token(request) if 'user' in json_web_token: logger.debug("Getting user from JWT TOKEN ===>") return fn(user=json_web_token['user'], *args, **kwargs) access_token = get_oauth_token(json_web_token) logger.debug('=== access_token: %s' % access_token) logger.debug( '=== Getting user data from google by access_token') user = validate_token(access_token) if user is not None: return fn(user=user, *args, **kwargs) response = jsonify(message='Check access token failed') response.status_code = 403 return response except DecodeError: response = jsonify(message='Token is invalid') response.status_code = 401 return response except ExpiredSignature: # try_dispach_whti_refresh_token(fn, *args, **kwargs) response = jsonify(message='JSON Web Token has expired') response.status_code = 403 return response response = jsonify(message='Missing authorization header') response.status_code = 401 return response