예제 #1
0
    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']
예제 #2
0
    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))
예제 #3
0
    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']
예제 #4
0
    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
예제 #5
0
 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)
예제 #6
0
    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
예제 #7
0
    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)
예제 #8
0
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)))
예제 #9
0
    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
예제 #10
0
    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')]
예제 #11
0
    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')]
예제 #12
0
    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)
예제 #13
0
    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)
예제 #14
0
    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)))
예제 #15
0
    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)
예제 #16
0
 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]
예제 #17
0
 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]
예제 #18
0
 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]
예제 #19
0
 def test_no_query_terms(self):
     # Regression test (this used to throw an exception).
     assert indexing.search('test', TextQuery(''), 100) == []
예제 #20
0
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
예제 #21
0
    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)))
예제 #22
0
    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))
예제 #23
0
    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)