def test_rank_and_order(self): res = [ TestPerson(first_name='Bryan', last_name='abc'), TestPerson(first_name='Bryan', last_name='abcef'), TestPerson(first_name='abc', last_name='Bryan'), TestPerson(first_name='Bryan abc', last_name='efg') ] sorted = indexing.rank_and_order(res, TextQuery('Bryan abc'), 100) assert ['%s %s'%(p.first_name, p.last_name) for p in sorted] == \ ['Bryan abc', 'abc Bryan', 'Bryan abc efg', 'Bryan abcef'] sorted = indexing.rank_and_order(res, TextQuery('Bryan abc'), 2) assert ['%s %s'%(p.first_name, p.last_name) for p in sorted] == \ ['Bryan abc', 'abc Bryan'] sorted = indexing.rank_and_order(res, TextQuery('abc Bryan'), 100) assert ['%s %s'%(p.first_name, p.last_name) for p in sorted] == \ ['abc Bryan', 'Bryan abc', 'Bryan abc efg', 'Bryan abcef'] res = [ TestPerson(first_name='abc', last_name='efg'), TestPerson(first_name='ABC', last_name='EFG'), TestPerson(first_name='ABC', last_name='efghij') ] sorted = indexing.rank_and_order(res, TextQuery('abc'), 100) assert ['%s %s'%(p.first_name, p.last_name) for p in sorted] == \ ['abc efg', 'ABC EFG', 'ABC efghij']
def get(self): if self.config.search_auth_key_required and not ( self.auth and self.auth.search_permission): self.info(403, message='Missing or invalid authorization key', style='plain') return pfif_version = self.params.version # Retrieve parameters and do some sanity checks on them. record_id = self.request.get('id') query_string = self.request.get('q') max_results = min(self.params.max_results or 100, HARD_MAX_RESULTS) results = [] if record_id: # Search by record ID (always returns just 1 result or nothing). person = model.Person.get(self.repo, record_id) if person: results = [person] elif query_string: # Search by query words. if self.config.external_search_backends: query = TextQuery(query_string) results = external_search.search( self.repo, query, max_results, self.config.external_search_backends) # External search backends are not always complete. Fall back to # the original search when they fail or return no results. if not results: if config.get('enable_fulltext_search'): results = full_text_search.search(self.repo, query_string, max_results) else: results = indexing.search(self.repo, TextQuery(query_string), max_results) else: self.info(400, message='Neither id nor q parameter specified', style='plain') records = [pfif_version.person_to_dict(result) for result in results] utils.optionally_filter_sensitive_fields(records, self.auth) # Define the function to retrieve notes for a person. def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.repo, person['person_record_id']) notes = [note for note in notes if not note.hidden] records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) return records self.response.headers[ 'Content-Type'] = 'application/xml; charset=utf-8' pfif_version.write_file(self.response.out, records, get_notes_for_person) utils.log_api_action(self, ApiActionLog.SEARCH, len(records))
def test_rank_and_order(self): res = [ create_person( given_name='Bryan', family_name='abc', ), create_person(given_name='Bryan', family_name='abcef'), create_person(given_name='abc', family_name='Bryan'), create_person(given_name='Bryan abc', family_name='efg') ] sorted = indexing.rank_and_order(res, TextQuery('Bryan abc'), 100) assert ['%s %s'%(p.given_name, p.family_name) for p in sorted] == \ ['Bryan abc', 'abc Bryan', 'Bryan abc efg', 'Bryan abcef'] sorted = indexing.rank_and_order(res, TextQuery('Bryan abc'), 2) assert ['%s %s'%(p.given_name, p.family_name) for p in sorted] == \ ['Bryan abc', 'abc Bryan'] sorted = indexing.rank_and_order(res, TextQuery('abc Bryan'), 100) assert ['%s %s'%(p.given_name, p.family_name) for p in sorted] == \ ['abc Bryan', 'Bryan abc', 'Bryan abc efg', 'Bryan abcef'] res = [ create_person(given_name='abc', family_name='efg'), create_person(given_name='ABC', family_name='EFG'), create_person(given_name='ABC', family_name='efghij') ] sorted = indexing.rank_and_order(res, TextQuery('abc'), 100) assert ['%s %s'%(p.given_name, p.family_name) for p in sorted] == \ ['abc efg', 'ABC EFG', 'ABC efghij']
def search(self, query_txt): """Performs a search and adds view_url attributes to the results.""" results = None if self.config.external_search_backends: results = external_search.search( self.repo, TextQuery(query_txt), MAX_RESULTS, self.config.external_search_backends) # External search backends are not always complete. Fall back to the # original search when they fail or return no results. if not results: if config.get('enable_fulltext_search'): results = full_text_search.search(self.repo, query_txt, MAX_RESULTS) else: results = indexing.search(self.repo, TextQuery(query_txt), MAX_RESULTS) for result in results: result.view_url = self.get_url('/view', id=result.record_id, role=self.params.role, query=self.params.query, given_name=self.params.given_name, family_name=self.params.family_name) result.latest_note_status = get_person_status_text(result) if result.is_clone(): result.provider_name = result.get_original_domain() result.should_show_inline_photo = (self.should_show_inline_photo( result.photo_url)) sanitize_urls(result) return results
def set_ranking_attr(self, person): """Consider save these into to db""" if not hasattr(person, '_normalized_given_name'): person._normalized_given_name = TextQuery(person.given_name) person._normalized_family_name = TextQuery(person.family_name) person._normalized_full_name = TextQuery(person.full_name) person._name_words = set(person._normalized_full_name.words) person._alt_name_words = set( TextQuery(person.alternate_names).words)
def search(self, query_name, query_location=None): """Get results for a query. Args: query_name: A name to query for (string). query_location: A location to query for (optional, string). """ text_query = TextQuery( '%s %s' % (query_name, query_location) if query_location else query_name) results = None if self._external_search_backends: results = external_search.search(self._repo, text_query, self._max_results, self._external_search_backends) # External search backends are not always complete. Fall back to the # original search when they fail or return no results. if not results: query_dict = {'name': query_name} if query_location: query_dict['location'] = query_location if self._enable_fulltext_search: results = full_text_search.search(self._repo, query_dict, self._max_results) else: results = indexing.search(self._repo, text_query, self._max_results) return results
def get(self): if self.config.search_auth_key_required and not ( self.auth and self.auth.search_permission): return self.error(403, 'Missing or invalid authorization key\n') pfif_version = pfif.PFIF_VERSIONS.get(self.params.version or '1.2') # Retrieve parameters and do some sanity checks on them. query_string = self.request.get("q") subdomain = self.request.get("subdomain") max_results = min(self.params.max_results or 100, HARD_MAX_RESULTS) if not query_string: return self.error(400, 'Missing q parameter') if not subdomain: return self.error(400, 'Missing subdomain parameter') # Perform the search. results = indexing.search(Person.all_in_subdomain(subdomain), TextQuery(query_string), max_results) records = [pfif_version.person_to_dict(result) for result in results] utils.optionally_filter_sensitive_fields(records, self.auth) # Define the function to retrieve notes for a person. def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.subdomain, person['person_record_id']) records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) return records self.response.headers['Content-Type'] = 'application/xml' pfif_version.write_file(self.response.out, records, get_notes_for_person)
def update_index_properties(entity): """Finds and updates all prefix-related properties on the given entity.""" # Using set to make sure I'm not adding the same string more than once. names_prefixes = set() for property in entity._fields_to_index_properties: for value in TextQuery(getattr(entity, property)).query_words: if property in entity._fields_to_index_by_prefix_properties: for n in xrange(1, len(value) + 1): pref = value[:n] if pref not in names_prefixes: names_prefixes.add(pref) else: if value not in names_prefixes: names_prefixes.add(value) # Add alternate names to the index tokens. We choose not to index prefixes # of alternate names so that we can keep the index size small. # TODI(ryok): This strategy works well for Japanese, but how about other # languages? names_prefixes |= get_alternate_name_tokens(entity) # Put a cap on the number of tokens, just as a precaution. MAX_TOKENS = 100 entity.names_prefixes = list(names_prefixes)[:MAX_TOKENS] if len(names_prefixes) > MAX_TOKENS: logging.debug('MAX_TOKENS exceeded for %s' % ' '.join(list(names_prefixes)))
def search(self, query_dict): """ Performs a search and adds view_url attributes to the results. Args: query_dict: A list contains two queries: Name query and Location query """ query_txt = " ".join(query_dict.values()) results = None if self.config.external_search_backends: results = external_search.search( self.repo, TextQuery(query_txt), MAX_RESULTS, self.config.external_search_backends) # External search backends are not always complete. Fall back to the # original search when they fail or return no results. if not results: if config.get('enable_fulltext_search'): results = full_text_search.search(self.repo, query_dict, MAX_RESULTS) else: results = indexing.search(self.repo, TextQuery(query_txt), MAX_RESULTS) query_name = self.get_query_value() for result in results: result.view_url = self.get_url('/view', id=result.record_id, role=self.params.role, query_name=query_name, query_location= self.params.query_location, given_name=self.params.given_name, family_name=self.params.family_name) result.latest_note_status = get_person_status_text(result) if result.is_clone(): result.provider_name = result.get_original_domain() result.should_show_inline_photo = ( self.should_show_inline_photo(result.photo_url)) if result.should_show_inline_photo and result.photo: # Only use a thumbnail URL if the photo was uploaded; we don't # have thumbnails for other photos. result.thumbnail_url = self.get_thumbnail_url(result.photo_url) sanitize_urls(result) return results
def test_search(self): persons = [ TestPerson(first_name='Bryan', last_name='abc'), TestPerson(first_name='Bryan', last_name='abcef'), TestPerson(first_name='abc', last_name='Bryan'), TestPerson(first_name='Bryan abc', last_name='efg'), TestPerson(first_name='AAAA BBBB', last_name='CCC DDD') ] for p in persons: indexing.update_index_properties(p) db.put(p) res = indexing.search(TestPerson.all(), TextQuery('Bryan abc'), 1) assert [(p.first_name, p.last_name) for p in res] == [('Bryan', 'abc')] res = indexing.search(TestPerson.all(), TextQuery('CC AAAA'), 100) assert [(p.first_name, p.last_name) for p in res] == \ [('AAAA BBBB', 'CCC DDD')]
def test_search(self): persons = [ create_person(given_name='Bryan', family_name='abc'), create_person(given_name='Bryan', family_name='abcef'), create_person(given_name='abc', family_name='Bryan'), create_person(given_name='Bryan abc', family_name='efg'), create_person(given_name='AAAA BBBB', family_name='CCC DDD') ] for p in persons: indexing.update_index_properties(p) db.put(p) res = indexing.search('test', TextQuery('Bryan abc'), 1) assert [(p.given_name, p.family_name) for p in res] == [('Bryan', 'abc')] res = indexing.search('test', TextQuery('CC AAAA'), 100) assert [(p.given_name, p.family_name) for p in res] == \ [('AAAA BBBB', 'CCC DDD')]
def search(self, query_name, query_location=None): """Get results for a query. Args: query_name: A name to query for (string). query_location: A location to query for (optional, string). """ if self._enable_fulltext_search: query_dict = {'name': query_name} if query_location: query_dict['location'] = query_location return full_text_search.search(self._repo, query_dict, self._max_results) else: text_query = TextQuery( '%s %s' % (query_name, query_location) if query_location else query_name) return indexing.search(self._repo, text_query, self._max_results)
def get(self): create_url = self.get_url( '/create', ui='' if self.env.ui == 'small' else self.env.ui, role=self.params.role, given_name=self.params.given_name, family_name=self.params.family_name) min_query_word_length = self.config.min_query_word_length third_party_search_engines = [] for i, search_engine in enumerate( self.config.third_party_search_engines or []): third_party_search_engines.append({ 'id': i, 'name': search_engine.get('name', '') }) if self.params.role == 'provide': # The order of family name and given name does matter (see the # scoring function in indexing.py). query_txt = get_full_name(self.params.given_name, self.params.family_name, self.config) query = TextQuery(query_txt) results_url = self.get_results_url(query_txt, '') # Ensure that required parameters are present. if not self.params.given_name: return self.reject_query(query) if self.config.use_family_name and not self.params.family_name: return self.reject_query(query) if (len(query.query_words) == 0 or max_word_length( query.query_words) < min_query_word_length): return self.reject_query(query) # Look for *similar* names, not prefix matches. # Eyalf: we need to full query string # for key in criteria: # criteria[key] = criteria[key][:3] # "similar" = same first 3 letters results = self.search({'name': query_txt}) # Filter out results with addresses matching part of the query. results = [ result for result in results if not getattr(result, 'is_address_match', False) ] if results: # Perhaps the person you wanted to report has already been # reported? return self.render( 'results.html', results=results, num_results=len(results), has_possible_duplicates=has_possible_duplicates(results), results_url=results_url, create_url=create_url, third_party_search_engines=third_party_search_engines, query_name=self.params.query_name, query_location=self.params.query_location, ) else: if self.env.ui == 'small': # show a link to a create page. return self.render('small-create.html', create_url=create_url) else: # No matches; proceed to create a new record. logging.info(repr(self.params.__dict__)) return self.redirect('/create', **self.params.__dict__) if self.params.role == 'seek': query_dict = { 'name': self.params.query_name, 'location': self.params.query_location } self.params.query = " ".join(q for q in query_dict.values() if q) query = TextQuery(self.params.query) results_based_on_input = True # If a query looks like a phone number, show the user a result # of looking up the number in the carriers-provided BBS system. if self.config.jp_mobile_carrier_redirect: try: if jp_mobile_carriers.handle_phone_number( self, query.query): return except Exception as e: logging.exception( 'failed to scrape search result for the phone number.') return self.error( 500, _('Failed to obtain search result ' 'for the phone number.')) if is_possible_phone_number(query.query): # If the query looks like a phone number, we show an empty # result page instead of rejecting it. We don't support # search by phone numbers, but third party search engines # may support it. results = [] results_url = None third_party_query_type = 'tel' elif (len(query.query_words) == 0 or max_word_length(query.query_words) < min_query_word_length): logging.info('rejecting %s' % query.query) return self.reject_query(query) else: # Look for prefix matches. results = self.search(query_dict) results_url = self.get_results_url(self.params.query_name, self.params.query_location) third_party_query_type = '' query_location = self.params.query_location # If there is no results match for both name and location # Check if there have results match for name if not results: if self.params.query_location: query_dict = { 'name': self.params.query_name, 'location': '' } results = self.search(query_dict) # search result not based on the user input results_based_on_input = False query_location = '' # Show the (possibly empty) matches. return self.render( 'results.html', results=results, num_results=len(results), has_possible_duplicates=has_possible_duplicates(results), results_url=results_url, create_url=create_url, third_party_search_engines=third_party_search_engines, query_name=self.params.query_name, query_location_original=self.params.query_location, query_location=query_location, third_party_query_type=third_party_query_type, results_based_on_input=results_based_on_input)
def post(self): if not (self.auth and self.auth.search_permission): self.info( 403, message='"key" URL parameter is either missing, invalid or ' 'lacks required permissions. The key\'s repo must be "*" ' 'and search_permission must be True.', style='plain') return body = self.request.body_file.read() doc = xml.dom.minidom.parseString(body) message_text = self.get_element_text(doc, 'message_text') receiver_phone_number = self.get_element_text(doc, 'receiver_phone_number') if message_text is None: self.info(400, message='message_text element is required.', style='plain') return if receiver_phone_number is None: self.info(400, message='receiver_phone_number element is required.', style='plain') return repo = (self.config.sms_number_to_repo and self.config.sms_number_to_repo.get(receiver_phone_number)) if not repo: self.info( 400, message='The given receiver_phone_number is not found in ' 'sms_number_to_repo config.', style='plain') return responses = [] m = re.search(r'^search\s+(.+)$', message_text.strip(), re.I) if m: query_string = m.group(1).strip() query = TextQuery(query_string) persons = indexing.search(repo, query, HandleSMS.MAX_RESULTS) if persons: for person in persons: responses.append(self.render_person(person)) else: responses.append('No results found for: %s' % query_string) responses.append('More at: google.org/personfinder/%s?ui=light' % repo) responses.append( 'All data entered in Person Finder is available to the public ' 'and usable by anyone. Google does not review or verify the ' 'accuracy of this data google.org/personfinder/global/tos.html' ) else: responses.append('Usage: Search John') self.response.headers['Content-Type'] = 'application/xml' self.write('<?xml version="1.0" encoding="utf-8"?>\n' '<response>\n' ' <message_text>%s</message_text>\n' '</response>\n' % django.utils.html.escape(' ## '.join(responses)))
def get(self): params = { 'role': self.params.role, 'given_name': self.params.given_name, 'family_name': self.params.family_name, } # Links to the default UI from the small UI. Otherwise preserves "ui" # param of the current page. Note that get_url() preserves "ui" param # by default (i.e., when it's not specified in +params+). if self.env.ui == 'small': params['ui'] = None create_url = self.get_url('/create', **params) min_query_word_length = self.config.min_query_word_length third_party_search_engines = [] for i, search_engine in enumerate( self.config.third_party_search_engines or []): third_party_search_engines.append({ 'id': i, 'name': search_engine.get('name', '') }) if self.params.role == 'provide': # The order of family name and given name does matter (see the # scoring function in indexing.py). query_txt = get_full_name(self.params.given_name, self.params.family_name, self.config) query = TextQuery(query_txt) results_url = self.get_results_url(query_txt, '') # Ensure that required parameters are present. if not self.params.given_name: return self.reject_query(query) if self.config.use_family_name and not self.params.family_name: return self.reject_query(query) if (len(query.query_words) == 0 or max_word_length( query.query_words) < min_query_word_length): return self.reject_query(query) # Look for *similar* names, not prefix matches. # Eyalf: we need to full query string # for key in criteria: # criteria[key] = criteria[key][:3] # "similar" = same first 3 letters results = self.search({'name': query_txt}) # Filter out results with addresses matching part of the query. results = [ result for result in results if not getattr(result, 'is_address_match', False) ] if results: # Perhaps the person you wanted to report has already been # reported? return self.render( 'results.html', results=results, num_results=len(results), has_possible_duplicates=has_possible_duplicates(results), results_url=results_url, create_url=create_url, third_party_search_engines=third_party_search_engines, query_name=self.get_query_value(), query_location=self.params.query_location, ) else: if self.env.ui == 'small': # show a link to a create page. return self.render('small-create.html', create_url=create_url) else: # No matches; proceed to create a new record. return self.redirect(create_url) if self.params.role == 'seek': # The query_name parameter was previously called "query", and we # continue to support it for third-parties that link directly to # search results pages. query_name = self.get_query_value() query_dict = { 'name': query_name, 'location': self.params.query_location } query = TextQuery(" ".join(q for q in query_dict.values() if q)) results_based_on_input = True # If a query looks like a phone number, show the user a result # of looking up the number in the carriers-provided BBS system. if self.config.jp_mobile_carrier_redirect: try: if jp_mobile_carriers.handle_phone_number( self, query.query): return except Exception as e: logging.exception( 'failed to scrape search result for the phone number.') return self.error( # Translators: An error message indicating that we # failed to obtain search result for the phone number # given by the user. 500, _('Failed to obtain search result ' 'for the phone number.')) if is_possible_phone_number(query.query): # If the query looks like a phone number, we show an empty # result page instead of rejecting it. We don't support # search by phone numbers, but third party search engines # may support it. results = [] results_url = None third_party_query_type = 'tel' elif (len(query.query_words) == 0 or max_word_length(query.query_words) < min_query_word_length): logging.info('rejecting %s' % query.query) return self.reject_query(query) else: # Look for prefix matches. results = self.search(query_dict) results_url = self.get_results_url(query_name, self.params.query_location) third_party_query_type = '' # If there is no results match for both name and location # Check if there have results match for name if not results: if self.params.query_location: query_dict = {'name': query_name, 'location': ''} results = self.search(query_dict) # search result not based on the user input results_based_on_input = False concatenated_query = (( '%s %s' % (query_name, self.params.query_location)).strip()) # Show the (possibly empty) matches. return self.render( 'results.html', results=results, num_results=len(results), has_possible_duplicates=has_possible_duplicates(results), results_url=results_url, create_url=create_url, third_party_search_engines=third_party_search_engines, query_name=query_name, query=concatenated_query, third_party_query_type=third_party_query_type, results_based_on_input=results_based_on_input)
def get_matches(self, query, limit=100): results = indexing.search(TestPerson.all(), TextQuery(query), limit) return [(p.first_name, p.last_name) for p in results]
def get_ranked(self, results, query, limit=100): ranked = indexing.rank_and_order(results, TextQuery(query), limit) return [(p.given_name, p.family_name) for p in results]
def get_matches(self, query, limit=100): results = indexing.search('test', TextQuery(query), limit) return [(p.given_name, p.family_name) for p in results]
def test_no_query_terms(self): # Regression test (this used to throw an exception). assert indexing.search('test', TextQuery(''), 100) == []
def get_alternate_name_tokens(person): """Returns alternate name tokens and their variations.""" tokens = set(TextQuery(person.alternate_names).query_words) # This is no-op for non-Japanese. tokens |= set(jautils.get_additional_tokens(tokens)) return tokens
def post(self): if not (self.auth and self.auth.search_permission and self.auth.domain_write_permission == '*'): self.info( 403, message='"key" URL parameter is either missing, invalid or ' 'lacks required permissions. The key\'s repo must be "*", ' 'search_permission must be True, and it must have write ' 'permission.', style='plain') return body = self.request.body_file.read() doc = xml.dom.minidom.parseString(body) message_text = self.get_element_text(doc, 'message_text') receiver_phone_number = self.get_element_text(doc, 'receiver_phone_number') if message_text is None: self.info(400, message='message_text element is required.', style='plain') return if receiver_phone_number is None: self.info(400, message='receiver_phone_number element is required.', style='plain') return repo = (self.config.sms_number_to_repo and self.config.sms_number_to_repo.get(receiver_phone_number)) if not repo: self.info( 400, message='The given receiver_phone_number is not found in ' 'sms_number_to_repo config.', style='plain') return responses = [] search_m = re.search(r'^search\s+(.+)$', message_text.strip(), re.I) add_self_m = re.search(r'^i am\s+(.+)$', message_text.strip(), re.I) if search_m: query_string = search_m.group(1).strip() query = TextQuery(query_string) persons = indexing.search(repo, query, HandleSMS.MAX_RESULTS) if persons: for person in persons: responses.append(self.render_person(person)) else: responses.append('No results found for: %s' % query_string) responses.append('More at: google.org/personfinder/%s?ui=light' % repo) responses.append( 'All data entered in Person Finder is available to the public ' 'and usable by anyone. Google does not review or verify the ' 'accuracy of this data google.org/personfinder/global/tos.html' ) elif self.config.enable_sms_record_input and add_self_m: name_string = add_self_m.group(1).strip() person = Person.create_original(repo, entry_date=utils.get_utcnow(), full_name=name_string, family_name='', given_name='') person.update_index(['old', 'new']) note = Note.create_original(repo, entry_date=utils.get_utcnow(), source_date=utils.get_utcnow(), person_record_id=person.record_id, author_name=name_string, author_made_contact=True, status='is_note_author', text=message_text) db.put(note) model.UserActionLog.put_new('add', note, copy_properties=False) person.update_from_note(note) db.put(person) model.UserActionLog.put_new('add', person, copy_properties=False) responses.append('Added record for found person: %s' % name_string) else: usage_str = 'Usage: "Search John"' if self.config.enable_sms_record_input: usage_str += ' OR "I am John"' responses.append(usage_str) self.response.headers['Content-Type'] = 'application/xml' self.write('<?xml version="1.0" encoding="utf-8"?>\n' '<response>\n' ' <message_text>%s</message_text>\n' '</response>\n' % django.utils.html.escape(' ## '.join(responses)))
def post(self): if not (self.auth and self.auth.search_permission and self.auth.domain_write_permission == '*'): self.info( 403, message= '"key" URL parameter is either missing, invalid or ' 'lacks required permissions. The key\'s repo must be "*", ' 'search_permission must be True, and it must have write ' 'permission with domain name "*".', style='plain') return body = self.request.body_file.read() doc = xml.dom.minidom.parseString(body) message_text = self.get_element_text(doc, 'message_text') receiver_phone_number = self.get_element_text( doc, 'receiver_phone_number') if message_text is None: self.info( 400, message='message_text element is required.', style='plain') return if receiver_phone_number is None: self.info( 400, message='receiver_phone_number element is required.', style='plain') return repo = ( self.config.sms_number_to_repo and self.config.sms_number_to_repo.get(receiver_phone_number)) if not repo: self.info( 400, message= 'The given receiver_phone_number is not found in ' 'sms_number_to_repo config.', style='plain') return query_lang = None query_action = None match = None for lang, action, regex in HandleSMS.QUERY_PATTERNS: match = re.search(regex, message_text.strip(), re.I) if match: query_lang = lang query_action = action break if query_lang: # Use the language for the following calls of _(). django_setup.activate(query_lang) responses = [] if query_action == 'search': query_string = match.group(1).strip() query = TextQuery(query_string) persons = indexing.search(repo, query, HandleSMS.MAX_RESULTS) if persons: for person in persons: responses.append(self.render_person(person)) else: responses.append( _('No results found for: %(query)s') % {'query': query_string}) responses.append( _('More at: %(url)s') % {'url': 'google.org/personfinder/%s?ui=light' % repo}) responses.append( _('All data entered in Person Finder is available to the ' 'public and usable by anyone. Google does not review or ' 'verify the accuracy of this data ' 'google.org/personfinder/global/tos')) elif self.config.enable_sms_record_input and query_action == 'add': name_string = match.group(1).strip() person = Person.create_original( repo, entry_date=utils.get_utcnow(), full_name=name_string, family_name='', given_name='') person.update_index(['old', 'new']) note = Note.create_original( repo, entry_date=utils.get_utcnow(), source_date=utils.get_utcnow(), person_record_id=person.record_id, author_name=name_string, author_made_contact=True, status='is_note_author', text=message_text) db.put(note) model.UserActionLog.put_new('add', note, copy_properties=False) person.update_from_note(note) db.put(person) model.UserActionLog.put_new('add', person, copy_properties=False) responses.append(_('Added a record for: %(person_name)s') % {'person_name': name_string}) else: usage_str = 'Usage: "Search John"' if self.config.enable_sms_record_input: usage_str += ' OR "I am John"' responses.append(usage_str) # Convert the response into ASCII because the SMS pipeline doesn't # support UTF-8. # e.g., It removes diacritics such as "ú" -> "u". # This seems acceptable for Spanish, but may not be for other # languages. ascii_response = unidecode(u' ## '.join(responses)) self.response.headers['Content-Type'] = 'application/xml; charset=utf-8' self.write( '<?xml version="1.0" encoding="utf-8"?>\n' '<response>\n' ' <message_text>%s</message_text>\n' '</response>\n' % django.utils.html.escape(ascii_response))
def get(self): results_url = self.get_url('/results', small='no', query=self.params.query, first_name=self.params.first_name, last_name=self.params.last_name) create_url = self.get_url('/create', small='no', role=self.params.role, first_name=self.params.first_name, last_name=self.params.last_name) min_query_word_length = self.config.min_query_word_length if self.params.role == 'provide': query = TextQuery(self.params.first_name + ' ' + self.params.last_name) # Ensure that required parameters are present. if not self.params.first_name: return self.reject_query(query) if self.config.use_family_name and not self.params.last_name: return self.reject_query(query) if (len(query.query_words) == 0 or max(map(len, query.query_words)) < min_query_word_length): return self.reject_query(query) # Look for *similar* names, not prefix matches. # Eyalf: we need to full query string # for key in criteria: # criteria[key] = criteria[key][:3] # "similar" = same first 3 letters results = self.search(query) if results: # Perhaps the person you wanted to report has already been # reported? return self.render('templates/results.html', results=results, num_results=len(results), results_url=results_url, create_url=create_url) else: if self.params.small: # show a link to a create page. create_url = self.get_url('/create', query=self.params.query) return self.render('templates/small-create.html', create_url=create_url) else: # No matches; proceed to create a new record. logging.info(repr(self.params.__dict__)) return self.redirect('/create', **self.params.__dict__) if self.params.role == 'seek': query = TextQuery(self.params.query) # Ensure that required parameters are present. if (len(query.query_words) == 0 or max(map(len, query.query_words)) < min_query_word_length): logging.info('rejecting %s' % query.query) return self.reject_query(query) # Look for prefix matches. results = self.search(query) # Show the (possibly empty) matches. return self.render('templates/results.html', results=results, num_results=len(results), results_url=results_url, create_url=create_url)