diff --git a/schema.json b/schema.json index 87e6d79..4fa646f 100644 --- a/schema.json +++ b/schema.json @@ -267,6 +267,36 @@ ] } }, + { + "description": "Match a user to their phone and email", + "method": "POST", + "href": "/v1/voters/contact_search", + "title": "search", + "rel": "matches", + "schema": { + "properties": { + "phone": { + "type": [ + "string" + ] + }, + "email": { + "type": [ + "string" + ] + }, + "max_matches": { + "type": [ + "integer" + ], + "minimum": 0 + } + }, + "type": [ + "object" + ] + } + }, { "description": "Find a user by ID", "method": "GET", diff --git a/schema/voters.json b/schema/voters.json index 44e5b67..d4895cf 100644 --- a/schema/voters.json +++ b/schema/voters.json @@ -72,6 +72,24 @@ "required": ["user"] } }, + { + "description": "Match a user to their phone and email", + "method": "POST", + "href": "/v1/voters/contact_search", + "title": "search", + "rel": "matches", + "schema": { + "properties": { + "phone": { "type": "string" }, + "email": { "type": "string" }, + "max_matches": { + "type": "integer", + "minimum": 0 + } + }, + "type": ["object"] + } + }, { "description": "Find a user by ID", "method": "GET", diff --git a/web.py b/web.py index 3ed463f..83fd473 100644 --- a/web.py +++ b/web.py @@ -4,6 +4,7 @@ from jsonschema import Draft4Validator from pyelasticsearch import ElasticHttpNotFoundError from raven import Client as RavenClient +from sets import Set import json import os @@ -206,6 +207,35 @@ def find_voter(id): return json.dumps(rec), 200, {'Content-Type': 'application/json'} +@app.route('/v1/voters/contact_search', methods=['POST']) +@validate_api_request +def contact_search(params): + """ Match voter records by name, phone and email """ + max_matches = params.get('max_matches', 100) + email = params.get('email', '') + phone = params.get('phone', '') + + email_hits = lookup_by_email(email, max_matches) if email else [] + phone_hits = lookup_by_phone(phone, max_matches) if phone else [] + + hits = [] + if not phone: + hits = email_hits + elif not email: + hits = phone_hits + else: + # both email and phone were specified - take the intersection of their matches + phone_ids = Set([hit['id'] for hit in phone_hits]) + hits = [ hit for hit in email_hits if hit['id'] in phone_ids] + + resp = json.dumps({'data': hits, 'num_results': len(hits), 'max_matches': max_matches}, + sort_keys=True, + indent=4, + separators=(',', ': ')) + + return resp, 200, {'Content-Type': 'application/json'} + + @app.route('/v1/voters/search', methods=['POST']) @statsd.timed('verifier.response_time.voters_search', tags=['revision:v1']) @validate_api_request